Quantify sharpness using frequencies [duplicate] - matlab
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I was wondering if there is a way to determine if an image is blurry or not by analyzing the image data.
Another very simple way to estimate the sharpness of an image is to use a Laplace (or LoG) filter and simply pick the maximum value. Using a robust measure like a 99.9% quantile is probably better if you expect noise (i.e. picking the Nth-highest contrast instead of the highest contrast.) If you expect varying image brightness, you should also include a preprocessing step to normalize image brightness/contrast (e.g. histogram equalization).
I've implemented Simon's suggestion and this one in Mathematica, and tried it on a few test images:
The first test blurs the test images using a Gaussian filter with a varying kernel size, then calculates the FFT of the blurred image and takes the average of the 90% highest frequencies:
testFft[img_] := Table[
(
blurred = GaussianFilter[img, r];
fft = Fourier[ImageData[blurred]];
{w, h} = Dimensions[fft];
windowSize = Round[w/2.1];
Mean[Flatten[(Abs[
fft[[w/2 - windowSize ;; w/2 + windowSize,
h/2 - windowSize ;; h/2 + windowSize]]])]]
), {r, 0, 10, 0.5}]
Result in a logarithmic plot:
The 5 lines represent the 5 test images, the X axis represents the Gaussian filter radius. The graphs are decreasing, so the FFT is a good measure for sharpness.
This is the code for the "highest LoG" blurriness estimator: It simply applies an LoG filter and returns the brightest pixel in the filter result:
testLaplacian[img_] := Table[
(
blurred = GaussianFilter[img, r];
Max[Flatten[ImageData[LaplacianGaussianFilter[blurred, 1]]]];
), {r, 0, 10, 0.5}]
Result in a logarithmic plot:
The spread for the un-blurred images is a little better here (2.5 vs 3.3), mainly because this method only uses the strongest contrast in the image, while the FFT is essentially a mean over the whole image. The functions are also decreasing faster, so it might be easier to set a "blurry" threshold.
Yes, it is. Compute the Fast Fourier Transform and analyse the result. The Fourier transform tells you which frequencies are present in the image. If there is a low amount of high frequencies, then the image is blurry.
Defining the terms 'low' and 'high' is up to you.
Edit:
As stated in the comments, if you want a single float representing the blurryness of a given image, you have to work out a suitable metric.
nikie's answer provide such a metric. Convolve the image with a Laplacian kernel:
1
1 -4 1
1
And use a robust maximum metric on the output to get a number which you can use for thresholding. Try to avoid smoothing too much the images before computing the Laplacian, because you will only find out that a smoothed image is indeed blurry :-).
During some work with an auto-focus lens, I came across this very useful set of algorithms for detecting image focus. It's implemented in MATLAB, but most of the functions are quite easy to port to OpenCV with filter2D.
It's basically a survey implementation of many focus measurement algorithms. If you want to read the original papers, references to the authors of the algorithms are provided in the code. The 2012 paper by Pertuz, et al. Analysis of focus measure operators for shape from focus (SFF) gives a great review of all of these measure as well as their performance (both in terms of speed and accuracy as applied to SFF).
EDIT: Added MATLAB code just in case the link dies.
function FM = fmeasure(Image, Measure, ROI)
%This function measures the relative degree of focus of
%an image. It may be invoked as:
%
% FM = fmeasure(Image, Method, ROI)
%
%Where
% Image, is a grayscale image and FM is the computed
% focus value.
% Method, is the focus measure algorithm as a string.
% see 'operators.txt' for a list of focus
% measure methods.
% ROI, Image ROI as a rectangle [xo yo width heigth].
% if an empty argument is passed, the whole
% image is processed.
%
% Said Pertuz
% Abr/2010
if ~isempty(ROI)
Image = imcrop(Image, ROI);
end
WSize = 15; % Size of local window (only some operators)
switch upper(Measure)
case 'ACMO' % Absolute Central Moment (Shirvaikar2004)
if ~isinteger(Image), Image = im2uint8(Image);
end
FM = AcMomentum(Image);
case 'BREN' % Brenner's (Santos97)
[M N] = size(Image);
DH = Image;
DV = Image;
DH(1:M-2,:) = diff(Image,2,1);
DV(:,1:N-2) = diff(Image,2,2);
FM = max(DH, DV);
FM = FM.^2;
FM = mean2(FM);
case 'CONT' % Image contrast (Nanda2001)
ImContrast = inline('sum(abs(x(:)-x(5)))');
FM = nlfilter(Image, [3 3], ImContrast);
FM = mean2(FM);
case 'CURV' % Image Curvature (Helmli2001)
if ~isinteger(Image), Image = im2uint8(Image);
end
M1 = [-1 0 1;-1 0 1;-1 0 1];
M2 = [1 0 1;1 0 1;1 0 1];
P0 = imfilter(Image, M1, 'replicate', 'conv')/6;
P1 = imfilter(Image, M1', 'replicate', 'conv')/6;
P2 = 3*imfilter(Image, M2, 'replicate', 'conv')/10 ...
-imfilter(Image, M2', 'replicate', 'conv')/5;
P3 = -imfilter(Image, M2, 'replicate', 'conv')/5 ...
+3*imfilter(Image, M2, 'replicate', 'conv')/10;
FM = abs(P0) + abs(P1) + abs(P2) + abs(P3);
FM = mean2(FM);
case 'DCTE' % DCT energy ratio (Shen2006)
FM = nlfilter(Image, [8 8], #DctRatio);
FM = mean2(FM);
case 'DCTR' % DCT reduced energy ratio (Lee2009)
FM = nlfilter(Image, [8 8], #ReRatio);
FM = mean2(FM);
case 'GDER' % Gaussian derivative (Geusebroek2000)
N = floor(WSize/2);
sig = N/2.5;
[x,y] = meshgrid(-N:N, -N:N);
G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
Rx = imfilter(double(Image), Gx, 'conv', 'replicate');
Ry = imfilter(double(Image), Gy, 'conv', 'replicate');
FM = Rx.^2+Ry.^2;
FM = mean2(FM);
case 'GLVA' % Graylevel variance (Krotkov86)
FM = std2(Image);
case 'GLLV' %Graylevel local variance (Pech2000)
LVar = stdfilt(Image, ones(WSize,WSize)).^2;
FM = std2(LVar)^2;
case 'GLVN' % Normalized GLV (Santos97)
FM = std2(Image)^2/mean2(Image);
case 'GRAE' % Energy of gradient (Subbarao92a)
Ix = Image;
Iy = Image;
Iy(1:end-1,:) = diff(Image, 1, 1);
Ix(:,1:end-1) = diff(Image, 1, 2);
FM = Ix.^2 + Iy.^2;
FM = mean2(FM);
case 'GRAT' % Thresholded gradient (Snatos97)
Th = 0; %Threshold
Ix = Image;
Iy = Image;
Iy(1:end-1,:) = diff(Image, 1, 1);
Ix(:,1:end-1) = diff(Image, 1, 2);
FM = max(abs(Ix), abs(Iy));
FM(FM<Th)=0;
FM = sum(FM(:))/sum(sum(FM~=0));
case 'GRAS' % Squared gradient (Eskicioglu95)
Ix = diff(Image, 1, 2);
FM = Ix.^2;
FM = mean2(FM);
case 'HELM' %Helmli's mean method (Helmli2001)
MEANF = fspecial('average',[WSize WSize]);
U = imfilter(Image, MEANF, 'replicate');
R1 = U./Image;
R1(Image==0)=1;
index = (U>Image);
FM = 1./R1;
FM(index) = R1(index);
FM = mean2(FM);
case 'HISE' % Histogram entropy (Krotkov86)
FM = entropy(Image);
case 'HISR' % Histogram range (Firestone91)
FM = max(Image(:))-min(Image(:));
case 'LAPE' % Energy of laplacian (Subbarao92a)
LAP = fspecial('laplacian');
FM = imfilter(Image, LAP, 'replicate', 'conv');
FM = mean2(FM.^2);
case 'LAPM' % Modified Laplacian (Nayar89)
M = [-1 2 -1];
Lx = imfilter(Image, M, 'replicate', 'conv');
Ly = imfilter(Image, M', 'replicate', 'conv');
FM = abs(Lx) + abs(Ly);
FM = mean2(FM);
case 'LAPV' % Variance of laplacian (Pech2000)
LAP = fspecial('laplacian');
ILAP = imfilter(Image, LAP, 'replicate', 'conv');
FM = std2(ILAP)^2;
case 'LAPD' % Diagonal laplacian (Thelen2009)
M1 = [-1 2 -1];
M2 = [0 0 -1;0 2 0;-1 0 0]/sqrt(2);
M3 = [-1 0 0;0 2 0;0 0 -1]/sqrt(2);
F1 = imfilter(Image, M1, 'replicate', 'conv');
F2 = imfilter(Image, M2, 'replicate', 'conv');
F3 = imfilter(Image, M3, 'replicate', 'conv');
F4 = imfilter(Image, M1', 'replicate', 'conv');
FM = abs(F1) + abs(F2) + abs(F3) + abs(F4);
FM = mean2(FM);
case 'SFIL' %Steerable filters (Minhas2009)
% Angles = [0 45 90 135 180 225 270 315];
N = floor(WSize/2);
sig = N/2.5;
[x,y] = meshgrid(-N:N, -N:N);
G = exp(-(x.^2+y.^2)/(2*sig^2))/(2*pi*sig);
Gx = -x.*G/(sig^2);Gx = Gx/sum(Gx(:));
Gy = -y.*G/(sig^2);Gy = Gy/sum(Gy(:));
R(:,:,1) = imfilter(double(Image), Gx, 'conv', 'replicate');
R(:,:,2) = imfilter(double(Image), Gy, 'conv', 'replicate');
R(:,:,3) = cosd(45)*R(:,:,1)+sind(45)*R(:,:,2);
R(:,:,4) = cosd(135)*R(:,:,1)+sind(135)*R(:,:,2);
R(:,:,5) = cosd(180)*R(:,:,1)+sind(180)*R(:,:,2);
R(:,:,6) = cosd(225)*R(:,:,1)+sind(225)*R(:,:,2);
R(:,:,7) = cosd(270)*R(:,:,1)+sind(270)*R(:,:,2);
R(:,:,7) = cosd(315)*R(:,:,1)+sind(315)*R(:,:,2);
FM = max(R,[],3);
FM = mean2(FM);
case 'SFRQ' % Spatial frequency (Eskicioglu95)
Ix = Image;
Iy = Image;
Ix(:,1:end-1) = diff(Image, 1, 2);
Iy(1:end-1,:) = diff(Image, 1, 1);
FM = mean2(sqrt(double(Iy.^2+Ix.^2)));
case 'TENG'% Tenengrad (Krotkov86)
Sx = fspecial('sobel');
Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
FM = Gx.^2 + Gy.^2;
FM = mean2(FM);
case 'TENV' % Tenengrad variance (Pech2000)
Sx = fspecial('sobel');
Gx = imfilter(double(Image), Sx, 'replicate', 'conv');
Gy = imfilter(double(Image), Sx', 'replicate', 'conv');
G = Gx.^2 + Gy.^2;
FM = std2(G)^2;
case 'VOLA' % Vollath's correlation (Santos97)
Image = double(Image);
I1 = Image; I1(1:end-1,:) = Image(2:end,:);
I2 = Image; I2(1:end-2,:) = Image(3:end,:);
Image = Image.*(I1-I2);
FM = mean2(Image);
case 'WAVS' %Sum of Wavelet coeffs (Yang2003)
[C,S] = wavedec2(Image, 1, 'db6');
H = wrcoef2('h', C, S, 'db6', 1);
V = wrcoef2('v', C, S, 'db6', 1);
D = wrcoef2('d', C, S, 'db6', 1);
FM = abs(H) + abs(V) + abs(D);
FM = mean2(FM);
case 'WAVV' %Variance of Wav...(Yang2003)
[C,S] = wavedec2(Image, 1, 'db6');
H = abs(wrcoef2('h', C, S, 'db6', 1));
V = abs(wrcoef2('v', C, S, 'db6', 1));
D = abs(wrcoef2('d', C, S, 'db6', 1));
FM = std2(H)^2+std2(V)+std2(D);
case 'WAVR'
[C,S] = wavedec2(Image, 3, 'db6');
H = abs(wrcoef2('h', C, S, 'db6', 1));
V = abs(wrcoef2('v', C, S, 'db6', 1));
D = abs(wrcoef2('d', C, S, 'db6', 1));
A1 = abs(wrcoef2('a', C, S, 'db6', 1));
A2 = abs(wrcoef2('a', C, S, 'db6', 2));
A3 = abs(wrcoef2('a', C, S, 'db6', 3));
A = A1 + A2 + A3;
WH = H.^2 + V.^2 + D.^2;
WH = mean2(WH);
WL = mean2(A);
FM = WH/WL;
otherwise
error('Unknown measure %s',upper(Measure))
end
end
%************************************************************************
function fm = AcMomentum(Image)
[M N] = size(Image);
Hist = imhist(Image)/(M*N);
Hist = abs((0:255)-255*mean2(Image))'.*Hist;
fm = sum(Hist);
end
%******************************************************************
function fm = DctRatio(M)
MT = dct2(M).^2;
fm = (sum(MT(:))-MT(1,1))/MT(1,1);
end
%************************************************************************
function fm = ReRatio(M)
M = dct2(M);
fm = (M(1,2)^2+M(1,3)^2+M(2,1)^2+M(2,2)^2+M(3,1)^2)/(M(1,1)^2);
end
%******************************************************************
A few examples of OpenCV versions:
// OpenCV port of 'LAPM' algorithm (Nayar89)
double modifiedLaplacian(const cv::Mat& src)
{
cv::Mat M = (Mat_<double>(3, 1) << -1, 2, -1);
cv::Mat G = cv::getGaussianKernel(3, -1, CV_64F);
cv::Mat Lx;
cv::sepFilter2D(src, Lx, CV_64F, M, G);
cv::Mat Ly;
cv::sepFilter2D(src, Ly, CV_64F, G, M);
cv::Mat FM = cv::abs(Lx) + cv::abs(Ly);
double focusMeasure = cv::mean(FM).val[0];
return focusMeasure;
}
// OpenCV port of 'LAPV' algorithm (Pech2000)
double varianceOfLaplacian(const cv::Mat& src)
{
cv::Mat lap;
cv::Laplacian(src, lap, CV_64F);
cv::Scalar mu, sigma;
cv::meanStdDev(lap, mu, sigma);
double focusMeasure = sigma.val[0]*sigma.val[0];
return focusMeasure;
}
// OpenCV port of 'TENG' algorithm (Krotkov86)
double tenengrad(const cv::Mat& src, int ksize)
{
cv::Mat Gx, Gy;
cv::Sobel(src, Gx, CV_64F, 1, 0, ksize);
cv::Sobel(src, Gy, CV_64F, 0, 1, ksize);
cv::Mat FM = Gx.mul(Gx) + Gy.mul(Gy);
double focusMeasure = cv::mean(FM).val[0];
return focusMeasure;
}
// OpenCV port of 'GLVN' algorithm (Santos97)
double normalizedGraylevelVariance(const cv::Mat& src)
{
cv::Scalar mu, sigma;
cv::meanStdDev(src, mu, sigma);
double focusMeasure = (sigma.val[0]*sigma.val[0]) / mu.val[0];
return focusMeasure;
}
No guarantees on whether or not these measures are the best choice for your problem, but if you track down the papers associated with these measures, they may give you more insight. Hope you find the code useful! I know I did.
Building off of Nike's answer. Its straightforward to implement the laplacian based method with opencv:
short GetSharpness(char* data, unsigned int width, unsigned int height)
{
// assumes that your image is already in planner yuv or 8 bit greyscale
IplImage* in = cvCreateImage(cvSize(width,height),IPL_DEPTH_8U,1);
IplImage* out = cvCreateImage(cvSize(width,height),IPL_DEPTH_16S,1);
memcpy(in->imageData,data,width*height);
// aperture size of 1 corresponds to the correct matrix
cvLaplace(in, out, 1);
short maxLap = -32767;
short* imgData = (short*)out->imageData;
for(int i =0;i<(out->imageSize/2);i++)
{
if(imgData[i] > maxLap) maxLap = imgData[i];
}
cvReleaseImage(&in);
cvReleaseImage(&out);
return maxLap;
}
Will return a short indicating the maximum sharpness detected, which based on my tests on real world samples, is a pretty good indicator of if a camera is in focus or not. Not surprisingly, normal values are scene dependent but much less so than the FFT method which has to high of a false positive rate to be useful in my application.
I came up with a totally different solution.
I needed to analyse video still frames to find the sharpest one in every (X) frames. This way, I would detect motion blur and/or out of focus images.
I ended up using Canny Edge detection and I got VERY VERY good results with almost every kind of video (with nikie's method, I had problems with digitalized VHS videos and heavy interlaced videos).
I optimized the performance by setting a region of interest (ROI) on the original image.
Using EmguCV :
//Convert image using Canny
using (Image<Gray, byte> imgCanny = imgOrig.Canny(225, 175))
{
//Count the number of pixel representing an edge
int nCountCanny = imgCanny.CountNonzero()[0];
//Compute a sharpness grade:
//< 1.5 = blurred, in movement
//de 1.5 à 6 = acceptable
//> 6 =stable, sharp
double dSharpness = (nCountCanny * 1000.0 / (imgCanny.Cols * imgCanny.Rows));
}
Thanks nikie for that great Laplace suggestion.
OpenCV docs pointed me in the same direction:
using python, cv2 (opencv 2.4.10), and numpy...
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
numpy.max(cv2.convertScaleAbs(cv2.Laplacian(gray, 3)))
result is between 0-255. I found anything over 200ish is very in focus, and by 100, it's noticeably blurry. the max never really gets much under 20 even if it's completely blurred.
One way which I'm currently using measures the spread of edges in the image. Look for this paper:
#ARTICLE{Marziliano04perceptualblur,
author = {Pina Marziliano and Frederic Dufaux and Stefan Winkler and Touradj Ebrahimi},
title = {Perceptual blur and ringing metrics: Application to JPEG2000,” Signal Process},
journal = {Image Commun},
year = {2004},
pages = {163--172} }
It's usually behind a paywall but I've seen some free copies around. Basically, they locate vertical edges in an image, and then measure how wide those edges are. Averaging the width gives the final blur estimation result for the image. Wider edges correspond to blurry images, and vice versa.
This problem belongs to the field of no-reference image quality estimation. If you look it up on Google Scholar, you'll get plenty of useful references.
EDIT
Here's a plot of the blur estimates obtained for the 5 images in nikie's post. Higher values correspond to greater blur. I used a fixed-size 11x11 Gaussian filter and varied the standard deviation (using imagemagick's convert command to obtain the blurred images).
If you compare images of different sizes, don't forget to normalize by the image width, since larger images will have wider edges.
Finally, a significant problem is distinguishing between artistic blur and undesired blur (caused by focus miss, compression, relative motion of the subject to the camera), but that is beyond simple approaches like this one. For an example of artistic blur, have a look at the Lenna image: Lenna's reflection in the mirror is blurry, but her face is perfectly in focus. This contributes to a higher blur estimate for the Lenna image.
Answers above elucidated many things, but I think it is useful to make a conceptual distinction.
What if you take a perfectly on-focus picture of a blurred image?
The blurring detection problem is only well posed when you have a reference. If you need to design, e.g., an auto-focus system, you compare a sequence of images taken with different degrees of blurring, or smoothing, and you try to find the point of minimum blurring within this set. I other words you need to cross reference the various images using one of the techniques illustrated above (basically--with various possible levels of refinement in the approach--looking for the one image with the highest high-frequency content).
I tried solution based on Laplacian filter from this post. It didn't help me. So, I tried the solution from this post and it was good for my case (but is slow):
import cv2
image = cv2.imread("test.jpeg")
height, width = image.shape[:2]
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
def px(x, y):
return int(gray[y, x])
sum = 0
for x in range(width-1):
for y in range(height):
sum += abs(px(x, y) - px(x+1, y))
Less blurred image has maximum sum value!
You can also tune speed and accuracy by changing step, e.g.
this part
for x in range(width - 1):
you can replace with this one
for x in range(0, width - 1, 10):
Matlab code of two methods that have been published in highly regarded journals (IEEE Transactions on Image Processing) are available here: https://ivulab.asu.edu/software
check the CPBDM and JNBM algorithms. If you check the code it's not very hard to be ported and incidentally it is based on the Marzialiano's method as basic feature.
i implemented it use fft in matlab and check histogram of the fft compute mean and std but also fit function can be done
fa = abs(fftshift(fft(sharp_img)));
fb = abs(fftshift(fft(blured_img)));
f1=20*log10(0.001+fa);
f2=20*log10(0.001+fb);
figure,imagesc(f1);title('org')
figure,imagesc(f2);title('blur')
figure,hist(f1(:),100);title('org')
figure,hist(f2(:),100);title('blur')
mf1=mean(f1(:));
mf2=mean(f2(:));
mfd1=median(f1(:));
mfd2=median(f2(:));
sf1=std(f1(:));
sf2=std(f2(:));
That's what I do in Opencv to detect focus quality in a region:
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];
Related
weighted CDF formula always returns 1
I am reading this paper for enhancing image quality. my problem is that when I am calculating weighted CDF, I always get 1 as output. here is the sequence of formulas: which gamma is defined like this: which Cw is the weighted CDF: which I think my main problem would be here. but to be more clear I will add the rest of the formulas too. corresponding Weighted Histogram Distribution function is: and Alpha=C(i) which: which h_c(i) is clipped histogram , and M is the total intensity levels ( which I'm not sure what is the M, I assumed since sum of Pi should be 1 so it must be sum of the hc_i ) and this is how it is clipping the histogram : and the clipping limit is calculated with this formula: here is my code: sample_img = imread('my image path'); sample_img = im2double(sample_img); L = 256 % The magnitude of each and every color channel is confined within the range [0 , L-1] redChannel = sample_img(:,:,1); greenChannel = sample_img(:,:,2); blueChannel = sample_img(:,:,3); max_blue = max(max(blueChannel)); max_green = max(max(greenChannel)); max_red = max(max(redChannel)); min_blue = min(min(blueChannel)); min_green = min(min(greenChannel)); min_red = min(min(redChannel)); bn = blueChannel - min_blue; rn = redChannel - min_red; gn = greenChannel - min_green; max_bn = max(max(bn)); max_rn = max(max(rn)); max_gn = max(max(gn)); b_stretched = bn/max_bn; r_stretched = rn/max_rn; g_stretched = gn/max_gn; % Recombine separate color channels into an RGB image. rgb_stretched_Image = cat(3, r_stretched, g_stretched, b_stretched); % Convert RGB to HSI hsi_image = rgb2hsi(rgb_stretched_Image); intensity = hsi_image(:, :, 3); figure() [counts , binLocations] = imhist(intensity); imhist(intensity); hist = counts; % the clipping limit is computed based on the mean value of the Tc = mean(hist); % histogram clipping length_hist = length(hist); clipped_hist = zeros(1,length_hist); for hist_id = 1:length_hist if hist(hist_id)<Tc disp('<Tc') disp(hist(hist_id)); clipped_hist(hist_id) = hist(hist_id); continue end disp('>Tc') clipped_hist(hist_id) = Tc; end % the corresponding PDF (p(i)) % this is where I just used sum(clipped_hist) instead of M Pi = clipped_hist / sum(clipped_hist); %CDF Ci = sum(Pi(1:L)); Alpha = Ci; %Weighted Histogram Distribution function Pmin = min(Pi); Pmax = max(Pi); Pwi = Pmax * power((Pi-Pmin)/(Pmax-Pmin),Alpha); %weighted PDF sum intensity_max = max(max(intensity*L)); Sum_Pwi = sum(Pwi(1:intensity_max)); % weighted CDF Cwi = sum(Pwi(1:intensity_max)/Sum_Pwi); %gamma gamma = 1 - Cwi; %Transformed pixel intensity tpi = round(power(intensity/intensity_max,gamma)); since as I said the CDF output is always 1 , the enhanced image is always a white image. and as I see this formula, it must always have 1 as it's output. Am I missing something here ? and am I right with the M value ?
nlinfit appears better than fitgmdist for fitting normal mixture
I have a vector of data consisting of about 2 million samples that I suspect is a mixture of two gaussian's. I try to fit the data, Data, to a mixture using matlab's fitgmdist. From histogram: % histogram counts of X with 1000 bins. [Yhist, x] = histcounts(Data, 1000, 'normalization', 'pdf'); x = (x(1:end-1) + x(2:end))/2; Using fitgmdist: % Increase no. of iterations. default is 100. opts.MaxIter = 300; % Ensure that it does all iterations. opts.TolFun = 0; GMModel = fitgmdist(Data, 2, 'Options', opts, 'Start', 'plus'); wts = GMModel.ComponentProportion; mu = GMModel.mu; sig = sqrt(squeeze(GMModel.Sigma)); Ygmfit = wts(1)*normpdf(x(:), mu(1), sig(1)) + wts(2)*normpdf(x(:), mu(2), sig(2)); Mixture results with fitgmdist: wts = [0.6780, 0.322], mu = [-7.6444, -9.7831], sig = [0.8243, 0.5947] Next I try using nlinfit: % Define the callback function for nlinfit. function y = nmmix(a, x) a(1:2) = a(1:2)/sum(a); y = a(1)*normpdf(x(:), a(3), a(5)) + a(2)*normpdf(x(:), a(4), a(6)); end init_wts = [0.66, 1-0.66]; init_mu = [-7.7, -9.75]; init_sig = [0.5, 0.5]; a = nlinfit(x(:), Yhist(:), #nmmix, [init_wts, init_mu, init_sig]); wts = a(1:2)/sum(a(1:2)); mu = a(3:4); sig = a(5:6); Ynlinfit = wts(1)*normpdf(x(:), mu(1), sig(1)) + wts(2)*normpdf(x(:), mu(2), sig(2)); Mixture results with nlinfit: wts = [0.6349, 0.3651], mu = [-7.6305, -9.6991], sig = [0.6773, 0.6031] % Plot to compare the results figure; hold on plot(x(:), Yhist, 'b'); plot(x(:), Ygmfit, 'k'); plot(x(:), Ynlinfit, 'r'); It seems to be that the non-linear fit (red curve) is intuitively a better approximation to the histogram (blue curve) than "fitgmdist" (black curve). The results are similar even if I use a finer histogram, say with 100,000 bins. What can be the source of this discrepancy? Added later: Of course one would not expect the results to be the same, but I would expect that the visual quality of the two fits would be comparable.
how to get Image of same size after processing
I am estimating ridge orientation of an fingerprint image by dividing it into blocks of 41*41..image is of size 240*320..here is my code and the problem is that I am getting output image size different than input image. % matalb code for orientation im =imread('D:\project\116_2_5.jpg'); im = double(im); [m,n] = size(im); % to normalise image nor = im - mean(im(:)); im = nor/std(nor(:)); w = 41; % To calculate x and y gradient component using 3*3 sobel mask [delx,dely] = gradient(im); % Ridge orientation for i=21:w:240-41 for j=21:w:320-41 A = delx(i-20:i+20,j-20:j+20); B = dely(i-20:i+20,j-20:j+20); Gxy = sum(sum(A.*B)); Gxx = sum(sum(A.*A)); Gyy = sum(sum(B.*B)); diff = Gxx-Gyy; theta(i-20:i+20,j-20:j+20) = (pi/2) + 0.5*atan2(2*Gxy,diff); end; end; but in this process i am loosing the pixels at the boundries so as to avoid the "index exceed" error i.e size of theta is m = 240-41 = 199 and n = 320-41=279..Thus my input image size is 240*320 and output image size is size 199*279..How can i get output image same as size of input image. one more thing that i dnt have to use "blockproc" function...Thanks in advance
You can use padarray to add zeros onto your matrix: A1 = padarray(A,[7 8],'post'); % 240+7=41*7, 320+8=41*8 B1 = padarray(B,[7 8],'post'); then generate Gxx, Gyy, and Gxy with A1 and B1. Method 2: Besides, I tried to simplify your code a little bit by removing the loops, for your reference: % Ridge orientation Gxy = delx .* dely; Gxx = delx .* delx; Gyy = dely .* dely; fun = #(x) sum(x(:))*ones(size(x)); theta_Gxy = blockproc(Gxy,[41 41],fun, 'PadPartialBlocks', true); theta_diff = blockproc(Gxx-Gyy,[41 41],fun, 'PadPartialBlocks', true); theta0 = pi/2 + 0.5 * atan2(2 * theta_Gxy, theta_diff); theta = theta0(1:240, 1:320); You may check blockproc for more details.
How to create 64 Gabor features at each scale and orientation in the spatial and frequency domain
Normally, a Gabor filter, as its name suggests, is used to filter an image and extract everything that it is oriented in the same direction of the filtering. In this question, you can see more efficient code than written in this Link Assume 16 scales of Filters at 4 orientations, so we get 64 gabor filters. scales=[7:2:37], 7x7 to 37x37 in steps of two pixels, so we have 7x7, 9x9, 11x11, 13x13, 15x15, 17x17, 19x19, 21x21, 23x23, 25x25, 27x27, 29x29, 31x31, 33x33, 35x35 and 37x37. directions=[0, pi/4, pi/2, 3pi/4]. The equation of Gabor filter in the spatial domain is: The equation of Gabor filter in the frequency domain is:
In the spatial domain: function [fSiz,filters,c1OL,numSimpleFilters] = init_gabor(rot, RF_siz) image=imread('xxx.jpg'); image_gray=rgb2gray(image); image_gray=imresize(image_gray, [100 100]); image_double=double(image_gray); rot = [0 45 90 135]; % we have four orientations RF_siz = [7:2:37]; %we get 16 scales (7x7 to 37x37 in steps of two pixels) minFS = 7; % the minimum receptive field maxFS = 37; % the maximum receptive field sigma = 0.0036*RF_siz.^2 + 0.35*RF_siz + 0.18; %define the equation of effective width lambda = sigma/0.8; % it the equation of wavelength (lambda) G = 0.3; % spatial aspect ratio: 0.23 < gamma < 0.92 numFilterSizes = length(RF_siz); % we get 16 numSimpleFilters = length(rot); % we get 4 numFilters = numFilterSizes*numSimpleFilters; % we get 16x4 = 64 filters fSiz = zeros(numFilters,1); % It is a vector of size numFilters where each cell contains the size of the filter (7,7,7,7,9,9,9,9,11,11,11,11,......,37,37,37,37) filters = zeros(max(RF_siz)^2,numFilters); % Matrix of Gabor filters of size %max_fSiz x num_filters, where max_fSiz is the length of the largest filter and num_filters the total number of filters. Column j of filters matrix contains a n_jxn_j filter (reshaped as a column vector and padded with zeros). for k = 1:numFilterSizes for r = 1:numSimpleFilters theta = rot(r)*pi/180; % so we get 0, pi/4, pi/2, 3pi/4 filtSize = RF_siz(k); center = ceil(filtSize/2); filtSizeL = center-1; filtSizeR = filtSize-filtSizeL-1; sigmaq = sigma(k)^2; for i = -filtSizeL:filtSizeR for j = -filtSizeL:filtSizeR if ( sqrt(i^2+j^2)>filtSize/2 ) E = 0; else x = i*cos(theta) - j*sin(theta); y = i*sin(theta) + j*cos(theta); E = exp(-(x^2+G^2*y^2)/(2*sigmaq))*cos(2*pi*x/lambda(k)); end f(j+center,i+center) = E; end end f = f - mean(mean(f)); f = f ./ sqrt(sum(sum(f.^2))); p = numSimpleFilters*(k-1) + r; filters(1:filtSize^2,p)=reshape(f,filtSize^2,1); fSiz(p)=filtSize; end end % Rebuild all filters (of all sizes) nFilts = length(fSiz); for i = 1:nFilts sqfilter{i} = reshape(filters(1:(fSiz(i)^2),i),fSiz(i),fSiz(i)); %if you will use conv2 to convolve an image with this gabor, so you should also add the equation below. But if you will use imfilter instead of conv2, so do not add the equation below. sqfilter{i} = sqfilter{i}(end:-1:1,end:-1:1); %flip in order to use conv2 instead of imfilter (%bug_fix 6/28/2007); convv=imfilter(image_double, sqfilter{i}, 'same', 'conv'); figure; imagesc(convv); colormap(gray); end
phi = ij*pi/4; % ij = 0, 1, 2, 3 theta = 3; sigma = 0.65*theta; filterSize = 7; % 7:2:37 G = zeros(filterSize); for i=(0:filterSize-1)/filterSize for j=(0:filterSize-1)/filterSize xprime= j*cos(phi); yprime= i*sin(phi); K = exp(2*pi*theta*sqrt(-1)*(xprime+ yprime)); G(round((i+1)*filterSize),round((j+1)*filterSize)) =... exp(-(i^2+j^2)/(sigma^2))*K; end end
As of R2015b release of the Image Processing Toolbox, you can create a Gabor filter bank using the gabor function in the image processing toolbox, and you can apply it to an image using imgaborfilt.
In the frequency domain: sigma_u=1/2*pi*sigmaq; sigma_v=1/2*pi*sigmaq; u0=2*pi*cos(theta)*lambda(k); v0=2*pi*sin(theta)*lambda(k); for u = -filtSizeL:filtSizeR for v = -filtSizeL:filtSizeR if ( sqrt(u^2+v^2)>filtSize/2 ) E = 0; else v_theta = u*cos(theta) - v*sin(theta); u_theta = u*sin(theta) + v*cos(theta); E=(1/2*pi*sigma_u*sigma_v)*((exp((-1/2)*(((u_theta-u0)^2/sigma_u^2))+((v_theta-v0)^2/sigma_v^2))) + (exp((-1/2)*(((u_theta+u0)^2/sigma_u^2))+((v_theta+v0)^2/sigma_v^2)))); end f(v+center,u+center) = E; end end
Implementation of shadow free 1d invariant image
I implemented a method for removing shadows based on invariant color features found in the paper Entropy Minimization for Shadow Removal. My implementation seems to be yielding similar computational results sometimes, but they are always off, and my grayscale image is blocky, maybe as a result of incorrectly taking the geometric mean. Here is an example plot of the information potential from the horse image in the paper as well as my invariant image. Multiply the x-axis by 3 to get theta(which goes from 0 to 180): And here is the grayscale Image my code outputs for the correct maximum theta (mine is off by 10): You can see the blockiness that their image doesn't have: Here is their information potential: When dividing by the geometric mean, I have tried using NaN and tresholding the image so the smallest possible value is .01, but it doesn't seem to change my output. Here is my code: I = im2double(imread(strname)); [m,n,d] = size(I); I = max(I, .01); chrom = zeros(m, n, 3, 'double'); for i = 1:m for j = 1:n % if ((I(i,j,1)*I(i,j,2)*I(i,j,3))~= 0) chrom(i,j, 1) = I(i,j,1)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3)); chrom(i,j, 2) = I(i,j,2)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3)); chrom(i,j, 3) = I(i,j,3)/((I(i,j,1)*I(i,j,2)*I(i,j, 3))^(1/3)); % else % chrom(i,j, 1) = 1; % chrom(i,j, 2) = 1; % chrom(i,j, 3) = 1; % end end end p1 = mat2gray(log(chrom(:,:,1))); p2 = mat2gray(log(chrom(:,:,2))); p3 = mat2gray(log(chrom(:,:,3))); X1 = mat2gray(p1*1/(sqrt(2)) - p2*1/(sqrt(2))); X2 = mat2gray(p1*1/(sqrt(6)) + p2*1/(sqrt(6)) - p3*2/(sqrt(6))); maxinf = 0; maxtheta = 0; data2 = zeros(1, 61); for theta = 0:3:180 M = X1*cos(theta*pi/180) - X2*sin(theta*pi/180); s = sqrt(std2(X1)^(2)*cos(theta*pi/180) + std2(X2)^(2)*sin(theta*pi/180)); s = abs(1.06*s*((m*n)^(-1/5))); [m, n] = size(M); length = m*n; sources = zeros(1, length, 'double'); count = 1; for x=1:m for y = 1:n sources(1, count) = M(x , y); count = count + 1; end end weights = ones(1, length); sigma = 2*s; [xc , Ak] = fgt_model(sources , weights , sigma , 10, sqrt(length) , 6 ); sum1 = sum(fgt_predict(sources , xc , Ak , sigma , 10 )); sum1 = sum1/sqrt(2*pi*2*s*s); data2(theta/3 + 1) = sum1; if (sum1 > maxinf) maxinf = sum1; maxtheta = theta; end end InvariantImage2 = cos(maxtheta*pi/180)*X1 + sin(maxtheta*pi/180)*X2; Assume the Fast Gauss Transform is correct.
I don't know whether this makes any difference as it is more than a month now, but the blockiness and different information potential plot is simply caused by compression of the used image. You can't expect to be getting same results using this image as they had, because they have used raw, high resolution uncompressed version of it. I have to say I am fairly impressed with your results, especially with implementing the information potential. That thing went over my head a little. John.