s60sc / ESP32-CAM_MJPEG2SD

ESP32 Camera motion capture application to record JPEGs to SD card as AVI files and stream to browser as MJPEG. If a microphone is installed then a WAV file is also created. Files can be uploaded via FTP or downloaded to browser.
GNU Affero General Public License v3.0
931 stars 214 forks source link

Inaccuracy in startPixel & endPixel variables #443

Closed steve-me closed 5 months ago

steve-me commented 5 months ago

I am currently attempting to modify your code to shoot at movement using a servo mounted water pistol. When/if I get it working correctly I will release it to you if you want. I have come across a small inaccuracy in your code. In the text below all sizes refer to the current defaults. In motiondetect.cpp you set the startPixel & endPixel. When set, both these variables have rounding errors. My understanding is that the start and end bands (by default, each band is 1/10th of the vertical screen) are not checked for movement.

The movement check is done over a resized image that is 96 x 96 pixels in size. If we consider this as a grid of pixels 96 rows by 96 columns the movement check should be done over all of the grid lines (with start and end bands removed).

The current method of getting the start and end pixels results in the pixels not being at the start or end of one of the 96 (by default) lines of pixels making up the frame being scanned. Changing the number of start and end bands means these 2 vars can be anywhere on the scan line. In most cases rounding errors (ie 96/10=9.6, 96/9=10.6) will cause the start and end pixels to be somewhere on an image scan line. Current code uint16_t startPixel = resizeDimLen(detectStartBand-1) / detectNumBands; 9216 (2) / 10 = 1843.2 or 1843 This is in row 20 column 20 of 96 x 96 grid. It should be row 20 but in column 0 uint16_t endPixel = resizeDimLen (detectEndBand) / detectNumBands; 9216 (8) / 10 = 7372.8 or 7372 This is in row 77 column 77 of 96 x 96 grid It should be in row 77 and column 95.

Side note: Your are using resizeDimLen here instead of RESIZE_DIM. For color images this increases the numbers by a factor of 3. Is this right? In both the greyscale and color images the rescaling is done to 96 x 96. resizeDimLen is right for the byte size of the bitmap, but is it right for pixel numbers?

Using the following code will set the start/end pixels to the start and end of the grid lines. I think this is OK for both greyscale and color, but I haven't done any color testing.

uint16_t startPixel = floor(RESIZE_DIM / detectNumBands) (detectStartBand - 1) RESIZE_DIM; // 9 2 96 = 1728 uint16_t endPixel = RESIZE_DIM_SQ - (floor(RESIZE_DIM / detectNumBands) (detectNumBands - detectEndBand) RESIZE_DIM) - (RESIZE_DIM + 1); // 9216 - ( 9 2 96) - 97 = 7391

The endPixel number (7391) is because I am starting the grid numbering at row & column 0. Arguably it could be 7392. or uint16_t gridLinesPerBand = floor(RESIZE_DIM / detectNumBands); // 96/10= 9.6 = 9 uint16_t startPixel = gridLinesPerBand (detectStartBand - 1) RESIZE_DIM; // 9 2 96 = 1728 uint16_t endPixel = RESIZE_DIM_SQ - (gridLinesPerBand (detectNumBands - detectEndBand) RESIZE_DIM) - (RESIZE_DIM + 1); // 9216 - (9 2 96) - 97 = 7391

I am using the gridLinesPerBand variable in other places, so I use this last method.

Regards stevem

s60sc commented 5 months ago

I'll investigate. Always happy to consider other peoples code

s60sc commented 5 months ago

To make a band start and end at a row boundary, I'll amend to the following:

  uint16_t startPixel = (RESIZE_DIM*(detectStartBand-1)/detectNumBands) * RESIZE_DIM * colorDepth;
  uint16_t endPixel = (RESIZE_DIM*(detectEndBand)/detectNumBands) * RESIZE_DIM * colorDepth;
steve-me commented 5 months ago

Hi, sorry I took so long to get back to you. Thanks for looking at it for me. I need the start and end pixels on the start and end of the row, in column 0 and 95. I can just change it to suit my needs. Thanks for the great app. steve