Can Mathematica recompose an image?
Yesterday I showed how to locate a subimage inside a large image using ImageCorrelate
. I will now show how to use the same approach to solve this problem.
Start by importing the images that you want to compose:
i1 = Import["http://i.stack.imgur.com/UjGAz.jpg"];
i2 = Import["http://i.stack.imgur.com/93kwm.jpg"];
GraphicsRow[{i1, i2}]
Since the right image is not completely contained by the left image, we cannot use my answer from the other question. However, if we split the right image into small enough pieces then there will be a piece that is covered completely by the left image. By locating this piece in the left image we know two positions, one in each image, that correspond to each other.
pieces = ImagePartition[i2, 64]
There may be several pieces that are covered by the left image, in which case there will be several good fits. I will select the piece that fits best, as given by ImageCorrelate
.
minPixelValue[image_Image][subimage_Image] := Module[{corr, idata},
corr = ImageCorrelate[image, subimage, EuclideanDistance];
idata = ImageData[corr];
idata = Map[Norm, idata, {2}];
Min[idata]
]
bestFit = MinimalBy[Flatten[pieces], minPixelValue[i1]] // First;
Now I can find out where in the two images the piece that I selected as the best fit belongs:
{p1} = correspondingPixel[i1, bestFit];
{p2} = correspondingPixel[i2, bestFit];
GraphicsRow[{
HighlightImage[i1, p1, Method -> {"DiskMarkers", 5}],
HighlightImage[i2, p2, Method -> {"DiskMarkers", 5}]
}]
Finally we need to compose the images. This is easier to do if we know where one of the images is positioned in the complete image, and also the dimensions of the complete image. I will assume such knowledge for convenience sake. I'll start by creating a padded version of the left image:
i = Import["http://i.stack.imgur.com/S2ISp.jpg"]; (* Full image *)
{right, bottom} = ImageDimensions[i] - ImageDimensions[i1];
padded = ImagePad[i1, {{0, right - 1}, {bottom - 1, 0}}]
And now I'll use ImageCompose
to merge the images:
ImageCompose[padded, i2, p1, p2]
We can apply the same method again to merge this image with the third image. In general, if there are $n$ images then they can be merged like this in a recursive manner. Unless all images overlap with each other the order in which images are merged will be important, so it may require finesse.
This is not very automated but perhaps it will motivate experts:
Copied the images
Changing image to graphic and finding corresponding points:
fun[img_] :=
With[{id = ImageDimensions[img]}, {Texture[img],
Polygon[{{1, 1}, {id[[1]], 1}, id, {1, id[[2]]}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]}]
{ma, mb} = ImageCorrespondingPoints[a, b];
{mta, mtc} = ImageCorrespondingPoints[a, c];
Using manipulate and pasting desired bookmarks:
Manipulate[
Graphics[{GeometricTransformation[
fun[a]~Join~{Red, PointSize[0.025], Point[ma]},
TranslationTransform[{x, y}]], Opacity[0.5], fun[b], Yellow,
PointSize[0.01], Point[mb]}],
{x, -300, 10, Appearance -> "Labeled"}, {y, -300, 100,
Appearance -> "Labeled"}]
Manipulate[
Graphics[{GeometricTransformation[
fun[c]~Join~{Red, PointSize[0.025], Point[mtc]},
TranslationTransform[{x, y}]], Opacity[0.5],
GeometricTransformation[fun[a], TranslationTransform[abt]], Yellow,
PointSize[0.01],
GeometricTransformation[Point[mta], TranslationTransform[abt]]}],
{x, -300, 10, Appearance -> "Labeled"}, {y, -300, 100,
Appearance -> "Labeled"}]
The bookmarks:
abt = "ab" /. {"ab" :> {x = -122.5`, y = -171.`}}
act = "ac" /. {"ac" :> {x = -128.`, y = 1.`}}
Piecing together:
Graphics[{GeometricTransformation[fun[a], TranslationTransform[abt]],
GeometricTransformation[fun[c], TranslationTransform[act]], fun[b]}]
The code could be made more concise. I do not have time at present (this was a "stream of consciousness"). I look forward to learning from other answers.
In case of doubt