Problem of sending image buffer in ESP32-CAM by using HTTP POST

Dear All

I had an Arduino program running on ESP32-CAM which send out an image to server by node js every time when I press the tact switch.

The problem is, when I send image data via HTTP Post to server, the server side receive garbage data, and the photo cannot be opened.

When I hard-code the data send to server to be text, the server side receive the data without problem.

The camera and TFT screen itself have no problem, if I press the button on breadboard, it can take picture and show in TFT screen.

Do any one of you know how could I modify my Arduino program to make it work?
I want the server side receive normal data but not garbage data.
I appreciate for your help, I really have no idea on how to correct it.

By my guessing, it seems that the problem occur at client.POST(fb->buf, fb->len); But everyone from the internet is teaching to use this code: int httpResponseCode = client.POST(fb->buf, fb->len);
Thanks.

Here is the Arduino programming code.

#include "esp_camera.h"
#include <TJpg_Decoder.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

#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

#define GFXFF 1
#define FSB9 &FreeSerifBold9pt7b

TFT_eSPI tft = TFT_eSPI();

const char* ssid = "ABCDE";
const char* password = "12345678";
const unsigned long timeout = 30000;  // 30 seconds

const int buttonPin = 4;  // the number of the pushbutton pin

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
}

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
  return 1;
}


void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println();
  pinMode(buttonPin, INPUT);

  Serial.println("INIT DISPLAY");
  tft.begin();
  tft.setRotation(3);
  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 = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  config.frame_size = FRAMESIZE_QVGA;
  config.jpeg_quality = 10;
  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;
  }

  initWiFi();
}

void buttonEvent() {
  //int reading = digitalRead(buttonPin);
  if (digitalRead(buttonPin) == HIGH) {
    sendingImage();
  } else {
    showingImage();
  }
}

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<JsonArray>();
  int yPos = 4;
  for (JsonVariant v : array) {
    JsonObject object = v.as<JsonObject>();
    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) {
  Serial.print("Picture Height: ");
  Serial.print(fb->height);
  Serial.println("");  // write the Height
  Serial.print("Picture Weidth: ");
  Serial.print(fb->width);
  Serial.println("");  // write the Width
  Serial.print("Picture Size: ");
  Serial.print(fb->len);
  Serial.println("");  // write the Size
  Serial.print("Data Buffer: ");
  for (int i = 0; i < fb->len; i++) {
    Serial.write(',');
    Serial.print(fb->buf[i]);
  }
  Serial.println();
  HTTPClient client;
  client.begin("http://192.168.241.182: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 {
    tft.drawString("Check Your Server!!!", 8, 4, GFXFF);
  }
  client.end();
}

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);
    postingImage(fb);
    esp_camera_fb_return(fb);
  }
}

void loop() {
  buttonEvent();
}

This is my nodeJS server side script

var fs = require('fs');
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"){
		console.log(`--Trasmission Start--`)
        var ImageFile = fs.createWriteStream(filePath, {encoding: 'utf8'});
        request.on('data', function(data){
			console.log(data.toString())
            ImageFile.write(data);
        });
 
        request.on('end',async function(){
			console.log(`--Trasmission End--`)
            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() {
  var o = [];
  // 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;
  
  labels.forEach(label => {
    o.push({description: label.description, score: label.score});
  });
  return o;
}
 
const port = 8888;
server.listen(port)
console.log(`Listening at ${port}`)

Post the serial output you got!

Is the size received equal to the size sent?
Usually you have to tell the server how much data you send or send it in chunks (which is probably out of reach of your programming skills at the moment).

I use FTP to send images from my ESP32 CAM's.

I enabled the web site to host FTP.

#include "sdkconfig.h" // used for log printing
#include "esp_system.h"
#include "freertos/FreeRTOS.h" //freeRTOS items to be used
#include "freertos/task.h"
#include "certs.h"
#include "esp_camera.h"
#include "soc/soc.h"           // Disable brownout problems
#include "soc/rtc_cntl_reg.h"  // Disable brownout problems
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <WiFiClient.h>
#include "ESP32_FTPClient.h"
//
WiFiClient wifiClient; // do the WiFi instantiation thing
ESP32_FTPClient ftp (ftp_server, ftp_user, ftp_pass, 5000, 2);
////
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
  switch (event) {
    case SYSTEM_EVENT_STA_CONNECTED:
      log_i("Connected to WiFi access point");
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      log_i("Disconnected from WiFi access point");
      break;
    case SYSTEM_EVENT_AP_STADISCONNECTED:
      log_i("WiFi client disconnected");
      break;
    default: break;
  }
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
void setup()
{
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  ////
  if ( configInitCamera() )
  {
    xTaskCreatePinnedToCore( capturePhoto_sendFTP, "capturePhoto_sendFTP", 20000, NULL, 3, NULL, 1 );
  } else {
    log_i( "camera failed to initilize. Quitting programed operations." );
  }
} // void setup()
////
void capturePhoto_sendFTP( void *pvParameters )
{
  TickType_t xLastWakeTime    = xTaskGetTickCount();
  const TickType_t xFrequency = 100; //delay for mS
  for (;;)
  {
    log_i( "tick");
    if ( WiFi.status() == WL_CONNECTED )
    {
      camera_fb_t * fb = NULL; // pointer
      fb = esp_camera_fb_get();
      if (!fb)
      {
        log_i( "Camera capture failed" );
      } else {
        ftp.OpenConnection(); // try open FTP
        if ( ftp.isConnected() )
        {
          //try send file ftp
          ftp.ChangeWorkDir( ftp_path );
          // Delete existing file, create the new file, and send the image to the file
          ftp.DeleteFile( ftp_file_name );
          ftp.InitFile( ftp_file_type ); //"Type I"
          ftp.NewFile( ftp_file_name );
          ftp.WriteData( (unsigned char *)fb->buf, fb->len );
          ftp.CloseFile();
          ftp.CloseConnection();
        }
        esp_camera_fb_return(fb); //return the frame buffer back to the driver for reuse
      }
    } else {
      log_i( "In capturePhoto_sendFTP found WiFi not connected ");
      connectToWiFi();
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
} //void capturePhoto_sendFTP( void *pvParameters )
////
void configureCameraSettings()
{
  sensor_t * s = esp_camera_sensor_get(); //see certs.h for more info
  s->set_brightness(s, -1);     // -2 to 2 **************************
  s->set_contrast(s, 0);       // -2 to 2
  s->set_saturation(s, 0);     // -2 to 2
  s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
  s->set_whitebal(s, 1);       // 0 = disable , 1 = enable
  s->set_awb_gain(s, 1);       // 0 = disable , 1 = enable
  s->set_wb_mode(s, 0);        // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
  s->set_exposure_ctrl(s, 1);  // 0 = disable , 1 = enable
  s->set_aec2(s, 0);           // 0 = disable , 1 = enable
  s->set_ae_level(s, 0);       // -2 to 2
  s->set_aec_value(s, 300);    // 0 to 1200
  s->set_gain_ctrl(s, 1);      // 0 = disable , 1 = enable
  s->set_agc_gain(s, 0);       // 0 to 30
  s->set_gainceiling(s, (gainceiling_t)0);  // 0 to 6
  s->set_bpc(s, 0);            // 0 = disable , 1 = enable
  s->set_wpc(s, 1);            // 0 = disable , 1 = enable
  s->set_raw_gma(s, 1);        // 0 = disable , 1 = enable
  s->set_lenc(s, 1);           // 0 = disable , 1 = enable
  s->set_hmirror(s, 0);        // 0 = disable , 1 = enable
  s->set_vflip(s, 0);          // 0 = disable , 1 = enable
  s->set_dcw(s, 1);            // 0 = disable , 1 = enable
  s->set_colorbar(s, 0);       // 0 = disable , 1 = enable
} //void configureCameraSettings()
////
bool configInitCamera()
{
  camera_config_t config = {}; // Stores the camera configuration parameters
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer   = LEDC_TIMER_0;
  config.pin_d0       = GPIO_NUM_5; //Y2
  config.pin_d1       = GPIO_NUM_18; //Y3
  config.pin_d2       = GPIO_NUM_19; //Y4
  config.pin_d3       = GPIO_NUM_21; //Y5
  config.pin_d4       = GPIO_NUM_36; //Y6
  config.pin_d5       = GPIO_NUM_39; //Y7
  config.pin_d6       = GPIO_NUM_34; //Y8
  config.pin_d7       = GPIO_NUM_35; // Y9
  config.pin_xclk     = GPIO_NUM_0; //XCLK
  config.pin_pclk     = GPIO_NUM_22; //PCLK
  config.pin_vsync    = GPIO_NUM_25; //VSSYNC
  config.pin_href     = GPIO_NUM_23; // HREF
  config.pin_sscb_sda = GPIO_NUM_26; //SIOD
  config.pin_sscb_scl = GPIO_NUM_27; //SIOC
  config.pin_pwdn     = GPIO_NUM_32; //PWDN
  config.pin_reset    = -1; //RESET
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG; //assuming default is has PSRAM
  config.frame_size = FRAMESIZE_UXGA; // FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
  config.jpeg_quality = 10; //0-63 lower number means higher quality
  config.fb_count = 2;
  // Initialize the Camera
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    log_i("Camera init failed with error 0x%x", err);
    return false;
  } else {
    configureCameraSettings();
    return true;
  }
} //void configInitCamera()
////
void connectToWiFi()
{
  int TryCount = 0;
  while ( WiFi.status() != WL_CONNECTED )
  {
    TryCount++;
    WiFi.disconnect();
    WiFi.begin( SSID, PASSWORD );
    vTaskDelay( 4000 );
    if ( TryCount == 10 )
    {
      ESP.restart();
    }
  }
  WiFi.onEvent( WiFiEvent );
}
////
void loop() {}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.