An ongoing purely recreational project. I got my introduction to image processing with this Rotating perspective... question and had a lot of fun with it.

Now I want to take it to the next step.

The great solutions to the earlier question led me to the following image as quite a small JPEG:


Now, I hope to create a poster of the image that I can have printed at say 4' horizontally. To do this I need a JPEG which will have at least a 4' horizontal dimension with a resolution of at least 300 dpi.

The artist created the original collage from pieces of cut colored paper - each piece a completely saturated color. The entire collage only has 10 or 11 colors. I can pretty easily identify RGB values for each.

Also, the shapes that look approximately rectangular should all show as actual rectangles. The artist originally used full sheets of the colored paper.

If you copy the above image into Mathematica and zoom in on it even a little like this:

zoom of collage

you'll see that it doesn't have crisp straight edges and many of the colors appear modulated rather than saturated. This will only get worse the more one blows up the image. To enlarge this up to 4' wide I need a way to address all of those issues.

Call the attached JPEG i = Import["https://i.sstatic.net/oPQMH.jpg"];

ImageResize[i, 5000]

gets me pretty close to the size I need.

ColorQuantize[i, 11]


begins to get me towards the saturation of color that I want.

But these approaches don't get me all the way.

Do I need to try point operations and/or transformations of some kind? Do I need to breakout grey scales for each of the RGB values?

Would some kind of mask help? Something so I break the problem down into smaller pieces.

Any guidance appreciated.

P.S., I have the original artist's full cooperation and permission in this little project. If anyone wants to make a print of the final product and display it he'd love to see it out in the world and enjoyed.

  • $\begingroup$ "The artist created the original collage from pieces of cut colored paper" I think you need a bigger photo of the collage. You need more pixels. $\endgroup$
    – user2484
    Commented Sep 30, 2012 at 23:21
  • $\begingroup$ Would some of the techniques in this question (the non-artisty ones) be of use? $\endgroup$
    – rm -rf
    Commented Sep 30, 2012 at 23:26
  • $\begingroup$ @res -- Unfortunately, the original no longer exists. We had to work from the only picture we had (see the original questions referenced above). $\endgroup$
    – Jagra
    Commented Sep 30, 2012 at 23:44
  • $\begingroup$ @J.M. -- Thanks for the edits. You cleaned things up nicely. $\endgroup$
    – Jagra
    Commented Oct 1, 2012 at 2:14
  • 1
    $\begingroup$ I have a suspicion that Mathematica's default JPEG Export function doesn't produce the highest possible quality image. And if you can work with PNG, at least you won't lose any quality... $\endgroup$
    – cormullion
    Commented Oct 1, 2012 at 6:52

1 Answer 1


The goal should not be getting a high-res JPEG! What you want is a vector graphic of your images which is arbitrarily scalable without losing quality. Converted to PDF, such a vector graphic can be printed by any printing service.

Let us try some basic image processing. We start with your original image from the post you referred to and apply the perspective transformation. Afterwards, crop the image a bit but leave enough white border around:

img = Import["https://i.sstatic.net/DOGOB.jpg"];
t = FindGeometricTransform[{{1924.19`, 880.846`}, {154.761`, 
     1200.69`}, {190.872`, 189.582`}, {1893.24`, 
     297.914`}}, {{1924.19`, 880.846`}, {175.395`, 
     1283.22`}, {175.395`, 571.325`}, {1893.24`, 297.914`}}, 
   "Transformation" -> "Perspective"];
persp = ImageTake[
  ImagePerspectiveTransformation[img, t[[2]], 1000, DataRange -> Full,
    PlotRange -> All], {50, -250}, {100, -15}]

Mathematica graphics

Fixing the lighting

The first thing I wondered while reading over the answers to your last question was why no one fixed the obvious thing in this image: the light. There is a global color gradient of lighting and a very bright spot in the upper left corner. Looking at a 3D plot of the brightness makes this more visible:

   GaussianFilter[Last[ColorSeparate@ColorConvert[persp, "HSB"]], 5], 
   "Real", DataReversed -> False][[1 ;; -1 ;; 10, 1 ;; -1 ;; 10]]]

Mathematica graphics

I don't want to take the bright spot into account which does not represent the global lighting very well, but with the other 3 corners, I have places in the image which should be of the same brightness.

What I do is, I take the upper right, lower left and lower right corner in the image and calculate the mean of the brightness in this area:

{ur, ll, lr} = Mean[Flatten@ImageData[ImageTake[Last[
 ColorSeparate[ColorConvert[persp, "HSB"]]], #1, #2], "Real"]] & @@@ 
 {{{1, 30}, {-1, -30}}, {{-1, -30}, {1, 30}}, {{-1, -30}, {-1, -30}}}
(* {0.647115, 0.442144, 0.415678} *)

With these 3 corners, we could calculate a plane in 3D space, representing the global behavior of the brightness:

{nx, ny} = ImageDimensions[persp];
sol = First@Block[{x0, x1, y0, y1},
   {x0, y0} = {1, 1};
   {x1, y1} = {nx, ny};
   Solve[Thread[{{x1, y0, 1}, {x0, y1, 1}, {x1, y1, 1}}.{a, b, 
        c} == {ur, ll, lr}], {a, b, c}]
corrFunc = Compile[{{x, _Real, 0}, {y, _Real, 0}, {f, _Real, 0}}, f - #] &[
  (a x + b y) /. sol];

Note that corrFunc takes a pixel-value f and subtracts the plane height at this point. The plane itself pretty much models the behavior of the lighting:

Mathematica graphics

Let's separate our persp image into the 3 channels (hue, saturation and brightness) of the HSB colorspace. We will apply the correction (of course) only on the brightness channel, since this is anyway the only thing that matters... if you don't believe me, take a look at the hChan. With the corrected brightness, we create a perspCorr image.

{hChan, sChan, bChan} = ColorSeparate[ColorConvert[persp, "HSB"]];
bChanCorr = Image[MapIndexed[corrFunc[#2[[2]], #2[[1]], #1] &, 
  ImageData[bChan, "Real"], {2}]];
perspCorr = 
 ColorConvert[ColorCombine[{hChan, sChan, bChanCorr}, "HSB"], "RGB"];

Mathematica graphics

Extracting a mask

The next thing I thought of is whether is possible to kill the background completely. After various tests, it seems the blue channel of the corrected image works if you want to separate background from the colored parts. Finding a good threshold can be done in a Manipulate:

 Binarize[GaussianFilter[Last[ColorSeparate[perspCorr]], 1], t], {t, 0, 1}]

where I found here that 0.534 is appropriate:

mask = ColorNegate[
 Binarize[GaussianFilter[Last[ColorSeparate[perspCorr]], 1], 0.534`]]

Mathematica graphics

We will use this later.

Color smoothing

Color smoothing can be done in various ways. There are many non-linear filters which would do the job, and without giving reasons I (the post is long enough anyway) choose the MeanShiftFilter here:

mshift = MeanShiftFilter[perspCorr, 4, .03, MaxIterations -> 50];
ImageTake[mshift, {200, 300}, {300, 500}]

This does not help you with the pixelized edges, but it smooths the homogeneous surfaces.

Mathematica graphics

Now, let's use the mask for removing the background completely:

preprocessed = 
 ImageAdd[ImageMultiply[mask, mshift], ColorNegate[mask]]

Mathematica graphics


With this image, I would leave Mathematica and take a good vectorizer. InkScape does a good job, and will convert this pixel graphic into a scalable vector graphic for you. Without manual adjustment, this will not solve your edge-problem completely.

But since we're already at Mathematica.SE we can surely try to use some functions from this thread as suggested by rm.

bdata = Flatten[
   MapIndexed[Flatten[{#2 + .9 RandomReal[{-1, 1}, 2], #1}] &, 
      ImageAdd[ImageMultiply[mask, bChanCorr], ColorNegate[mask]], 
      "Real", DataReversed -> True], {2}], 1];
ListDensityPlot[bdata[[1 ;; -1 ;; 10]], InterpolationOrder -> 0, 
 ColorFunction -> "SouthwestColors", BoundaryStyle -> None, 
 Frame -> False, PlotRangePadding -> 0, AspectRatio -> Automatic]

Mathematica graphics

Note that although the image looks pixelated here, it's not! First, I took only every 10th pixel to speed things up. Second, when you export the graphics as a 5000 pixel image, you get an image which looks from very near like a nice mosaic:

Mathematica graphics

  • 1
    $\begingroup$ Wow! An answer and an education. Thanks. $\endgroup$
    – Jagra
    Commented Oct 2, 2012 at 22:23

Your Answer

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

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