Yesterday the hedcut style was brought up in chat. How can we create a hedcut-like style automatically in Mathematica, using a photograph as a starting point?
I am looking to create a similar artistic feel, not necessarily reproduce the hedcut style precisely.
Relevant resources:
Halftone, spiral cut/engraving, and 'pointillism' effects from the recent image vectorization question. All of these re-compose the image out of dots of varying size or lines of varying width.
Sample portraits to work with:
@Silvia's idea from yesterday:
ImageDeconvolve[Import["http://www.alleba.com/blog/wp-content/photos/put001.jpg"],
GaussianMatrix[2.7], Method -> "TSVD"]
My own failed first attempt (the part that detect line directions may be useful to people who work on answers):
img = Import[
"http://www.stars-portraits.com/img/portraits/stars/j/jimi-hendrix/jimi-hendrix-by-BikerScout.jpg"]
(* "Real" images support negative numbers---for convenience *)
img = Image[ColorConvert[img, "GrayLevel"], "Real"];
img = ImageRotate[img, Right];
(* horizontal and vertical components of the gradient;
the direction can be computed using ArcTan *)
gv = ImageCorrelate[img, ( {
{0, -1, 0},
{0, 0, 0},
{0, 1, 0}
} )];
gh = ImageCorrelate[img, ( {
{0, 0, 0},
{1, 0, -1},
{0, 0, 0}
} )];
g = GradientFilter[img, 1];
(* verify the number of white pixels in Binarize[g] *)
Count[ImageData@Binarize[g], 1, Infinity]
(* create small strokes along the outlines *)
outline =
With[{point = RandomChoice[Position[ImageData@Binarize[g], 1], 1500]},
Graphics@MapThread[
Rotate[Disk[#1, {4, 1}], #2] &,
{point,
ArcTan @@@
Transpose[{Extract[ImageData[gh], point],
Extract[ImageData[gv], point]}]}
]
]
(* try to tone down plain grey/dark backgrounds *)
detail = ImageAdjust@
ImageAdd[img,
ImageMultiply[ColorNegate@ImageAdjust@EntropyFilter[img, 15], 2]]
coords = Outer[List, #2, #1] & @@ Range /@ ImageDimensions[img];
fill = With[{point =
RandomChoice[
Join @@ ImageData@ImageClip@ColorNegate[detail] ->
Join @@ coords, 5000]},
Graphics@MapThread[
Rotate[Disk[#1, {3, 0.8}], #2] &,
{point,
ArcTan @@@
Transpose[{Extract[ImageData[gh] + 10 $MachineEpsilon, point],
Extract[ImageData[gv], point]}]}
]
]
Show[fill, outline]
Note: I'm not fond of Putin, but his portrait I linked to seems to be easier to handle than some others.
Update:
Second attempt, based on @Silvia's suggestion to try ContourPlot
and wxffles's image vectorization approach. It's better, but still not achieving that feel.
img = Import["https://i.sstatic.net/YajUp.jpg"]
baseimg =
ColorConvert[ImageReflect@CurvatureFlowFilter[img], "GrayScale"];
(* Here we could simply use
ct=Table[p,{p,0,1,0.02}];
but the following approach gives a better balanced image *)
if = Interpolation[ImageLevels[baseimg]];
cif = Derivative[-1][if];
cifmax = cif[1];
f[x_] := cif[x]/cifmax
ct = Block[{x},
Table[
x /. First@FindRoot[f[x] == p, {x, 0.5, 0, 1}], {p, 0, 1, 0.02}]
];
lcp = ListContourPlot[ImageData[baseimg], Frame -> False,
Contours -> ct,
ContourStyle -> (Dashing[{#, 1/50}] &) /@ ((1 - ct)/50),
PlotRange -> {0, 1}, AspectRatio -> Automatic,
ContourShading -> None]