ArduCAM / Arduino

This is ArduCAM library for Arduino boards
MIT License
473 stars 348 forks source link

Slow Bitmap Speed #462

Open Davarco opened 4 years ago

Davarco commented 4 years ago

When reading a 320x240 bitmap image on an ESP32 (just reading, not writing it over Serial to my computer), it takes a long time, around 2 seconds. I’m guessing this is the limitations of sending the image over SPI from the ArduCAM to the ESP32. I was wondering there was a method to increase the speed of transmission. I might not need a 3-channel image, and a grayscale would work. The main goal is to do real time image processing (something quite simple) on board the ESP32. For reference, I am using a mini module camera shield with OV2640 camera module.

BillyBee123 commented 4 years ago

I'm starting image processing myself with an ArduCAM and ESP8266. Are you sending the image over wifi to your ESP32? I haven't tried that yet, but can offer some thoughts on transmission speed:

1) Agreed that the SPI transfer is the speed limitation. Yesterday, I posted code modifications to reduce BMP images from 320x240 to 160x120. This will make your transfer four times faster if the reduced image size is acceptable for your application.

2) Sending the image in grayscale rather than color won't be any faster. I've used the ArduCAM_Host_V2 to capture and write BMP files as Normal (color) and B&W (grayscale), and the image and file sizes are the same. For the OV2640, two bytes (16-bits) per pixel are used to store red, green, and blue channels (each with values from 0 to 31) whether the image is color or grayscale. For grayscale, all three channels would have the same value (grey = [red+green+blue]/3).

3) Does your application need to constantly send images in real time? Image processing takes place after capture using the image bytes stored in the buffer array. I would think your processing would look for a trigger (e.g. large changes in pixel values between images to indicate motion, or 'blobs' of similar pixel colors to detect objects) before sending an image. I suppose it would be useful during coding to send images to help us see what the computer 'sees' as pixel values. Again, I don't know your application, so this may not be helpful.

Davarco commented 4 years ago

Hi BillyBee123, Thanks for adding the code modifications. Based on what you said for part 3, is it possible to do some processing on the ArduCAM itself?

BillyBee123 commented 4 years ago

It doesn't look like much image processing could be done by the ArduCAM itself, beyond setting light and color filters (including grayscale) by registry settings.

Davarco commented 4 years ago

Awesome, thanks. Do you know where you posted your modifications to 160x120? I can't find them online.

BillyBee123 commented 4 years ago

https://github.com/ArduCAM/Arduino/issues/456

I've since made the modification for an 80x60 (QQQVGA) BMP. This uses a quarter of the RAM to store the image buffer as compared to 160x120, and has an acceptable resolution for image processing. I can post this as well if you're interested.

ArduCAM commented 4 years ago

@BillyBee123 Yes, we are also interested in image processing or ML on low performance MCU like EPS8266 or ESP32. Do you have any examples or guidelines for this?

Davarco commented 4 years ago

Hi @BillyBee123. Could you post the one for 80x60 too? Thanks so much!

BillyBee123 commented 4 years ago

Sure. These are the steps to change the BMP resolution from QVGA (320x240) to QQQVGA (80x60):

  1. In the ov2640_regs.h library registry file, make a copy of the struct sensor_reg OV2640_QVGA[] definition, and rename it OV2640_QQQVGA. In the copy, change the hex pairs from {0x5a, 0x50} to {0x5a, 0x14}, and {0x5b, 0x3c} to {0x5b, 0x0f}.

  2. In the ArduCAM.cpp library file, replace wrSensorRegs8_8(OV2640_QVGA) with wrSensorRegs8_8(OV2640_QQQVGA).

  3. In the sketch, replace the bitmap header definition with: const char bmp_header[BMPIMAGEOFFSET] PROGMEM = { 0x42, 0x4D, 0xB6, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00 }; This header is specific to a 80x60 image height, width, image size, and file size.

  4. Again in the sketch, find the nested loop where the image is transferred to serial, and reduce the i and j loop size from 240 and 320, to 60 and 80, respectively.

BillyBee123 commented 4 years ago

Lee -- I'm actively developing machine vision for ArduCAM to recognize solid colored quadrilaterals, similar to PixCam. To date, I've done the following:

1) Read and change pixel red, blue, and green values in the image buffer using masking and bit-shifting bitwise operations.

2) Average the red, green, and blue values (0 to 31) to manually produce a grayscale image.

3) Store the grayscale image shades in a matrix, then populate a histogram from 0 to 31 with a count of each shade.

4) Separate foreground shades from background shades by a threshold analysis on the histogram to minimize the sum of the light and dark shade variance (Otsu's Method).

5) Implement a row-by-row connected components algorithm to numerically label foreground pixels, then resolve a list of equivalent labels from adjoining labels using a quick union algorithm.

At this point, shapes of a common color can be separated from background pixels. Still to do is assigning each shape to an object class, then defining the axis-aligned or oriented bounding box, and calculating the RGB color of the shape. So far, I've been able to do all this from YouTube tutorials.

Bashima commented 4 years ago

@BillyBee123 Hi, Can you help me with changing the resolution to 32x32 bmp image?