How can I deform an image to fit a shape, but keep the same pixel values?

30 views (last 30 days)
Hi everybody,
I have an image region which has an irregular shape (a polygon with no holes). I have a second region with a different shape but this will always have the exact same number of pixels (again, a polygon with no holes).
I want to deform the image to fit into the second region, I want the structure of the image to stay the same as far as possible but I also want all the pixel values to be reused in the new region, I do not want new pixel values to be created, so I can't use interpolation. As far as I can tell, Matlab doesn't have an image transformation algorithm which works without interpolation in this way.
My first thought is to calculate the distance and angle of each pixel relative to the image centroid, then assign pixels to their distance/angle nearest neighbor in the second region. However, finding nearest neighbors is quite slow, I feel like this is a brute force approach and there may be a more elegant solution I have missed?
For example, if we imagine that each pixel was attached to its surrounding neighbors by elastic, we could ask how the image can be deformed to fit inside the second region while minimising the amount of 'tension' in the elastic. I know things like this exist for other purposes but can't really find something equivalent for images.
Any suggestions or help would be greatly appreciated.

Answers (2)

DGM
DGM on 6 Jan 2024
Edited: DGM on 6 Jan 2024
For the moment I'm going to assume that the input and output polygons have the same number of vertices or can be made to have the same number of vertices by some means of making neighboring edges colinear where necessary.
% an image
inpict = imread('blacklight2.jpg');
% these points describe a polygon
boxm = [183.4 251.2; 133.4 402.8; 217.3 463.5; 320.7 483.1; 390.3 286.8; 285 252.9]; % [x y]
% assert that this is where they're supposed to be
boxf = [843.4 459.9; 679.3 443.8; 616.9 563.4; 661.5 690; 806 709.6; 900.5 565.1]; % [x y]
% for sake of clarity, show these polygons over the image
imshow(inpict,'border','tight'); hold on
plot(boxm(:,1),boxm(:,2),'y','linewidth',2)
plot(boxf(:,1),boxf(:,2),'r','linewidth',2)
% deform the image using nearest-neighbor interpolation
TF = fitgeotrans(boxm,boxf,'pwl');
outview = imref2d(size(inpict));
outpict = imwarp(inpict,TF,'fillvalues',0,'interp','nearest','outputview',outview);
% again, draw the polygons for reference
imshow(outpict,'border','tight'); hold on
plot(boxm(:,1),boxm(:,2),'y','linewidth',2)
plot(boxf(:,1),boxf(:,2),'r','linewidth',2)
I could probably come up with a better image to work with, but I'm in the middle of something. I might come back to this, but even if I don't, I think it's fairly apparent that the image has been altered in an understandable manner given the position and orientation of the two hexagons.
Note that the entire image is deformed, even regions outside the cage. If it's desired to extract the region inside the initial polygon and then move it alone to the destination polygon, that can be done by using the vertex lists to generate at least one polygonal mask (e.g. poly2mask()) and then doing simple logical composition between the source and destination images as the intended result requires.
  2 Comments
Neurolab
Neurolab on 6 Jan 2024
I'm aware of the fitgeotrans > imref2d > imwarp pipeline, but unfortunately I do not want to create values through interpolation, I want to rearrange the set of existing pixels into the new shape (the starting image and target region always have the exact same number of pixels). I don't think there is an algorithm which fits this pipeline and that works without interpolation?
DGM
DGM on 7 Jan 2024
Edited: DGM on 7 Jan 2024
Oh good gravy. I don't know how I missed that. I read the constraint as "maintain a fixed set of possible colors", not "maintain a fixed population of pixels".
If area is assured to be constant and the shape doesn't get silly (no holes or self-intersection), it seems do-able, but I don't know of something off the top of my head that would make it convenient to do.
As to whether there's an elegant way, I'm generally not the one to ask. The closest I've done is a useless unidirectional sifting filter that's naive and slow.

Sign in to comment.


Image Analyst
Image Analyst on 6 Jan 2024
You cannot do it without "new" pixel values being interpolated especially if you enlarge the region. For example if the source region is a million pixels and the destination region is two million pixels and you use ONLY the original million pixels, then there will be a million "unassigned" pixels, which may show up as dots or holes in your destination image. If by "new" pixel values you meant values not in the original image, then some interpolation routines let you specify 'nearest' so that it will use the nearest existing pixel value rather than interpolating a new value.
Conversely if the destination region is smaller, you'd have to "throw away" pixels to make it fit into the new, smaller shape.
To warp an image see imwarp or see Steve's blog:
  5 Comments
Matt J
Matt J on 7 Jan 2024
It is dubious to attach importance to discrete image properties like the number of pixels in a certain region. The pixelization of an image is, after all, an artificial way of representing an object that is continuous. If you captured the image with the same object in a different position or orientation. The number of pixels covering the region would change.
Neurolab
Neurolab on 7 Jan 2024
The 'images' I'm working with are actually bivariate histograms of point data, so the 'pixels' (bins) do have a statistical meaning.

Sign in to comment.

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!