# How to use Mathematica to turn a picture into low poly style?

I want to use Mathematica to turn a picture into low poly style. That is, to make the following conversion: Bill to Bill low poly(Using Image Triangulator App).

I think the biggest difficulty is how to extract the points on the boundaries of different colors appropriately. Too much points make the output picture messy, while the picture generated by too little points are not beautiful.

And then, after I have extract the points of the original picture, how to turn the original picture to the low poly style? Is using DelaunayMesh possible? Or, extract the color of a certain point in a triangle(using ImageValue or some functions similar) and make it to be the main color of the triangle?

Edit: No, I don't think that the answers in artistic image vectorization fit my problem. Because you can see that the question is not using Delaunay mesh or other triangular mesh.

• You could build on top of this previous answer by Simon Woods: "This vectorisation attempts to represent the image with coloured triangles."
– user484
Sep 11, 2014 at 4:13
• It is amazing, and I will have a try. Thank you.@RahulNarain
– Ryan
Sep 11, 2014 at 5:03
• possible duplicate of Artistic image vectorization Sep 11, 2014 at 9:31
• @m_goldberg would not entirely agree - this question is more specific, while the alleged dupe was (originally) about hi-res printing. Sep 11, 2014 at 10:31
• Google en.wikipedia.org/wiki/Robert_Delaunay. Great question for art lovers (and, hopefully, some mathematicians too).
– eldo
Sep 11, 2014 at 20:28

My take on this, with some inspiration from shrx's great answer. I pick points randomly, but weighted by the image gradient to try to get more points on edges in the image. Then I use a Delaunay triangulation so that those edges are maintained in the mesh. Finally I colour it by taking the single pixel value at the centre of each triangle (rather than the slower but more accurate averaging approach used by shrx).

i = ExampleData[{"TestImage", "House"}];
n = 1000;

{x, y} = ImageDimensions[i];

pts = Reverse /@ RandomChoice[
Flatten @ ImageData @ GradientFilter[i, 2] -> Tuples @ {Range[y, 1, -1], Range[x]}, n];

pts = Join[pts, {{0, 0}, {x, 0}, {x, y}, {0, y}}];

m = DelaunayMesh @ pts;

Graphics[With[{col = RGBColor @ ImageValue[i, Mean @@ #]},
{EdgeForm @ col, col, #}] & /@ MeshPrimitives[m, 2]]


• I have tested several images to compare your code with shrx's, and I think your code runs faster and takes up less system resources. And your output is more similar to the original picture, great job!
– Ryan
Sep 12, 2014 at 5:38
i = ExampleData[{"TestImage", "Mandrill"}];
id = ImageDimensions[i];


Create some keypoints and use them to make a triangular mesh:

xy = ImageKeypoints[i, MaxFeatures -> 50];
m = VoronoiMesh[xy, {0, #} & /@ id];
mt = TriangulateMesh[#, MaxCellMeasure -> ∞,
MeshQualityGoal -> "Minimal"] & /@
Map[MeshRegion[MeshCoordinates[m], #] &, MeshCells[m, 2]];
p = Flatten[MeshPrimitives[#, 2] & /@ mt];


Create masks for calculations of mean color of triangles:

bp = Transpose[{Table[Black, {Length[p]}], p}];
Rasterize[
Graphics[{EdgeForm[Black], ReplacePart[bp, {n, 1} -> White]},
PlotRangePadding -> None], ImageSize -> id], {n, Length[p]}];
c = ParallelMap[
RGBColor @@


Put the colored triangles together:

Graphics[Transpose[{c, EdgeForm /@ c, p}], PlotRangePadding -> None]


• Wonderful, very cubistic! +1
– eldo
Sep 11, 2014 at 17:13
• Excellent, much better than the original :D Sep 11, 2014 at 18:01
• Your answer is good, but there is a little regret that it runs a little bit slow and takes up a lot of system resources. How should I optimize it?
– Ryan
Sep 12, 2014 at 5:46
• Determining the mean color of each triangle takes most of the time and resources. There are different ways to speed it up: you can scale down your image, or you can use a combination of ColorQuantize and DominantColors insteand of ImageMeasurements for each triangle, or you can just take the color from the center of each triangle, like @Simon Woods did in his approach.
– shrx
Sep 12, 2014 at 11:32