【问题标题】:How to divide image in tiles?如何在图块中划分图像?
【发布时间】:2016-11-04 12:53:01
【问题描述】:

我必须完成以下任务:

将图像分成小块,计算每个小块的平均颜色, 从服务器获取该颜色的图块,并合成 结果变成原始图像的照片马赛克。

最好的策略是什么?我想到的第一个解决方案是使用画布。

【问题讨论】:

    标签: javascript html image web html5-canvas


    【解决方案1】:

    尝试使用 JIMP javascript 库来读取像素颜色并使用 invert、normalize 或类似属性来修改图像。

    看看 jimp 库 https://github.com/oliver-moran/jimp

    【讨论】:

      【解决方案2】:

      我为此创建了一个解决方案(我没有从后端获取平铺图像)

        // first function call to create photomosaic 
        function photomosaic(image) {
      
            // Dimensions of each tile
            var tileWidth = TILE_WIDTH;
            var tileHeight = TILE_HEIGHT;
      
            //creating the canvas for photomosaic
            var canvas = document.createElement('canvas');
            var context = canvas.getContext("2d");
            canvas.height = image.height;
            canvas.width = image.width;
      
            var imageData = context.getImageData(0, 0, image.width, image.height);
            var pixels = imageData.data;
      
            // Number of mosaic tiles
            var numTileRows = image.width / tileWidth;
            var numTileCols = image.height / tileHeight;
      
      
            //canvas copy of image
            var imageCanvas = document.createElement('canvas');
            var imageCanvasContext = canvas.getContext('2d');
            imageCanvas.height = image.height;
            imageCanvas.width = image.width;
            imageCanvasContext.drawImage(image, 0, 0);
      
      
            //function for finding the average color
            function averageColor(row, column) {
                var blockSize = 1, // we can set how many pixels to skip
      
                    data, width, height,
                    i = -4,
                    length,
                    rgb = {
                        r: 0,
                        g: 0,
                        b: 0
                    },
                    count = 0;          
      
                try {
                    data = imageCanvasContext.getImageData(column * TILE_WIDTH, row * TILE_HEIGHT, TILE_HEIGHT, TILE_WIDTH);
                } catch (e) {
                    alert('Not happening this time!');
                    return rgb;
                }
      
                length = data.data.length;
      
                while ((i += blockSize * 4) < length) {
                    ++count;
                    rgb.r += data.data[i];
                    rgb.g += data.data[i + 1];
                    rgb.b += data.data[i + 2];
                }
      
                // ~~ used to floor values
                rgb.r = ~~(rgb.r / count);
                rgb.g = ~~(rgb.g / count);
                rgb.b = ~~(rgb.b / count);
      
                return rgb;
      
            }
      
            // Loop through each tile
            for (var r = 0; r < numTileRows; r++) {
                for (var c = 0; c < numTileCols; c++) {
                    // Set the pixel values for each tile
                    var rgb = averageColor(r, c)
                    var red = rgb.r;
                    var green = rgb.g;
                    var blue = rgb.b;
      
                    // Loop through each tile pixel
                    for (var tr = 0; tr < tileHeight; tr++) {
                        for (var tc = 0; tc < tileWidth; tc++) {
      
                            // Calculate the true position of the tile pixel
                            var trueRow = (r * tileHeight) + tr;
                            var trueCol = (c * tileWidth) + tc;
      
                            // Calculate the position of the current pixel in the array
                            var pos = (trueRow * (imageData.width * 4)) + (trueCol * 4);
      
                            // Assign the colour to each pixel
                            pixels[pos + 0] = red;
                            pixels[pos + 1] = green;
                            pixels[pos + 2] = blue;
                            pixels[pos + 3] = 255;
                        };
                    };
                };
            };
      
            // Draw image data to the canvas
            context.putImageData(imageData, 0, 0);
            return canvas;
        }
      
        function create() {
            var image = document.getElementById('image');
            var canvas = photomosaic(image);
            document.getElementById("output").appendChild(canvas);
        };
      

      演示:https://jsfiddle.net/gurinderiitr/sx735L5n/

      【讨论】:

        【解决方案3】:

        获取像素数据和查找图块方法的简单方法。代码将需要更多检查没有尺寸可以除以图块数量的图像。

        var image = new Image();
        image.src = ??? // the URL if the image is not from your domain you will have to move it to your server first
        
        // wait for image to load
        image.onload = function(){
            // create a canvas
            var canvas = document.createElement("canvas");
            //set its size to match the image
            canvas.width = this.width;
            canvas.height = this.height;
            var ctx = canvas.getContext("2d"); // get the 2d interface
            // draw the image on the canvas
            ctx.drawImage(this,0,0);
            // get the tile size
            var tileSizeX = Math.floor(this.width / 10);
            var tileSizeY = Math.floor(this.height / 10);
            var x,y;
            // array to hold tile colours
            var tileColours = [];
            // for each tile
            for(y = 0; y < this.height; y += tileSizeY){
                for(x = 0; x < this.width; x += tileSizeX){
                    // get the pixel data
                    var imgData = ctx.getImageData(x,y,tileSizeX,tileSizeY);
                    var r,g,b,ind;
                    var i = tileSizeY * tileSizeX; // get pixel count
                    ind = r = g = b = 0;
                    // for each pixel (rgba 8 bits each)
                    while(i > 0){
                        // sum the channels
                        r += imgData.data[ind++];
                        g += imgData.data[ind++];
                        b += imgData.data[ind++];
                        ind ++;
                        i --;
                    }
                    i = ind /4; // get the count again
                    // calculate channel means
                    r /= i;
                    g /= i;
                    b /= i;
                    //store the tile coords and colour
                    tileColours[tileColours.length] = {
                        rgb : [r,g,b],
                        x : x,
                        y : y,
                    }
                }
                // all done now fetch the images for the found tiles.
            }
        

        【讨论】:

        • ctx.getImageData(x,y,tileSizeX,tileSizeY) 应该返回平均颜色,因为图块大小不是单个像素,对吧?
        • @CodeYogi getImageData 将像素数据作为数组返回,它不处理数据。欲了解更多信息,请参阅developer.mozilla.org/en-US/docs/Web/API/…
        • 那么,getImageData 返回特定图块的像素数据,那么 ind 变量呢?
        • @CodeYogi ind(index 的缩写)是像素数组的索引,每个像素在数组中有 4 个项,每个项用于红色、绿色、蓝色和 alpha 通道,每个是字节,有 256 个值,范围从 0 到 255 。总字节数是像素数 tileSizeX 乘以 tileSizeY 乘以每个像素的字节数 4 (pixelDataArrayLength = tileSizeX * tileSizeY * 4)
        • 几乎完成codepen.io/vivekimsit/pen/yJbwLP?editors=1010,但似乎有一些极端情况。对于演示,请单击画布。我需要从服务器加载 svg,这似乎不是什么大问题。
        猜你喜欢
        • 2017-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        相关资源
        最近更新 更多