I'm trying to make seamless tiles - images that can be repeated on a grid without it being obvious where the joins are.

So far, I've followed the classic strategy of getting the edges working correctly:

i = ImageResize[ExampleData[{"TestImage", "Mandrill"}], 300];
requarter[im_] :=
  Module[{width = First[ImageDimensions[im]], 
    height = Last[ImageDimensions[im]]}, 
   iq = ImagePad[
     ImagePad[im, {{width/2., width/-2.}, {0, 0}}, 
      "Periodic"], {{0, 0}, {height/2., height/-2.}}, "Periodic"]];

irq = requarter[i]

and this quartered will tile well, except that the seams going through the middle (formerly the edges) have to be smoothed out. Somehow I need to blur these lines slightly, or make them overlap in some way, without affecting the rest of the image. What's the best way to do this? Perhaps the classic approach is wrong?

an unfortunate quartered mandrill

img = ExampleData[{"TestImage", "Mandrill"}];

This "rotates" the image like you did:

rot[img_] := 
 Image@RotateLeft[ImageData[img], Round[Reverse@ImageDimensions[img]/2]]

Mathematica graphics

Let's make a mask ...

mask[img_, margin_] := 
 ImagePad[Graphics[{}, ImageSize -> (ImageDimensions[img] - 2 margin),
    Background -> Black], margin, White]

Mathematica graphics

... and inpaint it:

Inpaint[rot[img], Blur[rot[mask[img, 10]], 3]]

Mathematica graphics

Adjust the parameters (mask thickness, blur radius) to your liking.

It will work better for texture-like images:

img = ExampleData[{"Texture", "Bricks3"}]

Inpaint[rot[img], rot[mask[img, 5]]]

Mathematica graphics

Note: often it is better to trace the mask manually, paying attention to features in the image. Right click the image, and choose Graphics Editing -> Drawing Tools. Draw the mask. Then again right click, and choose Graphics Editing -> Create Mask. I like to use the Freehand Line tool with a very thick line and round caps and joins---it's almost like painting with a brush in a photo editor.

  • 2
    $\begingroup$ You could use CrossMatrix to generate the mask. $\endgroup$ – David Feb 28 '12 at 17:47
  • $\begingroup$ @David Feel free to edit it in! $\endgroup$ – Szabolcs Feb 28 '12 at 19:07
  • $\begingroup$ Nope, because I can't figure out how to make the cross thicker without blowing the code up too much ;-) $\endgroup$ – David Feb 28 '12 at 19:11
  • $\begingroup$ @Szabolcs Good solution: I forgot about InPaint $\endgroup$ – cormullion Feb 29 '12 at 7:58

Since texture synthesis using Inpaint has already been mentioned, let me add for the record the obvious, easy, dirty, but sometimes satisfying technique of mirroring:

i = ImageTake[ExampleData[{"Texture", "Bricks3"}], {10, -10}, {70, -120}];
tile = ImageAssemble[
      {{j = ImageReflect[i, Top -> Bottom], ImageReflect[j, Right -> Left]},
       {i, ImageReflect[i, Right -> Left]}}];
ImageAssemble[ConstantArray[tile, {3, 4}]]

enter image description here


The Inpaint method is one approach, but I have never been pleased with the quality of automatic fills and I end up doing it by hand for any tile that matters.

There is a different method that I think often produces a better result. The idea is to overlap the edges of the image rather than joining them flush, and then "intelligently" choose a clipping path inside the overlap area. This comes at the cost of shrinking your image but I believe the quality is worth it, which is better than other automatic methods I have seen, although it doesn't work on all images. This Photoshop filter uses this method; the path it chooses is irregular to obscure the line, and it is placed where the images are most similar to minimize the seam.

You will find that it is necessary for an image to be self-similar on its edges if it is going to tile correctly. To help achieve this I suggest using frequency processing to remove the low frequency components of the image, removing gradients.

I do not have the filter referenced above but I shall attempt to show this process manually.

Here is my selected base image:

enter image description here

Here is what it looks like under internal rotation:

enter image description here

Here is the base image after frequency processing (approx. a 50px high pass, but preserving very-low-frequency information):

enter image description here

Here is the processed image under internal rotation (you can see the improvement):

enter image description here

Returning to the processed image, I overlap the right edge over the left edge by 50 pixels, placing the overlap on a separate layer:

enter image description here

Then I erase from the top (overlapped) layer the parts of the edge that are high contrast:

enter image description here

Then I overlap the bottom over the top by 40 pixels:

enter image description here

And once again erase the parts that have high contrast along the edge:

enter image description here

The process is now complete. Here is the result tiled over a larger area:

enter image description here

  • 2
    $\begingroup$ Why no code? :-( $\endgroup$ – Szabolcs Feb 28 '12 at 22:06
  • 1
    $\begingroup$ So this was not done with Mathematica? I am not sure how I would reproduce all the steps. $\endgroup$ – Szabolcs Feb 28 '12 at 22:39
  • 1
    $\begingroup$ @Szabolcs, no it was not done in Mathematica or I would surely have shared the code. Version 7 doesn't have some of the functions such as SetAlphaChannel that I would want to use. I see no good reason for me to take a long time implementing something I don't personally need using an obsolete tool kit. Which step in particular seems difficult? The selection of which parts were erased was done entirely by hand and I offer no algorithm to automate them; other than that I believe it is fairly direct, if a bit involved. $\endgroup$ – Mr.Wizard Feb 28 '12 at 23:04
  • 2
    $\begingroup$ @Mr.Wizard Thanks for this - it's very useful as an overview of the problem's solution. (And your Mathematica code is more concise than I've ever seen it before...! :) $\endgroup$ – cormullion Feb 29 '12 at 8:02
  • 4
    $\begingroup$ Can you use infix notation in Photoshop? $\endgroup$ – Dr. belisarius Mar 1 '12 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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