blur detection in Images taken with different cameras - c++

I want to detect blurred images using Laplacian Operator. This is the code I am using:
bool checkforblur(Mat img)
{
bool is_blur = 0;
Mat gray,laplacianImage;
Scalar mean, stddev, mean1, stddev1;
double variance1,variance2,threshold;
cvtColor(img, gray, CV_BGR2GRAY);
Laplacian(gray, laplacianImage, CV_64F);
meanStdDev(laplacianImage, mean, stddev, Mat());
meanStdDev(gray, mean1, stddev1, Mat());
variance1 = stddev.val[0]*stddev.val[0];
variance2 = stddev1.val[0]*stddev1.val[0];
double ratio= variance1/variance2;
threshold = 90;
cout<<"Variance is:"<<ratio<<"\n"<<"Threshold Used:"
<<threshold<<endl;
if (ratio <= threshold){is_blur=1;}
return is_blur;
}
This code takes an image as input and returns 1 or 0 based on whether the image is blurred or not.
As suggested I edited the code to check for ratio instead of variance of the laplacian image alone.
But still the threshold varies for images taken with different cameras.
Is the code scene dependent?
How should I change it?
Example:
For the above image the variance is 62.9 So it detects that the image is blurred.
For the above image the variance is 235, Hence it is detecting wrongly as not blurred.

The Laplacian operator is linear, so that its amplitude varies with the amplitude of the signal. Thus the response will be higher for images with a stronger contrast.
You might have a better behavior by normalizing the values, for instance using the ratio of the variance of the Laplacian over the variance of the signal itself, or over the variance of the gradient magnitude.
I also advise you to experiment using sharp images that you progressively blur with a wider and wider gaussian, and to look at the plots of "measured blurriness" versus the know bluriness.

As suggested above, you should normalize this ratio. Basically, if you divide your variance by the mean value you will get the normalized gray level variance, which I think is what you are looking for.
That said, there is an excellent thread on blur detection which I would recommend - full of good info and code examples.

Related

Thresholding an image in OpenCV using another image matrix of pixel standard deviations as threshold values

I have two videos, one of a background and one of that same background with a person sitting in the frame. I generated two images from the video of just the background: the mean image of the background video (by accumulating the frames and dividing by the number of frames) and an image of standard deviations from the mean per pixel, taken over the frames. In other words, I have two images representing the Gaussian distribution of the background video. Now, I want to threshold an image, not using one fixed threshold value for all pixels, but using the standard deviations from the image (a different threshold per pixel). However, as far as I understand, OpenCV's threshold() function only allows for one fixed threshold. Are there functions I'm missing, or is there a workaround?
A cv::Mat provides methodology to accomplish this.
The setTo() methods takes an optional InputArray as mask.
Assuming the following:
std is your standard deviations cv::Mat, in is the cv::Mat you want to threshold and thresh is the factor for your standard deviations.
Using these values the custom thresholding could be done like this:
// Computes threshold values based on input image + std dev
cv::Mat mask = in +/- (std * thresh);
// Set in.at<>(x,y) to 0 if value is lower than mask.at<>(x,y)
in.setTo(0, in < mask);
The in < mask expression creates a new MatExpr object, a matrix which is 0 at every pixel where the predicate is false, 255 otherwise.
This is a handy way to implement custom thresholding.

Is here any way to find out whether an image is blurry or not using Laplacian operator

I am working on this project where I have to automate the sharpness calculation of an camera taken image without actually looking a the image. I have tried many detection methods, but finally I am going further with Laplacian operator using openCV.
Now, the laplacian operator in the openCV returns the image matrix. But, I have to get boolean output whether the image is blurry or not depending upon my threshold.
Any link, algorithm or IEEE paper for the same would be helpful. Thanks!
You will find a lot of infos here.
Also the paper cited in one of the answers if quite interesting: Analysis of focus measure operators for shape from focus
Refer this https://stackoverflow.com/a/44579247/6302996
Laplacian(gray, laplacianImage, CV_64F);
Scalar mean, stddev; // 0:1st channel, 1:2nd channel and 2:3rd channel
meanStdDev(laplacianImage, mean, stddev, Mat());
double variance = stddev.val[0] * stddev.val[0];
double threshold = 2900;
if (variance <= threshold) {
// Blurry
} else {
// Not blurry
}

interpolation for smooth downscale of image in OpenCV

I noticed that of the two methods below for scaling an image N halfs that the first produced a more smooth image, looking more appealing to the eye.
while (lod-- > Payload->MaxZoom)
{
cv::resize(img, img, cv::Size(), 0.5, 0.5, cv::INTER_LINEAR);
}
vs
double scale = 1.0 / (1<< (lod - Payload->MaxZoom));
cv::resize(img, img, cv::Size(), scale, scale, cv::INTER_LINEAR);
I am interested in knowing if there is a interpolation that would produce similar result as the first resize but not having to loop over it N times.
Any mathematical insight into why doing the resize in multiply steps can result in a better result is also interesting.
The latter method above gives a very pixelated result (for N=5) where the first is very smooth (it makes sense since its the average of 4 pixel over N steps)
This happens because OpenCV's implementation of linear interpolation is rather simplistic.
A simple implementation of linear interpolation takes the values of four pixels closest to the interpolated point and interpolates between them. This is all right for upscaling, but for downscaling, this will ignore the values of many pixels - if there are N pixels in the output image, then it depends on at most 4N pixels of the input. This cannot give good results when the product of scaling factors is lower than 0.25.
The correct thing to do is to consider all input pixels that correspond to an output pixel after the transformation, and compute an average over them (or more generally, compute a convolution with a suitable resampling filter).
OpenCV seems to have an interpolation mode called cv::INTER_AREA, which should do the thing you want.

Detection of low light images using SURF

I have been using the code from the OpenCV website for detection of objects.I am a beginner to OpenCV and to image processing and have been trying to understand the working of SURF.I have a few doubts.
1.I have been using color images for detection and the results have been good so far.There are people who are recommending using grayscale images,will it increase the performance of the algorithm?
2.In the code,what is the significance of filtering by only having the matches with distance less than 3*mindist?
for( int i = 0; i < descriptors_object.rows; i++ )
{ if( matches[i].distance < 3*min_dist )
{ good_matches.push_back( matches[i]); }
}
3.Though the detection is robust in high illuminated images(i used 900 as the hessian value),the same image under low light conditions does not get detected with the same hessian value,is there a way to do both with the same hessian value and the same reference image for both conditions?Will cv::equalizeHist() be useful?If it is,can somebody please suggest a way for me to integrate with the SURF detection code?
4.DMatch structure which returns matches has a parameter called distance which returns the distance between descriptors.What does this mean?Is there a unit for the distance returned?
5.I would also like to know if there are better descriptors than SURF in terms of time complexity,scale and rotation invariance`for object detection.
Thanks in advance for your time and replies.
SURF works with grayscale images.
There are lot of false random matches (since if you have 100 features in img1, you will always have 100 matches) and to filter them is good idea. But better is to check relative distance - how it is done in Use Euclidean distance in SURF)
Yes, it can be used. You just use modified images instead of original.
You detect low number of features because of low pixel intensity and low contrast in the dark regions, which decreases detector response. When applied to the dark image, histogram equalization increases contrast which increases number of local maximas below the threshold.
cv::Mat img1, img1histEq;
cv::equalizeHist(img1,img1histEq);
SURF is can be viewed as 128-dimentional vector. Distance is distance between two such vectors in some space, usually Euclidean - sum of squared differences between corresponding vector elements. Other metrics, e.g. L1 also can be used, but Euclidean is the most used for SURF.
SIFT performs better in terms of invariance, but 3 times slower. You can find comparison of the different descriptors here and here.
It is not clear what do you mean by "object detection". What exactly do you need to do?

Difference between adaptive thresholding and normal thresholding in opencv

I have this gray video stream:
The histogram of this image:
The thresholded image by :
threshold( image, image, 150, 255, CV_THRESH_BINARY );
i get :
Which i expect.
When i do adaptive thresholding with :
adaptiveThreshold(image, image,255,ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY,15,-5);
i get :
Which looks like edge detection and not thresholding. What i expected was black and white areas . So my question is, why does this look like edge detection and not thresholding.
thx in advance
Adaptive Threshold works like this:
The function transforms a grayscale image to a binary image according
to the formulas:
THRESH_BINARY
THRESH_BINARY_INV
where T(x,y) is a threshold calculated individually for each pixel.
Threshold works differently:
The function applies fixed-level thresholding to a single-channel array.
So it sounds like adaptiveThreshold calculates a threshold pixel-by-pixel, whereas threshold calculates it for the whole image -- it measures the whole image by one ruler, whereas the other makes a new "ruler" for each pixel.
I had the same issue doing adaptive thresholding for OCR purposes. (sorry this is Python not C++)
img = cv.LoadImage(sys.argv[1])
bwsrc = cv.CreateImage( cv.GetSize(img), cv.IPL_DEPTH_8U, 1)
bwdst = cv.CreateImage( cv.GetSize(img), cv.IPL_DEPTH_8U, 1)
cv.CvtColor(img, bwsrc, cv.CV_BGR2GRAY)
cv.AdaptiveThreshold(bwsrc, bwdst, 255.0, cv.CV_THRESH_BINARY, cv.CV_ADAPTIVE_THRESH_MEAN_C,11)
cv.ShowImage("threshhold", bwdst)
cv.WaitKey()
The last paramter is the size of the neighborhood used to calculate the threshold for each pixel. If your neighborhood is too small (mine was 3), it works like edge detection. Once I made it bigger, it worked as expected. Of course, the "correct" size will depend on the resolution of your image, and size of the features you're looking at.