I am trying to write a program that can detect the path which I draw on paper and give me the coordinates. I want to guide a welding torch with use of these coordinates.
With use of edge() I could detect the edges of the path, but I have trouble detecting the middle of the path. I tried to interpolate the edges coordinates with a for loop but I can't.
This is my code:
%% defining & Addressing an Image
img0=imread('C:\Users\Sohrab\Downloads\Project\photo_2018-11-02_22-07-15.jpg');
img0=rgb2gray(img0);
img1=imresize(img0,0.6);
img1=medfilt2(img1,[10,10]);
%% Applying Edge Detection
img2=edge(img1,'sobel');
img3=edge(img1,'canny');
imgI=img3;
[Row,Col]=size(imgI);
%% Interpolation
for i = 1:1:Row
k=0;
ONPixel=0;
for j = 1:1:Col
if(imgI(i,j)==1)
ONPixel=ONPixel+j;
k=k+1;
end
end
imgI(i,:)=0;
if(k >= 2)
imgI(i,floor(ONPixel/k))=1;
end
end
%% showing Results
figure;
subplot(2,2,1)
imshow(img1)
title('ORGINAL IMAGE')
subplot(2,2,2)
imshow(img2)
title('SOBEl METHOD')
subplot(2,2,3)
imshow(img3)
title('CANNY Method')
subplot(2,2,4)
imshow(imgI)
title('Interpolation')
This is the result of interpolation:
the result is incorrect.
This is the image I used for calculation:
Related
I want to convert an image from Cartesian to Polar and to use it for opengl texture.
So I used matlab referring to the two articles below.
Link 1
Link 2
My code is exactly same with Link 2's anwser
% load image
img = imread('my_image.png');
% convert pixel coordinates from cartesian to polar
[h,w,~] = size(img);
[X,Y] = meshgrid((1:w)-floor(w/2), (1:h)-floor(h/2));
[theta,rho] = cart2pol(X, Y);
Z = zeros(size(theta));
% show pixel locations (subsample to get less dense points)
XX = X(1:8:end,1:4:end);
YY = Y(1:8:end,1:4:end);
tt = theta(1:8:end,1:4:end);
rr = rho(1:8:end,1:4:end);
subplot(121), scatter(XX(:),YY(:),3,'filled'), axis ij image
subplot(122), scatter(tt(:),rr(:),3,'filled'), axis ij square tight
% show images
figure
subplot(121), imshow(img), axis on
subplot(122), warp(theta, rho, Z, img), view(2), axis square
The result was exactly what I wanted, and I was very satisfied except for one thing. It's the area (red circled area) in the picture just below. Considering that the opposite side (blue circled area) is not, I think this part should also be filled. Because of this part is empty, so there is a problem when using it as a texture.
And I wonder how I can fill this part. Thank you.
(little difference from Link 2's answer code like degree<->radian and axis values. but i think it is not important.)
Those issues you show in your question happen because your algorithm is wrong.
What you did (push):
throw a grid on the source image
transform those points
try to plot these colored points and let MATLAB do some magic to make it look like a dense picture
Do it the other way around (pull):
throw a grid on the output
transform that backwards
sample the input at those points
The distinction is called "push" (into output) vs "pull" (from input). Only Pull gives proper results.
Very little MATLAB code is necessary. You just need pol2cart and interp2, and a meshgrid.
With interp2 you get to choose the interpolation (linear, cubic, ...). Nearest-neighbor interpolation leaves visible artefacts.
im = im2single(imread("PQFax.jpg"));
% center of polar map, manually picked
cx = 10 + 409/2;
cy = 7 + 413/2;
% output parameters
radius = 212;
dRho = 1;
dTheta = 2*pi / (2*pi * radius);
Thetas = pi/2 - (0:dTheta:2*pi);
Rhos = (0:dRho:radius);
% polar mesh
[Theta, Rho] = meshgrid(Thetas, Rhos);
% transform...
[Xq,Yq] = pol2cart(Theta, Rho);
% translate to sit on the circle's center
Xq = Xq + cx;
Yq = Yq + cy;
% sample image at those points
Ro = interp2(im(:,:,1), Xq,Yq, "cubic");
Go = interp2(im(:,:,2), Xq,Yq, "cubic");
Bo = interp2(im(:,:,3), Xq,Yq, "cubic");
Vo = cat(3, Ro, Go, Bo);
Vo = imrotate(Vo, 180);
imshow(Vo)
The other way around (get a "torus" from a "ribbon") is quite similar. Throw a meshgrid on the torus space, subtract center, transform from cartesian to polar, and use those to sample from the "ribbon" image into the "torus" image.
I'm more familiar with OpenCV than with MATLAB. Perhaps MATLAB has something like OpenCV's warpPolar(), or a generic remap(). In any case, the operation is trivial to do entirely "by hand" but there are enough supporting functions to take the heavy lifting off your hands (interp2, pol2cart, meshgrid).
1.- The white arcs tell that the used translation pol-cart introduces significant errors.
2.- Reversing the following script solves your question.
It's a script that goes from cart-pol without introducing errors or ignoring input data, which is what happens when such wide white arcs show up upon translation apparently correct.
clear all;clc;close all
clc,cla;
format long;
A=imread('shaffen dass.jpg');
[sz1 sz2 sz3]=size(A);
szx=sz2;szy=sz1;
A1=A(:,:,1);A2=A(:,:,2);A3=A(:,:,3); % working with binary maps or grey scale images this wouldn't be necessary
figure(1);imshow(A);
hold all;
Cx=floor(szx/2);Cy=floor(szy/2);
plot(Cx,Cy,'co'); % because observe image centre not centered
Rmin=80;Rmax=400; % radius search range for imfindcircles
[centers, radii]=imfindcircles(A,[Rmin Rmax],... % outer circle
'ObjectPolarity','dark','Sensitivity',0.9);
h=viscircles(centers,radii);
hold all; % inner circle
[centers2, radii2]=imfindcircles(A,[Rmin Rmax],...
'ObjectPolarity','bright');
h=viscircles(centers2,radii2);
% L=floor(.5*(radii+radii2)); % this is NOT the length X that should have the resulting XY morphed graph
L=floor(2*pi*radii); % expected length of the morphed graph
cx=floor(.5*(centers(1)+centers2(1))); % coordinates of averaged circle centres
cy=floor(.5*(centers(2)+centers2(2)));
plot(cx,cy,'r*'); % check avg centre circle is not aligned to figure centre
plot([cx 1],[cy 1],'r-.');
t=[45:360/L:404+1-360/L]; % if step=1 then we only get 360 points but need an amount of L points
% if angle step 1/L over minute waiting for for loop to finish
R=radii+5;x=R*sind(t)+cx;y=R*cosd(t)+cy; % build outer perimeter
hL1=plot(x,y,'m'); % axis equal;grid on;
% hold all;
% plot(hL1.XData,hL1.YData,'ro');
x_ref=hL1.XData;y_ref=hL1.YData;
% Sx=zeros(ceil(R),1);Sy=zeros(ceil(R),1);
Sx={};Sy={};
for k=1:1:numel(hL1.XData)
Lx=floor(linspace(x_ref(k),cx,ceil(R)));
Ly=floor(linspace(y_ref(k),cy,ceil(R)));
% plot(Lx,Ly,'go'); % check
% plot([cx x(k)],[cy y(k)],'r');
% L1=unique([Lx;Ly]','rows');
Sx=[Sx Lx'];Sy=[Sy Ly'];
end
sx=cell2mat(Sx);sy=cell2mat(Sy);
[s1 s2]=size(sx);
B1=uint8(zeros(s1,s2));
B2=uint8(zeros(s1,s2));
B3=uint8(zeros(s1,s2));
for n=1:1:s2
for k=1:1:s1
B1(k,n)=A1(sx(k,n),sy(k,n));
B2(k,n)=A2(sx(k,n),sy(k,n));
B3(k,n)=A3(sx(k,n),sy(k,n));
end
end
C=uint8(zeros(s1,s2,3));
C(:,:,1)=B1;
C(:,:,2)=B2;
C(:,:,3)=B3;
figure(2);imshow(C);
the resulting
3.- let me know if you'd like some assistance writing pol-cart from this script.
Regards
John BG
The MATLAB code below draws a 2D green Gaussian with varaying values of transparancy, which represent a wave function.
The code also draws a red plot, which represents a laser pulse. (See the attached figure).
I want to have the red laser pulse be plotted in the background, so that the part of it which crosses the 2D Gaussian will be invisible.
Is there some kind of a way to achieve this ??
function forQ
close all; clc
figure
xlim_min=-11;
xlim_max=11;
ylim_min=-11;
ylim_max=11;
global size_of_wavefunction; size_of_wavefunction=2.5;
global x_laser; x_laser=-10.5:0.01:10.5;
global omega; omega=8;
global laser_strength; laser_strength=10;
draw_main_wave_function;
hold on
laser_x_offset=-1.2;
hold on
drawLaser(laser_x_offset);
hold on
draw_main_wave_function;
ylim([ylim_min ylim_max])
xlim([xlim_min xlim_max])
axis square
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function drawLaser(x_offset)
global x_laser;
global omega;
global laser_strength;
envelope_extinction=3;
y_laser=laser_strength*exp(-envelope_extinction*(x_laser/10).^2).*cos(omega*(x_laser/10));
y_laser_for_plot=-y_laser;
x_laser_for_plot=x_laser+x_offset;
plot(x_laser_for_plot,y_laser_for_plot,'-r','LineWidth',3)
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function draw_main_wave_function
global size_of_wavefunction;
pre_exp_factor=0.5*0.8;
c1=size_of_wavefunction*0.3;
in_exp_factor=c1;
x_offset=0;
y_offset=0;
draw_wave_function(pre_exp_factor, in_exp_factor, x_offset, y_offset);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function draw_wave_function( pre_exp_factor,in_exp_factor,...
x_offset, y_offset )
x=-3:0.01:3;
y=-3:0.01:3;
if (y_offset~=0)
x=-5:0.1:5;
y=-11:0.1:11;
end
[X,Y]=meshgrid(x,y);
w_function=pre_exp_factor*exp(-in_exp_factor*((X-x_offset).^2+...
(Y-y_offset).^2));
colorMap = [0 , 1, 0];
colormap(colorMap);
min_alpha = 0; % desired minimum alpha
max_alpha = 1; % desired maximum alpha
alpha = min_alpha + (max_alpha-min_alpha)/max(w_function(:))*w_function; % compute alpha
imagesc(x,y,w_function,'AlphaData',alpha,'AlphaDataMapping','none'); % image with alpha
end
Use 3D plots with plot3 and manually set the placement of objects.
view(2) set the 3D figure view to the xy-plot (it might not be necessary in your code).
x = 0:0.1:2*pi;
figure
hold all
y = x(32);
plot3(y,sin(y),0*y+1,'go','MarkerSize',22,'MarkerFaceColor','g')
plot3(x,sin(x),0*x,'r-','LineWidth',3)
view(2)
Here is the input image 5.png:
Here is my code:
clear all; close all; clc;
%Input Image
A = imread('C:\Users\efu\Desktop\5.png');
% figure, imshow(A);
C=medfilt2(A,[3 5]);
% figure,imshow(C);
D=imfill(C);
% figure,imshow(D);
%Image obtained using MATLAB function 'edge'
E=edge(D,'canny',[0.01 .02],3);
figure, imshow(E); title('Image obtained using MATLAB function');
image=E;
img=im2bw(image);
% imshow(img)
se = strel('line',3,0);
zz = imerode(img,se);
figure, imshow(zz);
Output after canny edge detection:
After Eroding:
Here the problem is that after eroding all horizontal edges are broken, but I don't want that. I want to extract all horizontal lines without breaking, besides want to remove all vertical and diagonal lines.
Please someone modify the code.
It's a hack but it works. A short note, I would advise against using clear all. It has some negative effects such as clearing references to your mex functions. I'm not really sure what that means but there seems to be no real use for it unless you want to clear global variables.
Basically what I did here was threefold. I added a gaussian filter to give a bit more tolerance, increased the erosion rate of strel, and searched across angles to give a bit of angle tolerance. In the end, you have a bit more than you started with on the horizontal part but it does clear the image up a lot better. If you wanted you could just add up the zz matrices and threshold it to get a new binary image which could be a bit closer to your original. Really enjoyed the question by the way and made me look forward to image processing in the fall.
clear; close all;
%Input Image
A = imread('5.png');
% figure, imshow(A);
C=medfilt2(A,[3 5]);
% figure,imshow(C);
D=imfill(C);
% figure,imshow(D);
%Image obtained using MATLAB function 'edge'
E=edge(D,'canny',[0.01 .02],4);
figure, imshow(E); title('Image obtained using MATLAB function');
image=E;
img=double(image);
img = imgaussfilt(img,.5);
% imshow(img)
zz_out = zeros(size(img));
% se = strel('line',3,-90);
% zz = imerode(img,se);
% se2 = strel('line',3,0);
% zz2 = imerode(img,se2);
for ii = -5:.1:5
se = strel('line',20,ii);
zz = imerode(img,se);
zz_out = or(zz,zz_out);
end
% zz_out = img-zz;
figure, imshow(zz_out);
I have the following Matlab code, which is used for gif and avi animation creation;
Matlab imwrite is used to create frames of the gif; but I found lighting command is critical in order to successfully obtain the animated gif.
close all
clear all
clc; %
nFrames = 50;
% Preallocate movie structure.
mov(1:nFrames) = struct('cdata', [],'colormap', []);
% Create movie.
figure('color','white');
Z = peaks(150); surf(Z,Z,'edgecolor','none');
view(3);
axis vis3d tight equal off;
v = axis;
%
for k = 1:nFrames
clf;
surf(1.5*sin(2*pi*k/20)*Z,Z,'edgecolor','none');
axis(v);
axis off
camlight;
lighting phong
mov(k) = getframe;
[Inx,cmap]=rgb2ind(mov(k).cdata,256);
if k==1
imwrite(Inx,cmap,'testoutx.gif','gif','DelayTime',0.25,'LoopCount',Inf) %
else
imwrite(Inx,cmap,'testoutx.gif','gif','WriteMode','append','DelayTime',0.25) %
end
end
% Create AVI file.
movie2avi(mov, 'myPeaks.avi', 'compression', 'None');
When I comment "lighting phong", then the obtained gif is static, not animated. It seems only one of the frames is stored. I also tried to use drawnow before each getframe sentence, but that did not work. Why? How can I solve the problem without using lighting?
The desired gif (obtained from the code above):
The undesired gif with "lighting phong" commented:
I have a cube in which I have something as a anomaly, consider it as a cube of zeros and I put a smaller cube of numbers in it using the following code:
anomaly = zeros(100,100,100);
for j = 40:60
for jj = 40:60
for jjj=40:60
anomaly(j,jj,jjj)=10;
end
end
end
I want to somehow view it in a 3D figure, for which I can see the anomaly it it. How can I do it?
Go for isosurface. With isosurface you will be able to extract the inclusion. If you also want to show the whole box, I recommend you to do the following: Create a small box (so it has few faces when converted to isosurface) and then scale it to the real size of the box. You can see this in the following code:
anomaly = zeros(100,100,100); % The anomaly
an2=zeros(100/10+2,100/10+2,100/10+2); % For plotting pourposes
an2(2:10,2:10,2:10)=1; % Create a 10x10x10 box
for j = 40:60
for jj = 40:60
for jjj=40:60
anomaly(j,jj,jjj)=10;
end
end
end
iso=isosurface(anomaly,5); % Extract surface of inclusion
iso2=isosurface(an2,0.5); % create a box
iso2.vertices=(iso2.vertices-1)*10; % offset( so its in 1-10 range)
% and scaling to be 100x100x100
patch(iso,'facecolor','r','edgecolor','none')
patch(iso2,'facecolor','none');
% this last ones are for having a nicer plot
camlight
axis off
axis equal