diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index ac94cd971..fc5c9e4c8 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -76,7 +76,8 @@ jobs: - libraries/doom - libraries/KernelDebug - libraries/MCUboot - - libraries/Camera/examples + - libraries/Camera/examples/CameraCaptureRawBytes + - libraries/Camera/examples/CameraMotionDetect - libraries/Portenta_lvgl/examples/Portenta_lvgl - libraries/Portenta_SDCARD - libraries/Portenta_SDRAM @@ -115,6 +116,7 @@ jobs: additional-sketch-paths: | - libraries/PDM - libraries/Camera/examples/CameraCaptureRawBytes + - libraries/Camera/examples/CameraCaptureZoomPan - libraries/SE05X - libraries/STM32H747_System - libraries/ThreadDebug diff --git a/libraries/Camera/examples/CameraCaptureRawBytes/CameraCaptureRawBytes.ino b/libraries/Camera/examples/CameraCaptureRawBytes/CameraCaptureRawBytes.ino index 65458f26a..a0ca20775 100644 --- a/libraries/Camera/examples/CameraCaptureRawBytes/CameraCaptureRawBytes.ino +++ b/libraries/Camera/examples/CameraCaptureRawBytes/CameraCaptureRawBytes.ino @@ -6,8 +6,14 @@ Camera cam(galaxyCore); #define IMAGE_MODE CAMERA_RGB565 #elif defined(ARDUINO_PORTENTA_H7_M7) + // uncomment the correct camera in use #include "hm0360.h" HM0360 himax; + + // #include "himax.h" + // HM01B0 himax; + // Camera cam(himax); + Camera cam(himax); #define IMAGE_MODE CAMERA_GRAYSCALE #elif defined(ARDUINO_GIGA) @@ -60,7 +66,7 @@ void setup() { void loop() { if(!Serial) { - Serial.begin(921600); + Serial.begin(115200); while(!Serial); } diff --git a/libraries/Camera/examples/CameraCaptureZoomPan/CameraCaptureZoomPan.ino b/libraries/Camera/examples/CameraCaptureZoomPan/CameraCaptureZoomPan.ino new file mode 100644 index 000000000..964897a6a --- /dev/null +++ b/libraries/Camera/examples/CameraCaptureZoomPan/CameraCaptureZoomPan.ino @@ -0,0 +1,126 @@ +/* + * This example shows how to use the Nicla Vision to capture images from the camera + * with a zoom window and send them over the serial port. + * The zoom window will move from left to right and top to bottom + * in the predefined steps of pixels (ZOOM_X_STEP and ZOOM_Y_STEP). + * + * Whenever the board sends a frame over the serial port, the blue LED will blink. + * + * Instructions: + * 1. Upload this sketch to Nicla Vision. + * 2. Open the CameraRawBytesVisualizer.pde Processing sketch and change `useGrayScale` to `false`. + * 3. Adjust the serial port in the Processing sketch to match the one used by Nicla Vision. + * 4. Run the Processing sketch. + * + * Initial author: Sebastian Romero @sebromero + */ + +#include "camera.h" + +#ifndef ARDUINO_NICLA_VISION +#error "This sketch only works on Nicla Vision." +#endif + +#include "gc2145.h" +GC2145 galaxyCore; +Camera cam(galaxyCore); +#define IMAGE_MODE CAMERA_RGB565 + +#define CHUNK_SIZE 512 // Size of chunks in bytes +#define RESOLUTION CAMERA_R1600x1200 // Zoom in from the highest supported resolution +#define ZOOM_WINDOW_RESOLUTION CAMERA_R320x240 + +constexpr uint16_t ZOOM_WINDOW_WIDTH = 320; +constexpr uint16_t ZOOM_WINDOW_HEIGHT = 240; +constexpr uint16_t ZOOM_X_STEP = 100; +constexpr uint16_t ZOOM_Y_STEP = 100; + +FrameBuffer frameBuffer; +uint32_t currentZoomX = 0; +uint32_t currentZoomY = 0; +uint32_t maxZoomX = 0; // Will be calculated in setup() +uint32_t maxZoomY = 0; // Will be calculated in setup() + + +void blinkLED(uint32_t count = 0xFFFFFFFF) +{ + pinMode(LED_BUILTIN, OUTPUT); + + while (count--) { + digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level) + delay(50); // wait for a second + digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW + delay(50); // wait for a second + } +} + +void setup() { + // Init the cam QVGA, 30FPS + if (!cam.begin(RESOLUTION, IMAGE_MODE, 30)) { + blinkLED(); + } + + blinkLED(5); + + pinMode(LEDB, OUTPUT); + digitalWrite(LEDB, HIGH); + + // Flips the image vertically + cam.setVerticalFlip(true); + + // Mirrors the image horizontally + cam.setHorizontalMirror(true); + + // Calculate the max zoom window position + maxZoomX = cam.getResolutionWidth() - ZOOM_WINDOW_WIDTH; + maxZoomY = cam.getResolutionHeight() - ZOOM_WINDOW_HEIGHT; + + // Set the zoom window to 0,0 + cam.zoomTo(ZOOM_WINDOW_RESOLUTION, currentZoomX, currentZoomY); +} + +void sendFrame(){ + // Grab frame and write to serial + if (cam.grabFrame(frameBuffer, 3000) == 0) { + byte* buffer = frameBuffer.getBuffer(); + size_t bufferSize = cam.frameSize(); + digitalWrite(LEDB, LOW); + + // Split buffer into chunks + for(size_t i = 0; i < bufferSize; i += CHUNK_SIZE) { + size_t chunkSize = min(bufferSize - i, CHUNK_SIZE); + Serial.write(buffer + i, chunkSize); + Serial.flush(); + delay(1); // Small delay to allow the receiver to process the data + } + + digitalWrite(LEDB, HIGH); + } else { + blinkLED(20); + } +} + +void loop() { + if(!Serial) { + Serial.begin(115200); + while(!Serial); + } + + if(!Serial.available()) return; + byte request = Serial.read(); + + if(request == 1){ + sendFrame(); + currentZoomX += ZOOM_X_STEP; + + if(currentZoomX > maxZoomX){ + currentZoomX = 0; + currentZoomY += ZOOM_Y_STEP; + if(currentZoomY > maxZoomY){ + currentZoomY = 0; + } + } + cam.zoomTo(ZOOM_WINDOW_RESOLUTION, currentZoomX, currentZoomY); + } + +} diff --git a/libraries/Camera/examples/CameraMotionDetect/CameraMotionDetect.ino b/libraries/Camera/examples/CameraMotionDetect/CameraMotionDetect.ino index c920b0e0c..e0299c1e6 100644 --- a/libraries/Camera/examples/CameraMotionDetect/CameraMotionDetect.ino +++ b/libraries/Camera/examples/CameraMotionDetect/CameraMotionDetect.ino @@ -1,6 +1,12 @@ #include "camera.h" -#include "himax.h" -HM01B0 himax; + +// uncomment the correct camera in use +#include "hm0360.h" +HM0360 himax; + +// #include "himax.h" +// HM01B0 himax; + Camera cam(himax); #ifdef ARDUINO_NICLA_VISION diff --git a/libraries/Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde b/libraries/Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde index 43427a142..e8e098b13 100644 --- a/libraries/Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde +++ b/libraries/Camera/extras/CameraRawBytesVisualizer/CameraRawBytesVisualizer.pde @@ -20,7 +20,7 @@ final int cameraHeight = 240; final boolean useGrayScale = true; // Must match the baud rate in the Arduino sketch -final int baudRate = 921600; +final int baudRate = 115200; final int cameraBytesPerPixel = useGrayScale ? 1 : 2; final int cameraPixelCount = cameraWidth * cameraHeight; diff --git a/libraries/Camera/src/camera.cpp b/libraries/Camera/src/camera.cpp index 82a679755..e82ddfe90 100644 --- a/libraries/Camera/src/camera.cpp +++ b/libraries/Camera/src/camera.cpp @@ -137,6 +137,7 @@ const uint32_t restab[CAMERA_RMAX][2] = { {320, 240 }, // QVGA {320, 320 }, {640, 480 }, // VGA + {0, 0 }, // Empty entry because there's a jump in the resolution enum initializers {800, 600 }, // SVGA {1600, 1200}, // UXGA }; @@ -504,13 +505,32 @@ int Camera::setFrameRate(int32_t framerate) return -1; } -int Camera::setResolution(int32_t resolution) +int Camera::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, int32_t zoom_x, int32_t zoom_y) { if (this->sensor == NULL || resolution >= CAMERA_RMAX || pixformat >= CAMERA_PMAX || pixformat == -1) { return -1; } + // resolution = the full resolution to set the camera to + // zoom_resolution = the resolution to crop to when zooming (set equal to resolution for no zoom) + // final_resolution = the resolution to crop to (depends on zoom or not) + int32_t final_resolution; + // Check if zooming is asked for + if (resolution != zoom_resolution) + { + // Can't zoom into a larger window than the original + if (zoom_resolution > resolution) + { + return -1; + } + final_resolution = zoom_resolution; + } + else + { + final_resolution = resolution; + } + /* * @param X0 DCMI window X offset * @param Y0 DCMI window Y offset @@ -518,22 +538,87 @@ int Camera::setResolution(int32_t resolution) * @param YSize DCMI Line number */ HAL_DCMI_EnableCROP(&hdcmi); - uint32_t bpl = restab[resolution][0]; + uint32_t bpl = restab[final_resolution][0]; if (pixformat == CAMERA_RGB565 || (pixformat == CAMERA_GRAYSCALE && !this->sensor->getMono())) { // If the pixel format is Grayscale and sensor is Not monochrome, // the actual pixel format will be YUV (i.e 2 bytes per pixel). bpl *= 2; } - HAL_DCMI_ConfigCROP(&hdcmi, 0, 0, bpl - 1, restab[resolution][1] - 1); + HAL_DCMI_ConfigCROP(&hdcmi, 0, 0, bpl - 1, restab[final_resolution][1] - 1); - if (this->sensor->setResolution(resolution) == 0) { - this->resolution = resolution; + if (this->sensor->setResolutionWithZoom(resolution, zoom_resolution, zoom_x, zoom_y) == 0) { + this->resolution = final_resolution; return 0; } return -1; } +int Camera::setResolution(int32_t resolution) +{ + // Check for resolutions that would cause out-of-bounds indexing of restab + // This check is here because original_resolution will be trusted in all other code + if ((resolution < 0) || (resolution >= CAMERA_RMAX)) + { + return -1; + } + original_resolution = resolution; + return setResolutionWithZoom(resolution, resolution, 0, 0); +} + +int Camera::zoomTo(int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) +{ + // Check for zoom resolutions that would cause out-of-bounds indexing of restab + if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX)) + { + return -1; + } + // Check if the zoom window goes outside the frame on the x axis + // Notice that this form prevents uint32_t wraparound, so don't change it + if (zoom_x >= (restab[this->original_resolution][0]) - (restab[zoom_resolution][0])) + { + return -1; + } + // Check if the zoom window goes outside the frame on the y axis + // Notice that this form prevents uint32_t wraparound, so don't change it + if (zoom_y >= (restab[this->original_resolution][1]) - (restab[zoom_resolution][1])) + { + return -1; + } + return setResolutionWithZoom(this->original_resolution, zoom_resolution, zoom_x, zoom_y); +} + +int Camera::zoomToCenter(int32_t zoom_resolution) +{ + // Check for zoom resolutions that would cause out-of-bounds indexing of restab + if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX)) + { + return -1; + } + uint32_t zoom_x = (restab[this->original_resolution][0] - restab[zoom_resolution][0]) / 2; + uint32_t zoom_y = (restab[this->original_resolution][1] - restab[zoom_resolution][1]) / 2; + return setResolutionWithZoom(this->original_resolution, zoom_resolution, zoom_x, zoom_y); +} + +int Camera::setVerticalFlip(bool flip_enable) +{ + return (this->sensor->setVerticalFlip(flip_enable)); +} + +int Camera::setHorizontalMirror(bool mirror_enable) +{ + return (this->sensor->setHorizontalMirror(mirror_enable)); +} + +uint32_t Camera::getResolutionWidth() +{ + return (restab[this->original_resolution][0]); +} +uint32_t Camera::getResolutionHeight() +{ + return (restab[this->original_resolution][1]); +} + int Camera::setPixelFormat(int32_t pixformat) { if (this->sensor == NULL || pixformat >= CAMERA_PMAX) { diff --git a/libraries/Camera/src/camera.h b/libraries/Camera/src/camera.h index 1e5872daa..e7b2d77df 100644 --- a/libraries/Camera/src/camera.h +++ b/libraries/Camera/src/camera.h @@ -210,6 +210,18 @@ class ImageSensor { * @brief Set the resolution of the image sensor. * @note This has no effect on cameras that do not support variable resolutions. * @param resolution The desired resolution, as defined in the resolution enum + * @param zoom_resolution The desired zoom window size. + * @param zoom_x The desired x position of the zoom window. + * @param zoom_y The desired y position of the zoom window. + * @return int 0 on success, non-zero on failure + */ + virtual int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) = 0; + + /** + * @brief Set the resolution of the image sensor. + * + * @note This has no effect on cameras that do not support variable resolutions. + * @param resolution The desired resolution, as defined in the resolution enum * @return int 0 on success, non-zero on failure */ virtual int setResolution(int32_t resolution) = 0; @@ -276,12 +288,13 @@ class ImageSensor { * @return int 0 if no motion is detected, non-zero if motion is detected */ virtual int motionDetected() = 0; - + virtual int setVerticalFlip(bool flip_enable) = 0; + virtual int setHorizontalMirror(bool flip_enable) = 0; /** * @brief Output debug information to a stream. * You can use this function to output debug information to the serial port by passing Serial as the stream. * @param stream Stream to output the debug information - */ + */ virtual void debug(Stream &stream) = 0; /** @@ -370,6 +383,7 @@ class Camera { private: int32_t pixformat; /// Pixel format int32_t resolution; /// Camera resolution + int32_t original_resolution; /// The resolution originally set through setResolution() int32_t framerate; /// Frame rate ImageSensor *sensor; /// Pointer to the camera sensor int reset(); /// Reset the camera @@ -377,6 +391,8 @@ class Camera { Stream *_debug; /// Pointer to the debug stream arduino::MbedI2C *_i2c; /// Pointer to the I2C interface FrameBuffer *_framebuffer; /// Pointer to the frame buffer + int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, int32_t zoom_x, int32_t zoom_y); + public: /** @@ -522,6 +538,88 @@ class Camera { */ int motionDetected(); + /** + * @brief Zoom to a specific region of the image by setting the zoom window size and its position. + * The camera resolution must be set to a higher resolution than the zoom resolution for this to work. + * The zooming is done by cropping a higher resolution image to the zoom window. + * @note This function is currently only supported by the GC2145 sensor on the Arduino Nicla Vision. + * @param zoom_resolution The resolution of the zoom window. + * The resolution must be one of the following: + * - CAMERA_R160x120 + * - CAMERA_R320x240 + * - CAMERA_R320x320 + * - CAMERA_R640x480 + * - CAMERA_R800x600 + * If the desired resolution doesn't fit in the built-in memory, + * the framebuffer should be allocated on external RAM. + * @param zoom_x The x position of the zoom window. + * The value must be lower or equal to the width of the image minus the width of the zoom window. + * @param zoom_y The y position of the zoom window. + * The value must be lower or equal to the height of the image minus the height of the zoom window. + * @return 0 on success, -1 on failure. + */ + int zoomTo(int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y); + + /** + * @brief Zoom to the center of the image by setting the zoom window size. + * + * @param zoom_resolution The resolution of the zoom window. + * The resolution must be one of the following: + * - CAMERA_R160x120 + * - CAMERA_R320x240 + * - CAMERA_R320x320 + * - CAMERA_R640x480 + * - CAMERA_R800x600 + * If the desired resolution doesn't fit in the built-in memory, + * the framebuffer should be allocated on external RAM. + * @return 0 on success, -1 on failure. + */ + int zoomToCenter(int32_t zoom_resolution); + + /** + * @brief Flips the camera image vertically. + * + * @param flip_enable Set to true to enable vertical flip, false to disable. + * @return 0 on success, -1 on failure. + */ + int setVerticalFlip(bool flip_enable); + + /** + * @brief Mirrors the camera image horizontally. + * + * @param mirror_enable Set to true to enable horizontal mirror, false to disable. + * @return 0 on success, -1 on failure. + */ + int setHorizontalMirror(bool mirror_enable); + + /** + * @brief Get the width of the current camera resolution. + * This can for example be used to calculate the zoom window position and size. + * In the following example, the camera is zoomed to the top right side of the image: + * @code + * // Calculate the zoom window position + * uint32_t max_zoom_x = camera.getResolutionWidth() - 320; + * // Zoom to the calculated position and size + * camera.zoomTo(CAMERA_R320x240, max_zoom_x, 0); + * @endcode + * @return uint32_t The width of the camera resolution. + */ + uint32_t getResolutionWidth(); + + /** + * @brief Get the height of the current camera resolution. + * This can for example be used to calculate the zoom window position and size. + * In the following example, the camera is zoomed to the bottom left side of the image: + * @code + * // Calculate the zoom window position + * uint32_t max_zoom_y = camera.getResolutionHeight() - 240; + * // Zoom to the calculated position and size + * camera.zoomTo(CAMERA_R320x240, 0, max_zoom_y); + * @endcode + * @return uint32_t The height of the camera resolution. + */ + uint32_t getResolutionHeight(); + /** * @brief Output debug information to a stream. * You can use this function to output debug information to the serial port by passing Serial as the stream. diff --git a/libraries/GC2145/gc2145.cpp b/libraries/GC2145/gc2145.cpp index 435621618..21ec73d31 100644 --- a/libraries/GC2145/gc2145.cpp +++ b/libraries/GC2145/gc2145.cpp @@ -763,7 +763,36 @@ int GC2145::setFrameRate(int32_t framerate) return 0; } +int GC2145::setVerticalFlip(bool flip_enable) +{ + // The GC2145 doesn't return this value when reading the Analog mode 1 register + // so we have to save it for setHorizontalMirror() + vertical_flip_state = flip_enable; + // Using the Analog mode 1 register (0x17) + uint8_t old_value = regRead(GC2145_I2C_ADDR, 0x17); + int retVal = regWrite(GC2145_I2C_ADDR, 0x17, (old_value & 0b11111100) | (flip_enable << 1) | horizontal_mirror_state); + // Notice that the error codes from regWrite() are positive ones passed on from Wire, not -1 + return ((0 == retVal) ? 0 : -1); +} + +int GC2145::setHorizontalMirror(bool mirror_enable) +{ + // The GC2145 doesn't return this value when reading the Analog mode 1 register + // so we have to save it for setVerticalFlip() + horizontal_mirror_state = mirror_enable; + // Using the Analog mode 1 register (0x17) + uint8_t old_value = regRead(GC2145_I2C_ADDR, 0x17); + int retVal = regWrite(GC2145_I2C_ADDR, 0x17, (old_value & 0b11111100) | mirror_enable | (vertical_flip_state << 1)); + // Notice that the error codes from regWrite() are positive ones passed on from Wire, not -1 + return ((0 == retVal) ? 0 : -1); +} + int GC2145::setResolution(int32_t resolution) +{ + setResolutionWithZoom(resolution, resolution, 0, 0); +} + +int GC2145::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) { int ret = 0; @@ -809,6 +838,44 @@ int GC2145::setResolution(int32_t resolution) // Set readout window first. ret |= setWindow(0x09, win_x, win_y, win_w + 16, win_h + 8); + // Zoom mode active + if (resolution != zoom_resolution) + { + // Can't zoom into a larger window than the original + if (zoom_resolution > resolution) + { + return -1; + } + + // The zoom resolution constant is outside of the allowed range + if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX)) + { + return -1; + } + + uint32_t zoom_w = restab[zoom_resolution][0]; + uint32_t zoom_h = restab[zoom_resolution][1]; + + // Check if the zoom window goes outside the frame on the x axis + // Notice that this form prevents uint32_t wraparound, so don't change it + if (zoom_x >= (w - zoom_w)) + { + return -1; + } + // Check of the zoom window goes outside the frame on the y axis + // Notice that this form prevents uint32_t wraparound, so don't change it + if (zoom_y >= (h - zoom_h)) + { + return -1; + } + + // Set the cropping window parameters to the zoom window parameters + x = zoom_x; + y = zoom_y; + w = zoom_w; + h = zoom_h; + } + // Set cropping window next. ret |= setWindow(0x91, x, y, w, h); @@ -820,7 +887,6 @@ int GC2145::setResolution(int32_t resolution) ret |= regWrite(GC2145_I2C_ADDR, 0x9A, 0x0E); return ret; - } int GC2145::setPixelFormat(int32_t pixformat) diff --git a/libraries/GC2145/gc2145.h b/libraries/GC2145/gc2145.h index dce65b33b..378a1b5f9 100644 --- a/libraries/GC2145/gc2145.h +++ b/libraries/GC2145/gc2145.h @@ -28,6 +28,8 @@ class GC2145: public ImageSensor { arduino::MbedI2C *_i2c; int regWrite(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data, bool wide_addr = false); uint8_t regRead(uint8_t dev_addr, uint16_t reg_addr, bool wide_addr = false); + bool vertical_flip_state = false; + bool horizontal_mirror_state = false; public: GC2145(arduino::MbedI2C &i2c = CameraWire); @@ -37,6 +39,7 @@ class GC2145: public ImageSensor { bool getMono() { return false; }; uint32_t getClockFrequency() { return 12000000; }; int setFrameRate(int32_t framerate); + int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y); int setResolution(int32_t resolution); int setPixelFormat(int32_t pixformat); int enableMotionDetection(md_callback_t callback) { return 0; }; @@ -44,7 +47,9 @@ class GC2145: public ImageSensor { int setMotionDetectionWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { return 0; }; int setMotionDetectionThreshold(uint32_t threshold) { return 0; }; int motionDetected() { return 0; }; + int setVerticalFlip(bool flip_enable); + int setHorizontalMirror(bool mirror_enable); void debug(Stream &stream); }; - + #endif /* __GC2145_H */ diff --git a/libraries/Himax_HM01B0/himax.cpp b/libraries/Himax_HM01B0/himax.cpp index ee27b452b..81833ed69 100644 --- a/libraries/Himax_HM01B0/himax.cpp +++ b/libraries/Himax_HM01B0/himax.cpp @@ -341,10 +341,30 @@ int HM01B0::reset() return (max_timeout > 0) ? 0 : -1; } +int HM01B0::setVerticalFlip(bool flip_enable) +{ + return -1; +} + +int HM01B0::setHorizontalMirror(bool mirror_enable) +{ + return -1; +} + int HM01B0::setResolution(int32_t resolution) +{ + setResolutionWithZoom(resolution, resolution, 0, 0); +} + +int HM01B0::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) { int ret = 0; + if (resolution != zoom_resolution) + { + return -1; + } + switch (resolution) { case CAMERA_R160x120: for(uint32_t i = 0; himax_qqvga_regs[i][0]; i++) { diff --git a/libraries/Himax_HM01B0/himax.h b/libraries/Himax_HM01B0/himax.h index 38695d9b5..2aa365fa9 100644 --- a/libraries/Himax_HM01B0/himax.h +++ b/libraries/Himax_HM01B0/himax.h @@ -40,6 +40,7 @@ class HM01B0: public ImageSensor { bool getMono() { return true; }; uint32_t getClockFrequency() { return 6000000; }; int setFrameRate(int32_t framerate); + int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y); int setResolution(int32_t resolution); int setPixelFormat(int32_t pixformat); int setTestPattern(bool enable, bool walking) override; @@ -50,6 +51,8 @@ class HM01B0: public ImageSensor { int motionDetected(); int pollMotionDetection(); int clearMotionDetection(); + int setVerticalFlip(bool flip_enable); + int setHorizontalMirror(bool mirror_enable); uint8_t printRegs(); void debug(Stream &stream); diff --git a/libraries/Himax_HM0360/hm0360.cpp b/libraries/Himax_HM0360/hm0360.cpp index 8cd0b3703..3924afcc9 100644 --- a/libraries/Himax_HM0360/hm0360.cpp +++ b/libraries/Himax_HM0360/hm0360.cpp @@ -586,10 +586,30 @@ int HM0360::reset() return (max_timeout > 0) ? 0 : -1; } +int HM0360::setVerticalFlip(bool flip_enable) +{ + return -1; +} + +int HM0360::setHorizontalMirror(bool mirror_enable) +{ + return -1; +} + int HM0360::setResolution(int32_t resolution) +{ + setResolutionWithZoom(resolution, resolution, 0, 0); +} + +int HM0360::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) { int ret = 0; + if (resolution != zoom_resolution) + { + return -1; + } + switch (resolution) { case CAMERA_R160x120: for(uint32_t i = 0; himax_qqvga_regs[i][0]; i++) { diff --git a/libraries/Himax_HM0360/hm0360.h b/libraries/Himax_HM0360/hm0360.h index 5745bc101..8a4946b80 100644 --- a/libraries/Himax_HM0360/hm0360.h +++ b/libraries/Himax_HM0360/hm0360.h @@ -40,6 +40,7 @@ class HM0360: public ImageSensor { bool getMono() { return true; }; uint32_t getClockFrequency() { return 24000000; }; int setFrameRate(int32_t framerate); + int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y); int setResolution(int32_t resolution); int setPixelFormat(int32_t pixformat); int setTestPattern(bool enable, bool walking) override; @@ -50,6 +51,8 @@ class HM0360: public ImageSensor { int motionDetected(); int pollMotionDetection(); int clearMotionDetection(); + int setVerticalFlip(bool flip_enable); + int setHorizontalMirror(bool mirror_enable); uint8_t printRegs(); void debug(Stream &stream); diff --git a/libraries/OV7670/ov7670.cpp b/libraries/OV7670/ov7670.cpp index d4e8f9fd4..f6fd3255b 100644 --- a/libraries/OV7670/ov7670.cpp +++ b/libraries/OV7670/ov7670.cpp @@ -697,12 +697,32 @@ int OV7670::setFrameRate(int32_t framerate) return 0; } +int OV7670::setVerticalFlip(bool flip_enable) +{ + return -1; +} + +int OV7670::setHorizontalMirror(bool mirror_enable) +{ + return -1; +} + int OV7670::setResolution(int32_t resolution) +{ + setResolutionWithZoom(resolution, resolution, 0, 0); +} + +int OV7670::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) { int ret = 0; const uint8_t (*regs)[2]; + if (resolution != zoom_resolution) + { + return -1; + } + switch (resolution) { case CAMERA_R640x480: regs = vga_regs; diff --git a/libraries/OV7670/ov767x.h b/libraries/OV7670/ov767x.h index 60f89c025..2160de798 100644 --- a/libraries/OV7670/ov767x.h +++ b/libraries/OV7670/ov767x.h @@ -45,6 +45,7 @@ class OV7670: public ImageSensor { bool getMono() { return false; }; uint32_t getClockFrequency() { return 12000000; }; int setFrameRate(int32_t framerate); + int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y); int setResolution(int32_t resolution); int setPixelFormat(int32_t pixformat); int enableMotionDetection(md_callback_t callback) { return 0; }; @@ -52,6 +53,8 @@ class OV7670: public ImageSensor { int setMotionDetectionWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { return 0; }; int setMotionDetectionThreshold(uint32_t threshold) { return 0; }; int motionDetected() { return 0; }; + int setVerticalFlip(bool flip_enable); + int setHorizontalMirror(bool mirror_enable); void debug(Stream &stream); };