Skip to content

Commit 39bb1ba

Browse files
author
Alrik Vidstrom
committed
Add zoom, flip, and mirror functionality
Adds the functions zoomTo(), zoomToCenter(), setVerticalFlip(), setHorizontalMirror(), getResolutionWidth(), and getResolutionHeight() to the Camera library. The old setResolution() function is changed into the new private function setResolutionWithZoom(), which is called by the new version of setResolution(), as well as by the zoomTo() and zoomToCenter() functions. These changes required some changes in the abstract class ImageSensor, which, in turn, required further changes in the camera drivers. The only camera driver that fully supports the new functionality is GC2145, and the others return -1 on all calls. The function signature for setResolution() is changed, and two new functions are added: setVerticalFlip() and setHorizontalMirror().
1 parent cdaa048 commit 39bb1ba

File tree

10 files changed

+226
-15
lines changed

10 files changed

+226
-15
lines changed

libraries/Camera/src/camera.cpp

+90-5
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ const uint32_t restab[CAMERA_RMAX][2] = {
135135
{320, 240 },
136136
{320, 320 },
137137
{640, 480 },
138+
{0, 0 }, // Empty entry because there's a jump in the resolution enum initializers
138139
{800, 600 },
139140
{1600, 1200},
140141
};
@@ -502,36 +503,120 @@ int Camera::setFrameRate(int32_t framerate)
502503
return -1;
503504
}
504505

505-
int Camera::setResolution(int32_t resolution)
506+
int Camera::setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, int32_t zoom_x, int32_t zoom_y)
506507
{
507508
if (this->sensor == NULL || resolution >= CAMERA_RMAX
508509
|| pixformat >= CAMERA_PMAX || pixformat == -1) {
509510
return -1;
510511
}
511512

513+
// resolution = the full resolution to set the camera to
514+
// zoom_resolution = the resolution to crop to when zooming (set equal to resolution for no zoom)
515+
// final_resolution = the resolution to crop to (depends on zoom or not)
516+
int32_t final_resolution;
517+
// Check if zooming is asked for
518+
if (resolution != zoom_resolution)
519+
{
520+
// Can't zoom into a larger window than the original
521+
if (zoom_resolution > resolution)
522+
{
523+
return -1;
524+
}
525+
final_resolution = zoom_resolution;
526+
}
527+
else
528+
{
529+
final_resolution = resolution;
530+
}
531+
512532
/*
513533
* @param X0 DCMI window X offset
514534
* @param Y0 DCMI window Y offset
515535
* @param XSize DCMI Pixel per line
516536
* @param YSize DCMI Line number
517537
*/
518538
HAL_DCMI_EnableCROP(&hdcmi);
519-
uint32_t bpl = restab[resolution][0];
539+
uint32_t bpl = restab[final_resolution][0];
520540
if (pixformat == CAMERA_RGB565 ||
521541
(pixformat == CAMERA_GRAYSCALE && !this->sensor->getMono())) {
522542
// If the pixel format is Grayscale and sensor is Not monochrome,
523543
// the actual pixel format will be YUV (i.e 2 bytes per pixel).
524544
bpl *= 2;
525545
}
526-
HAL_DCMI_ConfigCROP(&hdcmi, 0, 0, bpl - 1, restab[resolution][1] - 1);
546+
HAL_DCMI_ConfigCROP(&hdcmi, 0, 0, bpl - 1, restab[final_resolution][1] - 1);
527547

528-
if (this->sensor->setResolution(resolution) == 0) {
529-
this->resolution = resolution;
548+
if (this->sensor->setResolution(resolution, zoom_resolution, zoom_x, zoom_y) == 0) {
549+
this->resolution = final_resolution;
530550
return 0;
531551
}
532552
return -1;
533553
}
534554

555+
int Camera::setResolution(int32_t resolution)
556+
{
557+
// Check for resolutions that would cause out-of-bounds indexing of restab
558+
// This check is here because original_resolution will be trusted in all other code
559+
if ((resolution < 0) || (resolution >= CAMERA_RMAX))
560+
{
561+
return -1;
562+
}
563+
original_resolution = resolution;
564+
return setResolutionWithZoom(resolution, resolution, 0, 0);
565+
}
566+
567+
int Camera::zoomTo(int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y)
568+
{
569+
// Check for zoom resolutions that would cause out-of-bounds indexing of restab
570+
if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX))
571+
{
572+
return -1;
573+
}
574+
// Check if the zoom window goes outside the frame on the x axis
575+
// Notice that this form prevents uint32_t wraparound, so don't change it
576+
if (zoom_x >= (restab[this->original_resolution][0]) - (restab[zoom_resolution][0]))
577+
{
578+
return -1;
579+
}
580+
// Check if the zoom window goes outside the frame on the y axis
581+
// Notice that this form prevents uint32_t wraparound, so don't change it
582+
if (zoom_y >= (restab[this->original_resolution][1]) - (restab[zoom_resolution][1]))
583+
{
584+
return -1;
585+
}
586+
return setResolutionWithZoom(this->original_resolution, zoom_resolution, zoom_x, zoom_y);
587+
}
588+
589+
int Camera::zoomToCenter(int32_t zoom_resolution)
590+
{
591+
// Check for zoom resolutions that would cause out-of-bounds indexing of restab
592+
if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX))
593+
{
594+
return -1;
595+
}
596+
uint32_t zoom_x = (restab[this->original_resolution][0] - restab[zoom_resolution][0]) / 2;
597+
uint32_t zoom_y = (restab[this->original_resolution][1] - restab[zoom_resolution][1]) / 2;
598+
return setResolutionWithZoom(this->original_resolution, zoom_resolution, zoom_x, zoom_y);
599+
}
600+
601+
int Camera::setVerticalFlip(bool flip_mode)
602+
{
603+
return (this->sensor->setVerticalFlip(flip_mode));
604+
}
605+
606+
int Camera::setHorizontalMirror(bool mirror_mode)
607+
{
608+
return (this->sensor->setHorizontalMirror(mirror_mode));
609+
}
610+
611+
uint32_t Camera::getResolutionWidth()
612+
{
613+
return (restab[this->original_resolution][0]);
614+
}
615+
uint32_t Camera::getResolutionHeight()
616+
{
617+
return (restab[this->original_resolution][1]);
618+
}
619+
535620
int Camera::setPixelFormat(int32_t pixformat)
536621
{
537622
if (this->sensor == NULL || pixformat >= CAMERA_PMAX) {

libraries/Camera/src/camera.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,15 @@ class ImageSensor {
7171
virtual bool getMono() = 0;
7272
virtual uint32_t getClockFrequency() = 0;
7373
virtual int setFrameRate(int32_t framerate) = 0;
74-
virtual int setResolution(int32_t resolution) = 0;
74+
virtual int setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y) = 0;
7575
virtual int setPixelFormat(int32_t pixelformat) = 0;
7676
virtual int enableMotionDetection(md_callback_t callback) = 0;
7777
virtual int disableMotionDetection() = 0;
7878
virtual int setMotionDetectionWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h) = 0;
7979
virtual int setMotionDetectionThreshold(uint32_t threshold) = 0;
8080
virtual int motionDetected() = 0;
81+
virtual int setVerticalFlip(bool flip_mode) = 0;
82+
virtual int setHorizontalMirror(bool flip_mode) = 0;
8183
virtual void debug(Stream &stream) = 0;
8284

8385
virtual int setStandby(bool enable) {
@@ -114,13 +116,15 @@ class Camera {
114116
private:
115117
int32_t pixformat;
116118
int32_t resolution;
119+
int32_t original_resolution; // The resolution originally set through setResolution()
117120
int32_t framerate;
118121
ImageSensor *sensor;
119122
int reset();
120123
ScanResults<uint8_t> i2cScan();
121124
Stream *_debug;
122125
arduino::MbedI2C *_i2c;
123126
FrameBuffer *_framebuffer;
127+
int setResolutionWithZoom(int32_t resolution, int32_t zoom_resolution, int32_t zoom_x, int32_t zoom_y);
124128
public:
125129
Camera(ImageSensor &sensor);
126130
bool begin(int32_t resolution=CAMERA_R320x240, int32_t pixformat=CAMERA_GRAYSCALE, int32_t framerate=30);
@@ -137,6 +141,12 @@ class Camera {
137141
int setMotionDetectionWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h);
138142
int setMotionDetectionThreshold(uint32_t threshold);
139143
int motionDetected();
144+
int zoomTo(int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y);
145+
int zoomToCenter(int32_t zoom_resolution);
146+
int setVerticalFlip(bool flip_mode);
147+
int setHorizontalMirror(bool mirror_mode);
148+
uint32_t getResolutionWidth();
149+
uint32_t getResolutionHeight();
140150
void debug(Stream &stream);
141151
};
142152

libraries/GC2145/gc2145.cpp

+63-2
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,31 @@ int GC2145::setFrameRate(int32_t framerate)
763763
return 0;
764764
}
765765

766-
int GC2145::setResolution(int32_t resolution)
766+
int GC2145::setVerticalFlip(bool flip_mode)
767+
{
768+
// The GC2145 doesn't return this value when reading the Analog mode 1 register
769+
// so we have to save it for setHorizontalMirror()
770+
vertical_flip_state = flip_mode;
771+
// Using the Analog mode 1 register (0x17)
772+
uint8_t old_value = regRead(GC2145_I2C_ADDR, 0x17);
773+
int retVal = regWrite(GC2145_I2C_ADDR, 0x17, (old_value & 0b11111100) | (flip_mode << 1) | horizontal_mirror_state);
774+
// Notice that the error codes from regWrite() are positive ones passed on from Wire, not -1
775+
return ((0 == retVal) ? 0 : -1);
776+
}
777+
778+
int GC2145::setHorizontalMirror(bool mirror_mode)
779+
{
780+
// The GC2145 doesn't return this value when reading the Analog mode 1 register
781+
// so we have to save it for setVerticalFlip()
782+
horizontal_mirror_state = mirror_mode;
783+
// Using the Analog mode 1 register (0x17)
784+
uint8_t old_value = regRead(GC2145_I2C_ADDR, 0x17);
785+
int retVal = regWrite(GC2145_I2C_ADDR, 0x17, (old_value & 0b11111100) | mirror_mode | (vertical_flip_state << 1));
786+
// Notice that the error codes from regWrite() are positive ones passed on from Wire, not -1
787+
return ((0 == retVal) ? 0 : -1);
788+
}
789+
790+
int GC2145::setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y)
767791
{
768792
int ret = 0;
769793

@@ -809,6 +833,44 @@ int GC2145::setResolution(int32_t resolution)
809833
// Set readout window first.
810834
ret |= setWindow(0x09, win_x, win_y, win_w + 16, win_h + 8);
811835

836+
// Zoom mode active
837+
if (resolution != zoom_resolution)
838+
{
839+
// Can't zoom into a larger window than the original
840+
if (zoom_resolution > resolution)
841+
{
842+
return -1;
843+
}
844+
845+
// The zoom resolution constant is outside of the allowed range
846+
if ((zoom_resolution < 0) || (zoom_resolution >= CAMERA_RMAX))
847+
{
848+
return -1;
849+
}
850+
851+
uint32_t zoom_w = restab[zoom_resolution][0];
852+
uint32_t zoom_h = restab[zoom_resolution][1];
853+
854+
// Check if the zoom window goes outside the frame on the x axis
855+
// Notice that this form prevents uint32_t wraparound, so don't change it
856+
if (zoom_x >= (w - zoom_w))
857+
{
858+
return -1;
859+
}
860+
// Check of the zoom window goes outside the frame on the y axis
861+
// Notice that this form prevents uint32_t wraparound, so don't change it
862+
if (zoom_y >= (h - zoom_h))
863+
{
864+
return -1;
865+
}
866+
867+
// Set the cropping window parameters to the zoom window parameters
868+
x = zoom_x;
869+
y = zoom_y;
870+
w = zoom_w;
871+
h = zoom_h;
872+
}
873+
812874
// Set cropping window next.
813875
ret |= setWindow(0x91, x, y, w, h);
814876

@@ -820,7 +882,6 @@ int GC2145::setResolution(int32_t resolution)
820882
ret |= regWrite(GC2145_I2C_ADDR, 0x9A, 0x0E);
821883

822884
return ret;
823-
824885
}
825886

826887
int GC2145::setPixelFormat(int32_t pixformat)

libraries/GC2145/gc2145.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class GC2145: public ImageSensor {
2828
arduino::MbedI2C *_i2c;
2929
int regWrite(uint8_t dev_addr, uint16_t reg_addr, uint8_t reg_data, bool wide_addr = false);
3030
uint8_t regRead(uint8_t dev_addr, uint16_t reg_addr, bool wide_addr = false);
31+
bool vertical_flip_state = false;
32+
bool horizontal_mirror_state = false;
3133

3234
public:
3335
GC2145(arduino::MbedI2C &i2c = CameraWire);
@@ -37,13 +39,15 @@ class GC2145: public ImageSensor {
3739
bool getMono() { return false; };
3840
uint32_t getClockFrequency() { return 12000000; };
3941
int setFrameRate(int32_t framerate);
40-
int setResolution(int32_t resolution);
42+
int setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y);
4143
int setPixelFormat(int32_t pixformat);
4244
int enableMotionDetection(md_callback_t callback) { return 0; };
4345
int disableMotionDetection() { return 0; };
4446
int setMotionDetectionWindow(uint32_t x, uint32_t y, uint32_t w, uint32_t h) { return 0; };
4547
int setMotionDetectionThreshold(uint32_t threshold) { return 0; };
4648
int motionDetected() { return 0; };
49+
int setVerticalFlip(bool flip_mode);
50+
int setHorizontalMirror(bool mirror_mode);
4751
void debug(Stream &stream);
4852
};
4953

libraries/Himax_HM01B0/himax.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,25 @@ int HM01B0::reset()
341341
return (max_timeout > 0) ? 0 : -1;
342342
}
343343

344-
int HM01B0::setResolution(int32_t resolution)
344+
int HM01B0::setVerticalFlip(bool flip_mode)
345+
{
346+
return -1;
347+
}
348+
349+
int HM01B0::setHorizontalMirror(bool mirror_mode)
350+
{
351+
return -1;
352+
}
353+
354+
int HM01B0::setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y)
345355
{
346356
int ret = 0;
347357

358+
if (resolution != zoom_resolution)
359+
{
360+
return -1;
361+
}
362+
348363
switch (resolution) {
349364
case CAMERA_R160x120:
350365
for(uint32_t i = 0; himax_qqvga_regs[i][0]; i++) {

libraries/Himax_HM01B0/himax.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class HM01B0: public ImageSensor {
4040
bool getMono() { return true; };
4141
uint32_t getClockFrequency() { return 6000000; };
4242
int setFrameRate(int32_t framerate);
43-
int setResolution(int32_t resolution);
43+
int setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y);
4444
int setPixelFormat(int32_t pixformat);
4545
int setTestPattern(bool enable, bool walking) override;
4646
int enableMotionDetection(md_callback_t callback=NULL);
@@ -50,6 +50,8 @@ class HM01B0: public ImageSensor {
5050
int motionDetected();
5151
int pollMotionDetection();
5252
int clearMotionDetection();
53+
int setVerticalFlip(bool flip_mode);
54+
int setHorizontalMirror(bool mirror_mode);
5355

5456
uint8_t printRegs();
5557
void debug(Stream &stream);

libraries/Himax_HM0360/hm0360.cpp

+16-1
Original file line numberDiff line numberDiff line change
@@ -586,10 +586,25 @@ int HM0360::reset()
586586
return (max_timeout > 0) ? 0 : -1;
587587
}
588588

589-
int HM0360::setResolution(int32_t resolution)
589+
int HM0360::setVerticalFlip(bool flip_mode)
590+
{
591+
return -1;
592+
}
593+
594+
int HM0360::setHorizontalMirror(bool mirror_mode)
595+
{
596+
return -1;
597+
}
598+
599+
int HM0360::setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y)
590600
{
591601
int ret = 0;
592602

603+
if (resolution != zoom_resolution)
604+
{
605+
return -1;
606+
}
607+
593608
switch (resolution) {
594609
case CAMERA_R160x120:
595610
for(uint32_t i = 0; himax_qqvga_regs[i][0]; i++) {

libraries/Himax_HM0360/hm0360.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class HM0360: public ImageSensor {
4040
bool getMono() { return true; };
4141
uint32_t getClockFrequency() { return 24000000; };
4242
int setFrameRate(int32_t framerate);
43-
int setResolution(int32_t resolution);
43+
int setResolution(int32_t resolution, int32_t zoom_resolution, uint32_t zoom_x, uint32_t zoom_y);
4444
int setPixelFormat(int32_t pixformat);
4545
int setTestPattern(bool enable, bool walking) override;
4646
int enableMotionDetection(md_callback_t callback=NULL);
@@ -50,6 +50,8 @@ class HM0360: public ImageSensor {
5050
int motionDetected();
5151
int pollMotionDetection();
5252
int clearMotionDetection();
53+
int setVerticalFlip(bool flip_mode);
54+
int setHorizontalMirror(bool mirror_mode);
5355

5456
uint8_t printRegs();
5557
void debug(Stream &stream);

0 commit comments

Comments
 (0)