python - 图像差异:忽略平移运动
问题描述
我正在寻找一些关于什么是解决我的问题的最佳方法的见解。我正在比较两个单独的图像的差异,但我遇到了小平移运动的问题。
我有一个“福音”形象,它本身就是“黄金标准”: 福音形象
然后我有多个不同的拍摄图像进行比较。这是一个示例:示例图像
这是显示我的问题的示例差异图像:差异图像
如您所见,它们非常小。我现在区分图像的方法是首先将图像大小调整为 32x32,手动将对比度降低 100,然后使用 OpenCV 应用模糊。
之后,我使用 skimage 的“structural_integrity”函数来减去和量化图像之间的差异。其余的纯粹是为了观看。
import cv2
import numpy as np
from PIL import Image
from skimage.metrics import structural_similarity
def change_contrast(img, level):
img = Image.fromarray(img)
factor = (259 * (level + 255)) / (255 * (259 - level))
def contrast(c):
return 128 + factor * (c - 128)
return np.asarray(img.point(contrast))
# Open and preprocess the images
image_orig = cv2.imread(IMAGE_PATH)
image = cv2.resize(image, (32, 32))
image = change_contrast(image_orig, -100)
image = cv2.blur(image, (5, 5))
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gospel_orig = cv2.imread(GOSPEL_PATH)
gospel = cv2.resize(gospel_orig, (32, 32))
gospel = change_contrast(gospel, -100)
gospel = cv2.blur(gospel, (5, 5))
gospel = cv2.cvtColor(gospel, cv2.COLOR_BGR2GRAY)
# Get image similarities and an output difference image
(score, diff) = structural_similarity(image, gospel, full=True)
print("Image similarity", score)
diff = (diff * 255).astype("uint8")
# Viewing stuff below
thresh = cv2.threshold(diff, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
filled_gospel = cv2.cvtColor(gospel, cv2.COLOR_GRAY2BGR)
for c in contours:
area = cv2.contourArea(c)
if area > 40:
x,y,w,h = cv2.boundingRect(c)
cv2.drawContours(filled_gospel, [c], 0, (0,255,0), -1)
cv2.imshow('image', image)
cv2.imshow('gospel', gospel)
cv2.imshow('diff',diff)
cv2.imshow('filled gospel',filled_gospel)
cv2.waitKey(0)
当我执行上述步骤时,您可以看到“福音”和拍摄的图像之间的一些翻译差异。解决这个问题的最佳方法是什么,因为我只想得到字母黑色的差异,而不是它的对齐程度?
解决方案
这是我在 Python/OpenCV 中进行模板匹配和差异化的方法。
- 阅读参考和示例图像
- 使用背景灰色将示例图像填充到其尺寸的两倍。
- 与参考进行模板匹配以找到最佳匹配位置和匹配分数。
- 裁剪填充的示例图像,使其左上角位于匹配位置,但参考图像的大小
- 获取绝对差图像
- 保存结果
参考:
例子:
import cv2
import numpy as np
# read reference and convert to gray
ref = cv2.imread('reference.png')
ref_gray = cv2.cvtColor(ref, cv2.COLOR_BGR2GRAY)
hr, wr = ref_gray.shape
# read example and convert to gray
ex = cv2.imread('example.png')
ex_gray = cv2.cvtColor(ex, cv2.COLOR_BGR2GRAY)
he, we = ex_gray.shape
# pad the example to double its dimensions with gray=190
color=190
wp = we // 2
hp = he // 2
ex_gray = cv2.copyMakeBorder(ex_gray, hp,hp,wp,wp, cv2.BORDER_CONSTANT, value=color)
# do template matching
corrimg = cv2.matchTemplate(ref_gray,ex_gray,cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(corrimg)
max_val_corr = '{:.3f}'.format(max_val)
print("correlation: " + max_val_corr)
xx = max_loc[0]
yy = max_loc[1]
print('x_match_loc =',xx,'y_match_loc =',yy)
# crop the padded example image at top left corner of xx,yy and size hr x wr
ex_gray_crop = ex_gray[yy:yy+hr, xx:xx+wr]
# get absolute difference image
ref_grayf = ref_gray.astype(np.float32)
ex_gray_cropf = ex_gray_crop.astype(np.float32)
diff = 255 - np.abs(cv2.add(ref_gray, -ex_gray_crop))
# compute mean of diff
mean = cv2.mean(diff)[0]
print("mean of diff in range 0 to 100 =",mean)
cv2.imshow('ref_gray', ref_gray)
cv2.imshow('ex_gray', ex_gray)
cv2.imshow('ex_gray_crop', ex_gray_crop)
cv2.imshow('correlation image', corrimg)
cv2.imshow('diff', diff)
cv2.waitKey(0)
cv2.destroyAllWindows()
# save results
cv2.imwrite('reference_gray.jpg', ref_gray)
cv2.imwrite('example_gray_padded.jpg', ex_gray)
cv2.imwrite('reference_example_correlation.jpg', (255*corrimg).clip(0,255).astype(np.uint8))
cv2.imwrite('example_gray_padded_cropped.jpg', ex_gray_crop)
cv2.imwrite('reference_example_diff.jpg', diff)
填充示例:
显示最佳匹配位置的相关图像:
比赛结果:
correlation: 0.969
x_match_loc = 10 y_match_loc = 9
mean of diff in range 0 to 100 = 1.3956887102667155
裁剪以与参考对齐的示例:
差异图像(白色是它们不同的地方):
推荐阅读
- python - 合并熊猫df中的值
- c# - 按标签页名称访问标签页控件
- android - 我必须为 GET 请求改造 android 创建哪个项目结构?
- python - 对 n< 中的 batch_size 感到困惑
在 Keras 中
- apache-spark - SparkSession:ActiveSession 与 DefaultSession
- mongodb - 创建一个好的 mongodb 模式
- java - 如何为 Apache Ignite 缓存配置持久存储?
- unity3d - 导出 CATIA - Maya 到 Unity 问题
- string - 算法 - KMP 前缀表:是否有两种选择可以跳转?
- php - 使用 Codeigniter 激活发送邮件