Having input and output arguments
In our color reduction example, the transformation is directly applied to the input image, which is called an in-place transformation. This way, no extra image is required to hold the output result, which could save on memory usage when it is a concern. However, in some applications, the user wants to keep the original image intact. The user would then be forced to create a copy of the image before calling the function. Note that the easiest way to create an identical deep copy of an image is to call the clone method; for example, take a look at the following code:
// read the image image= cv::imread("boldt.jpg"); // clone the image cv::Mat imageClone= image.clone(); // process the clone // orginal image remains untouched colorReduce(imageClone); // display the image result cv::namedWindow("Image Result"); cv::imshow("Image Result",imageClone);
This extra overload can be avoided by defining a function that gives the user the option either to use or not use in-place processing. The signature of the method would then be as follows:
void colorReduce(const cv::Mat &image, // input image cv::Mat &result, // output image int div=64);
Note that the input image is now passed as a const reference, which means that this image will not be modified by the function. The output image is passed as a reference so that the calling function will see the output argument modified by this call. When in-place processing is preferred, the same image is specified as the input and output:
colorReduce(image,image);
If not, another cv::Mat instance can be provided; for example, take a look at the following code:
cv::Mat result; colorReduce(image,result);
The key here is first to verify whether the output image has an allocated data buffer with a size and pixel type that matches one of the input images. Very conveniently, this check is encapsulated inside the create method of cv::Mat. This is the method that is to be used when a matrix must be reallocated with a new size and type. If, by chance, the matrix already has the size and type specified, then no operation is performed and the method simply returns without touching the instance. Therefore, our function should simply start with a call to create unclear a matrix (if necessary) of the same size and type as the input image:
result.create(image.rows,image.cols,image.type());
The allocated memory block has a size of total()*elemSize().The looping is then done with two pointers:
for (int j=0; j<nl; j++) { // get the addresses of input and output row j const uchar* data_in= image.ptr<uchar>(j); uchar* data_out= result.ptr<uchar>(j); for (int i=0; i<nc*nchannels; i++) { // process each pixel --------------------- data_out[i]= data_in[i]/div*div + div/2; // end of pixel processing ---------------- } // end of line }
In cases where the same image is provided as the input and output, this function becomes completely equivalent to the first version presented in this recipe. If another image is provided as the output, the function will work correctly irrespective of whether the image has been allocated prior to the function call.