Binarization image does not have good effect - matlab

I have a problem when binarizing an image:
The walker in the picture is lost after binarizing. Could anyone offer help? Here's the code I used:
clc;
clear;
video = VideoReader('C:\Users\Small_Bird\Desktop\ch02_20170323193606~2.avi');
nFrames = video.NumberOfFrames;
H = video.Height;
W = video.Width;
Rate = video.Preallocate movie structure.
for frameNum = 3500:nFrames
P = read(video,frameNum);
grayImage=rgb2gray(P);
cannyEdge=edge(grayImage,'canny');
[m,n]=size(grayImage);
for i=1:m
for j=1:n
if 1==cannyEdge(i,j)
h(i,j)=grayImage(i,j)+3;
else
h(i,j)=grayImage(i,j);
end
end
end
thresh=graythresh(h);
I2=im2bw(h,thresh);
subplot(2,2,1);
imshow(grayImage),title('original image');
subplot(2,2,2);
imshow(cannyEdge),title('image after extracting edge');
subplot(2,2,3);
imshow(h),title('image after strengthening edge');
subplot(2,2,4);
imshow(I2),title('image after binaryzation');
end

The issue is the choice of threshold for im2bw. You're using the function graythresh to compute a global threshold across the whole image, which your results show only succeeds in separating the black parts of the image from the gray-or-higher parts of the image. You'll need to choose a higher threshold, either an absolute one you use for all images or one computed from some features of each image.
If you have MATLAB version R2016a or newer you have options for computing a locally adaptive threshold using either adaptthresh or im2binarize (the replacement for the im2bw function in newer versions) using the 'adaptive' method. This may give you better results than a simple global threshold.

Related

How do I fit distributions to data sets in matlab?

I'm trying to find a fit to my data using matlab but I'm having a lot of trouble, here's what ive done so far:
A = load('homicide_crime.txt') % A is a two column array the first column is the year and the second column is crime in that year
norm_crime = (A(:,2)-mean(A(:,2)))/std(A(:,2));
[f,x]=hist(norm_crime,20);
plot(x,f/trapz(x,f))
y=normpdf(x,0,1);
hold on
plot(x,y)
This is the resulting plot
.
So i tried afterwards using the distribution fitter which gave me this.
Neither of these things look right since the peak aren't aligned and the fit is too small.
Here is the data set for anyone intrested
https://pastebin.com/CyddrN1R.
Any help is much appreciated.
Actually, I think you are confusing data transformation with distribution fitting.
DATA TRANSFORMATION
In this approach, data is manipulated through a non-linear transformation in order to achieve a perfect fit. This means that it forces your data to follow the chosen distribution rule. To accomplish this with a normal distribution, all you have to do is applying the following code:
A = load('homicide_crime.txt');
years = A(:,1);
crimes = A(:,2);
figure(),histfit(crimes);
rank = tiedrank(crimes);
p = rank ./ (numel(rank) + 1);
crimes_normal = norminv(p,0,1);
figure(),histfit(crimes_normal);
Using the following manipulation:
crimes_normal = (crimes - mean(crimes)) ./ std(crimes);
that can also be written as:
crimes_normal = zscore(crimes);
you modify your observations so that they have mu=0 and sigma=1, but this is far from making them perfectly fit a normal distribution.
DISTRIBUTION FITTING
In this approach, the parameters of the chosen distribution are calculated over the given dataset, and then random observations are drawn. On one side you have your empirical observations, and on the other side you have your fitted data. A goodness-of-fit test can finally tell you how well empirical observations fit the given distribution comparing them to theoretical observations.
Since your are working with a normal distribution, you know that it is fully described by two parameters: mu and sigma. Hence:
A = load('homicide_crime.txt');
years = A(:,1);
crimes_emp = A(:,2);
[mu,sigma] = normfit(crimes_emp);
% you can also use
% mu = mean(crimes);
% sigma = std(crimes);
% to achieve the same result
[f,x] = hist(crimes_emp);
crimes_the = normpdf(x,mu,sigma) .* max(f);
figure();
bar(x, (f ./ sum(f)));
hold on;
plot(x,crimes_the,'-r','LineWidth',2);
hold off;
And this returns something very close to the problem you originally noticed. As you can clearly see, without even running a Kolmogorov-Smirnov or an Anderson-Darling... your data doesn't fit a normal distribution well.
You can try a non-parametric density estimation method. I used kernel density estimation (KDE) with the default normal distribution as the kernel, to obtain the result as shown below. The Matlab command for the same is ksdensity() and documentation can be found here.
A = load('homicide_crime.txt') % load data
years = A(:,1);
values = A(:,2);
[f0,x0] = hist(values,100); % plot the actual histogram
[f1,x1,b1] = ksdensity(values); % KDE with automatically assigned bandwidth
[f2,x2,b2] = ksdensity(values,'Bandwidth',b1*0.6); % 60% of initial bandwidth (b1)
[f3,x3,b3] = ksdensity(values,'Bandwidth',b2*0.6); % 60% of previous bandwidth (b2) = 36% of initial bandwidth (b1)
[f4,x4,b4] = ksdensity(values,'Bandwidth',b3*0.6); % 60% of previous bandwidth (b3) = 21.6% of initial bandwidth (b1)
figure; hold on;
bar(years, f0/(sum(f0)*10) ); % scaled for visualization
plot(years, f1, 'y')
plot(years, f2, 'c')
plot(years, f3, 'g')
plot(years, f4, 'r','linewidth',3) % Final fit
In the code above, I first plot the histogram and then calculate the kde without any user specified bandwidth. This leads to an oversmooth fitting (yellow curve). With a few trials by reducing the bandwidth as only 60% of the previous iteration, I finally was able to get the closest fit (red curve). You can play around the bandwidth to get a still better desirable fit.

how to do image segmentation using built in fcm function in matlab?

I am new to matlab. Actually I have to do retinal blood vessels segmentation. I have used kmeans clustering for segmentation, but result is not satisfactory. Now I want to try out fuzzy c means clustering technique. However I am not able to find out how to use matlab built in function for this purpose. Please guide me about this. I have gone through the following page, but I am not able to understand how to apply all this to my image.
https://cn.mathworks.com/help/fuzzy/fcm.html
Thanks
A minimal working example:
% some sample rgb image
MyImage = imread('autumn.tif');
% display it
figure; imshow(MyImage)
% size of the image
sz = size(MyImage);
% reshape the image to column format (each color band into one column). I guess you
%also did this for the k-means. If not that's why you did get poor results.
ImageInColumnFormat = reshape(MyImage,[],sz(3));
% number of clusters you want
NumberOfClusters = 4;
% U shows how likely each pixel belongs to each cluster.
% double() is only necessary because the sample image is uint8 and fcm has trouble with that format. You may not have to do that.
[~,U] = fcm(double(ImageInColumnFormat),NumberOfClusters);
% Get for each pixel the most likely cluster
[~,Labels] = max(U,[],1);
% reshape it back into the image format
LabelsInImageFormat = reshape(Labels,sz(1),sz(2));
% show result
figure; imagesc(LabelsInImageFormat)

Image deblurring using the Wiener deconvolution

I am trying to deblur the following image by Wiener deconvolution. I was not given the original PSF, and I came up with an arbitrary value for the noise figure. I tried to optimize the code by playing around with the sigma values but I cannot get it to work.
my code...
img = im2double(imread('C:\Users\adhil\Desktop\matlab pics\test.JPG'));
LEN = 2;
THETA = 5;
PSF = fspecial('gaussian', LEN, THETA);
wnr1 = deconvwnr(img, PSF, 0.0000001);
imshow(wnr1);
title('Restored Image');
subplot(1,2,1);imshow(img);title('Before');
subplot(1,2,2);imshow(wnr1);title('After');
here is the result...
please advise
If you have no idea what the point spread function is, or you try an approximation that is far from the actual point spread function, Wiener deconvolution won't work very well, because it relies on knowing the point spread function.
You might have better results trying blind deconvolution (Matlab function):
deconvblind
using an array of ones the same size as your Gaussian PSF guess as the initial PSF (using the array of ones is suggested by the Matlab documentation).

Would Richardson–Lucy deconvolution work for recovering the latent kernel?

I am aware that Richardson–Lucy deconvolution is for recovering the latent image, but suppose we have a noisy image and the original image. Can we find the kernel that caused the transformation?
Below is a MATLAB code for Richardson-Lucy deconvolution and I am wondering if it is easy to modify and make it recover the kernel instead of the latent image. My thoughts are that we change the convolution options to valid so the output would represent the kernel, what do you think?
function latent_est = RL_deconvolution(observed, psf, iterations)
% to utilise the conv2 function we must make sure the inputs are double
observed = double(observed);
psf = double(psf);
% initial estimate is arbitrary - uniform 50% grey works fine
latent_est = 0.5*ones(size(observed));
% create an inverse psf
psf_hat = psf(end:-1:1,end:-1:1);
% iterate towards ML estimate for the latent image
for i= 1:iterations
est_conv = conv2(latent_est,psf,'same');
relative_blur = observed./est_conv;
error_est = conv2(relative_blur,psf_hat,'same');
latent_est = latent_est.* error_est;
end
Thanks in advance.
This is a very simple problem. Convolution is commutative. Hence, you don't need to change the implementation of RL deconvolution to obtain PSF, you can simply call it as follows:
psf = RL_deconvolution(observed, latent_est, iterations)

Smoothing of histogram with a low-pass filter in MATLAB

I have an image and my aim is to binarize the image. I have filtered the image with a low pass Gaussian filter and have computed the intensity histogram of the image.
I now want to perform smoothing of the histogram so that I can obtain the threshold for binarization. I used a low pass filter but it did not work. This is the filter I used.
h = fspecial('gaussian', [8 8],2);
Can anyone help me with this? What is the process with respect to smoothing of a histogram?
imhist(Ig);
Thanks a lot for all your help.
I've been working on a very similar problem recently, trying to compute a threshold in order to exclude noisy background pixels from MRI data prior to performing other computations on the images. What I did was fit a spline to the histogram to smooth it while maintaining an accurate fit of the shape. I used the splinefit package from the file exchange to perform the fitting. I computed a histogram for a stack of images treated together, but it should work similarly for an individual image. I also happened to use a logarithmic transformation of my histogram data, but that may or may not be a useful step for your application.
[my_histogram, xvals] = hist(reshape(image_volume), 1, []), number_of_bins);
my_log_hist = log(my_histogram);
my_log_hist(~isfinite(my_log_hist)) = 0; % Get rid of NaN values that arise from empty bins (log of zero = NaN)
figure(1), plot(xvals, my_log_hist, 'b');
hold on
breaks = linspace(0, max_pixel_intensity, numberofbreaks);
xx = linspace(0, max_pixel_intensity, max_pixel_intensity+1);
pp = splinefit(xvals, my_log_hist, breaks, 'r');
plot(xx, ppval(pp, xx), 'r');
Note that the spline is differentiable and you can use ppdiff to get the derivative, which is useful for finding maxima and minima to help pick an appropriate threshold. The numberofbreaks is set to a relatively low number so that the spline will smooth the histogram. I used linspace in the example to pick the breaks, but if you know that some portion of the histogram exhibits much greater curvature than elsewhere, you'd want to have more breaks in that region and less elsewhere in order to accurately capture the shape of the histogram.
To smooth the histogram you need to use a 1-D filter. This is easily done using the filter function. Here is an example:
I = imread('pout.tif');
h = imhist(I);
smooth_h = filter(normpdf(-4:4, 0,1),1,h);
Of course you can use any smoothing function you choose. The mean would simply be ones(1,8).
Since your goal here is just to find the threshold to binarize an image you could just use the graythresh function which uses Otsu's method.