I'm trying to read a rbg565 image w esp32-cam and then process it, maybe change some of the pixels and then upload to a web server.
When I try and do the frame2jpg_cb(fb, quality, &buffer_jpeg, NULL);
where the buffer_jpeg supposedly moves the jpg data back into frame buffer it crashes.
Anyone attempted to do something like this ?
Found PSRAM, this will improve performance!
Camera init success
Guru Meditation Error: Core 0 panic'ed (Double exception).
Core 0 register dump:
PC : 0x403874da PS : 0x00040136 A0 : 0x8037f0d3 A1 : 0x3fcc2150
A2 : 0x00040136 A3 : 0x00040026 A4 : 0x00000027 A5 : 0x3c0ce6a3
A6 : 0x00000001 A7 : 0x00000004 A8 : 0x3fcc2210 A9 : 0x00000000
A10 : 0x0000005c A11 : 0x00000804 A12 : 0x3fca7de8 A13 : 0x00000000
A14 : 0x3fcc2650 A15 : 0x3c100908 SAR : 0x00000004 EXCCAUSE: 0x00000002
EXCVADDR: 0x00000000 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xfffffffe
Backtrace: 0x403874d7:0x3fcc2150 0x4037f0d0:0x00060f23 |<-CORRUPTED
Here is the code
#include <ArduinoOTA.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>
#include "camera.h"
#include "esp_camera.h"
#include "base64.h"
#include <Adafruit_NeoPixel.h>
uint16_t jpeg_length = 0;
#define LEFTRIGHT 40
#define UPDOWN 40
#define BACKUP 5
// 1 means use USB 0 means use web
#define SERIALUSB 1
// Replace with your network credentials
//const char *ssid = "omghi2u"; //"OCWirelessIoT";
//const char *password = "SkolVikings"; //"willywonkaoompaloompa";
const char *ssid = "OCWirelessIoT";
const char *password = "willywonkaoompaloompa";
//pick the board - ESP32S3 Dev Module
// Define the pin where the built-in RGB LED is connected
#define LED_PIN 48
// Define the number of LEDs in the strip (usually 1 for built-in LED)
#define NUM_LEDS 1
// Create an instance of the Adafruit_NeoPixel class
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
// Create an instance of AsyncWebServer
AsyncWebServer server(80);
void setup() {
// Serial and WebSerial setup
Serial.begin(115200);
light_on();
WiFi.begin(ssid, password);
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
//WebSerial.begin(&server);
//WebSerial.onMessage(recvMsg);
Serial.println("Connected to WiFi");
String ipString = WiFi.localIP().toString();
Serial.printf("IP Address: %s\n", ipString);
Serial.println("ESP Board MAC Address: ");
Serial.println(WiFi.macAddress().c_str());
// Initialize the camera
Serial.println("init camera before");
initCamera();
Serial.println("init camera after");
// Web server route to serve text
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/plain", "ESP32-CAM Web Server is running!");
});
Serial.println("after / dir");
// Web server route to serve a picture
server.on("/capture", HTTP_GET, [](AsyncWebServerRequest *request) {
String photo = capturePhoto();
if (photo.length() > 0) {
String html = "<!DOCTYPE html><html lang='en'><head><meta name='viewport' content='width=device-width, initial-scale=1.0'>";
html += "<title>ESP32-CAM Capture</title></head><body>";
html += "<h1>ESP32-CAM Web Server</h1>";
html += "<p>This is a snapshot from ESP32-CAM.</p>";
html += "<img src='" + photo + "'>";
html += "'>";
html += "</body></html>";
request->send(200, "text/html", html);
Serial.println("send to capture server");
} else {
request->send(500, "text/plain", "Camera capture failed");
}
});
Serial.println("after /capture");
// Start the server
server.begin();
Serial.println("after server begin");
// Port defaults to 3232
// ArduinoOTA.setPort(3232);
// Hostname defaults to esp3232-[MAC]
ArduinoOTA.setHostname("esp32-cam");
// No authentication by default
ArduinoOTA.setPassword("admin");
// Password can be set with it's md5 value as well
// MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
// ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
} //end of setup
void loop() {
// WebSerial works asynchronously
ArduinoOTA.handle();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// capture a photo and return the buffer
String capturePhoto() {
light_on();
delay(300);
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return "";
} else {
Serial.println("Took picture success");
}
//find angle of red dial
findangle(fb, 0);
// encode to jpeg
uint8_t quality = 90;
frame2jpg_cb(fb, quality, &buffer_jpeg, NULL);
String photo = "data:image/jpeg;base64,";
photo += base64::encode(fb->buf, fb->len);
esp_camera_fb_return(fb);
Serial.println("converted to base64");
return photo;
}
void recvMsg(uint8_t *data, size_t len) {
Serial.println("Received Data...");
String d = "";
for (int i = 0; i < len; i++) {
d += char(data[i]);
}
Serial.println(d);
if (d == "ON") {
light_on();
}
if (d == "OFF") {
light_off();
}
}
void light_on() {
strip.setPixelColor(0, strip.Color(255, 255, 255)); // White
strip.show();
}
void light_off() {
strip.setPixelColor(0, strip.Color(0, 0, 0)); // White
strip.show();
}
float findangle(camera_fb_t *fb, int start_angle) {
Serial.println("starting findangle");
int center_x = fb->width / 2;
int center_y = fb->height / 2;
int r = (3 * center_x) / 7;
Serial.printf("center x,y:%d %d\n ", center_x, center_y);
Serial.printf("radius is %d\n", r);
int x, y, up, down, left, right, x1, y1, degree;
uint16_t pixel;
float angle = -1;
bool found = false;
for (int a = 0; a < 360; a++) {
degree = (start_angle + a - BACKUP) % 360;
float radians = degree * .0174533;
x1 = center_x + (r * cos(radians));
y1 = center_y + (r * sin(radians));
pixel = ((uint16_t *)fb->buf)[y1 * fb->width + x1];
if (isRed(pixel)) {
Serial.printf("angle,x,y,%d,%d,%d,RED\n", degree, x1, y1);
// found dial
limitx(x1, left, right, fb->width);
limity(y1, up, down, fb->height);
found = true;
} else {
Serial.printf("angle,x,y,%d,%d,%d\n", degree, x1, y1);
}
//make green dots
uint16_t *pixels = (uint16_t *)fb->buf; // Cast buffer to 16-bit
pixels[(y1 * fb->width) + x1] = 0x07E0; // Set pixel to green
esp_camera_fb_return(fb);
}
Serial.println("findangle done.");
return angle;
}
bool isRed(uint16_t pixel) {
uint8_t r = (pixel >> 11) & 0x1F;
uint8_t g = (pixel >> 5) & 0x3F;
uint8_t b = pixel & 0x1F;
bool red = false;
// Simple threshold to detect red color
if (r > 20 && g < 15 && b < 15) {
red = true;
}
//Serial.printf("r-g-b-RED %d %d %d %d\n",r,g,b,red);
return red;
}
void limitx(int x, int &left, int &right, int width) {
left = x - LEFTRIGHT;
if (left < 0) {
left = 0;
}
right = x + LEFTRIGHT;
if (right > width) {
right = width;
}
}
void limity(int y, int &up, int &down, int height) {
down = y - UPDOWN;
if (down < 0) {
down = 0;
}
up = y + UPDOWN;
if (up > height) {
up = height;
}
}
String base64Encode(uint8_t *data, size_t len) {
return base64::encode(data, len);
}
/**
* Put JPEG-encoded data back into the original frame
* (you don't have to modify this)
*/
size_t buffer_jpeg(void *arg, size_t index, const void* data, size_t len) {
if (index == 0) {
// first MCU block => reset jpeg length
jpeg_length = 0;
}
if (len == 0) {
// encoding is done
((camera_fb_t *)arg)->len = jpeg_length;
return 0;
}
jpeg_length += len;
// override input data
memcpy( (uint8_t*) arg + index, (uint8_t*) data, len);
return len;
}
