Use canvas to achieve a LOW-POLY image effect,
Previously, I accidentally saw Ovilia using threejs to do a low poly, that is, the effect of the image plane triangle, which was amazing. Then I took some time to try it.
I have never used threejs, So I directly use the 2d drawing API of canvas, because it seems that threejs is not used for this effect.
Directly on the demo first: http://whxaxes.github.io/canvas-test/src/Funny-demo/lowpoly/index.html (can also be seen on the Mobile End, but because of the large amount of computing, mobile devices will spend more time computing than PC .)
To do this, you need to triangle the image and perform a marginal inspection on the image. These two algorithms are the first to use the Adaboost triangle algorithm and the second to use the sobel edge detection algorithm. It sounds very high. Both algorithms have corresponding open-source components that can be used directly: ironwallaby's node-9 component and Miguel Mota's sobel component.
These two algorithms, sobel, are even better, and the accuracy of the algorithm is complicated. You can study these algorithms later. However, you can still use these components to achieve only one effect.
The two most important components are available, and the rest is simple:
First, draw the image on the canvas:
canvas.width = (img.width > 800) ? 800 : img.width;canvas.height = img.height * canvas.width/img.width;ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
Obtain the imgData of the canvas, and then return the new imgData through sobel calculation.
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);var newImgData = Sobel(imgData);
If we put newImgData on the canvas, we will find that the color image has become a gray image like this:
Because the Sobel component mentioned above is not very suitable for your use, and the code is also inappropriate, you have made appropriate modifications and optimizations and optimized the loop method, this accelerates the operation and adds callback functions. For details, see the sobel. js file in github of this project.
ImgData. when data is traversed, the callback function is called to record the coordinates of the color value greater than 40 (that is, the gray level is rgb (40, 40) or above. Then some edge points are randomly obtained, and some random coordinates and the coordinate values of the four corners are added. In this way, we can get the coordinates we need.
Var imgData = ctx. getImageData (0, 0, canvas. width, canvas. height); // collect edge pixels with a color value greater than 40 var collectors = []; Sobel (imgData, function (value, x, y) {if (value> 40) {collectors. push ([x, y]) ;}}); // Add some random points for (var I = 0; I <300; I ++) {participant. push ([Math. random () * canvas. width, Math. random () * canvas. height]);} // Add Random Edge points. The number is the number of edge points except 50var length = ~~ (Collectors. length/50), random; for (var l = 0; l <length; l ++) {random = (Math. random () * collectors. length) <0; participant. push (collectors [random]); collectors. splice (random, 1);} // Add the coordinates of the four vertices. push ([0, 0], [0, canvas. height], [canvas. width, 0], [canvas. width, canvas. height]);
After obtaining the coordinate point, you can obtain the triangle coordinate array with the correct order through the calculation of the Adaboost component and connect the points in these arrays. This effect can be achieved:
Of course, the effect we need is not a line, but to fill all triangles with colors, that is, to obtain the three coordinates of the triangle, and then calculate the coordinates of the center, then, the corresponding rgb color value is obtained in imgData Based on the coordinates of the center point, and then filled in the Triangle Area:
// Obtain the triangle coordinate var triangles = Dirichlet by using the Adaboost triangle. triangulate (participant); var x1, x2, x3, y1, y2, y3, cx, cy; for (var I = 0; I <triangles. length; I + = 3) {x1 = participant [triangles [I] [0]; x2 = participant [triangles [I + 1] [0]; x3 = participant [triangles [I + 2] [0]; y1 = participant [triangles [I] [1]; y2 = participant [triangles [I + 1] [1]; y3 = participant [triangles [I + 2] [1]; // obtain the coordinates of the triangle center cx = ~~ (X1 + x2 + x3)/3); cy = ~~ (Y1 + y2 + y3)/3); // obtain the color value index = (cy * imgData. width + cx) * 4; var color_r = imgData. data [index]; var color_g = imgData. data [index + 1]; var color_ B = imgData. data [index + 2]; // draw the triangle ctx. save (); ctx. beginPath (); ctx. moveTo (x1, y1); ctx. lineTo (x2, y2); ctx. lineTo (x3, y3); ctx. closePath (); ctx. fillStyle = "rgba (" + color_r + "," + color_g + "," + color_ B + ", 1)"; ctx. fill (); ctx. restore ();}
Note that the obtained coordinates of the center must be rounded up to obtain the correct color parameters. If you do not want to get an integer, you can get an integer when obtaining the rgb index, the obtained color value is incorrect. This is because the obtained pixel is not the central pixel.
After the color is also obtained, it is a simple line, and then fill the operation, the final effect is:
The above content introduces how to use canvas to implement a low poly image. I hope it will be helpful to you!