使用javascript比较旋转图像

Compare rotated images using javascript

本文关键字:图像 旋转 比较 javascript 使用      更新时间:2023-09-26

我有一个样本图像和一组其他图像,我想比较第一个图像。所以我把它们都画在画布上,检查它们是否相同。

我在这里使用了这个概念:比较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);
        }

在上面的代码中,我正在迭代图像。我给出样本图像在 samplcanvas canvas1是我画我的图像列表。然后我要比较它们。但我不知道怎么做。

我怎么能比较两个图像在不同的方向旋转在随机角度使用JavaScript?

我可以比较颜色吗?

假设这两个图像都是矩形,并且旋转确实没有裁剪它们,您可以循环画布中的所有像素以确定最上、最下、最左和最右像素(*),并从那里您可以将其旋转到一个位置,它只能"正确旋转"或颠倒(或者,对于正方形,向左或向右90°),让您检查更少的情况。从那里,你可以从另一个图像中"减去"一个图像,并检查差异是否接近于零。

(*):理论上,两个角就足够了,但更多的角有助于提高精度,因为我们处理的是近似值(因为float)。

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的示例图像。

"Same"就像…真的,但是真的一样吗?几乎不可能的。
一旦图像被旋转,可能是裁剪,修剪等(你错过了解释什么是边缘情况,并显示一些代码)。

只是给你一个想法如何处理这个问题:

  • 我将这两个图像转换为B/W(得到0个零白色和1个黑色数据)
  • 去除噪声(滤波/清洗隔离的"1"(black)像素数据)
  • 重叠图像并从0-359度的步骤旋转一个
  • 在每一步(旋转)过程中,平均排除算法(基本上1-1=0)
  • 然后逐块处理整个合并结果

所以基本上如果合并的结果是一个几乎完全白色的(大部分是"0")结果-
你有

如果你不知道旋转角度,这是计算机视觉中一个经典的图像匹配案例。

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

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

编辑

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