How it works...

The cv::Mat class includes several methods to access the different attributes of an image. The public member variables, cols and rows, give you the number of columns and rows in the image. For element access, cv::Mat has the at (int y, int x) method. However, the type returned by a method must be known at compile time, and since cv::Mat can hold elements of any type, the programmer needs to specify the return type that is expected. This is why the at method has been implemented as a template method. So, when you call it, you must specify the image element type as follows:

         image.at<uchar>(j,i)= 255;  

It is important to note that it is the programmer's responsibility to make sure that the type specified matches the type contained in the matrix. The at method does not perform any type of conversion.

In color images, each pixel is associated with three components—the red, green, and blue channels. Therefore, a cv::Mat class that contains a color image will return a vector of three 8-bit values. OpenCV has a defined type for such short vectors, and it is called cv::Vec3b. This is a vector of three unsigned characters. This explains why the element access to the pixels of a color pixel is written as follows:

         image.at<cv::Vec3b>(j,i)[channel]= value;  

The channel index designates one of the three color channels. OpenCV stores the channel values in the blue, green, red order (blue is, therefore, channel 0).

Similar vector types also exist for two-element and four-element vectors (cv::Vec2b and cv::Vec4b) as well as for other element types. For example, for a two-element float vector, the last letter of the type name would be replaced by f, that is, cv::Vec2f. In the case of a short integer, the last letter is replaced by s, by i for an integer, and by d for a double-precision floating-point vector. All of these types are defined using the cv::Vec<T,N> template class, where T is the type and N is the number of vector elements.

On a last note, you might have been surprised by the fact that our image-modifying function uses a pass-by-value image parameter. This works because when images are copied, they still share the same image data. So, you do not necessarily have to transmit images by references when you want to modify their content. Incidentally, pass-by-value parameters often make code optimization easier for the compiler.