How does cv::normalize work for multi channel images? - opencv

When i have a multi-channel image as cv::Mat and i run a min-max normalization like that:
cv::Mat normalizedImage = cv::Mat::zeros(imageToNormalize.size(), CV_32F);
cv::normalize(imageToNormalize, normalizedImage, -1.0, 1.0, cv::NORM_MINMAX);
Is every channel of the image normalized independently, or are the min-max values gathered from all channels and applied to all accordingly?

Related

Fastest way to apply color matrix to RGB image using OpenCV 3.0?

I have a color image represented as an OpenCV Mat object (C++, image type CV_32FC3). I have a color correction matrix that I want to apply to each pixel of the RGB color image (or BGR using OpenCV convention, doesn't matter here). The color correction matrix is 3x3.
I could easily iterate over the pixels and create a vector v (3x1) representing RGB, and then compute M*v, but this would be too slow for my real-time video application.
The cv::cvtColor function is fast, but does not seem to allow for custom color transformations.
http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor
Similar to the following, but I am using OpenCV for C++, not Python.
Apply transformation matrix to pixels in OpenCV image
Here's the code that worked using cv::reshape. It was fast enough for my application:
#define WIDTH 2048
#define HEIGHT 2048
...
Mat orig_img = Mat(HEIGHT, WIDTH, CV_32FC3);
//put some data in orig_img somehow ...
/*The color matrix
Red:RGB; Green:RGB; Blue:RGB
1.8786 -0.8786 0.0061
-0.2277 1.5779 -0.3313
0.0393 -0.6964 1.6321
*/
float m[3][3] = {{1.6321, -0.6964, 0.0393},
{-0.3313, 1.5779, -0.2277},
{0.0061, -0.8786, 1.8786 }};
Mat M = Mat(3, 3, CV_32FC1, m).t();
Mat orig_img_linear = orig_img.reshape(1, HEIGHT*WIDTH);
Mat color_matrixed_linear = orig_img_linear*M;
Mat final_color_matrixed = color_matrixed_linear.reshape(3, HEIGHT);
A few things to note from the above: The color matrix in the comment block is the one I would ordinarily apply to an RGB image. In defining the float array m, I switched rows 1 and 3, and columns 1 and 3 for OpenCV's BGR ordering. The color matrix also must be transposed. Usually a color matrix is applied as M* v = v_new, where M is 3x3 and v is 3x1 but here we are doing vT *MT = v_newT to avoid having to transpose each 3-channel pixel.
Basically the linked answer uses reshape to convert your CV_32FC3 mat of size m x n to a CV_32F mat of size (mn) x 3. After that, each row of the matrix contains exactly color channels of one pixel. You can then apply usual matrix multiplication to obtain a new mat and reshape it back to the original shape with three channels.
Note: It may be worth noticing that the default color space of opencv is BGR, not RGB.

How to judge color space of processed image?

I am studying the OpenCV. Now I am vary confusing the following problem.
Here is the code:
Mat img = imread("...");
Mat imgHSV;
Mat imgThresholded;
cvtColor(img, imgHSV, COLOR_BGR2HSV);
inRange(imgHSV, Scalar(150, 50, 75), Scalar(179, 255, 255), imgThresholded);
Now, I get a processed image imgThresholded. is this imgThresolded in RGB color space or HSV color space?
As per the documentation,
void inRange(InputArray src, InputArray lowerb, InputArray upperb,
OutputArray dst)
dst – output array of the same size as src and CV_8U type
This means that for 3 channel input image the output would be a single channel image, in case of thresholding, the output is a binary image which has only white(255) and black(0) pixels and the format is CV_8U only.
It is 1 a one channel image with either 0 or 255 values.
If you want to go back to your original RGB space just do the following:
cv::Mat FinalRGB;
cv::cvtColor(imgThresholded, imgThresholded, CV_GRAY2BGR);
cv::bitwise_and(imgThresholded, img, FinalRGB);
EDIT:
As #Micka stated:
cv::Mat imgMasked;
img.copyTo(imgMasked, imgThresholded);
will do the same idea but faster.
inRange() will give binary image. Not HSV or RGB. But yeah, it will consider HSV image for computation as you have given imHSV as the input image.
The function inRange() works as follows:
imThresholded (I) is set to 255 (all 1 -bits) if imHSV (I) is
within the specified 1D, 2D, 3D, ... box and 0 otherwise.
When the lower and/or upper boundary parameters are scalars, the indexes (I) at lowerb and upperb in the above formulas should be omitted.

Scaling OpenCV Mat for Caffe

I've been following the Caffe MINST example and trying to deploy a test of the trained model with C++ where I use OpenCV to read in the images. In the example, they mention how for the training and test images they
scale the incoming pixels so that they are in the range [0,1). Why
0.00390625? It is 1 divided by 256.
I've heard how there's a DataTransformer class in Caffe you can use to scale your images, but if I multiplied each pixel in the OpenCV Mat object by 0.00390625 would this give the same result?
The idea is right. But remember to convert your OpenCV Mats to float or double type before scaling.
Something like:
cv::Mat mat; // assume this is one of your images (grayscale)
/* convert it to float */
mat.convertTo(mat, CV_32FC1); // use CV_32FC3 for color images
/* scaling here */
mat = mat * 0.00390625;
Update #1: Converting and scaling can also simply be done in one line, i.e.
cv::Mat mat; // assume this is one of your images (grayscale)
/* convert and scale here */
mat.convertTo(mat, CV_32FC1, 0.00390625);

How do I create a histogram which can be used for calcBackProject in opencv?

I have specified the histogram as
MatND skinCrCbHist =Mat::zeros(Size(256,256),CV_8UC1);
ellipse(skinCrCbHist, Point(113, 155.6), Size(283.4, 159.2), 43.0, 0.0, 360.0, Scalar(255), -1); // Using a really big ellipse to find any sort of back projection in CrCb domain.
cvtColor(src, ycrcb, CV_BGR2YCrCb); //src is input, image of a person
float crrange[]={0,255};
float cbrange[]={0,255};
const float* ranges[]={crrange,cbrange};
int channelsy[]={1,2};
calcBackProject( &ycrcb, 1, channelsy, skinCrCbHist, backproj, ranges, 255, true );
imshow("bp",backproj);
The problem i face is that backproj shows a completely black image.
When I used a normal histogram created with calcHist on a natural image, i do get some sort of backprojection. But how do i use a histogram, i create artificially, by specifying an ellipse, to get a backprojection.
If I understood your problem correctly, you could use mask with the original calcHist function.
You didn't specified which version of OpenCV you are using, so I will assume the latest 2.4.6.0. The method prototype is following (omitting defaults, and types):
calcHist(images, nimages, channels, mask, hist, dims, histSize, ranges)
The third parameter is mask. The mask means, that the function will ignore all pixels which matches zero pixels in mask. In program the mask is another image correctly setup.
Here is pseudo-code for you problem:
1) get input image
2) create matrix of same size as input of type CV_8UC1 filled with zeros
3) draw white (value 255) ellipse on the new image
4) call caclHist with the new image as mask
http://docs.opencv.org/modules/imgproc/doc/histograms.html

How to detect when an image is out of focus?

At times our optical inspection system gets out of focus which results in nonsensical measurements. I've been tasked to develop an 'out of focus' detector which will be used to drive the Z axis of the camera system. The images available to me are bmp.
I'm looking for approaches and algorithms to investigate. For instance, should I be isolating features and measuring conformance or could edge detection be used?
This is the in focus image:
And this is the out of focus image:
The key is that in-focus image has much more strong gradients and sharp features.
So what I suggest is to apply a Gaussian Laplace filter and then look at the distribution of pixel values of the result. The plot below shows the application of this idea to your images, where black refers to the out of focus image, and red to the one in focus. The in-focus one has much more high values (because the image has more sharp gradients).
When you have the histograms, you can distinguish one from another by comparing e.g. 90%th percentiles of the distributions (which is sensitive to tails).
For the out of focus image it is 7
and for the in-focus image it is 13.6 (so twice the difference).
A quick and dirty version of the contrast algorithm is to sum the differences between adjacent pixels - higher sum is more contrast.
That's what I do in OpenCV to detect the focus quality:
Mat grad;
int scale = 1;
int delta = 0;
int ddepth = CV_8U;
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
Sobel(matFromSensor, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
/// Gradient Y
Sobel(matFromSensor, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
cv::Scalar mu, sigma;
cv::meanStdDev(grad, /* mean */ mu, /*stdev*/ sigma);
focusMeasure = mu.val[0] * mu.val[0];

Resources