How can I deform an image to fit a shape, but keep the same pixel values?
17 views (last 30 days)
Show older comments
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.
0 Comments
Answers (2)
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
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.
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.
5 Comments
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.
See Also
Categories
Find more on Interpolation in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!