19
$\begingroup$

The OP in this post on superuser.com asks how to recompose an image; quoting:

I have a set of images, which are parts of a bigger image.

I would like the images to assembled as automated as possible, to recompose the whole picture.

How can I do that?

Just out of curiosity: how can I do that with Mathematica?

Probably ImageAssemble may work in most cases, but notice that in his example the various parts overlap: how to handle this?

Here three overlapping parts of an image:

enter image description here

enter image description here

enter image description here

And what if some of the parts are rotated? Like this:

enter image description here

The full image if needed:

enter image description here

$\endgroup$
2
  • $\begingroup$ Take a look at bottom examples from FindGeometricTransform. Won't work out of the box though. $\endgroup$
    – Kuba
    Jun 8, 2016 at 9:29
  • $\begingroup$ @mattiav27 I never heard that anybody use Mathematica to avoid graphical captcha. You are the first :) $\endgroup$
    – Rom38
    Jun 8, 2016 at 11:08

2 Answers 2

17
$\begingroup$

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["https://i.stack.imgur.com/UjGAz.jpg"];
i2 = Import["https://i.stack.imgur.com/93kwm.jpg"];
GraphicsRow[{i1, i2}]

Mathematica graphics

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]

Mathematica graphics

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}]
  }]

Mathematica graphics

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["https://i.stack.imgur.com/S2ISp.jpg"]; (* Full image *)
{right, bottom} = ImageDimensions[i] - ImageDimensions[i1];
padded = ImagePad[i1, {{0, right - 1}, {bottom - 1, 0}}]

Mathematica graphics

And now I'll use ImageCompose to merge the images:

ImageCompose[padded, i2, p1, p2]

Mathematica graphics

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.

$\endgroup$
5
  • 1
    $\begingroup$ Out of curiosity: would it be possible to adjust your process such that it could account for rotated (and presumably otherwise transformed) images as was also stated in OP's question? $\endgroup$
    – Amndeep7
    Jun 8, 2016 at 20:50
  • 1
    $\begingroup$ @Amndeep7 You'd have to try different transformations to transform the image back to the original. The correct transformation is that which maximizes the image correlation, so in a sense this method can be extended to handle that, yes. But it would be computationally expensive to try lots of different transformations, so a small number of possible transformations would have to be given, or one would have to frame it as an optimization problem in such a way that an efficient algorithm exists to solve it. $\endgroup$
    – C. E.
    Jun 8, 2016 at 21:42
  • 1
    $\begingroup$ Regarding rotation (and scaling): One can use a log-polar transformation to transform inter-image scaling and rotation into translation. See, for instance, this. $\endgroup$ Jun 9, 2016 at 5:13
  • $\begingroup$ @Amndeep7, if you can find corresponding key points in your images, then FindGeometricTransform[] is a possible way to deal with your scenario. $\endgroup$ Jul 23, 2016 at 17:00
  • $\begingroup$ This answer currently lacks a definition of correspondingPixel $\endgroup$
    – SPPearce
    Nov 5, 2018 at 10:17
15
$\begingroup$

This is not very automated but perhaps it will motivate experts:

Copied the images

enter image description here

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"}]

enter image description here

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"}]

enter image description here

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.

enter image description here

In case of doubt enter image description here

$\endgroup$
2
  • 1
    $\begingroup$ It seem ImageCorrespondingPoints have a low precision $\endgroup$
    – yode
    Jun 8, 2016 at 11:10
  • 1
    $\begingroup$ "This is not very automated but[...]" -- I find instructive, (+1). $\endgroup$ Jun 8, 2016 at 11:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.