Image deblurring using MATLAB - matlab

I have two images, one is degraded and one is part of the original image. I need to enhance the first image by using the second one, and I need to do this in the frequency domain. I cut the same area from the degraded image, took its FFT, and tried to calculate the transfer function, but when I applied that function to the image the result was terrible.
So I tried h=fspecial('motion',9,45); to be my transfer function and then reconstructed the image with the code given below.
im = imread('home_degraded.png');
im = rgb2gray(im);
h = fspecial('motion',9,45);
H = zeros(519,311);
H(1:7,1:7) = h;
Hf = fft2(H);
d = 0.02;
Hf(find(abs(Hf)<d))=1;
I = ifft2(fft2(im)./Hf);
imshow(mat2gray(abs(I)))
I have two questions now:
How can I generate a transfer function by using the small rectangles (I mean by not using h=fspecial('motion',9,45);)?
What methods can I use to remove noise from an enhanced image?

I can recommend you a few ways to do that:
Arithmetic mean filter:
f = imfilter(g, fspecial('average', [m n]))
Geometric mean filter
f = exp(imfilter(log(g), ones(m, n), 'replicate')) .^ (1/(m*n))
Harmonic mean filter
f = (m*n) ./ imfilter(1 ./ (g + eps), ones(m, n), 'replicate');
where n and m are size of a mask (for instance, you can set m = 3 n = 3)

Basically what you want to do has two steps (at least) to it:
Estimate the PSF (blur kernel) by using the patch of the image with the squares in it.
Use the estimated kernel to do deconvolution to your blurry image
If you want to "guess" the PSF for step 1, that's fine but it's better to calculate it.
For step 2, you MUST first use edgetaper which will subside the ringing effects in your image, which you call noise.
The you use non-blind deconvolution (step 2) by using the function deconvlucy following this syntax:
J = deconvlucy(I,PSF)
this deconvolution procedure adds some noise, especially if your PSF is not 100% accurate, but you can make it smoother if you allow for more iterations (trading in details, NFL).
For the first step, if you don't care about the fact that you have the "sharp" square, you can just use blind deconvolution deconvblind and get some estimate for the PSF.
If you want to do it correctly and use the sharp patch then you can use it as your data term target in any optimization scheme involving the estimation of the PSF.

Related

Discrete Approximation to Gaussian smoothing

I am trying to find a discrete approximation to the Gaussian smoothing operation, as shown in the link :
http://bit.ly/1cSgkwt
G is some discrete smoothing kernel, a Gaussian in this case and * is the convolution operation. Basically, I want to apply a smoothing kernel to each pixel in the image. I am doing this in MATLAB and using the following code to create the matrix G, which is naive and hence painfully slow :
z = rgb2gray(imread('train_02463_1.bmp'));
im_sz = size(z);
ksize = 5;
% Gaussian kernel of size ksize*ksize
gw_mat = g_sigma(1,2*ksize+1)'*g_sigma(1,2*ksize+1);
G = sparse(length(ksize+1:im_sz(1)-ksize),prod(im_sz));
for i = ksize+1:im_sz(1)-ksize
for j = ksize+1:im_sz(2)-ksize
[x,y] = meshgrid(i-ksize:i+ksize,j-ksize:j+ksize);
row_num = sub2ind(im_sz,i,j);
colnums = sub2ind(im_sz,x,y);
G(row_num,colnums(:)) = gw_mat(:)';
end
end
Is there a more efficient way to do this ?
EDIT: I should apologize for not complete specifying the problem. Most of the answers below are valid ones, but the issue here is the above approximation is part of a optimization objective where the variable is z. The whole problem looks something like this :
http://goo.gl/rEE02y
Thus, I have to pre-generate a matrix G which approximates a smoothing function in order to feed this objective to a solver. I am using cvx, if that helps.
Typically people do it by applying two 1D Gaussian functions sequentially instead of one 2D function (idea of separable filters). You can approximate 1D horizontal Gaussian pretty fast, apply it to each pixel, save result in temp, and then apply a vertical Gaussian to temp. The expected speed up is quite significant: O(ksize*ksize) -> O(ksize+ksize)
You can use approximate Gaussian smoothing via box filters, e.g see integgaussfilt.m:
This function approximates Gaussian filtering by repeatedly applying
averaging filters. The averaging is performed via integral images which
results in a fixed and very low computational cost that is independent of
the Gaussian size.
The fastest way to apply Spatially Invariant Filter on an image using MATLAB would be using imfilter.
imfilter will automatically notice "Seperable" Kernel and will apply it in 2 steps (Vertically / Horizontally).
For creating some known and useful kernels you may look at fspecial.

manipulate data to better fit a Gaussian Distribution

I have got a question concerning normal distribution (with mu = 0 and sigma = 1).
Let say that I firstly call randn or normrnd this way
x = normrnd(0,1,[4096,1]); % x = randn(4096,1)
Now, to assess how good x values fit the normal distribution, I call
[a,b] = normfit(x);
and to have a graphical support
histfit(x)
Now come to the core of the question: if I am not satisfied enough on how x fits the given normal distribution, how can I optimize x in order to better fit the expected normal distribution with 0 mean and 1 standard deviation?? Sometimes because of the few representation values (i.e. 4096 in this case), x fits really poorly the expected Gaussian, so that I wanna manipulate x (linearly or not, it does not really matter at this stage) in order to get a better fitness.
I'd like remarking that I have access to the statistical toolbox.
EDIT
I made the example with normrnd and randn cause my data are supposed and expected to have normal distribution. But, within the question, those functions are only helpful to better understand my concern.
Would it be possible to appy a least-squares fitting?
Generally the distribution I get is similar to the following:
My
Maybe, you can try to normalize your input data to have mean=0 and sigma=1. Like this:
y=(x-mean(x))/std(x);
If you are searching for a nonlinear transformation that would make your distribution look normal, you can first estimate the cumulative distribution, then take the function composition with the inverse of standard normal CDF. This way you can transform almost any distribution to a normal through invertible transformation. Take a look at the example code below.
x = randn(1000, 1) + 4 * (rand(1000, 1) < 0.5); % some funky bimodal distribution
xr = linspace(-5, 9, 2000);
cdf = cumsum(ksdensity(x, xr, 'width', 0.5)); cdf = cdf / cdf(end); % you many want to use a better smoother
c = interp1(xr, cdf, x); % function composition step 1
y = norminv(c); % function composition step 2
% take a look at the result
figure;
subplot(2,1,1); hist(x, 100);
subplot(2,1,2); hist(y, 100);

Matlab - Watershed to extract lines - lost information

I have a vein image as follow. I use watershed algorithm to extract the skeleton of the vein.
My code: (K is the original image).
level = graythresh(K);
BW = im2bw(K,level);
D = bwdist(~BW);
DL = watershed(D);
bgm = DL == 0;
imshow(bgm);
The result is:
As you can see lot of information is lost. Can anybody help me out? Thanks.
It looks like the lighting is somewhat uneven. This can be corrected using certain morphological operations. The basic idea is to compute an image that represents just the uneven lighting and subtract it, or to divide by it (which also enhances contrast). Because we want to find just the lighting, it is important to use a large enough structuring element, so that the operation examines more global properties rather than local ones.
%# Load image and convert to [0,1].
A = im2double(imread('http://i.stack.imgur.com/TQp1i.png'));
%# Any large (relative to objects) structuring element will do.
%# Try sizes up to about half of the image size.
se = strel('square',32);
%# Removes uneven lighting and enhances contrast.
B = imdivide(A,imclose(A,se));
%# Otsu's method works well now.
C = B > graythresh(B);
D = bwdist(~C);
DL = watershed(D);
imshow(DL==0);
Here are C (left), plus DL==0 (center) and its overlay on the original image:
You are losing information because when you apply im2bw, you are basically converting your uint8 image, where the pixel brightness takes a value from intmin('uint8')==0 to intmax('uint8')==255, into a binary image (where only logical values are used). This is what entails a loss of information that you observed.
If you display the image BW you will see that all the elements of K that had a value greater than the threshold level turn into ones, while those ones below the threshold turn into zeros.
Yes, you'll need to lower your threshold likely (lower than what Otsu's method is giving you). And if the edge map is noisy when you lower the threshold, you should apply a 2-D Gaussian smoothing filter before you lower the threshold. This will move the edges slightly but will clean up noise too, so it's a tradeoff.
The 2-D Gaussian can be applied doing something like
w=gausswin(N,Alpha) % you'll have to play with N and alpha
K = imfilter(K,w,'same','symmetric'); % something like these options
Before you apply the rest of your algorithm.

MATLAB image processing HELP!

I am trying to find the area of some regions on an image.
alt text http://img821.imageshack.us/img821/7541/cell1.jpg
For example, I want find the area of the dark-large region on the upper left side.
and I want to find the area of any of the closed geometry from the image.
How can I do that in matlab.
I looked online and I tried regionprops(), but it didn't identify the different regions.
filter your image using 'imfilter'. use 'fspecial' to define your filter. Then use an active contour model to segment the large objects. google 'active contour matlab'. use the 'polygon' and area function to find the area of enclosed contours.
I can reccomand you a few ways to do that:
a) Arithmetic mean filter:
f = imfilter(g, fspecial('average', [m n]))
b) Geometric mean filter
f = exp(imfilter(log(g), ones(m, n), 'replicate')) .^ (1/(m*n))
c) Harmonic mean filter
f = (m*n) ./ imfilter(1 ./ (g + eps), ones(m, n), 'replicate');
where n and m are size of a mask (for instace you can set m=3 n=3)
To add to hkf's answer, you might want to apply some pre-processing to your image to make it easier to handle.
I think you're on the right track with noise reduction. Your contours look relatively easy to detect - maybe you could simply binarize your image, apply combinations of imdilate, imclose and imerode to take care of artifacts (this is mostly trial and error), then try detecting the contours.
Then, of course, the challenge is to find a recipe that works for all images, and not just one sample.
I think you can use contour methods for this problem. Finally, you can extract with the help of a contourdata extracting function. Research, you will see it on the Mathworks web site.

Mean filter for smoothing images in Matlab

I need to test some basic image processing techniques in Matlab. I need to test and compare especially two types of filters: mean filter and median filter.
To smooth image using median filtering, there is a great function medfilt2 from image processing toolbox. Is there any similar function for mean filter? Or how to use the filter2 function to create the mean filter?
One of the most important things for me is to have the possibility of setting radius of the filter. I.e. for median filter, if I want the [3 x 3] radius (mask), I just use
imSmoothed = medfilt2(img, [3 3]);
I would like to achieve something similar for mean filter.
h = fspecial('average', n);
filter2(h, img);
See doc fspecial:
h = fspecial('average', n) returns an averaging filter. n is a 1-by-2 vector specifying the number of rows and columns in h.
I see good answers have already been given, but I thought it might be nice to just give a way to perform mean filtering in MATLAB using no special functions or toolboxes. This is also very good for understanding exactly how the process works as you are required to explicitly set the convolution kernel. The mean filter kernel is fortunately very easy:
I = imread(...)
kernel = ones(3, 3) / 9; % 3x3 mean kernel
J = conv2(I, kernel, 'same'); % Convolve keeping size of I
Note that for colour images you would have to apply this to each of the channels in the image.
I = imread('peppers.png');
H = fspecial('average', [5 5]);
I = imfilter(I, H);
imshow(I)
Note that filters can be applied to intensity images (2D matrices) using filter2, while on multi-dimensional images (RGB images or 3D matrices) imfilter is used.
Also on Intel processors, imfilter can use the Intel Integrated Performance Primitives (IPP) library to accelerate execution.
and the convolution is defined through a multiplication in transform domain:
conv2(x,y) = fftshift(ifft2(fft2(x).*fft2(y)))
if one channel is considered... for more channels this has to be done every channel
f=imread(...);
h=fspecial('average', [3 3]);
g= imfilter(f, h);
imshow(g);