# Coloured image transformation in pointillism

I would like to transform an image (a photo for example) into a set of single colour circles with fixed but adjustable diameter (bigger than the pixel size), into a kind of pointillism. The number of colours can be reduced. I tried to follow the examples in Artistic image vectorization, but I need to have divided circles rather than adjacent poligonal blocks. Final vectorisation will be more than welcome Thanks Virgilio

• If you tried something but got stuck somewhere it would be good to add that to your question. – Sjoerd C. de Vries Aug 25 '15 at 12:29
• – rhermans Aug 26 '15 at 4:59

Here's one way to go about it. First choose an image (the view outside Van Gogh's asylum).

Define some auxiliary functions:

img = Import["http://i.stack.imgur.com/eMced.jpg"];
aspImg[im_] := ImageDimensions[im][[2]]/ImageDimensions[im][[1]];
imgSpheres[im_, diam_, numSphere_] :=
Module[{r1, r2},
colorfun = BSplineFunction[ImageData[im], SplineDegree -> 1];
Graphics[
Table[{r1, r2} =
RandomReal[{0, 1}, 2]; {RGBColor[colorfun[1 - r2, r1]],
Disk[{r1, r2}, diam]}, {i, 1, numSphere}],
AspectRatio -> aspImg[im], Axes -> False, ImageSize -> Large]];


Now call the function:

ImageCompose[img, {imgSpheres[img, 0.01, 3000], 1}]


The first argument to imgSpheres is the image, the second argument is the size of the circles, and the third is the number of circles to draw. The final argument allows some of the original image to show through by adjusting the opacity.

ImageCompose[{img, 1}, {imgSpheres[img, 0.02, 3000], 0.8}]


This works for version 9 (November 20, 2012). Make a Delaunay triangulation of random points laid down in the image, find the incircles of the triangles, and colour them by the underlying image. Placing more points results in smaller disks.

GraphicsMeshMeshInit[]
(* {"PacletManager", "QuantityUnits", "WebServices",
"System","Global", "GraphicsMesh"} *)

Incircle[{{x1_, y1_}, {x2_, y2_}, {x3_, y3_}}] :=
With[{a = Norm[{x2 - x3, y2 - y3}], b = Norm[{x3 - x1, y3 - y1}],
c = Norm[{x1 - x2, y1 - y2}]},
Circle[(a {x1, y1} + b {x2, y2} + c {x3, y3})/(a + b + c),
Sqrt[-(a - b - c) (a + b - c) (a - b + c)/(a + b + c)]/2]]

• image is a colour image, no transparency channel
• n is the number of points to place in the image
• s=-1 for more points in light areas, fewer in dark
• s=+1 for more points in dark areas, fewer in light
• e is an exponent for nonlinear colour scaling
• opts is a list of Graphics options

The above parameters are passed to the following function.

DelaunayImageColour[image_, n_, s_, e_, opts___] :=
Block[{w, h, data, ij, p, gopt, rr, gg, bb},
{w, h} = ImageDimensions[image];
data = ImageData[ImageRotate[image, Right]];
ij = Transpose[{RandomInteger[{1, w}, n], RandomInteger[{1, h}, n]}];
p = Pick[ij,
Sign[RandomReal[{0., 1.}, n] -
(Extract[data, ij] /. {rr_, gg_, bb_} ->
0.299 rr + 0.587 gg + 0.114 bb)], s];
gopt = FilterRules[{opts}, Options[Graphics]];
Graphics[
Map[{Apply[RGBColor, Mean[Extract[data, Floor[#]]]^e],
Incircle[#]} &, Delaunay[p]] /. Circle -> Disk, gopt]]


For example,

   DelaunayImageColour[Import["VanGogh.jpg"], 100000, -1, 1.0, Background -> Black]


• @KennyCoinago Your function Delaunay isn't defined, did you forget to add it? I'm using v10.4. – M.R. Apr 18 '16 at 1:04
• @M.R. The function Delaunay is defined for v9, as stated. For v10, after the statement defining p, use: m=DelaunayMesh[p] to define the mesh m. Then get the mesh vertices 'v' with v=MeshCoordinates[m]. Finally, form the triangles t with t=Map[v[[#]]&,MeshCells[m,2][[All,1]]]. In the function DelaunayImageColour replace Delaunay[p] with 't'. – KennyColnago Apr 21 '16 at 14:43
img = ExampleData[{"TestImage", "Lena"}];

Rotate[Graphics@
Join[
MapIndexed[
{RGBColor[#1], Disk[4 Most@#2 + RandomReal[{-1, 1}, 2], 4]} &,
ParallelTable[
Table[
Take[
SortBy[Tally[
Flatten[Map[Round[#, 0.01] &, ImageData[im], {2}], 1]],
Last], -1][[All, 1]]
, {im, iml}]
, {iml, ImagePartition[img, 20]}
], {3}],
MapIndexed[
{RGBColor[#1 + RandomReal[{-0.2, 0.3}, 3]],
Disk[Most@#2 + RandomReal[{-1, 1}, 2], Last@#2/10]} &,
ParallelTable[
Table[
Take[
SortBy[Tally[
Flatten[Map[Round[#, 0.01] &, ImageData[im], {2}], 1]],
Last], -4][[All, 1]]
, {im, iml}]
, {iml, ImagePartition[img, 5]}
], {3}]], -\[Pi]/2]
`

• Your Lena's got an eye from zombies movie – Dr. belisarius Aug 25 '15 at 20:22