The Adafruit_OV7670 library provides a number of special image effects. Some of these are “in-camera” effects — every frame from the camera continuously comes out this way in real time, with no processing required on the host microcontroller. Others are “postprocessing” effects, requiring that the camera be paused while the host microcontroller does a number on the last-received image in memory.

For reference, here’s a normal unmodified scene captured from the OV7670 and shown on a TFT display.

In-Camera Effects

The camera can mirror (flip) the image on the horizontal and/or vertical axes, set with the flip() function. This expects two boolean values (true or false, or 1 or 0) to select flips for the horizontal and vertical axes, respectively:

cam.flip(false, false); Disables flips, captures images normally.

cam.flip(true, false); Enables horizontal flip only. This can be helpful for selfie previews…like a mirror, what happens on your left or right shows on the screen’s corresponding left or right.

cam.flip(false, true); Enables vertical flip only.

cam.flip(true, true); Flips both axes. This is equivalent to 180 degree rotation, and can be helpful if your camera and display must be physically mounted in opposite orientations (or, many screens also have their own function providing the same).

Night mode can sometimes take better images in low-light situations. The tradeoff is a reduced frame rate, as the camera is adding up several images over time. The maximum number of frames to accumulate can be specified…though, if lighting is sufficient, the camera might ignore this and use a lesser setting. It’s enabled or disabled with:

cam.night(setting);

where setting is one of:

  • OV7670_NIGHT_MODE_8 — Accumulate up to 8 frames maximum.
  • OV7670_NIGHT_MODE_4 — Up to 4 frames max.
  • OV7670_NIGHT_MODE_2 — Up to 2 frames.
  • OV7670_NIGHT_MODE_OFF — Disable night mode and return to normal full frame rate.

The camera can output test patterns, if that’s useful to anybody:

cam.test_pattern(setting);

where setting is one of:

  • OV7670_TEST_PATTERN_SHIFTING_1 — single-pixel-wide vertical RGB stripes.
  • OV7670_TEST_PATTERN_COLOR_BAR — 8 color bars (second bar is yellow, but is “blown out” by the exposure in this photo, sorry).
  • OV7670_TEST_PATTERN_COLOR_BAR_FADE — 8 color bars with a fade to white.
  • OV7670_TEST_PATTERN_NONE — Turn off test pattern and return to normal image capture.

Postprocessing Effects

The following effects are generated in code, not by the camera. It’s therefore necessary to pause the camera output before performing any of these operations, else the next incoming frame will overwrite the interim results in RAM.

Download: file
// Pause camera before processing image
cam.suspend();

// Call processing function(s)
cam.image_edges();

// Do something with image data here -- TFT display, SD card, etc.

// Finished with image, return image buffer to camera
cam.resume();

All of the postprocessing function names begin with image_

You can chain multiple processing functions, each will modify the output of the prior function. For example, image_median() then image_edges(). The order of operations will affect the outcome; they are not interchangeable.

Remember that these only process the last-captured image in memory. They are not continuously applied while the camera is “live.” You must suspend, process, do something with the image data, then resume.

Some of these functions only work in RGB mode, YUV is not always supported.

cam.image_negative() inverts the image — light becomes dark, dark becomes light, a red dragon becomes cyan.

cam.image_threshold() reduces an image to 1 bit each for red, green and blue. It accepts an optional argument (0 to 255, default is 128) to set the brightness level below/above which the 1-bit determination is made.

cam.image_posterize(n) reduces the number of brightness “steps” or levels in an image. Whereas image_threshold() always results in 2 levels, image_posterize() can generate some in-between brightness levels — 3, 4, 5 and so forth — specified by the single argument.

The following work with RGB images only, YUV is not handled.

cam.image_mosaic(tile_width, tile_height) applies a low-res “shower door effect” to the image, averaging all the pixels within each block.

The two arguments are the width and height (in pixels) of the mosaic tiles. These do not need to be powers of two, anything >= 1 will suffice. If the image size does not divide evenly into the tile size, the fractional tiles will always be along the right and/or bottom edge(s).

cam.image_median() reduces the amount of pixel “noise” in an image while generally preserving higher contrast details.

This is a fairly math-intensive operation and might only manage 1-2 frames per second, that’s normal.

cam.image_edges() looks for high-contrast changes in an image and generally highlights object edges.

This requires objects be in-focus and adequately lit. In some cases the result might be nearly empty or totally full of pixel “snow,” so image_edges() accepts an optional value to configure the edge sensitivity — pass a value from 0 to 31 (default is 4), where smaller values make it more sensitive to edges, larger values less so.

This guide was first published on Jul 28, 2020. It was last updated on Jul 28, 2020.
This page (Arduino Library: Effects) was last updated on Sep 21, 2020.