首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用vips逐行比较图像

使用vips逐行比较图像
EN

Stack Overflow用户
提问于 2019-10-22 06:21:43
回答 2查看 459关注 0票数 0

背景:我有图像,我需要比较的差异。这些图像很大(大约为1400x9000 px)、机器生成的和高度受限的(特定线性用户界面的截图),预计它们几乎是相同的,区别是以下三种可能性之一:

  • 图1有一个区段,缺少图像2。
  • 图1缺少图像2所包含的部分
  • 这两个图像都有给定的部分,但其内容不同。

我正在尝试构建一个工具来突出人类审查员的不同之处,本质上是一个面向行的差异的图像版本。为了达到这个目的,我尝试逐行扫描图像,并比较它们,以确定它们是否相同。我的最终目标是一个实际的差别化输出,它可以检测出缺失/添加/不同的部分,并为相同内容的其余部分尽快同步图像,但对于第一个剪切,我将采用一种更简单的方法,即两幅图像被覆盖(alpha混合),以及以特定颜色突出显示的不同线条(即。阿尔法-混合第三行固体颜色)。起初,我尝试使用Python,但这太慢了好几个数量级,所以我决定尝试使用vips,这应该要快得多。但是,我完全不知道如何表达我在使用vips操作之后要做的事情。较简单版本的伪代码实质上是:

代码语言:javascript
复制
out = []
# image1 and image2 are expected, but not guaranteed to have the same height
# they are likely to have different heights if different
# most lines are entirely white pixels
for line1, line2 in zip(image1, image2):
    if line1 == line2:
        out.append(line1)
    else:
        # ALL_RED is a line composed of solid red pixels
        out.append(line1.blend(line2, 0.5).blend(ALL_RED, 0.5))

我在我的项目中使用pyvips,但我也对使用普通vips或任何其他绑定的代码感兴趣,因为这些操作是共享的,并且很容易跨方言进行翻译。

编辑:根据请求添加示例图像

编辑2:缺少/添加/更改部分的全尺寸图像:

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-22 08:51:33

就用迪夫怎么样?挺快的。您所需要做的就是将您的PNG转换为文本,每次扫描,然后解析diff输出。

例如:

代码语言:javascript
复制
#!/usr/bin/env python3

import sys
import os
import re
import pyvips

# calculate a checksum for each scanline and write to name_out    
def scanline_checksum(name_in, name_out):
    a = pyvips.Image.new_from_file(name_in, access="sequential")
    # unfold colour channels to make a wider 1-band image
    a = a.bandunfold()
    # xyz makes an index image, where the value of each pixel is its coordinate
    b = pyvips.Image.xyz(a.width, a.height)
    # make a pow gradient image ... each pixel is some power of the x coordinate
    b = b[0] ** 0.5
    # now multiply and sum to make a checksum for each scanline
    # "project" returns sum of columns, sum of rows
    sum_of_columns, sum_of_rows = (a * b).project()
    sum_of_rows.write_to_file(name_out)

to_csv(sys.argv[1], "1.csv")
to_csv(sys.argv[2], "2.csv")

os.system("diff 1.csv 2.csv > diff.csv")

for line in open("diff.csv", "r"):
    match = re.match("(\\d+),(\\d+)c(\\d+),(\\d+)", line)
    if not match:
        continue
    print(line)

对于您的两个测试图像,我看到:

代码语言:javascript
复制
$ time ./diff.py 1.png 2.png 
264,272c264,272
351,359c351,359
real    0m0.346s
user    0m0.445s
sys 0m0.033s

在这台老笔记本电脑上。您所需要做的就是使用这些“更改”命令来标记您的图像。

票数 1
EN

Stack Overflow用户

发布于 2019-10-22 08:09:11

如果OpenCV和NumPy是您的选项,那么至少有一个非常简单的解决方案,用于查找和着色不同的行。

在我的方法中,我只使用np.abs计算像素级的差异,用np.nonzero查找非零行索引。使用这些已找到的行索引,我设置了一个额外的黑色图像,并为每一行绘制了红线。最后的混合只是一些线性混合:

代码语言:javascript
复制
0.5 * image1 + 0.5 * image2

对于所有相等的行,或

代码语言:javascript
复制
0.333 * image1 + 0.333 * image2 + 0.333 * red

所有不同的行。

下面是最后的代码:

代码语言:javascript
复制
import cv2
import numpy as np

# Load images
first = cv2.imread('9gOlq.png', cv2.IMREAD_COLOR)
second = cv2.imread('1Hdx4.png', cv2.IMREAD_COLOR)

# Calcluate absolute differences between images
diff = np.abs(np.float32(first) - np.float32(second))

# Find all non-zero rows
nz_rows = np.unique(np.nonzero(diff)[0])

# Set up image with red lines
red = np.zeros(first.shape, np.uint8)
red[nz_rows, :, :] = [0, 0, 255]

# Set up output image
output = np.uint8(0.5 * first + 0.5 * second)
output[nz_rows, :, :] = 0.333 * first[nz_rows, :, :] + 0.333 * second[nz_rows, :, :] + 0.333 * red[nz_rows, :, :]

# Show results
cv2.imshow("diff", np.array(diff, dtype=np.uint8))
cv2.imshow("output", output)
cv2.waitKey()
cv2.destroyAllWindows()

差异图像diff如下所示:

最后一个output看起来如下所示:

正如您在问题中所描述的,如果看到两个输入图像中省略的部分,将会很有趣。此外,使用原始大小的图像测试这种方法是必要的,因为您提到了时间是至关重要的。

不管怎样-希望这能帮上忙!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58498151

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档