使用javascript比较旋转的图像

时间:2015-10-12 15:09:12

标签: javascript

我有一个样本图像和一组其他图像,我想用它来比较第一张图像。所以我将它们都绘制到画布上并检查它们是否相同。

我在这里使用了这个概念:Compare two Images in JavaScript

问题是图像以随机角度旋转。所以图像的base64值似乎不相互匹配。

注意:我无法计算角度,并且试错法太耗费资源

match=-1;
for(i=0;i<7;i++)
        {
            context1.drawImage(img,xPos[i],5,width[i],height,0,0,width[i],height);;
                if(canvas1.toDataURL()==samplecanvas.toDataURL()){
                    match=i+1;
                    break;
                }

            context1.clearRect(0, 0, canvas1.width, canvas1.height);
        }

在上面的代码中,我正在迭代图像。我在 samplecanvas 处获得了示例图像,而 canvas1 是我绘制图像列表的地方。然后我想比较它们。但我不知道如何。

如何使用JavaScript比较以随机角度在不同方向旋转的两幅图像?

我可以比较颜色吗?

3 个答案:

答案 0 :(得分:2)

假设两个图像都是矩形,并且旋转不裁剪它们,您可以遍历画布中的所有像素以确定最高,低,左和右边的像素(*),从那里你可以将它旋转到一个位置,在这个位置它只能“正确旋转”或颠倒(或者,对于正方形,向左或向右90°),让你的情况更少检查。
从那里开始,你可以从另一个图像中“减去”一个图像并检查差异是否接近于零。

(*):从理论上讲,两个角就足够了,但是更多的角有助于提高准确性,因为我们正在处理近似值(因为浮动)。

var canvas = [];
var ctx = [];
for(var i = 1; i <= 7; i++)
{
    canvas[i] = document.getElementById('canvas' + i);
    ctx[i] = canvas[i].getContext('2d');
    ctx[i].translate(250, 250);
}
var img = new Image();
var result = document.getElementById('result');

var diffCanvases = function(c1, c2)
{
    var other = c2.getImageData(0, 0, 500, 500).data;
    return c1.getImageData(0, 0, 500, 500).data.map(function(val, i)
    {
        return Math.abs(val - other[i]);
    }).reduce(function(previous, current)
    {
        return previous + current;
    });
};

var drawRotatedImage = function()
{
    var angle1 = Math.random() * 2 * Math.PI;
    var angle2 = Math.random() * 2 * Math.PI;
    ctx[1].rotate(angle1);
    ctx[2].rotate(angle2);
    ctx[1].drawImage(img, -200, -150);
    ctx[2].drawImage(img, -200, -150);
}

var undoRotation = function()
{
    var data = [ctx[1].getImageData(0, 0, 500, 500).data, ctx[2].getImageData(0, 0, 500, 500).data];
    var extremes = [{}, {}];
    for(var i = 0; i < 2; i++)
    {
        top:
        for(var y = 0; y < 500; y++)
        {
            for(var x = 0; x < 500; x++)
            {
                if(data[i][(y * 500 + x) * 4] + data[i][(y * 500 + x) * 4 + 1] + data[i][(y * 500 + x) * 4 + 2] + data[i][(y * 500 + x) * 4 + 3] > 0)
                {
                    extremes[i].top = {x: x, y: y};
                    break top;
                }
            }
        }
        bottom:
        for(var y = 499; y >= 0; y--)
        {
            for(var x = 499; x >= 0; x--)
            {
                if(data[i][(y * 500 + x) * 4] + data[i][(y * 500 + x) * 4 + 1] + data[i][(y * 500 + x) * 4 + 2] + data[i][(y * 500 + x) * 4 + 3] > 0)
                {
                    extremes[i].bottom = {x: x, y: y};
                    break bottom;
                }
            }
        }
        left:
        for(var x = 0; x < 500; x++)
        {
            for(var y = 0; y < 500; y++)
            {
                if(data[i][(y * 500 + x) * 4] + data[i][(y * 500 + x) * 4 + 1] + data[i][(y * 500 + x) * 4 + 2] + data[i][(y * 500 + x) * 4 + 3] > 0)
                {
                    extremes[i].left = {x: x, y: y};
                    break left;
                }
            }
        }
        right:
        for(var x = 499; x >= 0; x--)
        {
            for(var y = 499; y >= 0; y--)
            {
                if(data[i][(y * 500 + x) * 4] + data[i][(y * 500 + x) * 4 + 1] + data[i][(y * 500 + x) * 4 + 2] + data[i][(y * 500 + x) * 4 + 3] > 0)
                {
                    extremes[i].right = {x: x, y: y};
                    break right;
                }
            }
        }
    }
    var angles = [];
    for(var i = 0; i < 2; i++)
    {
        // Diagonals yield the highest accuracy
        var topBottom = Math.atan((extremes[i].bottom.y - extremes[i].top.y) / (extremes[i].bottom.x - extremes[i].top.x));
        var leftRight = Math.atan((extremes[i].left.y - extremes[i].right.y) / (extremes[i].left.x - extremes[i].right.x));
        angles.push(((topBottom + leftRight + Math.PI) / 2) % (Math.PI / 2));
    }
    ctx[3].rotate(-angles[0]);
    ctx[3].drawImage(canvas[1], -250, -250);
    for(var i = 0; i < 4; i++)
    {
        ctx[4 + i].rotate(-angles[1] + Math.PI * i / 2);
        ctx[4 + i].drawImage(canvas[2], -250, -250);
    }
    result.textContent = 'Canvas 3 vs 4: ' + diffCanvases(ctx[3], ctx[4]) + '\n' +
                         'Canvas 3 vs 5: ' + diffCanvases(ctx[3], ctx[5]) + '\n' +
                         'Canvas 3 vs 6: ' + diffCanvases(ctx[3], ctx[6]) + '\n' +
                         'Canvas 3 vs 7: ' + diffCanvases(ctx[3], ctx[7]) + '\n';
}

img.addEventListener('load', function()
{
    drawRotatedImage();
    undoRotation();
});
img.crossOrigin = '';
img.src = 'https://i.imgur.com/o2scuuY.jpg';
canvas
{
    border: solid 1px #999;
    display: block;
}
#result
{
    white-space: pre;
}
Original canvases:
<canvas id="canvas1" width="500" height="500"></canvas>
<canvas id="canvas2" width="500" height="500"></canvas>
Canvas 1 "fixed":
<canvas id="canvas3" width="500" height="500"></canvas>
All options for canvas 2 "fixed":
<canvas id="canvas4" width="500" height="500"></canvas>
<canvas id="canvas5" width="500" height="500"></canvas>
<canvas id="canvas6" width="500" height="500"></canvas>
<canvas id="canvas7" width="500" height="500"></canvas>
<div id="result"></div>

在这个版本中,单个像素移位已经产生了巨大的差异。通过检测所有“固定”图像的顶部和左侧偏移,将第一个画布与其他四个画布进行比较,并调整图像以平衡差异,可以轻松地将其最小化。 但是根据我的口味,我今天已经把画布和图片搞得一团糟了。

取自LoremPixel的示例图片。

答案 1 :(得分:0)

如果您不知道旋转角度,那么它就是计算机视觉中的经典图像匹配案例。

图像匹配计算量很大,不适合Web应用程序。

我会尝试找到一种方法来计算旋转角度并在比较之前将图像旋转回来。 如果没有其他办法,我会使用opencv或类似的库来实现匹配rest api的图像。

修改

为了访问画布像素数据,请使用getImageData函数。

答案 2 :(得分:0)

“相同”,如..真的,但真的一样吗?几乎不可能。
一旦图像旋转,可能会裁剪修剪等。(您错过了解释边缘情况并显示一些代码)。

只是为了给您一个想法如何解决问题:

  • 我将两个图像转换为B / W(白色为0,黑色数据为为1)
  • 去除噪音(过滤/清理隔离的"1"(black)像素数据)
  • 重叠图像并从0-359度步进旋转
  • 在每一步(旋转)过程中,平均排除算法(基本上是1-1 = 0)
  • 比chunk
  • 处理整个合并结果块

所以基本上如果合并结果几乎完全是白色(大多数是“0”零)结果 -
 您有可能的匹配