利用canvas自动裁切图片非透明区域

之前在做图片相似度对比的时候,碰到了这么一个问题,主体相同的两张图片因为边缘留的透明区域不同被判定为不相似,就像下面2张图片

绿色为背景,表示此处是透明区域,我们可以看到2张图片的主体完全一致,仅仅是边缘留白不一样被判定了不一致,这样的结果对于程序运行来讲是一个符合预期的结果,但是对于真实的场景需要来讲是远远达不到预期的。那么如何让程序将这类图片判定为相似呢?如果我们简单的通过一点的特殊处理去屏蔽这种差异显然是行不通的,毕竟留白不确定,那么怎么做才是正确的呢?

前面说到了这类图片的主体是一样的,那么我们是不是可以将透明的留白全部去掉,只裁剪出主体,然后再进行对比不就可以了呢。

现在问题变成了图和去除透明区域并裁剪出主体,我们知道图片的imageData是一个width x height x 4大小的矩阵,其中每4位分别代表一个像素点的r, g, b, a通道的值,其中a代表alpha通道,如果a通道的值为0,即此像素全透,但是实际操作中我们可能需要预定义一个阈值,最好不要直接使用0来做判定依据。然后分别从上下左右4个方向一行一行往图片中心逼近扫描,找出第一个非透明元素i,那么i-1就是我们需要裁减的透明像素的长度,操作示意如下图:

在开始写代码之前,我们先定义一个常量:透明度的阙值,这里将其定义为120;

const alphaThreshold = 120;

然后我们开始编写分别从四个方向不同方向向中间扫描的算法:

1、从左侧往中心扫描:

function getLeftOpacityLength(imageData) {
    const { width, height, data } = imageData;
    for (let i=0; i<width; i++) {
        for (let j=0; j<height; j++) {
            const index = j * width * 4 + i * 4;
            if (data[index+3] > alphaThreshold) {
                return i - 1;
            }
        }
    }
}

2、从右侧往中心扫描:

function getRightOpacityLength(imageData) {
    const { width, height, data } = imageData;
    for (let i=width-1; i>=0; i--) {
        for (let j=0; j<height-1; j++) {
            const index = j * width * 4 + i * 4;
            if (data[index+3] > alphaThreshold) {
                return width - i -1;
            }
        }
    }
}

3、从顶部往中心扫描:

function getTopOpacityLength(imageData) {
    const { width, height, data } = imageData;
    for (let j=0; j<height; j++) {
        for (let i=0; i<width; i++) {
            const index = i * 4 + j * width * 4;
            if (data[index+3] > alphaThreshold) {
                return j - 1;
            }
        }
    }
}

4、从底部往中心扫描

function getBottomOpacityLength(imageData) {
    const { width, height, data } = imageData;
    for (let j=height-1; j>=0; j--) {
        for (let i=0; i<width; i++) {
            const index = j * width * 4 + i * 4;
            if (data[index+3] > alphaThreshold) {
                return height - j - 1;
            }
        }
    }
}

当我们分别计算出四边的透明区域的长度后,再根据四边的透明长度做一定的裁剪就可以得到主体区域,你可以猛戳这里查看在线demo,测试图片素材可以保存本页最上面2张图片,最后附上运行截图。

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章