i have images with bands. The bands are not always 100% straight and not always 100% horizontal. They can be tilted and bent. Each band has a constant width.
I need the width of each band on the image and show the edges of each band as smooth as possible:
Example_edge_detection.png Example_straight.png Example_tilted.png
I have already a solution for 100% straight-horizontal bands. But i dont know how to do it with tilted bands. Maybe Polyfit or houghlines are needed? Please help me. Thank You!
Here the working code for the straight-horizontal bands!
clc;
close all;
clear;
workspace;
format long g;
format compact;
fontSize = 20;
folder = pwd;
baseFileName = 'Example_straight.png';
grayImage = imread(baseFileName);
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels > 1
grayImage = min(grayImage, [], 3);
end
hFig = gcf;
hFig.WindowState = 'maximized';
grayImage = adapthisteq(grayImage);
verticalProfile = mean(grayImage, 2);
threshold = 118;
binaryImage = imfill(grayImage < threshold, 'holes');
% Take the 3 largest blobs
binaryImage = bwareafilt(binaryImage, 3);
% Snip off small tendrils using imopen()
binaryImage = imopen(binaryImage, true(1, 3));
% Take the 3 largest blobs
binaryImage = bwareafilt(binaryImage, 3);
subplot(1, 1, 1);
imshow(baseFileName);
hFig = gcf;
hFig.WindowState = 'maximized'; %
axis('on', 'image');
title('Edge Detection', 'FontSize', fontSize, 'Interpreter', 'None');
binaryProfile = (verticalProfile > threshold)';
bandStarts = strfind(binaryProfile, [0, 1]);
bandStops = strfind(binaryProfile, [1, 0]);
for k = 1 : length(bandStarts)
yline(bandStarts(k), 'Color', 'r', 'LineWidth', 1);
yline(bandStops(k), 'Color', 'r', 'LineWidth', 1);
end
It looks like your algorithm currently just does a simple threshold to find horizontal lines, where the threshold is applied to the difference in the mean horizontal pixel value between two adjacent rows. If that's good enough to get the job done, that's good enough for me.
As for non-horizontal lines, maybe you can try a routine like this to simply straighten out the image first.
I have a heat map
and want to convert this 2D matrix to a 3D volume/shape/surface data points for further processing. Not simply display it in 3D using surf.
What would be a good way to do this?
With a lot of help from this community I could come closer:
I shrunk the size to 45x45 px for simplicity.
I = (imread("TESTGREYPLASTIC.bmp"))./2+125;
Iinv = 255-(imread("TESTGREYPLASTIC.bmp"))./2-80;%
for i = 1:45
for j = 1:45
A(i, j, I(i,j) ) = 1;
A(i, j, Iinv(i,j) ) = 1;
end
end
volshow(A)
Its not ideal but the matrix is what I wanted now. Maybe the loop can be improved to run faster when dealing with 1200x1200 points.
How do I create a real closed surface now?
Following your conversation with #BoilermakerRV, I guess you are looking for one of the following two results:
A list of 3d points, where x and y are index of pixels in the image, and z is value of corresponding pixels. The result will be an m*n by 3 matrix.
An m by n by 256 volume of zeros and ones, that for (i,j)-th pixel in the image, all voxels of the (i, j)-the pile of the volume are 0, except the one at I(i, j).
Take a look at the following example that generates both results:
close all; clc; clear variables;
I = rgb2gray(imread('data2.png'));
imshow(I), title('Data as image')
% generating mesh grid
[m, n] = size(I);
[X, Y] = meshgrid(1:n, 1:m);
% converting image to list of 3-d points
P = [Y(:), X(:), I(:)];
figure
scatter3(P(:, 1), P(:, 2), P(:, 3), 3, P(:, 3), '.')
colormap jet
title('Same data as a list of points in R^3')
% converting image to 256 layers of voxels
ind = sub2ind([m n 256], Y(:), X(:), I(:));
V = zeros(m, n, 256);
V(ind) = 1.0;
figure
h = slice(V, [250], [250], [71]) ;
[h.EdgeColor] = deal('none');
colormap winter
camlight
title('And finally, as a matrix of 0/1 voxels')
The contour plot that is shown can't be generated with "2D" data. It requires three inputs as follows:
[XGrid,YGrid] = meshgrid(-4:.1:4,-4:.1:4);
C = peaks(XGrid,YGrid);
contourf(XGrid,YGrid,C,'LevelStep',0.1,'LineStyle','none')
colormap('gray')
axis equal
Where XGrid, YGrid and C are all NxN matrices defining the X values, Y values and Z values for every point, respectively.
If you want this to be "3D", simply use surf:
surf(XGrid,YGrid,C)
I have attached a Code of Hough Transform in MATLAB below:
%Hough Transform to find lines
%Load an Image and Convert to Grayscale to apply canny Filter
im = imread('lines.jpg');
im_gray = rgb2gray(im);
im_edge = edge(im_gray, 'canny');
figure, imshow(im), title('Original Image');
figure, imshow(im_gray), title('Grayscale Image');
figure, imshow(im_edge), title('Canny Filter Edge');
%Apply Hough Transform to Find the Candidate Lines
[accum theta rho] = hough(im_edge);
figure, imagesc(accum, 'xData', theta, 'ydata', rho), title('Hough Accumulator');
peaks = houghpeaks(accum, 100, 'Threshold', ceil(0.6 * max(accum(:))),'NHoodSize', [5,5]);
size(peaks);
%Finding the line segments in the image
line_segs = houghlines(edges, theta, rows, peaks, 'FillGap', 50,'MinLength', 100);
%Plotting
figure, imshow(im), title('Line Segments');
hold on;
for k=1:length(line_segs)
endpoints = [line_segs(k).point1; line_segs(k).point2];
plot(endpoints(:,1), endpoints(:,2), 'LineWidth', 2, 'Color','green');
end
hold off;
When I'm trying to implement the same in OCTAVE by changing the 'hough into houghtf', 'houghlines to hough_line' and 'houghpeaks into immaximas' in the following way:
%Hough Transform to find lines
pkg load image;
%Load an Image and Convert to Grayscale to apply canny Filter
im = imread('lines.jpg');
im_gray = rgb2gray(im);
im_edge = edge(im_gray, 'canny');
figure, imshow(im), title('Original Image');
figure, imshow(im_gray), title('Grayscale Image');
figure, imshow(im_edge), title('Canny Filter Edge');
%Apply Hough Transform to Find the Candidate Lines
[accum theta rho] = houghtf(im_edge); %In Octave and 'hough' in MATLAB
figure, imagesc(accum, 'xData', theta, 'ydata', rho), title('Hough Accumulator');
peaks = immaximas(accum, 100, 'Threshold', ceil(0.6 * max(accum(:))),'NHoodSize', [5,5]);
size(peaks);
%Finding the line segments in the image
line_segs = hough_line(edges, theta, rows, peaks, 'FillGap', 50, 'MinLength', 100);
%Plotting
figure, imshow(im), title('Line Segments');
hold on;
for k=1:length(line_segs)
endpoints = [line_segs(k).point1; line_segs(k).point2];
plot(endpoints(:,1), endpoints(:,2), 'LineWidth', 2, 'Color', 'green');
end
hold off;
I get the following error while executing it:
error: element number 3 undefined in return list
error: called from
HoughTransformLines at line 14 column 18
I am getting the error stating 'rho' is undefined.
I am completely new to MATLAB and Octave. Can anyone please help me implement the Hough-Transform in Octave?
I suggest the following updates for the original code:
%Hough Transform to find lines
pkg load image;
%Load an Image and Convert to Grayscale to apply canny Filter
im = imread('lines.jpg');
im_gray = rgb2gray(im);
im_edge = edge(im_gray, 'canny');
figure 1, imshow(im), title('Original Image');
figure 2, imshow(im_gray), title('Grayscale Image');
figure 3, imshow(im_edge), title('Canny Filter Edge');
%Apply Hough Transform to Find the Candidate Lines
accum = houghtf(im_edge);
theta = -90:90;
diag_length = (size(accum)(1) - 1) / 2;
rho = -diag_length:diag_length;
figure 4, imagesc(theta, rho, accum), title('Hough Accumulator');
peaks = houghpeaks(accum, 100, 'Threshold', ceil(0.6 * max(accum(:))), 'NHoodSize', [5,5]);
%Finding the line segments in the image
line_segs = houghlines(im_edge, theta, rho, peaks, 'FillGap', 50, 'MinLength', 100);
%Plotting
figure 5, imshow(im), title('Line Segments');
hold on;
for k=1:length(line_segs)
endpoints = [line_segs(k).point1; line_segs(k).point2];
plot(endpoints(:,1), endpoints(:,2), 'LineWidth', 2, 'Color', 'green');
end
hold off;
Let's walk through all updates and review them:
%Hough Transform to find lines
pkg load image;
%Load an Image and Convert to Grayscale to apply canny Filter
im = imread('lines.jpg');
im_gray = rgb2gray(im);
im_edge = edge(im_gray, 'canny');
figure 1, imshow(im), title('Original Image');
figure 2, imshow(im_gray), title('Grayscale Image');
figure 3, imshow(im_edge), title('Canny Filter Edge');
There are only very minor changes - the indices for the figures were added to divide them into consistent separate windows (see Multiple Plot Windows).
After that we are applying Hough transform and restoring "lost" theta and rho values in the Octave:
%Apply Hough Transform to Find the Candidate Lines
accum = houghtf(im_edge);
theta = -90:90;
diag_length = (size(accum)(1) - 1) / 2;
rho = -diag_length:diag_length;
figure 4, imagesc(theta, rho, accum), title('Hough Accumulator');
According to the houghtf function's docs, it returns only an accumulator with rows corresponding to indices of rho values, and columns - to indices of theta values. How can we restore the original rho and theta values? Well, the number of rho values (rows in the accum matrix variable) goes up to 2*diag_length - 1, where diag_length is the length of the diagonal of the input image. Knowing this, we should restore the diagonal length (it is a reversed action): diag_length = (size(accum)(1) - 1) / 2. Then we can restore rho values, which go from minus diagonal to diagonal: rho = -diag_length:diag_length. With thetas everything is easier - they are in the range of pi*(-90:90)/180, but we will use degrees instead: theta = -90:90. I've added the index for figure as did before and changed the call to imagesc according to its docs - it should be called as imagesc (x, y, img).
After that we use houghpeaks function to get the peaks:
peaks = houghpeaks(accum, 100, 'Threshold', ceil(0.6 * max(accum(:))), 'NHoodSize', [5,5]);
And we use houghlines to get the result line segments (guess there were some errata with variables' names):
line_segs = houghlines(im_edge, theta, rho, peaks, 'FillGap', 50, 'MinLength', 100);
And finally there goes plotting code - it wasn't changed at all, because it worked correctly.
The reason why Octave tells you that rho is undefined is because Matlab's hough function and Octave's houghtf function are not exact equivalents.
Here's the description of the output arguments returned by hough from the corresponding Mathwork's webpage:
The function returns rho, the distance from the origin to the line
along a vector perpendicular to the line, and theta, the angle in
degrees between the x-axis and this vector. The function also returns
the Standard Hough Transform, H, which is a parameter space matrix
whose rows and columns correspond to rho and theta values
respectively.
Octave's houghtf, on the other hand, only returns matrix H:
The result H is an N by M matrix containing the Hough transform. Here,
N is the number different values of r that has been attempted. This is
computed as 2*diag_length - 1, where diag_length is the length of the
diagonal of the input image. M is the number of different values of
theta. These can be set through the third input argument arg. This
must be a vector of real numbers, and is by default pi*(-90:90)/180.
Now, in your script, the only place where you call rho is on line 15, when trying to display the Hough accumulator.
I suggest you instead plot the accumulator this way:
figure, imagesc(H),xlabel('xData'),ylabel('ydata'),title('Hough accumulator')
Let me know if this works for you!
[H] = houghtf(edges);
You have to pass the argument in this manner since the octave returns only a matrix of values. you can't assign three different variables to a matrix.
So, assign a single variable to that and you will get the result.
How do I add white Gaussian noise with SNR=5dB to an image using imnoise?
I know that the syntax is:
J = imnoise(I,type,parameters)
and:
SNR = 10log10[var(image)/var(error image)]
How do I use this SNR value to add noise to the image?
Let's start by seeing how the SNR relates to the noise. Your error image is the difference between the original image and the noisy image, meaning that the error image is the noise itself. Therefore, the SNR is actually:
SNR = 10log10[var(image)/var(noise)]
For a given image and SNR=5db, the variance of the noise would be:
var(noise) = var(image)/10SNR/10 = var(image)/sqrt(10)
Now let's translate all of this into MATLAB code. To add white Gaussian noise to an image (denote it I) using the imnoise command, the syntax is:
I_noisy = imnoise(I, 'gaussian', m, v)
where m is the mean noise and v is its variance. It is also important to note that imnoise assumes that the intensities in image I range from 0 to 1.
In our case, we'll add zero-mean noise and its variance is v = var(I(:))/sqrt(10). The complete code is:
%// Adjust intensities in image I to range from 0 to 1
I = I - min(I(:));
I = I / max(I(:));
%// Add noise to image
v = var(I(:)) / sqrt(10);
I_noisy = imnoise(I, 'gaussian', 0, v);
Clarification: we use var(I(:)) to treat compute the variance of all samples in image I (instead of var(I), which computes variance along columns).
Hope this helps!
Example
I = imread('eight.tif');
I = double(I);
%// Adjust intensities in image I to range from 0 to 1
I = I - min(I(:));
I = I / max(I(:));
%// Add noise to image
v = var(I(:)) / sqrt(10);
I_noisy = imnoise(I, 'gaussian', 0, v);
%// Show images
figure
subplot(1, 2, 1), imshow(I), title('Original image')
subplot(1, 2, 2), imshow(I_noisy), title('Noisy image, SNR=5db')
Here's the result:
My task was to deblur a image. I used Weiner Filter and got this kind of image. Is it possible to improve it further?
Here is my code:
I = im2double(imread('Demo4_b.jpg'));
imshow(I);
title('Original Image');
LEN = 21;
THETA = 11;
PSF = fspecial('motion', LEN, THETA);
estimated_nsr = 0;
wnr2 = deconvwnr(I, PSF, estimated_nsr);
figure, imshow(wnr2)
title('Restoration of Blurred, Noisy Image Using NSR = 0')
estimated_nsr = noise_var / var(I(:));
wnr3 = deconvwnr(I, PSF, estimated_nsr);
figure, imshow(wnr3)
title('Restoration of Blurred, Noisy Image Using Estimated NSR');
I am getting same output in both with NSR and without NSR cases. Here is my original image:
You use the motion kernel from the matlab example. The image, however, looks more like it was smoothed with a gaussian kernel. That is the reason you're getting the wobbly lines.
Try this:
I = im2double(imread('a.jpg'));
imshow(I);
title('Original Image');
PSF = fspecial('gaussian', [51 51], 5);
wnr2 = deconvwnr(blurred, PSF, 0.0003 / var(I(:)));
figure, imshow(wnr2)
title('Restoration of Blurred, Noisy Image Using NSR = 0')
You can still tune it with the two parameters (5 and 0.0003)