Radon Transform Line Detection - matlab

I'm trying to detect lines in a grayscale image. For that purpose, I'm using Radon transform in MATLAB. An example of my m-file is like below. I can detect multiple lines using this code. I also draw lines using shift and rotation properties for lines. However, I didn't understand how to get the start and end points of the detecting lines after getting rho and theta values.
It is easy for Hough transform since there is a function called houghlines() that returns the list of the lines for the given peaks. Is there any function that i can use for Radon transform similar to this function?
% Radon transform line detection algorithm
clear all; close all;
% Determine the path of the input image
str_inputimg = '3_lines.png' ;
% Read input image
I = imread(str_inputimg) ;
% If the input image is RGB or indexed color, convert it to grayscale
img_colortype = getfield(imfinfo(str_inputimg), 'ColorType') ;
switch img_colortype
case 'truecolor'
I = rgb2gray(I) ;
case 'indexedcolor'
I = ind2gray(I) ;
end
figure;
subplot(2,2,1) ;
imshow(I) ;
title('Original Image') ;
% Convert image to black white
%BW = edge(I,'Sobel');
BW=im2bw(I,0.25) ;
subplot(2,2,2) ;
imshow(BW);
title('BW Image') ;
% Radon transform
% Angle projections
theta = [0:179]' ;
[R, rho] = radon(BW, theta) ;
subplot(2,2,3) ;
imshow(R, [], 'XData', theta, 'YData', rho, 'InitialMagnification', 'fit');
xlabel('\theta'), ylabel('\rho');
axis on, axis normal, hold on;
% Detect the peaks of transform output
% Threshold value for peak detection
threshold_val = ceil(0.3*max(R(:))) ;
% Maximum nof peaks to identify in the image
max_nofpeaks = 5 ;
max_indexes = find(R(:)>threshold_val) ;
max_values = R(max_indexes) ;
[sorted_max, temp_indexes] = sort(max_values, 'descend') ;
sorted_indexes = max_indexes(temp_indexes) ;
% Get the first highest peaks for the sorted array
if (length(sorted_max) <= max_nofpeaks)
peak_values = sorted_max(1:end) ;
peak_indexes = sorted_indexes(1:end) ;
else
peak_values = sorted_max(1:max_nofpeaks) ;
peak_indexes = sorted_indexes(1:max_nofpeaks) ;
end
[y, x] = ind2sub(size(R), peak_indexes ) ;
peaks = [rho(y) theta(x)] ;
plot(peaks(:,2), peaks(:,1), 's', 'color','white');
title('Radon Transform & Peaks') ;
% Detected lines on the image
subplot(2,2,4), imshow(I), title('Detected lines'), hold on
x_center = floor(size(I, 2)/2) ;
y_center = floor(size(I, 1)/2) ;
for p=1:length(peaks)
x_1 = [-x_center, x_center] ;
y_1 = [0, 0] ;
% Shift at first
x_1_shifted = x_1 ;
y_1_shifted = [y_1(1)-peaks(p,1), y_1(2)-peaks(p,1)] ;
% Rotate
peaks(p,2) = 90 - peaks(p,2) ;
t=peaks(p,2)*pi/180;
rotation_mat = [ cos(t) -sin(t) ; sin(t) cos(t) ] ;
x_y_rotated = rotation_mat*[x_1_shifted; y_1_shifted] ;
x_rotated = x_y_rotated(1,:) ;
y_rotated = x_y_rotated(2,:) ;
plot( x_rotated+x_center, y_rotated+y_center, 'b', 'linewidth', 2 );
end
hold off;

There's a suggestion at math.SE which might help. Then there's a rather complicated-looking research paper "Sharp endpoint estimates for the X-ray transform and the Radon
transform in finite fields", which appears just to show certain bounds on estimation accuracy.
From skimming other papers, it appears that it's a nontrivial problem. I suspect it may be simpler (if less accurate) to use some adaptation of a Sobel-operation to identify high gradient points along the discovered line, and claim those as endpoints.

Related

How to plot 3D path data as a ribbon in Matlab

I have scatter data X1,Y1,Z1 in 3D, which I can plot as
a=1; c=1; t=0:100;
X1 = (a*t/2*pi*c).*sin(t);
Y1 = (a*t/2*pi*c).*cos(t);
Z1 = t/(2*pi*c);
scatter3(X1,Y1,Z1);
% or plot3(X1,Y1,Z1);
The points define a 3D path. How do I make this into a ribbon plot, similar to the one below?
With delaunay triangulation I can plot it as a surface:
tri = delaunay(X1,Y1);
h = trisurf(tri, X1, Y1, Z1);
But ribbon does not give the desired result:
ribbon(Y1)
The figure below shows what I am after.
The ribbon function can only accept 2D inputs because it uses the 3rd dimension to 'build' the ribbon.
One way to achieve a 3D ribbon is to build series of patch or surface between each point and orient them properly so they look continuous.
The following code will build a ribbon around any arbitrary 3D path defined by an (x,y,z) vector. I will not explain each line of the code but there are plenty of comments and I stopped for intermediate visualisations so you can understand how it is constructed.
%% Input data
a=1; c=1; t=0:.1:100;
x = (a*t/2*pi*c).*sin(t);
y = (a*t/2*pi*c).*cos(t);
z = t/(2*pi*c);
nPts = numel(x) ;
%% display 3D path only
figure;
h.line = plot3(x,y,z,'k','linewidth',2,'Marker','none');
hold on
xlabel('X')
ylabel('Y')
zlabel('Z')
%% Define options
width = ones(size(x)) * .4 ;
% define surface and patch display options (FaceAlpha etc ...), for later
surfoptions = {'FaceAlpha',0.8 , 'EdgeColor','k' , 'EdgeAlpha',0.8 , 'DiffuseStrength',1 , 'AmbientStrength',1 } ;
%% get the gradient at each point of the curve
Gx = diff([x,x(1)]).' ;
Gy = diff([y,y(1)]).' ;
Gz = diff([z,z(1)]).' ;
% get the middle gradient between 2 segments (optional, just for better rendering if low number of points)
G = [ (Gx+circshift(Gx,1))./2 (Gy+circshift(Gy,1))./2 (Gz+circshift(Gz,1))./2] ;
%% get the angles (azimuth, elevation) of each plane normal to the curve
ux = [1 0 0] ;
uy = [0 1 0] ;
uz = [0 0 1] ;
for k = nPts:-1:1 % running the loop in reverse does automatic preallocation
a = G(k,:) ./ norm(G(k,:)) ;
angx(k) = atan2( norm(cross(a,ux)) , dot(a,ux)) ;
angy(k) = atan2( norm(cross(a,uy)) , dot(a,uy)) ;
angz(k) = atan2( norm(cross(a,uz)) , dot(a,uz)) ;
[az(k),el(k)] = cart2sph( a(1) , a(2) , a(3) ) ;
end
% compensate for poor choice of initial cross section plane
az = az + pi/2 ;
el = pi/2 - el ;
%% define basic ribbon element
npRib = 2 ;
xd = [ 0 0] ;
yd = [-1 1] ;
zd = [ 0 0] ;
%% Generate coordinates for each cross section
cRibX = zeros( nPts , npRib ) ;
cRibY = zeros( nPts , npRib ) ;
cRibZ = zeros( nPts , npRib ) ;
cRibC = zeros( nPts , npRib ) ;
for ip = 1:nPts
% cross section coordinates.
csTemp = [ ( width(ip) .* xd ) ; ... %// X coordinates
( width(ip) .* yd ) ; ... %// Y coordinates
zd ] ; %// Z coordinates
%// rotate the cross section (around X axis, around origin)
elev = el(ip) ;
Rmat = [ 1 0 0 ; ...
0 cos(elev) -sin(elev) ; ...
0 sin(elev) cos(elev) ] ;
csTemp = Rmat * csTemp ;
%// do the same again to orient the azimuth (around Z axis)
azi = az(ip) ;
Rmat = [ cos(azi) -sin(azi) 0 ; ...
sin(azi) cos(azi) 0 ; ...
0 0 1 ] ;
csTemp = Rmat * csTemp ;
%// translate each cross section where it should be and store in global coordinate vector
cRibX(ip,:) = csTemp(1,:) + x(ip) ;
cRibY(ip,:) = csTemp(2,:) + y(ip) ;
cRibZ(ip,:) = csTemp(3,:) + z(ip) ;
end
%% Display the full ribbon
hd.cyl = surf( cRibX , cRibY , cRibZ , cRibC ) ;
set( hd.cyl , surfoptions{:} )
Now you have your graphic object contained in one surface object, you can set the options for the final rendering. For example (only an example, explore the surface object properties to find all te possibilities).
%% Final render
h.line.Visible = 'off' ;
surfoptionsfinal = {'FaceAlpha',0.8 , 'EdgeColor','none' , 'DiffuseStrength',1 , 'AmbientStrength',1 } ;
set( hd.cyl , surfoptionsfinal{:} )
axis off
Note that this code is an adaptation (simplification) of the code provided in this answer (to that question: Matlab: “X-Ray” plot line through patch).
This method allows to draw an arbitrary cross section (a disc in the answer) and build a surface which will follow a path. For your question I replaced the disc cross section by a simple line. You could also replace it with any arbitrary cross section (a disc, a square, a potatoid ... the sky is the limit).
Edit
Alternative Method:
Well it turns out there is a Matlab function which can do that. I first discarded it because it is meant for 3D volume visualisations, and most ways to call it require gridded input (meshgrid style). Luckily for us, there is also a calling syntax which can work with your data.
% Same input data
a=1; c=1; t=0:.1:100;
x = (a*t/2*pi*c).*sin(t);
y = (a*t/2*pi*c).*cos(t);
z = t/(2*pi*c);
% Define vertices (and place in cell array)
verts = {[x.',y.',z.']};
% Define "twistangle". We do not need to twist it in that direction but the
% function needs this input so filling it with '0'
twistangle = {zeros(size(x.'))} ;
% call 'streamribbon', the 3rd argument is the width of the ribbon.
hs = streamribbon(verts,tw,0.4) ;
% improve rendering
view(25,9)
axis off
shading interp;
camlight
lighting gouraud
Will render the following figure:
For additional graphic control (over the edges of the ribbon), you can refer to this question and my answer: MATLAB streamribbon edge color

Detecting lanes in a video using matlab and image processing.

I am a little bit new to matlab and imageprocessing and I was given a task at my faculty to carry out a project which detects the lanes for a moving car in a video. I tried to use some tutorials on Mathworks and other sites and there were really helpful and I came out with a code that detects lanes in an image and I just want to know how to apply my code on a video as I see it working properly on an image.
and here is my code :
img = imread ('test_image.jpg');
I = rgb2gray (img);
%making a gaussian kernel
sigma = 1 ; %standard deviation of distribution
kernel = zeros (5,5); %for a 5x5 kernel
W = 0 ;
for i = 1:5
for j = 1:5
sq_dist = (i-3)^2 + (j-3)^2 ;
kernel (i,j) = exp (-1*exp(sq_dist)/(2*sigma));
W = W + kernel (i,j) ;
end
end
kernenl = kernel/W ;
%Now we apply the filter to the image
[m,n] = size (I) ;
output = zeros (m,n);
Im = padarray (I , [2 2]);
for i=1:m
for j=1:n
temp = Im (i:i+4 , j:j+4);
temp = double(temp);
conv = temp.*kernel;
output(i,j) = sum(conv(:));
end
end
output = uint8(output);
%--------------Binary image-------------
level = graythresh(output);
c= im2bw (output,level);
%---------------------------------------
output2 = edge (c , 'canny',level);
figure (1);
%Segment out the region of interest
ROI = maskedImage;
CannyROI = edge (ROI , 'canny',.45);
%----------------------------------
set (gcf, 'Position', get (0,'Screensize'));
%subplot (141), imshow (I), title ('original image');
%subplot (142), imshow (c), title ('Binary image');
%subplot (143), imshow (output2), title ('Canny image');
%subplot (144), imshow (CannyROI), title ('ROI image');
[H ,T ,R] = hough(CannyROI);
imshow (H,[],'XData',T,'YData',R,'initialMagnification','fit');
xlabel('\theta'), ylabel('\rho');
axis on , axis normal, hold on ;
P = houghpeaks(H,5,'threshold',ceil (0.3*max(H(:))));
x = T(P(:,2));
y = R(P(:,1));
plot (x,y,'s','color','white');
%Find lines and plot them
lines = houghlines (CannyROI,T,R,P,'FillGap',5,'MinLength',7);
figure, imshow (img), hold on
max_len = 0 ;
for k = 1:length(lines);
xy = [lines(k).point1; lines(k).point2];
plot (xy(:,1), xy(:,2), 'LineWidth', 5 , 'Color', 'blue');
%plot beginnings and ends of the lines
plot (xy(1,1), xy(1,2),'x', 'LineWidth', 2, 'Color', 'yellow');
plot (xy(2,1), xy(2,2),'x', 'LineWidth', 2, 'Color', 'red');
%determine the endpoints of the longest line segment
len = norm(lines(k).point1 - lines(k).point2);
if (len>max_len)
max_len = len;
xy_long = xy;
end
end
and here is the link of the image and the video :
https://github.com/rslim087a/road-video
https://github.com/rslim087a/road-image
Thanks in advance.
Basically video processing happens in such a way that video will be converted to video frames (images). So if you need, you can convert your video to video frames and run the code, looping over the folder having the video frames. Change the imread function to get images from video frames folder...
img = imread(path_to_video_frames_folder/*)

Create 3D effect of 2D line plot matlab [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Question, I have a line data. However I wanted to be plotted with a 3D effect, which you can also choose as an option, for instance, within Office Excel/Powerpoint.
Currently I have the code below which kind of mimmics the effect (simply putting a lot of plots after each other):
Excel:
Matlab:
Matlab code:
x = 1:10;
y = rand(1, 10);
z = rand(1, 10);
figure;
hold on;
for i = 1:20
hFill = fill3(i*0.01*ones(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
hFill = fill3((i*0.01*(ones(1, 12)))+2, x([1 1:end end]), [0 z 0], 'g', 'FaceAlpha', 0.5);
end
grid on;
xlim([0 10]);
view(3);
You could probably construct a closed surface in one single graphic object to represent your 3D curve, however I don't have time to work that out completely so I'll go the lazy way:
Instead of stacking multiple fill objects to give a 3d feeling, I build each curve with 3 objects:
A top surface, with the desired thickness
2 patch objects to close the sides
Here goes:
%% Sample data
rng(12)
x = 1:10;
y = rand(1, 10) + .5 ;
z = rand(1, 10) + .5 ;
%% Parameters
alphaTop = .5 ; % alpha value of the top of the surface
alphaSide = .5 ; % alpha value of the sides
thickness = .5 ; % thickness of each curve
separation = 1 ; % separation of each curve
colors = {'b';'r'} ; % color for each curve
%% prepare patch coordinates
xp = x([1 1:end end 1]) ;
yp1 = [0 y 0 0] ;
yp2 = [0 z 0 0] ;
zp1 = zeros(size(yp1)) ;
zp2 = zeros(size(yp2)) + 1 ;
%% Prepare surface coordinates
xs = [ xp; xp] ;
ys1 = [yp1;yp1] ;
ys2 = [yp2;yp2] ;
zs1 = zeros(size(xs)) ;
zs1(2,:) = zs1(2,:) + thickness ;
zs2 = zs1 + separation ;
%% Display
figure
hold on
% plot the sides (one patch on each side of each curve)
hp11 = patch(zp1 ,xp,yp1, colors{1} , 'FaceAlpha', alphaSide) ;
hp12 = patch(zp1+thickness,xp,yp1, colors{1} , 'FaceAlpha', alphaSide) ;
hp21 = patch(zp2 ,xp,yp2, colors{2} , 'FaceAlpha', alphaSide) ;
hp22 = patch(zp2+thickness,xp,yp2, colors{2} , 'FaceAlpha', alphaSide) ;
% plot the top surfaces
hs1 = surf(zs1,xs,ys1, 'FaceColor',colors{1},'FaceAlpha',alphaTop) ;
hs2 = surf(zs2,xs,ys2, 'FaceColor',colors{2},'FaceAlpha',alphaTop) ;
% refine plot
xlim([0 10]);ylim([0 10]); view(3);
xlabel('X') ; ylabel('Y') ; zlabel('Z') ;
Which yields:
Once this is built, you can regroup the graphic handles to group common properties assignments. For example:
%% Optional (modify common properties in group)
% regroup graphic handles for easy common property assignment
hg1 = [hp11;hp12;hs1] ;
hg2 = [hp21;hp22;hs2] ;
% set properties in group
set(hg1,'EdgeColor',colors{1},'FaceAlpha',0.2) ;
set(hg2,'EdgeColor',colors{2},'FaceAlpha',0.2) ;
To give your curves a nice transparent mesh style:
Ultimately, if you plan to apply this method to many curves, you should either package it in a function, or at least build your curves with a loop. It should be easy to convert as long as the parameters for each curve are in an array you can index into (like I did for the colors).

Matlab - how to plot monte carlo paths transforming into horizontal histogram in one chart

I want to create a chart which would present all the paths resulting from a simulation and then at the point t=T to transform it into horizontal histogram presenting the frequency of the end results.
Is this possible to do in one chart in Matlab?
I don't think there is a really nice way to do this, but I managed to hack together something which looks similar to what you describe. See below my example with a Monte Carlo simulation of a random walk.
% Setup, create test data
col = [0 0.2 0.741] ; % colour
rng(0) ; % reset random number seed
n = 20 ; % number of bins
Te = 1000 ; % simulation length
T = 600 ; % length of trajectory to plot
X = cumsum(randn(Te,1)) ;
Ugly plot code:
% create histogram based on the end of the sample
[H,C] = hist(X(T+1:Te),n) ;
% new figure
fh = figure(999) ;
clf() ;
% trajectory for the first part of the sample
ax0 = subplot(1,2,1) ;
lh = plot(X(1:T),'Parent',ax0) ;
lh.Color = col ;
% histogram for the second part of the sample
ax1 = subplot(1,2,2) ;
bh = barh(ax1,C,H,1) ;
bh.EdgeColor = col ;
bh.FaceColor = col ;
ax1.XTickLabel = '' ;
ax1.YTickLabel = '' ;
% make both axes have the same YLim property and make sure we don't clip anything
YLim(2) = max(ax0.YLim(2),ax1.YLim(2)) ;
YLim(1) = min(ax0.YLim(1),ax1.YLim(1)) ;
ax1.YLim = YLim ;
linkaxes([ax1,ax0],'y') ;
% bump the axes together
ax0.Position = [0.13 0.11 0.440552147239264 0.815] ;
It's not pretty but it works. Result:

How to perform matching by MSER and HOG in Matlab

I wanted to know if there is any full implementation of image-matching by MSER and HOG in Matlab. Currently I am using VLFeat but found difficulties when performing the image matching. Any help?
Btw, I've tried the below code in VLFeat -Matlab environment but unfortunately the matching can't be performed.
%Matlab code
%
pfx = fullfile(vl_root,'figures','demo') ;
randn('state',0) ;
rand('state',0) ;
figure(1) ; clf ;
Ia = imread(fullfile(vl_root,'data','roofs1.jpg')) ;
Ib = imread(fullfile(vl_root,'data','roofs2.jpg')) ;
Ia = uint8(rgb2gray(Ia)) ;
Ib = uint8(rgb2gray(Ib)) ;
[ra,fa] = vl_mser(I,'MinDiversity',0.7,'MaxVariation',0.2,'Delta',10) ;
[rb,fb] = vl_mser(I,'MinDiversity',0.7,'MaxVariation',0.2,'Delta',10) ;
[matches, scores] = vl_ubcmatch(fa, fb);
figure(1) ; clf ;
imagesc(cat(2, Ia, Ib));
axis image off ;
vl_demo_print('mser_match_1', 1);
figure(2) ; clf ;
imagesc(cat(2, Ia, Ib));
xa = ra(1, matches(1,:));
xb = rb(1, matches(2,:)) + size(Ia,2);
ya = ra(2, matches(1,:));
yb = rb(2,matches(2,:));
hold on ;
h = line([xa ; xb], [ya ; yb]);
set(h, 'linewidth', 1, 'color', 'b');
vl_plotframe(ra(:,matches(1,:)));
rb(1,:) = fb(1,:) + size(Ia,2);
vl_plotframe(rb(:,mathces(2,:)));
axis image off ;
vl_demo_print('mser_match_2', 1);
%%%%%%
There are a couple problems. First, the code has several errors and doesn't run as-is. I've pasted my working version below.
More importantly, you're trying to use the SIFT feature-matching function to match the MSER ellipsoids. This won't work at all, since SIFT gives a very high dimensional feature vector based on local image gradients, and the MSER detector is just giving you a bounding ellipsoid.
VLFeat doesn't appear to include an MSER-matching function, so you'll probably have to write your own. Take a look at the original MSER paper to understand how they did matching:
"Robust wide-baseline stereo from maximally stable extremal regions", Matas et al. 2002
% Read the input images
Ia = imread(fullfile(vl_root,'data','roofs1.jpg')) ;
Ib = imread(fullfile(vl_root,'data','roofs2.jpg')) ;
% Convert to grayscale
Ia = uint8(rgb2gray(Ia)) ;
Ib = uint8(rgb2gray(Ib)) ;
% Find MSERs
[ra,fa] = vl_mser(Ia, 'MinDiversity',0.7,'MaxVariation',0.2,'Delta',10) ;
[rb,fb] = vl_mser(Ib, 'MinDiversity',0.7,'MaxVariation',0.2,'Delta',10) ;
% Match MSERs
[matches, scores] = vl_ubcmatch(fa, fb);
% Display the original input images
figure(1); clf;
imagesc(cat(2, Ia, Ib));
axis image off;
colormap gray;
% Display a second copy with the matches overlaid
figure(2) ; clf ;
imagesc(cat(2, Ia, Ib));
axis image off;
colormap gray;
xa = fa(1, matches(1,:));
ya = fa(2, matches(1,:));
xb = fb(1, matches(2,:)) + size(Ia,2);
yb = fb(2, matches(2,:));
hold on ;
h = line([xa ; xb], [ya ; yb]);
set(h, 'linewidth', 1, 'color', 'y');
I don't know how, but MSER matching works in Matlab itself.
The code below
file1 = 'roofs1.jpg';
file2 = 'roofs2.jpg';
I1 = imread(file1);
I2 = imread(file2);
I1 = rgb2gray(I1);
I2 = rgb2gray(I2);
% %Find the SURF features.
% points1 = detectSURFFeatures(I1);
% points2 = detectSURFFeatures(I2);
points1 = detectMSERFeatures(I1);
points2 = detectMSERFeatures(I2);
%Extract the features.
[f1, vpts1] = extractFeatures(I1, points1);
[f2, vpts2] = extractFeatures(I2, points2);
%Retrieve the locations of matched points. The SURF featurevectors are already normalized.
indexPairs = matchFeatures(f1, f2, 'Prenormalized', true) ;
matched_pts1 = vpts1(indexPairs(:, 1));
matched_pts2 = vpts2(indexPairs(:, 2));
figure; showMatchedFeatures(I1,I2,matched_pts1,matched_pts2,'montage');
legend('matched points 1','matched points 2');
gives the following picture