From ed63809963ef5a774d7ed5e207ae605926e1e3e2 Mon Sep 17 00:00:00 2001 From: Eric Date: Sat, 28 Dec 2019 21:23:56 -0800 Subject: [PATCH] =?UTF-8?q?ESP32=20CAM=20|=20Google=20Vision=20-=20[Part.7?= =?UTF-8?q?]=20AI=20Camera=F0=9F=93=B7=F0=9F=94=A5(Image=20labeling)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ESP32_CAM_ARDUINO/ESP32_CAM_ARDUINO.ino | 225 ++++++++ .../ESP32_CAM_ARDUINO/camera_pins.h | 99 ++++ .../VisionAPITest/package-lock.json | 508 +++++++++++++++++ .../VisionAPITest/resources/car.jpeg | Bin 0 -> 33951 bytes .../VisionAPITest/test.js | 35 ++ .../VisionServer/package-lock.json | 530 ++++++++++++++++++ .../VisionServer/server.js | 50 ++ 7 files changed, 1447 insertions(+) create mode 100644 ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/ESP32_CAM_ARDUINO.ino create mode 100644 ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/camera_pins.h create mode 100644 ESP32_CAM_AICamera_Labelling/VisionAPITest/package-lock.json create mode 100644 ESP32_CAM_AICamera_Labelling/VisionAPITest/resources/car.jpeg create mode 100644 ESP32_CAM_AICamera_Labelling/VisionAPITest/test.js create mode 100644 ESP32_CAM_AICamera_Labelling/VisionServer/package-lock.json create mode 100644 ESP32_CAM_AICamera_Labelling/VisionServer/server.js diff --git a/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/ESP32_CAM_ARDUINO.ino b/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/ESP32_CAM_ARDUINO.ino new file mode 100644 index 0000000..eaf3b77 --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/ESP32_CAM_ARDUINO.ino @@ -0,0 +1,225 @@ +#include "esp_camera.h" +#define CAMERA_MODEL_AI_THINKER +#include "camera_pins.h" +#include +#include +#include +#include +#include +#include + +#define GFXFF 1 +#define FSB9 &FreeSerifBold9pt7b + +TFT_eSPI tft = TFT_eSPI(); + +const char* ssid = "ESP32-THAT-PROJECT"; +const char* password = "California"; +const unsigned long timeout = 30000; // 30 seconds + +const int buttonPin = 4; // the number of the pushbutton pin +int buttonState; +int lastButtonState = LOW; +unsigned long lastDebounceTime = 0; // the last time the output pin was toggled +unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers +bool isNormalMode = true; + + +bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap) +{ + // Stop further decoding as image is running off bottom of screen + if ( y >= tft.height() ) return 0; + + // This function will clip the image block rendering automatically at the TFT boundaries + tft.pushImage(x, y, w, h, bitmap); + + // This might work instead if you adapt the sketch to use the Adafruit_GFX library + // tft.drawRGBBitmap(x, y, bitmap, w, h); + + // Return 1 to decode next block + return 1; +} + + + +void setup() { + Serial.begin(115200); + delay(1000); + + Serial.println(); + pinMode(buttonPin, INPUT); + + Serial.println("INIT DISPLAY"); + tft.begin(); + tft.setRotation(1); + tft.setTextColor(0xFFFF, 0x0000); + tft.fillScreen(TFT_YELLOW); + tft.setFreeFont(FSB9); + + TJpgDec.setJpgScale(1); + TJpgDec.setSwapBytes(true); + TJpgDec.setCallback(tft_output); + + Serial.println("INIT CAMERA"); + camera_config_t config; + config.ledc_channel = LEDC_CHANNEL_0; + config.ledc_timer = LEDC_TIMER_0; + config.pin_d0 = Y2_GPIO_NUM; + config.pin_d1 = Y3_GPIO_NUM; + config.pin_d2 = Y4_GPIO_NUM; + config.pin_d3 = Y5_GPIO_NUM; + config.pin_d4 = Y6_GPIO_NUM; + config.pin_d5 = Y7_GPIO_NUM; + config.pin_d6 = Y8_GPIO_NUM; + config.pin_d7 = Y9_GPIO_NUM; + config.pin_xclk = XCLK_GPIO_NUM; + config.pin_pclk = PCLK_GPIO_NUM; + config.pin_vsync = VSYNC_GPIO_NUM; + config.pin_href = HREF_GPIO_NUM; + config.pin_sscb_sda = SIOD_GPIO_NUM; + config.pin_sscb_scl = SIOC_GPIO_NUM; + config.pin_pwdn = PWDN_GPIO_NUM; + config.pin_reset = RESET_GPIO_NUM; + config.xclk_freq_hz = 10000000; + config.pixel_format = PIXFORMAT_JPEG; + //init with high specs to pre-allocate larger buffers + if(psramFound()){ + config.frame_size = FRAMESIZE_QVGA; // 320x240 + config.jpeg_quality = 10; + config.fb_count = 2; + } else { + config.frame_size = FRAMESIZE_SVGA; + config.jpeg_quality = 12; + config.fb_count = 1; + } + + + // camera init + esp_err_t err = esp_camera_init(&config); + if (err != ESP_OK) { + Serial.printf("Camera init failed with error 0x%x", err); + return; + } +} + +bool wifiConnect(){ + unsigned long startingTime = millis(); + WiFi.begin(ssid, password); + + while(WiFi.status() != WL_CONNECTED){ + delay(500); + if((millis() - startingTime) > timeout){ + return false; + } + } + return true; +} + +void buttonEvent(){ + int reading = digitalRead(buttonPin); + if (reading != lastButtonState) { + lastDebounceTime = millis(); + } + + if ((millis() - lastDebounceTime) > debounceDelay) { + if (reading != buttonState) { + buttonState = reading; + + if (buttonState == HIGH) { + isNormalMode = !isNormalMode; + + //Additional Code + if(!isNormalMode) + sendingImage(); + // + } + } + } + lastButtonState = reading; +} + +camera_fb_t* capture(){ + camera_fb_t *fb = NULL; + esp_err_t res = ESP_OK; + fb = esp_camera_fb_get(); + return fb; +} + +void showingImage(){ + camera_fb_t *fb = capture(); + if(!fb || fb->format != PIXFORMAT_JPEG){ + Serial.println("Camera capture failed"); + esp_camera_fb_return(fb); + return; + }else{ + TJpgDec.drawJpg(0,0,(const uint8_t*)fb->buf, fb->len); + esp_camera_fb_return(fb); + } +} + + +void parsingResult(String response){ + DynamicJsonDocument doc(1024); + deserializeJson(doc, response); + JsonArray array = doc.as(); + int yPos = 4; + for(JsonVariant v : array){ + JsonObject object = v.as(); + const char* description = object["description"]; + float score = object["score"]; + String label = ""; + label += description; + label += ":"; + label += score; + + tft.drawString(label, 8, yPos, GFXFF); + yPos += 16; + } +} + +void postingImage(camera_fb_t *fb){ + HTTPClient client; + client.begin("http://34.94.219.131:8888/imageUpdate"); + client.addHeader("Content-Type", "image/jpeg"); + int httpResponseCode = client.POST(fb->buf, fb->len); + if(httpResponseCode == 200){ + String response = client.getString(); + parsingResult(response); + }else{ + //Error + tft.drawString("Check Your Server!!!", 8, 4, GFXFF); + } + + client.end(); + WiFi.disconnect(); +} + +void sendingImage(){ + camera_fb_t *fb = capture(); + if(!fb || fb->format != PIXFORMAT_JPEG){ + Serial.println("Camera capture failed"); + esp_camera_fb_return(fb); + return; + }else{ + TJpgDec.drawJpg(0,0,(const uint8_t*)fb->buf, fb->len); + + tft.drawString("Wifi Connecting!", 8, 4, GFXFF); + + if(wifiConnect()){ + //tft.drawString("Wifi Connected!", 8, 4, GFXFF); + TJpgDec.drawJpg(0,0,(const uint8_t*)fb->buf, fb->len); + postingImage(fb); + }else{ + tft.drawString("Check Wifi credential!", 8, 4, GFXFF); + } + esp_camera_fb_return(fb); + } +} + +void loop() { + buttonEvent(); + + if(isNormalMode) + showingImage(); + +} diff --git a/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/camera_pins.h b/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/camera_pins.h new file mode 100644 index 0000000..7855722 --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/ESP32_CAM_ARDUINO/camera_pins.h @@ -0,0 +1,99 @@ + +#if defined(CAMERA_MODEL_WROVER_KIT) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 21 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 19 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 5 +#define Y2_GPIO_NUM 4 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_ESP_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 37 +#define Y7_GPIO_NUM 38 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 35 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 13 +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#elif defined(CAMERA_MODEL_M5STACK_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_WIDE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_AI_THINKER) +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 0 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 21 +#define Y4_GPIO_NUM 19 +#define Y3_GPIO_NUM 18 +#define Y2_GPIO_NUM 5 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#else +#error "Camera model not selected" +#endif diff --git a/ESP32_CAM_AICamera_Labelling/VisionAPITest/package-lock.json b/ESP32_CAM_AICamera_Labelling/VisionAPITest/package-lock.json new file mode 100644 index 0000000..c755282 --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/VisionAPITest/package-lock.json @@ -0,0 +1,508 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@google-cloud/promisify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", + "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==" + }, + "@google-cloud/vision": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@google-cloud/vision/-/vision-1.7.2.tgz", + "integrity": "sha512-Y3e8B2Ly7rGP4Z+93JGVQlngJtGCpFcXvOkiwT/NewjvGzaGjDedGMNX0AgphY17hYXj6fvgRn+ueEegr882qw==", + "requires": { + "@google-cloud/promisify": "^1.0.0", + "google-gax": "^1.7.5", + "is": "^3.2.1" + } + }, + "@grpc/grpc-js": { + "version": "0.6.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.6.15.tgz", + "integrity": "sha512-BFK5YMu8JILedibo0nr3NYM0ZC5hCZuXtzk10wEUp3d3pH11PjdvTfN1yEJ0VsfBY5Gtp3WOQ+t7Byq0NzH/iQ==", + "requires": { + "semver": "^6.2.0" + } + }, + "@grpc/proto-loader": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.3.tgz", + "integrity": "sha512-8qvUtGg77G2ZT2HqdqYoM/OY97gQd/0crSG34xNmZ4ZOsv3aQT/FQV9QfZPazTGna6MIoyUd+u6AxsoZjJ/VMQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@types/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", + "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" + }, + "@types/node": { + "version": "10.17.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", + "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, + "gaxios": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.2.0.tgz", + "integrity": "sha512-54Y7s3yvtEO9CZ0yBVQHI5fzS7TzkjlnuLdDEkeyL1SNYMv877VofvA56E/C3dvj3rS7GFiyMWl833Qrr+nrkg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^3.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.3.0.tgz", + "integrity": "sha512-uO3P/aByOQmoDu5bOYBODHmD1oDCZw7/R8SYY0MdmMQSZVEmeTSxmiM1vwde+YHYSpkaQnAAMAIZuOqLvgfp/Q==", + "requires": { + "gaxios": "^2.1.0", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.7.0.tgz", + "integrity": "sha512-uclMldsQNf64Qr67O8TINdnqbU/Ixv81WryX+sF9g7uP0igJ98aCR/uU399u1ABLa53LNsyji+bo+bP8/iL9dA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.2.0", + "gtoken": "^4.1.0", + "jws": "^3.1.5", + "lru-cache": "^5.0.0" + } + }, + "google-gax": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.12.0.tgz", + "integrity": "sha512-BeeoxVO6y9K20gUsexUwptutd0PfrTItrA02JWwwstlBIOAcvgFp86MHWufQsnrkPVhxBjHXq65aIkSejtJjDg==", + "requires": { + "@grpc/grpc-js": "^0.6.12", + "@grpc/proto-loader": "^0.5.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^3.6.0", + "google-auth-library": "^5.0.0", + "is-stream-ended": "^0.1.4", + "lodash.at": "^4.6.0", + "lodash.has": "^4.5.2", + "node-fetch": "^2.6.0", + "protobufjs": "^6.8.8", + "retry-request": "^4.0.0", + "semver": "^6.0.0", + "walkdir": "^0.4.0" + } + }, + "google-p12-pem": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.3.tgz", + "integrity": "sha512-Tq2kBCANxYYPxaBpTgCpRfdoPs9+/lNzc/Iaee4kuMVW5ascD+HwhpBsTLwH85C9Ev4qfB8KKHmpPQYyD2vg2w==", + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.3.tgz", + "integrity": "sha512-ofW+FiXjswyKdkjMcDbe6E4K7cDDdE82dGDhZIc++kUECqaE7MSErf6arJPAjcnYn1qxE1/Ti06qQuqgVusovQ==", + "requires": { + "gaxios": "^2.1.0", + "google-p12-pem": "^2.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0" + } + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.at": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz", + "integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } +} diff --git a/ESP32_CAM_AICamera_Labelling/VisionAPITest/resources/car.jpeg b/ESP32_CAM_AICamera_Labelling/VisionAPITest/resources/car.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..74421320e5c63bc96c484863781ec4aca6af8288 GIT binary patch literal 33951 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 Q>?I8Q30K={`z>1k+4QHO^8f$< literal 0 HcmV?d00001 diff --git a/ESP32_CAM_AICamera_Labelling/VisionAPITest/test.js b/ESP32_CAM_AICamera_Labelling/VisionAPITest/test.js new file mode 100644 index 0000000..1ac56c9 --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/VisionAPITest/test.js @@ -0,0 +1,35 @@ +// Copyright 2017 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +// [START vision_quickstart] +async function quickstart() { + // Imports the Google Cloud client library + const vision = require('@google-cloud/vision'); + + // Creates a client + const client = new vision.ImageAnnotatorClient(); + + // Performs label detection on the image file + const [result] = await client.labelDetection('./resources/car.jpeg'); + const labels = result.labelAnnotations; + console.log('Labels:'); + labels.forEach(label => { + console.log(label); + }); +} +// [END vision_quickstart] + +quickstart().catch(console.error); \ No newline at end of file diff --git a/ESP32_CAM_AICamera_Labelling/VisionServer/package-lock.json b/ESP32_CAM_AICamera_Labelling/VisionServer/package-lock.json new file mode 100644 index 0000000..b061f9b --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/VisionServer/package-lock.json @@ -0,0 +1,530 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@google-cloud/promisify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", + "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==" + }, + "@google-cloud/vision": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@google-cloud/vision/-/vision-1.7.2.tgz", + "integrity": "sha512-Y3e8B2Ly7rGP4Z+93JGVQlngJtGCpFcXvOkiwT/NewjvGzaGjDedGMNX0AgphY17hYXj6fvgRn+ueEegr882qw==", + "requires": { + "@google-cloud/promisify": "^1.0.0", + "google-gax": "^1.7.5", + "is": "^3.2.1" + } + }, + "@grpc/grpc-js": { + "version": "0.6.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.6.15.tgz", + "integrity": "sha512-BFK5YMu8JILedibo0nr3NYM0ZC5hCZuXtzk10wEUp3d3pH11PjdvTfN1yEJ0VsfBY5Gtp3WOQ+t7Byq0NzH/iQ==", + "requires": { + "semver": "^6.2.0" + } + }, + "@grpc/proto-loader": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.3.tgz", + "integrity": "sha512-8qvUtGg77G2ZT2HqdqYoM/OY97gQd/0crSG34xNmZ4ZOsv3aQT/FQV9QfZPazTGna6MIoyUd+u6AxsoZjJ/VMQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@types/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", + "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" + }, + "@types/node": { + "version": "10.17.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.13.tgz", + "integrity": "sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, + "file-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/file-match/-/file-match-1.0.2.tgz", + "integrity": "sha1-ycrSZdLIrfOoFHWw30dYWQafrvc=", + "requires": { + "utils-extend": "^1.0.6" + } + }, + "file-system": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/file-system/-/file-system-2.2.2.tgz", + "integrity": "sha1-fWWDPjojR9zZVqgTxncVPtPt2Yc=", + "requires": { + "file-match": "^1.0.1", + "utils-extend": "^1.0.4" + } + }, + "gaxios": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.2.0.tgz", + "integrity": "sha512-54Y7s3yvtEO9CZ0yBVQHI5fzS7TzkjlnuLdDEkeyL1SNYMv877VofvA56E/C3dvj3rS7GFiyMWl833Qrr+nrkg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^3.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.3.0.tgz", + "integrity": "sha512-uO3P/aByOQmoDu5bOYBODHmD1oDCZw7/R8SYY0MdmMQSZVEmeTSxmiM1vwde+YHYSpkaQnAAMAIZuOqLvgfp/Q==", + "requires": { + "gaxios": "^2.1.0", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.7.0.tgz", + "integrity": "sha512-uclMldsQNf64Qr67O8TINdnqbU/Ixv81WryX+sF9g7uP0igJ98aCR/uU399u1ABLa53LNsyji+bo+bP8/iL9dA==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.2.0", + "gtoken": "^4.1.0", + "jws": "^3.1.5", + "lru-cache": "^5.0.0" + } + }, + "google-gax": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.12.0.tgz", + "integrity": "sha512-BeeoxVO6y9K20gUsexUwptutd0PfrTItrA02JWwwstlBIOAcvgFp86MHWufQsnrkPVhxBjHXq65aIkSejtJjDg==", + "requires": { + "@grpc/grpc-js": "^0.6.12", + "@grpc/proto-loader": "^0.5.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^3.6.0", + "google-auth-library": "^5.0.0", + "is-stream-ended": "^0.1.4", + "lodash.at": "^4.6.0", + "lodash.has": "^4.5.2", + "node-fetch": "^2.6.0", + "protobufjs": "^6.8.8", + "retry-request": "^4.0.0", + "semver": "^6.0.0", + "walkdir": "^0.4.0" + } + }, + "google-p12-pem": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.3.tgz", + "integrity": "sha512-Tq2kBCANxYYPxaBpTgCpRfdoPs9+/lNzc/Iaee4kuMVW5ascD+HwhpBsTLwH85C9Ev4qfB8KKHmpPQYyD2vg2w==", + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.3.tgz", + "integrity": "sha512-ofW+FiXjswyKdkjMcDbe6E4K7cDDdE82dGDhZIc++kUECqaE7MSErf6arJPAjcnYn1qxE1/Ti06qQuqgVusovQ==", + "requires": { + "gaxios": "^2.1.0", + "google-p12-pem": "^2.0.0", + "jws": "^3.1.5", + "mime": "^2.2.0" + } + }, + "https-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz", + "integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==", + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "lodash.at": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz", + "integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-extend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/utils-extend/-/utils-extend-1.0.8.tgz", + "integrity": "sha1-zP17ZFQPjpDuIe7Fd2nQZRyril8=" + }, + "walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } +} diff --git a/ESP32_CAM_AICamera_Labelling/VisionServer/server.js b/ESP32_CAM_AICamera_Labelling/VisionServer/server.js new file mode 100644 index 0000000..db6bb3a --- /dev/null +++ b/ESP32_CAM_AICamera_Labelling/VisionServer/server.js @@ -0,0 +1,50 @@ +var fs = require('file-system'); +const http = require('http'); +const server = http.createServer(); +const filePath = './resources/test.jpeg'; + +server.on('request', (request, response)=>{ + if(request.method == 'POST' && request.url === "/imageUpdate"){ + + var ImageFile = fs.createWriteStream(filePath, {encoding: 'utf8'}); + request.on('data', function(data){ + ImageFile.write(data); + }); + + request.on('end',async function(){ + ImageFile.end(); + const labels = await labelAPI(); + response.writeHead(200, {'Content-Type' : 'application/json'}); + response.end(JSON.stringify(labels)); + }); + + + }else{ + console.log("error"); + response.writeHead(405, {'Content-Type' : 'text/plain'}); + response.end(); + } +}); + +async function labelAPI() { + // Imports the Google Cloud client library + const vision = require('@google-cloud/vision'); + + // Creates a client + const client = new vision.ImageAnnotatorClient(); + + // Performs label detection on the image file + const [result] = await client.labelDetection(filePath); + const labels = result.labelAnnotations; + var o = []; + labels.forEach(label => { + o.push({description: label.description, score: label.score}); + }); + return o; +} + +const port = 8888; +server.listen(port) +console.log(`Listening at ${port}`) + +