Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I need to apply Van Gogh's stroke brush effect to a random image Van Gogh's painting

Take the following image as an example:Example Image

Thank you so much if you could help!

share|improve this question
4  
Probably the way to do it is to read all of these papers on painterly rendering and implement one of them in Mathematica. –  Rahul Narain Dec 18 '13 at 4:57
3  
Any special reason to do it with Mathematica? –  belisarius Dec 18 '13 at 5:35
4  
Many raster image processing programs come with a filter similar to the one you request. Adobe Photoshop is an example of one such. –  m_goldberg Dec 18 '13 at 6:38
    
You will probably end up doing this in a photo editor. Some old filter exist that could help you. Fantastic Machines PaintEngine (beta) is free and simple, but not particularly powerful. The Impressionist filter from Microsoft Image Composer does a better job; I think it used to be freely available but I cannot find a copy now. There was also a filter called "Xaos Tools Paint Alchemy" which I think was similar to Impressionist; it may be "abandonware" or simply unavailable. –  Mr.Wizard Dec 18 '13 at 6:58
    
There is probably a newer, commercial version of this type of filter now but I'm not familiar with it. –  Mr.Wizard Dec 18 '13 at 6:59
show 4 more comments

4 Answers 4

Edit

Here is a different approach using Graphics to actually draw some brush strokes. I run a GradientOrientationFilter on a smaller version of the image to estimate the local image gradient, and use that information to create a collection of randomly shaded lines:

img = Import["http://i.stack.imgur.com/XwYg7.jpg"];

im = img ~ImageResize~ 200 ~ColorConvert~ "Grayscale";

gof = im ~GradientOrientationFilter~ 5;

lines = MapIndexed[{GrayLevel@RandomReal[], 
     Line[{#2 - 2 {Cos[#1], Sin[#1]}, #2 + 2 {Cos[#1], Sin[#1]}}]} &, 
   Reverse /@ Transpose@ImageData@gof, {2}];

brush = Image[
   Graphics[lines, 
    PlotRange -> {{1, #1}, {1, #2}} & @@ ImageDimensions[im], 
    Background -> GrayLevel[0.5], ImageSize -> ImageDimensions[img]], 
   ColorSpace -> "Grayscale"];

Here is the brush image:

enter image description here

I use a gentle tone-mapping on the original image to equalise the brightness a bit, and then combine the ton-mapped image with the brush strokes.

tm = Image`ToneMapHDRI[img, Method -> {"AdaptiveLog", "Bias" -> 1.0}];

Image[0.7 (ImageData@Blur[brush, 2] - 0.6) + ImageData@tm]

enter image description here

You can vary the effect by altering parameters such as the scale of the gradient orientation filter and the length of the lines.

Original

Here's an attempt using tone mapping to equalise the brightness across the image, and a gradient filter to enhance outlines. I added some noise to the image before doing the gradient filter, to try and get some variation in the sky. I found it quite difficult to avoid highlighting the jpeg artefacts in the sky.

img = Import["http://i.stack.imgur.com/XwYg7.jpg"];
tm = Image`ToneMapHDRI[img, Method -> {"AdaptiveLog"}];
edges = ColorNegate[
 img ~ImageEffect~ {"GaussianNoise", 0.1} ~GradientFilter~ 3] ~ImageAdjust~ {0.2, 0, 5};

ImageMultiply[tm, edges]

enter image description here

share|improve this answer
    
Looks nice - the sky is a problem as you say, just not very van-goghy to start with .. It probably needs some of your hedcut-style texturing... –  cormullion Dec 19 '13 at 7:43
    
@cormullion, I wondered if ListLineIntegralConvolutionPlot might help with texturing, but it's so slow! I decided to just draw some straight lines with plain old Line primitives and it came out quite nicely. –  Simon Woods Dec 19 '13 at 21:30
    
Like it. Next time let's hope the questioner asks for Seurat or Mondrian or Vaserely... :) –  cormullion Dec 19 '13 at 22:30
    
Your second attempt looks very promising! Perhaps you should find a way to make the randomly shaped brushes depend in a stronger way on the gradient of the image... The twoer and the sky seems to be made with the same brush stroke. Maybe by using a much more contrasted image as a base for that? (Just guessing) –  Peltio Dec 19 '13 at 22:31
    
Results from GradientOrientationFilter look really nice :)! –  Kardashev3 Dec 20 '13 at 6:37
show 1 more comment

Mathematica has a few very limited 'effects' built-in:

i = Import["http://i.stack.imgur.com/XwYg7.jpg"];
oil = ImageEffect[i, {"OilPainting", 4}]

oil

boss = ImageEffect[i, {"Embossing", 15}]

embossed

Combining them:

ImageAdjust[ImageCompose[boss, {oil, .5}], {1, 0}]

combined

But for the best effects, you'll have to start drinking absinthe...

share|improve this answer
2  
Soaking your left ear in absinthe while drinking it may get better results yet. –  belisarius Dec 18 '13 at 11:50
    
@belisarius You go to some interesting parties... –  cormullion Dec 18 '13 at 11:51
    
Those aren't my parties! –  belisarius Dec 18 '13 at 12:11
add comment

You can achieve an effect like this by using CurvatureFlowFilter and GaborFilter. The effects are best viewed in full resolution.

Here is the original image:

img = Import["http://i.stack.imgur.com/XwYg7.jpg"]

Mathematica graphics

Now we smooth is nicely with the CurvatureFlowFilter:

imgsmooth = CurvatureFlowFilter[img, 2]

Mathematica graphics

And generate a gradient image of the original image:

grad = ImageAdjust@GradientFilter[img, 1]

Mathematica graphics

Using the gradient image we now compute an image based on a series of GaborFilters:

gab = ParallelTable[
ImageAdjust[GaborFilter[grad, {40, 7}, {Sin[n], Cos[n]}]], {n, 0, 
Pi, 0.1}];
dirs = ImageApply[Max, gab]

Mathematica graphics

Finally we compose the final image:

res = ImageAdjust[ImageCompose[dirs, {imgsmooth, .5}], {1, 0}]

Mathematica graphics

Simply tune the parameters a bit and adjust them to your needs - Van Gogh would certainly be jealous ;).

share|improve this answer
    
Wow! Nicely done. –  Gabriel Dec 18 '13 at 17:43
    
Fancy!!! Thank you! –  user10495 Dec 18 '13 at 18:47
add comment

I see the "Van Gogh" style as a combination of brush strokes and an averaging filter. This is the best result of my effort to simulate this style. I'm sure someone with better knowledge can improve it.

First, we try to split the picture to regions that will have the same brush stroke pattern.

orig = Image[ImageData[ImageResize[img, 500]][[All, All, 1 ;; 3]]];(* get rid of the alpha channel which would cause trouble later on *)

wsc = WatershedComponents[GradientFilter[orig, 5], 
   MaxDetect[GaussianFilter[orig, 30], Padding -> 1]];
(wsc[[Sequence @@ #]] = wsc[[Sequence @@ (# - {0, 1})]]) & /@ 
  Position[wsc, 0];
wsc // Colorize

(components)

Next, we select significant parts and create masks for them:

partAreas = Count[Flatten[wsc], #] & /@ Range[Max[wsc]];
significantParts = 
 Flatten[Position[partAreas, _?(# > Max[partAreas]/200 &)]];
masks = Table[
  Image[Map[DiscreteDelta[n - #] &, wsc, {2}]], {n, significantParts}]

masks

Then we create brush strokes:

brushMasks = (xr = RandomInteger[{1, 10}]; 
    yr = RandomInteger[{1, 10}]; 
    strPlot = 
     StreamPlot[{xr + Sin[2 + (x - y)*5], 
       yr + Sin[2 + (x + y)*5]}, {x, -3, 3}, {y, -3, 3}, 
      StreamScale -> {.05, .1, 0.001}, 
      StreamPoints -> {2000, .01, .01}, PlotRange -> All, 
      PlotRangePadding -> None, Frame -> False, 
      StreamStyle -> 
       Directive[{GrayLevel[.7], CapForm["Round"], 
         AbsoluteThickness[3]}], ImageSize -> ImageDimensions[orig], 
      AspectRatio -> Divide @@ Reverse[ImageDimensions[orig]]];
    GaussianFilter[ImageMultiply[#, Rasterize[strPlot]], 2]) & /@ 
  masks

brush stroke masks

Finally, we apply masks on our image and combine them together:

maskedParts = 
 Image[Map[Clip[#, {0, 1}] &, 
     ImageData[ImageSubtract[orig, ColorNegate[#]]], {3}]] & /@ 
  brushMasks
brushedImage = maskedParts[[1]];
n = 2;
While[n <= Length[maskedParts], 
  brushedImage = ImageAdd[brushedImage, maskedParts[[n]]]; n++];
MedianFilter[brushedImage, 1]

final image

There are two issues with this method:

1) Brush strokes take a very long time to generate with my method (using StreamPlot); I'm sure there's a better way.

2) The borders between the components can be seen in the final image. I'm not sure how to avoid this.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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