Fastest way to send images from ESP32CAM to cloud server
Posted: Thu Jul 18, 2024 9:59 am
Hi,
My idea is to use ESP32CAM for image processing projects. Since the ESP32 core is not powerful enough, I am planning to send the video (as images) from ESP32CAM into my python flask server and perform image processing over there using openCV.
I am aware that ESP32CAM is not powerful enough to stream video live into my cloud server, so I will be doing it image by image. Right now I have used the below code to get things working
On my flask server side I am saving the image using the below code
I am trying to stitch the images together to get a video so that i can do real time image processing. I am even okay with very slow FPS, something like 3-5. But here in the above code it takes 7-9 seconds for a single image to reach my cloud. How can i speed this up?
I have tried capturing images in grayscale but that did not improve the speed
I also tried reducing image size to 96x96 but then the code stopped working with error shown below
My idea is to use ESP32CAM for image processing projects. Since the ESP32 core is not powerful enough, I am planning to send the video (as images) from ESP32CAM into my python flask server and perform image processing over there using openCV.
I am aware that ESP32CAM is not powerful enough to stream video live into my cloud server, so I will be doing it image by image. Right now I have used the below code to get things working
Code: Select all
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
const char* ssid = "CircuitDigest";
const char* password = "nnnnnn";
String serverName = "circuitdigestxxxxx.pythonanywhere.com"; // Replace with your PythonAnywhere domain
String serverPath = "/receive_image"; // Adjust path based on your Flask route
const int serverPort = 443; // Server port for HTTPS
int count = 0;
WiFiClientSecure client;
// Camera GPIO pins - adjust based on your ESP32-CAM board
#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
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println();
Serial.print("ESP32-CAM IP Address: ");
Serial.println(WiFi.localIP());
// Configure 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_GRAYSCALE;
if(psramFound()){
config.frame_size = FRAMESIZE_96X96;
config.jpeg_quality = 20; // Lower number means higher quality (0-63)
config.fb_count = 2;
Serial.printf("PSRAM found");
} else {
config.frame_size = FRAMESIZE_CIF;
config.jpeg_quality = 12; // Lower number means higher quality (0-63)
config.fb_count = 1;
}
// Initialize camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
delay(1000);
ESP.restart();
}
// Initial photo send
sendPhoto();
}
void loop() {
// Example: Send photo every 30 seconds
unsigned long currentMillis = millis();
static unsigned long previousMillis = 0;
const int timerInterval = 10000;
if (currentMillis - previousMillis >= timerInterval) {
Serial.println("Lets send next image..");
sendPhoto();
previousMillis = currentMillis;
}
}
String sendPhoto() {
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
return "Camera capture failed";
}
Serial.println("Connecting to server: " + serverName);
client.setInsecure(); // Skip certificate validation (for simplicity, consider security implications in a production environment)
if (client.connect(serverName.c_str(), serverPort)) {
Serial.println("Connection successful!");
count=count+1;
Serial.println(count);
// Generate a unique filename using the current timestamp
//String filename = "esp32-cam-" + String(count) + ".jpg";
String filename = "esp32-cam-image.jpg";
String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"" + filename + "\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--RandomNerdTutorials--\r\n";
uint32_t imageLen = fb->len;
uint32_t extraLen = head.length() + tail.length();
uint32_t totalLen = imageLen + extraLen;
// Send HTTP POST request with multipart/form-data
client.println("POST " + serverPath + " HTTP/1.1");
client.println("Host: " + serverName);
client.println("Content-Length: " + String(totalLen));
client.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
client.println();
client.print(head);
// Send image data in chunks
uint8_t *fbBuf = fb->buf;
size_t fbLen = fb->len;
for (size_t n = 0; n < fbLen; n = n + 1024) {
if (n + 1024 < fbLen) {
client.write(fbBuf, 1024);
fbBuf += 1024;
} else {
size_t remainder = fbLen % 1024;
client.write(fbBuf, remainder);
}
}
client.print(tail);
// Clean up
esp_camera_fb_return(fb);
// Wait for server response
String response;
long startTime = millis();
while (client.connected() && millis() - startTime < 10000) {
if (client.available()) {
char c = client.read();
response += c;
}
}
// Print server response
Serial.println(response);
client.stop();
return response;
} else {
Serial.println("Connection to server failed");
return "Connection to server failed";
}
}
On my flask server side I am saving the image using the below code
Code: Select all
# Ensure the 'mysite/static' directory exists
UPLOAD_FOLDER = 'mysite/static/'
if not os.path.exists(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
# Path to save the image
IMAGE_FILE_PATH = os.path.join(UPLOAD_FOLDER, 'received_image.jpg')
@app.route('/mysite/static/<filename>')
def uploaded_file(filename):
return send_from_directory(UPLOAD_FOLDER, filename)
@app.route('/receive_image', methods=['POST'])
def receive_image():
if 'imageFile' not in request.files:
return jsonify({'error': 'No image file provided'}), 400
imageFile = request.files['imageFile']
if imageFile.filename == '':
return jsonify({'error': 'No selected file'}), 400
# Save the file to the specified directory
file_path = os.path.join(UPLOAD_FOLDER, imageFile.filename)
imageFile.save(file_path)
return jsonify({'message': 'Image received and saved successfully'}), 200
I have tried capturing images in grayscale but that did not improve the speed
I also tried reducing image size to 96x96 but then the code stopped working with error shown below
Code: Select all
ESP32-CAM IP Address: 192.168.29.178
PSRAM foundConnecting to server: circuitdigest.pythonanywhere.com
Connection successful!
1
[ 19876][E][ssl_client.cpp:37] _handle_error(): [send_ssl_data():382]: (-80) UNKNOWN ERROR CODE (0050)
Lets send next image..
Connecting to server: circuitdigest.pythonanywhere.com
Connection successful!
2
[ 24205][E][ssl_client.cpp:37] _handle_error(): [send_ssl_data():382]: (-80) UNKNOWN ERROR CODE (0050)
Lets send next image..
Connecting to server: circuitdigest.pythonanywhere.com