Image filtering
means the processing of images using a filter. The term filter
in computer vision usually means pixel values modification, which for the given pixel depends only on the pixel values in the neighborhood of the pixel and is independent of the pixel's position. The simplest filters are pixel operations, which transform each pixel value using a rule; for example, the multiplication of each image's pixel with some scalar value. So, += value
, -= value
, *= value
and set( value )
functions, discussed in the Working with ofxCv images section, are pixel operations.
The ofxCv images contain the following filtering functions and pixel operations:
blur( winSize )
function is a smoothing filter that averages the pixel values in a square window around the given pixel with size winSize
× winSize
pixels. Here, winSize
must be an odd integer (that is winSize
is equal to 2*rad+1
for some integer rad). Increasing the winSize
parameter leads to more smoothing. This filter is very fast and gives a smoothing result of moderate quality.blurGaussian( winSize )
function is a smoothing filter that uses the Gaussian weight function for averaging. The window size is winSize
× winSize
pixels and winSize
must be an odd integer. This filter is more accurate than blur
(because blur
adds artifacts such as moire due to its square averaging). However, blurGaussian()
is more CPU-expensive.If you wish to compare the results of blur
and blurGaussian()
, you should use different window sizes. The size in blurGaussian()
should be greater than blur()
by at least twice; for example, blur( 11 )
and blurGaussian( 21 )
.
erode()
function is a minimizing filter that sets the minimal value to a pixel from a square window of 3
× 3
pixels. This operation is called morphological erosion. It is often used for binary images where it is used for removing small noisy white areas.dilate()
function is a maximizing filter that sets the maximal value to a pixel from a square window of 3
× 3
pixels. This operation is called morphological dilation. It is often used for binary images where it is used for filling small holes in the white areas.convertToRange( minValue, maxValue )
pixel operation maps pixel values from the range of the image class to the [minValue
, maxValue
] range. It is very useful for any linear transformation of pixel values; for example, floatImage.convertToRange( 0.5, 1.5 )
maps the pixel values from the range [0, 1] to the range [0.5
, 1.5
] so it acts on pixel values by formula value = 0.5 + value * (1.5 - 0.5).invert()
function is a pixel operation that inverts every bit of the pixel value. It is useful for images of the type ofxCvGrayscaleImage
where it acts by the formula value that equals 255-value
, and so it transforms the pixel value from 0 to 255 and 255 to 0. Such an operation can be done using grayImage.convertToRange( 255, 0 )
but invert()
works faster.ofxCvGrayscaleImage
class has a very important pixel operation of thresholding threshold( threshValue )
. It sets the pixel value to 255 for each pixel if its value is not less than threshValue
or 0. Otherwise, there is the second optional parameter in the function, doInvert
of the type bool
. When it is true
, that is threshold( threshValue, true )
, the result is inverted.threshold()
function is a crucial step in many computer vision processing algorithms because it converts a grayscale halftone image to a binary image. These binary images are then used for detecting, recognizing, and measuring objects such as human fingers and objects on a table. The reason for this is that binary images are simple objects used for performing shape analysis, area and perimeter calculation, and other things. See the example in the An example for searching bright objects in video section.Now we will consider examples of using filtering.
Gaussian smoothing is probably the most used filter in computer vision because this filter optimally suppresses random noise in the image for the corresponding filter window size. Additionally, because smoothing gives a smoothed image, it is better suited for further processing such as binarization.
We will consider an example that demonstrates a smoothing effect using the Gaussian filter. You will see and compare the thresholded original image and the thresholded smoothed image.
Use the Project Generator wizard for creating an empty project with the linked ofxOpenCv addon (see the Using ofxOpenCv section). Then, copy the sunflower.png
image into bin/data
of the project.
In the testApp.h
file, add a line that includes the addon's header just after the #include "ofMain.h"
line:
#include "ofMain.h"
#include "ofxOpenCv.h"
Add the following members to the testApp
class declaration:
ofxCvColorImage image; //Original image ofxCvGrayscaleImage grayImage; //Grayscaled original image ofxCvGrayscaleImage filtered; //Image used for filtering
In testApp.cpp
, the setup()
function loads an image from the file, copies it to the color image image
, and creates its grayscaled copy grayImage
. Note that for loading the image from the file, we use a temporary object imageOf
as follows:
void testApp::setup(){ ofImage imageOf; //Temporary image for loading from the file imageOf.loadImage( "sunflower.png" ); //Load image from //the file //Set image pixels image.setFromPixels( imageOf.getPixelsRef() ); //Convert to a grayscale image grayImage = image; }
To obtain a shorter code, we perform the all image processing steps right in draw()
and directly draw its results on the screen using just one filtered
image. A more accurate approach is to declare a separate image for each image we want draw, and then process it once in update()
. Also, in the example, the input image has not changed so we can do the processing right in setup()
. So, the update()
function is empty here, and the draw()
function does all the image processing:
void testApp::draw(){ ofBackground( 128, 128, 128 ); //Set the background color //Get image dimensions int w = image.width; int h = image.height; ofSetColor( 255, 255, 255 ); //Set a color for images drawing //Draw original image grayImage.draw( 0, 0, w, h ); //Thresholding original image filtered = grayImage; //Copy the image filtered.threshold( 128 ); //Thresholding original image //using thresold 128 filtered.draw( w+10, 0, w, h ); //Draw //Smoothing original image filtered = grayImage; //Copy the image filtered.blurGaussian( 9 ); //Gaussian blurring //with window size 9x9 filtered.draw( 0, h+10, w, h ); //Draw //Thresholding smoothed image filtered.threshold( 128 ); //Thresholding smoothed image //using thresold 128 filtered.draw( w+10, h+10, w, h ); //Draw }
Run the example and you will see four images:
Note that the Thresholded smoothed image has more smooth contours.
Here are two parameters of the algorithm:
9
as shown in the following line:filtered.blurGaussian( 9 );
128
as outlined in the following two lines:filtered.threshold( 128 ); //Thresholding original image ... filtered.threshold( 128 ); //Thresholding smoothed image
Adjust these parameters and watch how the smoothness of the contours and the overall number of white pixels change. Now we will consider geometrical transformation of images.