53
$\begingroup$

I tried to ask Mathematica to imitate Andy Warhol, let it convert a Marilyn Monroe's portrait so that it looks like Warhol's world famous pop-art painting. However, the result shown below is far from satisfactory. How can I obtain a better result?

Warhol's world famous pop-art painting:

enter image description here

Result from the code below:

enter image description here

im = Import["https://i.sstatic.net/RSKpk.jpg"];
images = {{im, im, im, im}, {im, im, im, im}};
 Do[images[[n, m]] = ImagePad[ (Colorize[Binarize[im ] ,
       ColorRules -> {0 -> RandomColor[], 1 -> RandomColor[]}
      ]  ), 6, White] , {n, 1, 2}, {m, 1, 4}] ;

ImageAssemble[images ]
$\endgroup$
9
  • 2
    $\begingroup$ The first thing I would note is that you are using a binary model. While Andy Warhol seems to be using 4-5 colors. Maybe add 2,3, and 4 to allowed values of the transformation and apply RandomColor to those as well? $\endgroup$
    – James Wine
    Commented Sep 8, 2014 at 4:52
  • 3
    $\begingroup$ This one seems to be the original Marilyn s2.hubimg.com/u/4262573_f520.jpg $\endgroup$ Commented Sep 8, 2014 at 7:46
  • $\begingroup$ Perhaps the methods described here will be useful: 55684 Unfortunately my student licence has expired and I can't bring myself to do such heavy image manipulation on my Raspberry Pi. $\endgroup$
    – shrx
    Commented Sep 8, 2014 at 7:57
  • 1
    $\begingroup$ Just to note, in case it isn't obvious, that AW manually enhanced his screen prints especially around the eyes and lips. See also sothebys.com/en/news-video/blogs/all-blogs/… Also note the "sloppy" yellow paint above Liz Taylors left eye. $\endgroup$
    – Jaydee
    Commented Sep 8, 2014 at 15:22
  • 1
    $\begingroup$ Use Clustering algorithms. Here's a blog which suggests that's what Warhol did, albeit in analog space. aschinchon.wordpress.com/2014/03/03/warholing-grace-with-clara The code is in R but should be pretty easy to port if desired $\endgroup$ Commented Sep 9, 2014 at 13:01

5 Answers 5

68
$\begingroup$

Let's do it Andy's way

So you are Andy. Nice to meet you. And you never got those hands on a computer. It doesn't matter, I will show you!

First you need to go to Marilyn's place. Don't worry, JF isn't there right now. Ask her for a nice photograph and the negatives.

i = ImageCrop@Import@"https://i.sstatic.net/W8hV5.png"

Mathematica graphics

Outstanding picture, good work!

Now please, ask the lab to make a fully saturated neg. Yeah, they'll know how. Let me ask a cab for you, you're too high.

ib = ImageResize[Binarize[i, .55], {440,439}]

Mathematica graphics

Ok, now it's your artistic moment. What? Too drunk? I don't care. Just go and paint some stupid doodles all over that pictures. Use your crayons, don't drink the paint.

cr = Import/@ ("https://i.sstatic.net/" <> # <> ".png" & /@ {"lnMTz", "8W9Mf", "CD2c9", "E041Z"})

Mathematica graphics

Five minutes! Is that all you can do? OMG! You'll never ever get to be recognized. What a lazy artist you are!

No! Don't go to sleep yet. Wait. You're the artist. What should I do with these shi..mmering red blots?
I'll clip them, so nobody is going to see how you spoiled those beautiful pictures. Leave those Campbell's cans alone and give me the scissors.

chV = ChanVeseBinarize[#, "TargetColor" -> {Gray, Red}] & /@ cr;
Row[Framed /@ chV]

Mathematica graphics

Hey! Andy, I need to make a phone call. Don't touch anything. Get your hands off those paint buckets. You're going to ... too late.

cs = RandomSample[ColorData[22, "ColorList"], 4];
chVcol = MapThread[ColorReplace[#1, {Black -> #2, White -> Black}] &, {chV, cs}]

Mathematica graphics

Ok. so now we have a few silly painted "what should we call them". I hope you are happy now. All that work turned garbage and Marilyn will go mad. Yes! do whatever you want with them. Just leave me alone and tell me where you stock the beer. Collage?, yes, whatever you want I said.

if = Fold[ImageAdd[ImageMultiply[#1, ColorNegate@Binarize@#2], #2] &, chVcol];
ImageMultiply[if, ib]

Let's go to the MoMA, you're late again!

Mathematica graphics

$\endgroup$
4
  • 6
    $\begingroup$ +1, had a laugh. Also I totally failed to notice the colors of the background and eyebrows are the same, and for the lips and clothes as well. $\endgroup$
    – shrx
    Commented Sep 9, 2014 at 7:35
  • 4
    $\begingroup$ as I began reading, I thought it was a joke... it wasn't until the very end when I realized you actually did better than Andy - same effect with much less Obetrol used - kudos! $\endgroup$
    – user11734
    Commented Sep 10, 2014 at 16:50
  • 1
    $\begingroup$ @vaxquis I followed the same general procedure, yes. The "scissors-collage" metaphor is not accurate, tough. But I thought the actual process he followed is too cumbersome for intended joke. $\endgroup$ Commented Sep 10, 2014 at 16:59
  • 4
    $\begingroup$ The only thing @ belisarius that made me laugh today. Truman Capote, one of Andy's closest friends, once remarked (I quote by memory): "He's the least intelligent male I know who ever became famous." $\endgroup$
    – eldo
    Commented Sep 10, 2014 at 20:11
30
$\begingroup$

Alright, instead of separating the picture by graylevels, I tried to get more involved with component detections. I noticed the original painting has a different color for hair, face, mouth, eyes, and clothes. I tried my best to replicate this.

i = ImageCrop[Import["http://s2.hubimg.com/u/4262573_f520.jpg"]];
id = ImageDimensions[i];
back := Image[RandomColor[], ImageSize -> id];

bw = ChanVeseBinarize[i, Binarize[GradientFilter[i, 1], .05]] // 
   ColorNegate;
ib = ColorConvert[
   RemoveAlphaChannel[
    RemoveBackground[i, {"Background", {"Uniform", 0.1}}], 
    Darker[Gray, 1]], "Grayscale"];
noback = DeleteSmallComponents[ChanVeseBinarize[ib, EdgeDetect[ib]]];

face = Round[FindFaces[bw]][[1]];
facemask = 
  Rasterize[
   Style[Show[{SetAlphaChannel[bw, 0], 
      Graphics[{Black, Disk[Mean[face], (Mean[face]/2)*{1, 1.4}]}, 
       Background -> Transparent]}], Antialiasing -> False]];
facemask = SetAlphaChannel[facemask, facemask // ColorNegate];
facemaskc := 
  ColorReplace[facemask, 
   Black -> RandomColor[Hue[_, _, RandomReal[{.6, 1}]]]];

mouth = ImageTake[
   DeleteSmallComponents[
     RemoveAlphaChannel[
       RemoveBackground[
        ImagePad[ImageTrim[bw, face], {{0, 0}, {0, 10}}, Black]], 
       White] // ColorNegate] // ColorNegate, {11, -1}];
mouth = ImagePad[
   RemoveAlphaChannel[
    ColorConvert[
     SetAlphaChannel[mouth, 
      ColorNegate[
       Dilation[Closing[ColorNegate[mouth], 30], 
        DiskMatrix[{2, 5}]]]], "RGB"], 
    Black], {{face[[1, 1]], id[[1]] - face[[2, 1]]}, {face[[1, 2]], 
     id[[2]] - face[[2, 2]]}}, White];
mouthc := 
  ColorReplace[
   SetAlphaChannel[mouth, Binarize[mouth, .9999] // ColorNegate], 
   Black -> RandomColor[]];

Rasterize[
  Overlay[{noback, 
    SetAlphaChannel[Binarize[facemask], Binarize[facemask]]}]];
ImageAdd[#, DeleteSmallComponents[# // ColorNegate]] &[%];
eyesNose = 
  DeleteSmallComponents[Opening[%, 2] // ColorNegate] // ColorNegate;
lines = ImageLines[EdgeDetect[eyesNose], MaxFeatures -> 1][[1]];
eyes = SelectComponents[ColorNegate[eyesNose], "Centroid", 
    Abs[#[[2]] - Mean[lines[[All, 2]]]] < 20 &] // ColorNegate;
eyes = ImageTake[
   ImagePad[
    RemoveAlphaChannel[
     ColorConvert[
      SetAlphaChannel[eyes, 
       ColorNegate[
        Dilation[Closing[ColorNegate[eyes], 10], 
         DiskMatrix[{2, 7}]]]], "RGB"], Black], {{0, 0}, {7, 0}}, 
    White], {8, -1}];
eyesc := ColorReplace[
   SetAlphaChannel[eyes, Binarize[eyes] // ColorNegate], 
   Black -> RandomColor[]];

SetAlphaChannel[ColorConvert[noback, "RGB"], noback];
hair = ImageTake[%, id[[2]] - face[[1, 2]] + 1];
torso = ImageTake[%%, -face[[1, 2]] + 1];
hairTorso := 
  ImageAssemble[
   Map[ColorReplace[#, 
      White -> RandomColor[]] &, {{hair}, {torso}}, {2}]];

composition := 
 Rasterize[
  Overlay[{back, 
    ImageCompose[hairTorso, ImageCompose[facemaskc, ImageCompose[eyesc,
       ImageCompose[mouthc, 
        SetAlphaChannel[
         ColorReplace[bw, 
          Black -> RandomColor[Hue[_, _, RandomReal[{.05, .5}]]]], 
         bw // ColorNegate]]]]]}]]

GraphicsGrid[Partition[Table[composition, {8}], 4], ImageSize -> 800]

Mathematica graphics

I'm quite pleased with the result, but the code got kind of long and I'm sure it could be optimiesd.

$\endgroup$
6
  • $\begingroup$ +1, very nice. It captures the spirit of the original image set very well. Did you do this on a Raspberry Pi? O_o $\endgroup$
    – C. E.
    Commented Sep 8, 2014 at 21:03
  • 1
    $\begingroup$ @Pickett I tried to, but FindFaces is not included in the Pi release. I used a friend's computer whose university still has the licence. $\endgroup$
    – shrx
    Commented Sep 8, 2014 at 21:23
  • $\begingroup$ @shrx Are you using the very latest RPi release? (Just curious, I don't have the RPi handy at the moment.) $\endgroup$
    – Szabolcs
    Commented Sep 8, 2014 at 21:24
  • $\begingroup$ @Szabolcs yeah it should be, I update regularly. $\endgroup$
    – shrx
    Commented Sep 8, 2014 at 21:46
  • 1
    $\begingroup$ @bobthechemist That's more a confession than an error msg $\endgroup$ Commented Sep 9, 2014 at 21:33
27
$\begingroup$

Making use of the "Posterization" option in ImageEffect:

img = Import@"https://i.sstatic.net/yNEqN.png";
awImage := ColorReplace[#, Thread[DominantColors[#] -> RandomColor[4]]] &
 [ImageEffect[img, {"Posterization", 2}]]
GraphicsGrid[Partition[Table[awImage, {8}], 4]]

Images

$\endgroup$
22
$\begingroup$
i = Import@"https://i.sstatic.net/yNEqN.png";
h = ColorQuantize[ColorSeparate[i, "HSB"][[3]], 4, Dithering -> False]; 
tr = Array[Thread[Rule[Union@Flatten@ImageData@h,List@@@RandomSample[ColorData[22, "ColorList"], 4]]]&, 
                                                                                            {4, 4}];
Grid[Map[Image[ImageData@h /. #] &, tr, {2}]]

Mathematica graphics

$\endgroup$
11
$\begingroup$

Here's another way of creating false-color Marilyns: take a greyscale image and apply a Cos[] function to the RGB channels, each with a different frequency parameter:

i = RemoveAlphaChannel@ColorConvert[
   ImageCrop@Import@"https://i.sstatic.net/W8hV5.png","Grayscale"]; 
negFunc[x_, par_] := 1 - Cos[2 Pi par x];
imgNegate[im_, r_] := ImageApply[negFunc[#, r] &, im];
GraphicsGrid@Partition[Table[r := RandomReal[{0, 2}];
  ColorCombine[{imgNegate[i, r], imgNegate[i, r], imgNegate[i, r]},"RGB"], {k, 12}], 4]

enter image description here

Replacing the Cos with TriangleWave is also quite effective.

$\endgroup$

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