esp32cam-demo/Misc/esp32camdemo-greyscale.ino

443 wiersze
19 KiB
C++

/*******************************************************************************************************************
*
* ESP32Cam development board demo sketch using Arduino IDE
*
* demo using greyscale data
* root web page shows captured greyscale image data
*
*
*******************************************************************************************************************/
#if !defined ESP32
#error This sketch is only for an ESP32Cam module
#endif
#include "esp_camera.h" // https://github.com/espressif/esp32-camera
// #include "camera_pins.h"
// ******************************************************************************************************************
// ---------------------------------------------------------------------------------------------------------
// Wifi Settings
#include <wifiSettings.h> // delete this line, un-comment the below two lines and enter your wifi details
//const char *SSID = "your_wifi_ssid";
//const char *PWD = "your_wifi_pwd";
// ---------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------
// -SETTINGS
// ---------------------------------------------------------------
const char* stitle = "ESP32Cam-demo-gs"; // title of this sketch
const char* sversion = "07Jun21"; // Sketch version
const bool serialDebug = 1; // show info. on serial port (1=enabled, disable if using pins 1 and 3 as gpio)
#define useMCP23017 0 // if MCP23017 IO expander chip is being used (on pins 12 and 13)
// Camera related
const bool flashRequired = 1; // If flash to be used when capturing image (1 = yes)
const framesize_t FRAME_SIZE_IMAGE = FRAMESIZE_QQVGA;// Image resolution:
// default = "const framesize_t FRAME_SIZE_IMAGE = FRAMESIZE_VGA"
// 160x120 (QQVGA), 128x160 (QQVGA2), 176x144 (QCIF), 240x176 (HQVGA),
// 320x240 (QVGA), 400x296 (CIF), 640x480 (VGA, default), 800x600 (SVGA),
// 1024x768 (XGA), 1280x1024 (SXGA), 1600x1200 (UXGA)
#define PIXFORMAT PIXFORMAT_GRAYSCALE; // image format, Options = YUV422, GRAYSCALE, RGB565, JPEG, RGB888
#define WIDTH 160 // image size
#define HEIGHT 120
int cameraImageExposure = 0; // Camera exposure (0 - 1200) If gain and exposure both set to zero then auto adjust is enabled
int cameraImageGain = 0; // Image gain (0 - 30)
const int TimeBetweenStatus = 600; // speed of flashing system running ok status light (milliseconds)
const int indicatorLED = 33; // onboard small LED pin (33)
const int brightLED = 4; // onboard Illumination/flash LED pin (4)
const int iopinA = 13; // general io pin 13
const int iopinB = 12; // general io pin 12 (must not be high at boot)
const int iopinC = 16; // input only pin 16 (used by PSRam but you may get away with using it for a button)
const int serialSpeed = 115200; // Serial data speed to use
// camera settings (for the standard - OV2640 - CAMERA_MODEL_AI_THINKER)
// see: https://randomnerdtutorials.com/esp32-cam-camera-pin-gpios/
// set camera resolution etc. in 'initialiseCamera()' and 'cameraImageSettings()'
#define CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32 // power to camera (on/off)
#define RESET_GPIO_NUM -1 // -1 = not used
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26 // i2c sda
#define SIOC_GPIO_NUM 27 // i2c scl
#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 // vsync_pin
#define HREF_GPIO_NUM 23 // href_pin
#define PCLK_GPIO_NUM 22 // pixel_clock_pin
// ******************************************************************************************************************
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h> // used by requestWebPage()
#include "driver/ledc.h" // used to configure pwm on illumination led
WebServer server(80); // serve web pages on port 80
// Used to disable brownout detection
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
// sd-card
#include "SD_MMC.h" // sd card - see https://randomnerdtutorials.com/esp32-cam-take-photo-save-microsd-card/
#include <SPI.h>
#include <FS.h> // gives file access
#define SD_CS 5 // sd chip select pin = 5
// MCP23017 IO expander on pins 12 and 13 (optional)
#if useMCP23017 == 1
#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp;
// Wire.setClock(1700000); // set frequency to 1.7mhz
#endif
// Define some global variables:
uint32_t lastStatus = millis(); // last time status light changed status (to flash all ok led)
uint32_t lastCamera = millis(); // timer for periodic image capture
bool sdcardPresent; // flag if an sd card is detected
int imageCounter; // image file name on sd card counter
uint32_t illuminationLEDstatus; // current brightness setting of the illumination led
// ******************************************************************************************************************
// ---------------------------------------------------------------
// -SETUP SETUP SETUP SETUP SETUP SETUP
// ---------------------------------------------------------------
void setup() {
if (serialDebug) {
Serial.begin(serialSpeed); // Start serial communication
Serial.println("\n\n\n"); // line feeds
Serial.println("-----------------------------------");
Serial.printf("Starting - %s - %s \n", stitle, sversion);
Serial.println("-----------------------------------");
// Serial.print("Reset reason: " + ESP.getResetReason());
}
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // Turn-off the 'brownout detector'
// small indicator led on rear of esp32cam board
pinMode(indicatorLED, OUTPUT);
digitalWrite(indicatorLED,HIGH);
// Connect to wifi
digitalWrite(indicatorLED,LOW); // small indicator led on
if (serialDebug) {
Serial.print("\nConnecting to ");
Serial.print(SSID);
Serial.print("\n ");
}
WiFi.begin(SSID, PWD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if (serialDebug) Serial.print(".");
}
if (serialDebug) {
Serial.print("\nWiFi connected, ");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
server.begin(); // start web server
digitalWrite(indicatorLED,HIGH); // small indicator led off
// define the web pages (i.e. call these procedures when url is requested)
server.on("/", capture_still); // demo converting image to RGB
// set up camera
if (serialDebug) Serial.print(("\nInitialising camera: "));
if (initialiseCamera()) {
if (serialDebug) Serial.println("OK");
}
else {
if (serialDebug) Serial.println("Error!");
}
// define i/o pins
pinMode(indicatorLED, OUTPUT); // defined again as sd card config can reset it
digitalWrite(indicatorLED,HIGH); // led off = High
pinMode(iopinA, OUTPUT); // pin 13 - free io pin, can be used for input or output
pinMode(iopinB, OUTPUT); // pin 12 - free io pin, can be used for input or output (must not be high at boot)
pinMode(iopinC, INPUT); // pin 16 - free input only pin
// MCP23017 io expander (requires adafruit MCP23017 library)
#if useMCP23017 == 1
Wire.begin(12,13); // use pins 12 and 13 for i2c
mcp.begin(&Wire); // use default address 0
mcp.pinMode(0, OUTPUT); // Define GPA0 (physical pin 21) as output pin
mcp.pinMode(8, INPUT); // Define GPB0 (physical pin 1) as input pin
mcp.pullUp(8, HIGH); // turn on a 100K pullup internally
// change pin state with mcp.digitalWrite(0, HIGH);
// read pin state with mcp.digitalRead(8)
#endif
// startup complete
if (serialDebug) Serial.println("\nSetup complete...");
} // setup
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -LOOP LOOP LOOP LOOP LOOP LOOP LOOP
// ----------------------------------------------------------------
void loop() {
server.handleClient(); // handle any incoming web page requests
// <<< YOUR CODE HERE >>>
// // demo to Capture an image and save to sd card every 5 seconds (i.e. time lapse)
// if ( ((unsigned long)(millis() - lastCamera) >= 5000) && sdcardPresent ) {
// lastCamera = millis(); // reset timer
// storeImage(); // save an image to sd card
// }
// flash status LED to show sketch is running ok
if ((unsigned long)(millis() - lastStatus) >= TimeBetweenStatus) {
lastStatus = millis(); // reset timer
digitalWrite(indicatorLED,!digitalRead(indicatorLED)); // flip indicator led status
}
} // loop
// ******************************************************************************************************************
// ----------------------------------------------------------------
// Initialise the camera
// ----------------------------------------------------------------
// returns TRUE if successful
bool initialiseCamera() {
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; // XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
config.pixel_format = PIXFORMAT; // Options = YUV422, GRAYSCALE, RGB565, JPEG, RGB888
config.frame_size = FRAME_SIZE_IMAGE; // Image sizes: 160x120 (QQVGA), 128x160 (QQVGA2), 176x144 (QCIF), 240x176 (HQVGA), 320x240 (QVGA),
// 400x296 (CIF), 640x480 (VGA, default), 800x600 (SVGA), 1024x768 (XGA), 1280x1024 (SXGA),
// 1600x1200 (UXGA)
config.jpeg_quality = 10; // 0-63 lower number means higher quality
config.fb_count = 1; // if more than one, i2s runs in continuous mode. Use only with JPEG
// check the esp32cam board has a psram chip installed (extra memory used for storing captured images)
// Note: if not using "AI thinker esp32 cam" in the Arduino IDE, PSRAM must be enabled
if (!psramFound()) {
if (serialDebug) Serial.println("Warning: No PSRam found so defaulting to image size 'CIF'");
config.frame_size = FRAMESIZE_CIF;
}
//#if defined(CAMERA_MODEL_ESP_EYE)
// pinMode(13, INPUT_PULLUP);
// pinMode(14, INPUT_PULLUP);
//#endif
esp_err_t camerr = esp_camera_init(&config); // initialise the camera
if (camerr != ESP_OK) {
if (serialDebug) Serial.printf("ERROR: Camera init failed with error 0x%x", camerr);
}
cameraImageSettings(); // apply custom camera settings
return (camerr == ESP_OK); // return boolean result of camera initialisation
}
// ******************************************************************************************************************
// ----------------------------------------------------------------
// -Change camera image settings
// ----------------------------------------------------------------
// Adjust image properties (brightness etc.)
// Defaults to auto adjustments if exposure and gain are both set to zero
// - Returns TRUE if successful
// BTW - some interesting info on exposure times here: https://github.com/raduprv/esp32-cam_ov2640-timelapse
bool cameraImageSettings() {
sensor_t *s = esp_camera_sensor_get();
// something to try?: if (s->id.PID == OV3660_PID)
if (s == NULL) {
if (serialDebug) Serial.println("Error: problem reading camera sensor settings");
return 0;
}
// if both set to zero enable auto adjust
if (cameraImageExposure == 0 && cameraImageGain == 0) {
// enable auto adjust
s->set_gain_ctrl(s, 1); // auto gain on
s->set_exposure_ctrl(s, 1); // auto exposure on
s->set_awb_gain(s, 1); // Auto White Balance enable (0 or 1)
} else {
// Apply manual settings
s->set_gain_ctrl(s, 0); // auto gain off
s->set_awb_gain(s, 1); // Auto White Balance enable (0 or 1)
s->set_exposure_ctrl(s, 0); // auto exposure off
s->set_agc_gain(s, cameraImageGain); // set gain manually (0 - 30)
s->set_aec_value(s, cameraImageExposure); // set exposure manually (0-1200)
}
return 1;
} // cameraImageSettings
// // More camera settings available:
// // If you enable gain_ctrl or exposure_ctrl it will prevent a lot of the other settings having any effect
// // more info on settings here: https://randomnerdtutorials.com/esp32-cam-ov2640-camera-settings/
// s->set_gain_ctrl(s, 0); // auto gain off (1 or 0)
// s->set_exposure_ctrl(s, 0); // auto exposure off (1 or 0)
// s->set_agc_gain(s, cameraImageGain); // set gain manually (0 - 30)
// s->set_aec_value(s, cameraImageExposure); // set exposure manually (0-1200)
// s->set_vflip(s, cameraImageInvert); // Invert image (0 or 1)
// s->set_quality(s, 10); // (0 - 63)
// s->set_gainceiling(s, GAINCEILING_32X); // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128)
// s->set_brightness(s, cameraImageBrightness); // (-2 to 2) - set brightness
// s->set_lenc(s, 1); // lens correction? (1 or 0)
// s->set_saturation(s, 0); // (-2 to 2)
// s->set_contrast(s, cameraImageContrast); // (-2 to 2)
// s->set_sharpness(s, 0); // (-2 to 2)
// s->set_hmirror(s, 0); // (0 or 1) flip horizontally
// s->set_colorbar(s, 0); // (0 or 1) - show a testcard
// s->set_special_effect(s, 0); // (0 to 6?) apply special effect
// s->set_whitebal(s, 0); // white balance enable (0 or 1)
// s->set_awb_gain(s, 1); // Auto White Balance enable (0 or 1)
// 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_dcw(s, 0); // downsize enable? (1 or 0)?
// s->set_raw_gma(s, 1); // (1 or 0)
// s->set_aec2(s, 0); // automatic exposure sensor? (0 or 1)
// s->set_ae_level(s, 0); // auto exposure levels (-2 to 2)
// s->set_bpc(s, 0); // black pixel correction
// s->set_wpc(s, 0); // white pixel correction
// ----------------------------------------------------------------
// -access image as greyscale data - i.e. http://x.x.x.x/
// ----------------------------------------------------------------
bool capture_still() {
WiFiClient client = server.client(); // open link with client
// log page request including clients IP address
if (serialDebug) {
IPAddress cip = client.remoteIP();
Serial.printf("Greyscale data requested from: %d.%d.%d.%d \n", cip[0], cip[1], cip[2], cip[3]);
}
client.write("<!DOCTYPE html> <html lang='en'> <head> <title>photo</title> </head> <body>\n"); // basic html header
client.write("<br>Greyscale data<br>");
camera_fb_t *frame = esp_camera_fb_get();
if (!frame)
return false;
// for each pixel in image
// only shows first 3 lines of image as otherwise there is an awful lot of data
// to show all data use the line: for (size_t i = 0; i < frame->len; i++) {
for (size_t i = 0; i < (160 * 3); i++) {
const uint16_t x = i % WIDTH; // x position in image
const uint16_t y = floor(i / WIDTH); // y position in image
byte pixel = frame->buf[i]; // pixel value
// show data
if (x==0) client.println("<br>"); // new line
client.print(String(pixel)); // print byte as a string
client.print(", ");
}
esp_camera_fb_return(frame); // return storage space
// end html
client.print("<br>Finished");
client.print("</body></html>\n");
delay(3);
client.stop();
return true;
}
// ******************************************************************************************************************
// end