CS798 Assignment 1 : Painterly rendering


Introduction

Painterly rendering is a technique that automatically creates images that have handed-painted appearance from a photograph.

One such algorithm has been described by Aaron Hertzmann in "Painterly Rendering with Curved Brush Strokes of Multiple Sizes" , from SIGGRAPH'98 conference. The algorithm applies successive layers of strokes on the canvas. The radius of the strokes decreases to convey more details at each iteration. The strokes are applied where the canvas differ sufficiently from the reference image. The strokes follow splines curves of nearly constant color in the reference image.

For my extra, I implemented some prettier strokes, by adding some height and opacity map texture. This extension has been proposed by Aaron Hertzmann in "Fast Paint Texture", for the NPAR 2002 conference.



Part I : Painterly Rendering with Curved Brush Strokes of Multiples Sizes


Implementation Details

The program is written in Python for the flexibility of the interface and uses C++ with OpenGL to generate efficiently the geometry of the strokes of the final painting. The Python Imaging Library allows to load and save images easily. I use PIL_usm to apply a Gaussian blurring to the reference image. I use the code provided by Craig Kaplan, painthelp.cpp and paint.py (without libart) and also some parts of color.h, Point.h, Stroke.h, and Stroke.cpp, donated to the course by Aaron Hertzmann.


Parameters

The paper defines a set of parameters that help to produce the different painting style. These parameters are constants in my program.

Parameters

Impressionist

Expressionist

Colorist Wash

Pointillist

Threshold

100

50

200

100

Brush sizes

8, 4, 2

8, 4, 2

8, 4, 2

4, 2

Curvature filter

1

0.25

1

1

Blur factor

0.5

0.5

0.5

0.5

Stroke length

[ 4 .. 16 ]

[ 10 .. 16 ]

[ 4 .. 16 ]

[ 1 ]

Alpha

1.0

0.7

0.5

1.0

Grid size

1.0

1.0

1.0

0.5

Color jitter

None

None

[-3..+3]

[-3..+3]



Note :
No particular interface is implemented.
Jitter for hue, jh, saturation js and value jv not used.



Algorithm Steps

repeat for each brush radius Ri :
  1. Blur reference image by f_s * Ri.
  2. Compute the blur reference image gradient for each point using the Sobel filtered luminance.
  3. Make splines strokes that have control points that roughly match (corresponding to threshold the isocontours of the reference image.
  4. Render randomly all the strokes of radius Ri (tesselation as triangle strip along cubic B-spline of stroke control point).
Explanation in images


Results I : Different Brush Layers



Results II : Different Painting Styles


Part II : Fast Paint Texture

Fast Paint Texture is a technique for simulating the physical appearance of paint strokes under lighting. The list of strokes generated by my painterly rendering program produces an height field image by rendering the brush strokes with texture height map assigned to each stroke.
To implement Fast Paint Texture using the potential of OpenGL I modify my code that renders the strokes, to use OpenGL instead of libart. The given Stroke.cpp class provided by Aaron Hertzmann helped me a lot. I used the following opacity and height map for the strokes.
  • Stroke Height Map
  • Stroke Opacity Map
  • Notes :
    1. I modified the stroke height map given in the paper. I darken it (0 .. 0.1) since I add a constant to the color of the texture when more strokes are painted. Since black represents 0 no height, by the last iteration the texture needs to be whiter since there are many layers of stroke underneath.
    2. I also modified the opacity map given in the paper. I smooth the gradient change.

    Explanations


    Results

    Comments

    The effect of texture differs according to the painting style (i.e. impressionist, expressionist, colorist wash or pointillist) of the painterly rendered picture. The stroke height map that I used, may be more appropriate in some painting style, like impressionist and expressionist. The result is not deceiving in all cases, but for example colorist wash is often a unique layer of wet media and applying bump mapping to it, produces thicker and dryer strokes that may be desired. On the other hand, texturing the strokes is ideal in oil looking painting, like the ones rendered with impressionist or expressionist styles.

    Conclusion

    I really enjoyed doing the painterly rendering program and experimenting it on different images. I found that my extra to add texture to the strokes produces a nice effect that is noticeable and visually interesting. I had trouble at first to figure out the easy and fast implementation the "Fast Paint Texture" talks about, but Kevin Moule pointed me out the right function of OpenGL to use.


    References