Chris
Chris

Reputation: 43

Rectification / unwrapping of a cylindrical object on a picture in matlab

I'm trying to unwrapp a cylinder on a picture in matlab, as I need the red markers and the yellow threads (see picture attached) to be on a 2D-plane in line. I have tried a few approaches with "imtransform" but it doesn't seem to work.

I was also thinking of adding a grid on the cylinder so that I know how to adjust the transformation.

Did anyone have the same problem? I would be very happy to get some ideas of how to solve this problem.

enter image description here

Upvotes: 1

Views: 1076

Answers (1)

ceiltechbladhm
ceiltechbladhm

Reputation: 214

Strictly speaking, this cannot be done

The imtransform can allow images to be rectified through a projective transform, but this assumes that the objects in the image lie on a planar surface. This is like taking a picture of a chessboard from two different angles. See the image below.

Rectifying a chessboard

The only reason the chessboard can be rectified is because it is planar. Because your cylinder is 3D, you cannot rectify the points.

What you can do instead

It is possible to extract subimages from the cylinder, rectify each subimage, then stitch them back together.

Example

First, get subimages by selecting points inbetween the red dots (shown as red o's on the image). Note that the bottom one are arbitrary. Then, pick the places where you want those red dots to end up shown as the (green x's). Image with subimages

Next, rectify each subimage. Note that the red dots now lie on the green x's.

Subim1

First Sub image

Subim2

Second Sub-image

Subim3

Third Sub-image

Now stitch the image back together. Note that now, all the red dots lie on the same line.

Stitched Image

close all; clear all; clc;

%Read image
im1 = imread('crCTbm.jpg');

%Location of your red dots
x1 = [49; 106; 178; 234];
y1 = [115 116 126 136];

%Red dots will be aligned on yline in the final image
yline = y1(1);

%Initialize cells
subim = cell(1,length(x1)-1);       %Tracks parsed images
Transform = cell(1,length(x1)-1);   %Projective transform for each subim
RectifiedIm = cell(1,length(x1)-1); %Rectified images

%Initialize boundaries of image (Due to warping, sometimes the images can
%stretch beyond the border of the original image)
xdataout = [1,1]; ydataout = [1,1];

t1 = figure; imshow(im1);
for ii = 1:length(x1)-1
    %Extract a subimage defined by your red dots
    tim = zeros(size(im1));
    tim(:,x1(ii):x1(ii+1),:) = im1(:,x1(ii):x1(ii+1),:);
    subim{ii} = tim;

    %Define four points in the original image
    originalpoints{ii} = [x1(ii),y1(ii);... %Red Dot
        x1(ii+1),y1(ii+1);...               %Red Dot
        x1(ii),y1(ii)+50;...                %Arbitrary point
        x1(ii+1),y1(ii)+50];                %Arbitrary point

    %Define where there four points should lie in the rectified image
    correctedpoints{ii} = [x1(ii),yline;... %Red dot should stay on the same x-coordinate, but y-coordinate is shited to the yline
        x1(ii+1),yline;...                  %Red dot should stay on the same x-coordinate, but y-coordinate is shited to the yline
        x1(ii),yline+50;...                 %Rectilinear point
        x1(ii+1),yline+50];                 %Rectilinear point

    %Plot the original and corrected coordinates on the image
    figure(t1); hold on;
    plot(originalpoints{ii}(:,1),originalpoints{ii}(:,2),'ro');
    plot(correctedpoints{ii}(:,1),correctedpoints{ii}(:,2),'gx');
    legend('Original Points','correctedpoints{ii}');

    %Sometimes the rectified image extends beyond the borders of the
    %original boundary. This finds the worst case scenario for warping and
    %sets the boundaries to that
    Transform{ii} = maketform('projective',originalpoints{ii},correctedpoints{ii});
    [~,xdataim2t,ydataim2t]=imtransform(im1,Transform{ii});
    % now xdataim2t and ydataim2t store the bounds of the transformed im2
    xdataout=[min([1,xdataim2t(1),xdataout(1)]) max([size(im1,2),xdataim2t(2),xdataout(2)])];
    ydataout=[min([1,ydataim2t(1),xdataout(1)]) max([size(im1,1),ydataim2t(2),xdataout(2)])];
end

%Rectify the images
rectifiedx = floor(xdataout(1)):ceil(xdataout(2))+1;    %x-coordinates of new image
rectifiedy = floor(ydataout(1)):ceil(ydataout(2))+1;    %y-coordinates of new image
for ii = 1:length(x1)-1
    RectifiedIm{ii}=imtransform(subim{ii},Transform{ii},'XData',xdataout,'YData',ydataout);
    figure; image(rectifiedx,rectifiedy,uint8(RectifiedIm{ii})); hold on;
    plot(originalpoints{ii}(:,1),originalpoints{ii}(:,2),'ro');
    plot(correctedpoints{ii}(:,1),correctedpoints{ii}(:,2),'gx');
    legend('Original Points','Rectified Points');
end

%Stitch the subimages together
finalim = zeros(size(RectifiedIm{1}));
for ii = 1:length(RectifiedIm)
    finalim = max(double(finalim),double(RectifiedIm{ii}));
end
figure; imshow(uint8(finalim));

EDIT:

If you only care about aligning points in 1D, it is also possible to align them along epipolar lines.

Upvotes: 1

Related Questions