# How to ask Mathematica to imitate Andy Warhol's pop-art painting?

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:

Result from the code below:

im = Import["http://i.stack.imgur.com/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 ]

• 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? – James Wine Sep 8 '14 at 4:52
• This one seems to be the original Marilyn s2.hubimg.com/u/4262573_f520.jpg – Dr. belisarius Sep 8 '14 at 7:46
• 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. – shrx Sep 8 '14 at 7:57
• 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. – Jaydee Sep 8 '14 at 15:22
• 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 – Carl Witthoft Sep 9 '14 at 13:01

# 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@"http://i.stack.imgur.com/W8hV5.png"


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


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/@ ("http://i.stack.imgur.com/" <> # <> ".png" & /@ {"lnMTz", "8W9Mf", "CD2c9", "E041Z"})


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]


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


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!

• +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. – shrx Sep 9 '14 at 7:35
• 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! – vaxquis Sep 10 '14 at 16:50
• @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. – Dr. belisarius Sep 10 '14 at 16:59
• 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." – eldo Sep 10 '14 at 20:11

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]];
Rasterize[
Style[Show[{SetAlphaChannel[bw, 0],
Graphics[{Black, Disk[Mean[face], (Mean[face]/2)*{1, 1.4}]},
Background -> Transparent]}], Antialiasing -> False]];
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}];
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,
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[
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[mouthc,
SetAlphaChannel[
ColorReplace[bw,
Black -> RandomColor[Hue[_, _, RandomReal[{.05, .5}]]]],
bw // ColorNegate]]]]]}]]

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


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

• +1, very nice. It captures the spirit of the original image set very well. Did you do this on a Raspberry Pi? O_o – C. E. Sep 8 '14 at 21:03
• @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. – shrx Sep 8 '14 at 21:23
• @shrx Are you using the very latest RPi release? (Just curious, I don't have the RPi handy at the moment.) – Szabolcs Sep 8 '14 at 21:24
• @Szabolcs yeah it should be, I update regularly. – shrx Sep 8 '14 at 21:46
• @bobthechemist That's more a confession than an error msg – Dr. belisarius Sep 9 '14 at 21:33

Making use of the "Posterization" option in ImageEffect:

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


i = Import@"http://i.stack.imgur.com/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}]]


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@"http://i.stack.imgur.com/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]


Replacing the Cos with TriangleWave is also quite effective.