In order to access each individual element of a matrix, you just need to specify its row and column numbers. The corresponding element, which can be a single numerical value or a vector of values in the case of a multi-channel image, will be returned.
Getting ready
To illustrate the direct access to pixel values, we will create a simple function that adds salt-and-pepper noise to an image. As the name suggests, salt-and-pepper noise is a particular type of noise in which some randomly selected pixels are replaced by a white or a black pixel. This type of noise can occur in faulty communications when the value of some pixels is lost during the transmission. In our case, we will simply randomly select a few pixels and assign them a white color.
How to do it...
We create a function that receives an input image. This is the image that will be modified by our function. The second parameter is the number of pixels on which we want to overwrite white values:
void salt(cv::Mat image, int n) {
int i,j;
for (int k=0; k<n; k++) {
// rand() is the random number generator
i= std::rand()%image.cols;
j= std::rand()%image.rows;
if (image.type() == CV_8UC1) { // gray-level image
image.at<uchar>(j,i)= 255;
} else if (image.type() == CV_8UC3) { // color image
The signature of our color reduction function will be as follows:
void colorReduce(cv::Mat image, int div=64);
The user provides an image and the per-channel reduction factor. Here, the processing is done in-place, that is, the pixel values of the input image are modified by the function. See the There's more… section of this recipe for a more general function signature with input and output arguments.
The processing is simply done by creating a double loop that goes over all pixel values as follows:
An iterator object for a cv::Mat instance can be obtained by first creating a cv::MatIterator_ object. As is the case with cv::Mat_, the underscore indicates that this is a template subclass. Indeed, since image iterators are used to access the image elements, the return type must be known at the time of compilation. The iterator is then declared as follows:
cv::MatIterator_<cv::Vec3b> it;
Alternatively, you can also use the iterator type defined inside the Mat_ template class as follows:
cv::Mat_<cv::Vec3b>::iterator it;
You then loop over the pixels using the usual begin and end iterator methods, except that these ones are, again, template methods. Consequently, our color reduction function is now written as follows:
In order to measure the execution time of a function or a portion of code, there exists a very convenient OpenCV function called cv::getTickCount(). This function gives you the number of clock cycles that have occurred since the last time you started your computer. Since we want the execution time of a code portion given in seconds, we use another method, cv::getTickFrequency(). This gives us the number of cycles per second. The usual pattern to be used in order to obtain the computational time of a given function (or portion of code) would then be as follows:
This time, the processing cannot be accomplished in-place. Users need to provide an output image. The image scanning is done using three pointers, one for the current line, one for the line above, and another one for the line below. Also, since each pixel computation requires access to the neighbors, it is not possible to compute a value for the pixels of the first and last row of the image as well as the pixels of the first and last column. The loop can then be written as follows:
Images can be combined in different ways. Since they are regular matrices, they can be added, subtracted, multiplied, or divided. OpenCV offers various image arithmetic operators, and their use is discussed in this recipe.
Getting ready
Let's work with a second image that we will combine to our input image using an arithmetic operator. The following represents this second image:
Getting ready
How to do it...
Here, we add two images. This is useful when we want to create some special effects or to overlay information over an image. We do this by calling the cv::add function, or more precisely here, the cv::addWeighted function, since we want a weighted sum as follows:
In the recipes of this chapter, you learned how to read and modify the pixel values of an image. The last recipe will teach you how to modify the appearance of an image by moving its pixels. The pixel values are not changed by this process; it is rather the position of each pixel that is remapped to a new location. This is useful in order to create special effects on an image or to correct image distortions caused, for example, by a lens.
How to do it...
In order to use the OpenCV remap function, you simply have to first define the map to be used in the remapping process. Second, you have to apply this map on an input image. Obviously, it is the way you define your map that will determine the effect that will be produced. In our example, we define a transformation function that will create a wavy effect on the image: