Home Water Leak Detection using the ESP32 Camera Module - Part I




I've included code from the video below:

Code for Arduino sketch and associated files based on ESP32 Camera Web Server example below. Note that there is a dependence on various ESP32 files from Espressif including "esp_camera.h" and "camera_pins.h".  Installation has been covered in a previous video on the ESP32 CAM board.

#include "esp_camera.h"
#include <WiFi.h>
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//
// Select camera model
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
#include "camera_pins.h"
const char* ssid     = "****";   //input your wifi name
const char* password = "****";   //input your wifi passwords
void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();
  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_RGB888; // RGB888 format capture (change from original WebServer sketch)
  
config.frame_size = FRAMESIZE_96X96; // Only capture 96x96 pictures //FRAMESIZE_QQVGA; //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("Msg: Camera init failed with error 0x%x", err);
    return;
  }
  sensor_t * s = esp_camera_sensor_get();
  // drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_96X96);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("Msg: Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}
void loop() {
  // put your main code here, to run repeatedly:
  delay(500);
  //Serial.println ("Image capture from ESP32 camera utility with serial output.");
  //Serial.println ("Capture image when we receive 'Capture' from serial port...");
  // wait for serial input of 'Capture' to send out stream of frame buffer data
  while (Serial.available() == 0){}
  String testStr = Serial.readString();
  testStr.trim();
  if (testStr == "Capture")
  {
    delay(500);
    camera_fb_t * fb = esp_camera_fb_get();
    size_t fbsize = fb->len;
    int row_idx = 0;
    int col_idx = 0;
    if (!fb)
    {
      Serial.println("Msg: Camera capture failed");
    } else
    {
      Serial.println("START");
      int fbidx = 0;
      for (int pixel_idx = 0; pixel_idx < 9216; pixel_idx++) // fixed 96x96 frame grab
      {
         fbidx = pixel_idx*3;
         Serial.print(fb->buf[fbidx]);
         Serial.print(",");
         Serial.print(fb->buf[fbidx+1]);
         Serial.print(",");
         Serial.println(fb->buf[fbidx+2]);
      }
      Serial.println("END");
      esp_camera_fb_return(fb);
    }      
  } else
  {
    Serial.println("No capture.");
  }
}

Serial reader Python script to run on your PC below. This works in conjunction with the above code running on the ESP32 Camera module to collect image data and dump it to a file. This requires the pySerial library.

# Serial data reader from ESP32 serial output
# Corresponding Arduino sketch waits for serial input of 'Capture' to initiate a single camera frame grab and output of pixels
# This code will initiate a frame by frame grab and write each picture into a separate file
# dependency on pySerial (pip install pySerial)
import serial
ser = serial.Serial('COM4', 115200) # change 'COM4' to match whatever serial port your ESP32 board is connected to
ser.flushInput()

# capture a series of images and write to file
for img_idx in range (1,30): # hard code 30 images to capture for now...
    print("iteration start")
    imgfile = "imgdump" + str(img_idx) + ".txt"
    f = open(imgfile, 'w', encoding='UTF8', newline='')
    print("About to make file: " + imgfile)
    ser.write(b'Capture\n')

    while True:
      try:
         ser_bytes = ser.readline()
         dataString = ser_bytes.decode('utf-8')
         data = dataString[0:][:-2]
         #print (data)
         if (data == "START"):
            print("START")
         if ((data != "START") & (data != "END")):
            f.write(data)
            f.write("\n")
         if (data == "END"):
            print("END...")
            break
      except KeyboardInterrupt:
         print("Keyboard Interrupt")
         break

    f.close()
    print("Iteration end")


Python code to read the image files generated by above serial reader and display them below.
Lots of hard-coded stuff... 

# Reads camera image files generated by serial_reader code and displays them

# get image from dump
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageOps

IMG_X = 96
IMG_Y = 96

for img_idx in range (1,20): # hard-code 20 images to read from for now...
    print("reading files")
    imgfile = "imgdump" + str(img_idx) + ".txt"
    print(imgfile)
    f = open(imgfile, 'r')
    Lines = f.readlines()

    pixel_array = np.zeros([IMG_X,IMG_Y,3], dtype=np.uint8)
    single_pix = np.zeros([1,1,3], dtype=np.uint8)

    count = 0
    for line in Lines:
       cleanLine = line.strip()
       OneLine = cleanLine.split(",")
       #single_pix = (int(OneLine[0]), int(OneLine[1]), int(OneLine[2]))
       # Output from frame buffer is BGR... so let's swap into RGB order
       single_pix = (int(OneLine[2]), int(OneLine[1]), int(OneLine[0]))
       #print(single_pix)
       y = count // 96
       x = count % 96
       pixel_array[y,x] = single_pix
       count+=1
   
    print("Total Count: " + str(count))

    FinalImg = Image.fromarray(pixel_array)
    FinalImg.show()





Comments

Popular posts from this blog

ESP32 Based Pulse-Oximeter using MAX30102

ESP32 Web Sockets - Transferring Image Raw Data

Heart Rate Measurement with ESP32 and Pulse Oximeter Module using FFT