Warping an image based on lines given with different orientations
I would like to warp an image based on lines given with different orientations:
- for each line on the input image, I can get the coordinates of the pixels on the line
- then I would map these pixels to the 开发者_C百科warped image so that each line is now a column.
I would use interp2
since I already have X
, Y
and Z
, and I would make Xi
and Yi
with the coordinates obtained for each line. However, how would you:
- avoid making a
for
loop which index goes all over the number of lines? - make sure each column in the output warped image is the same size?
- sample the input image with radial lines?
- the hardest question in my opinion, how would you keep the neighbourhood structure even if I use different orientations : for instance, the horiontal lines (rows) of the left part of the input image, and the radial lines for the right part?
The input image here is a tire, there is this nice pattern of circles. I could make radial lines from the center of the tire and I would like to get a new image whose columns are the pixels from the radial lines.
Here is the code I have so far (no interp2
yet as I have not solved the problems explained above).
close all
%% Image
Z = imread('tire.tif');
% The corresponding mesh
sz = size(Z);
[X,Y] = meshgrid(1:sz(2), 1:sz(1));
%% Line
lineEquation = @(c, v) (v(1)*(X-c(2))+v(2)*(Y-c(1)))/norm(v);
getLine = @(c, v) abs(lineEquation(c, v))<1/2;
% Example
c = [93, 109];
v = [2, 1];
line = getLine(c, v);
%% Circle
circleEquation = @(c, r) ((X-c(2)).^2+(Y-c(1)).^2-r^2)/r^2;
getCircle = @(c, r) abs(circleEquation(c, r))<1/r;
% Example
r = 24;
circle = getCircle(c, r);
%% Plot a sequence of line
figure;
for delta = -1:0.1:1
v = [0.1, delta];
line_delta = getLine(c, v);
Z_line = Z;
Z_line(line_delta) = 255;
imagesc(Z_line);
colormap('gray');
pause(0.05);
end
%% Plot examples
figure;
subplot(221);
imagesc(Z);
title('Image');
subplot(222);
Z_line = Z;
Z_line(line) = 255;
imagesc(Z_line);
title('Line');
subplot(223);
Z_circle = Z;
Z_circle(circle) = 255;
imagesc(Z_circle);
title('Circle');
subplot(224);
% TODO
title('Warped image');
colormap('gray');
Here are different outputs:
Here is the warped image:
Here is the code from the answer:
[ANG, RAD] = meshgrid(0:0.01:2*pi, 0:0.5:166);
XI = c(2) + cos(ANG).*RAD;
YI = c(1) + sin(ANG).*RAD;
WARPED = interp2(X, Y, double(Z), XI, YI);
WARPED(isnan(WARPED))= max(WARPED(:));
imagesc(WARPED);
title('Warped image');
colormap('gray');
Your main problem (I think) is constructing matrices XI and YI needed for interp2. You construct these by realising that in your new image the horizontal axis represents the angle of the line, and the vertical axis represents the distance from the centre of the circle so to construct those:
%% angle from 360 to 0, radius from 0 to 100
%% resulting image will be 361 x 101 pixels
[ANG, RAD] = meshgrid(360:-1:0,0:100);
%% I take the centre of the circle at (93, 109) Is this correct?
%% From there you can create XI and YI
%% from the angle and radius you have at each point
XI = ones(size(ANG))*93 + cos(ANG/(2*PI)).*RAD;
YI = ones(size(ANG))*109 + sin(ANG/(2*PI)).*RAD;
WARPED = interp2(X,Y,Z, XI, YI)
The output will be heavily distorted (of course) because the circle at each radius is stretched to be the same length. Along the lines distortion will be minimal. If all goes well and my math-fu hasn't left me this should give you a rolled out image of the tire, cut on the line from the centre to the right.
The best way: Use polynomial transformation of second order to transform all the circles to lines and then just cut out the lines you need. Use 2 Matlab commands cp2tform() with parameter 'polynomial' and imtransform() Set inside the transformation T the values 1 for x^2 and y^2 to create a circle and translation to define the center pixel of the tire.
Sorry that I don't supply code, since I answer from iPhone. P.s. Check Matlab help about polynomial and conformal transformation. They do exactly what you need.
精彩评论