使用opencv查找两张图片不同的部分

简介
有一款游戏叫《大家一起来找茬》不知道大家有没有玩过,就是给出2张相似图片,在规定的时间内找出图片上有几处不同并标记出来。本文将介绍如何通过opencv替代肉眼快速找出准确的答案。
材料准备
  • 通过搜索引擎,找出要比较的素材。如下 找茬素材1
  • 将素材裁剪成2张图片
// ubuntu 系统命令裁剪
convert -crop 50%x100% image01.jpg image01.png
上面命令将生成image01-0.pngimage01-1.png两张图片,至今素材准备完毕
环境
  • python3
  • ubuntu
暴力匹配
def matchAB(fileA, fileB):
    # 读取图像数据
    imgA = cv2.imread(fileA)
    imgB = cv2.imread(fileB)

    # 转换成灰色
    grayA = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
    grayB = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)

    # akaze特征量抽出
    akaze = cv2.AKAZE_create()
    kpA, desA = akaze.detectAndCompute(grayA, None)
    kpB, desB = akaze.detectAndCompute(grayB, None)

    # BFMatcher定义和图形化
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(desB, desB)
    matches = sorted(matches, key=lambda x: x.distance)
    matched_image = cv2.drawMatches(imgA, kpA, imgB, kpB, matches, None, flags=2)

    plt.imshow(cv2.cvtColor(matched_image, cv2.COLOR_BGR2RGB))
    plt.show()
暴力匹配从上图可以看出,图片上大概的轮廓都标记并匹配上,但两张图片的不同之所才几个,用这样的方法就没啥效果了
图片重合匹配
通过2个图片重叠在一起,再找出2张图片上轮廓不同的地方。可能两张图片由于裁剪等原因,会有位置偏移的情况,所以以图片A为参照物,去寻找图片B的最佳重合位置,然后再查找图片的不同之处。
def matchAB(fileA, fileB):
    # 读取图像数据
    imgA = cv2.imread(fileA)
    imgB = cv2.imread(fileB)

    # 转换成灰色
    grayA = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
    grayB = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)

    # 获取图片A的大小
    height, width = grayA.shape

    # 取局部图像,寻找匹配位置
    result_window = np.zeros((height, width), dtype=imgA.dtype)
    for start_y in range(0, height-100, 10):
        for start_x in range(0, width-100, 10):
            window = grayA[start_y:start_y+100, start_x:start_x+100]
            match = cv2.matchTemplate(grayB, window, cv2.TM_CCOEFF_NORMED)
            _, _, _, max_loc = cv2.minMaxLoc(match)
            matched_window = grayB[max_loc[1]:max_loc[1]+100, max_loc[0]:max_loc[0]+100]
            result = cv2.absdiff(window, matched_window)
            result_window[start_y:start_y+100, start_x:start_x+100] = result

    plt.imshow(result_window)
    plt.show()
图片重复匹配从上图,大概可以知道两张图片不同的部分大致在哪里。当两张图片不同部位颜色对比明显时,表示计算机更容易识别。
基于图片重叠匹配结果标记位置
从图片重叠匹配结果中获取不同部分的坐标值,根据坐标值依次在原图片上进行标记。
def matchAB(fileA, fileB):
    # 读取图像数据
    imgA = cv2.imread(fileA)
    imgB = cv2.imread(fileB)

    # 转换成灰色
    grayA = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
    grayB = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)

    # 获取图片A的大小
    height, width = grayA.shape

    # 取局部图像,寻找匹配位置
    result_window = np.zeros((height, width), dtype=imgA.dtype)
    for start_y in range(0, height-100, 10):
        for start_x in range(0, width-100, 10):
            window = grayA[start_y:start_y+100, start_x:start_x+100]
            match = cv2.matchTemplate(grayB, window, cv2.TM_CCOEFF_NORMED)
            _, _, _, max_loc = cv2.minMaxLoc(match)
            matched_window = grayB[max_loc[1]:max_loc[1]+100, max_loc[0]:max_loc[0]+100]
            result = cv2.absdiff(window, matched_window)
            result_window[start_y:start_y+100, start_x:start_x+100] = result

    # 用四边形圈出不同部分
    _, result_window_bin = cv2.threshold(result_window, 30, 255, cv2.THRESH_BINARY)
    _, contours, _ = cv2.findContours(result_window_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    imgC = imgA.copy()
    for contour in contours:
        min = np.nanmin(contour, 0)
        max = np.nanmax(contour, 0)
        loc1 = (min[0][0], min[0][1])
        loc2 = (max[0][0], max[0][1])
        cv2.rectangle(imgC, loc1, loc2, 255, 2)

    plt.subplot(1, 3, 1), plt.imshow(cv2.cvtColor(imgA, cv2.COLOR_BGR2RGB)), plt.title('A'), plt.xticks([]), plt.yticks([])
    plt.subplot(1, 3, 2), plt.imshow(cv2.cvtColor(imgB, cv2.COLOR_BGR2RGB)), plt.title('B'), plt.xticks([]), plt.yticks([])
    plt.subplot(1, 3, 3), plt.imshow(cv2.cvtColor(imgC, cv2.COLOR_BGR2RGB)), plt.title('Answer'), plt.xticks([]), plt.yticks([])
    plt.show()
图片重复匹配结果标记从上图四边形所圈出的不同部分就是分析出来的结果。但细心的朋友会发现,右上角的屋顶的条纹,程序并没有给出。这时,我们可能需要调整程序的cv2.threshold的阈值来提高精度。有兴趣的同学可以亲自动手实验下。
源代码仓库
https://github.com/cangyan/image-detect
参考链接
https://qiita.com/fukuit/items/817c5282fc1a78872dd1

查看原文:https://www.huuinn.com/archives/394
更多技术干货:风匀坊
关注公众号:风匀坊
### 使用 OpenCV 进行图像差异检测并查找新增区域 对于图像差异检测以及识别新增区域的任务,可以采用多种方法来实现。一种常见的方式是通过计算两幅图像之间的绝对差分,并应用阈值处理以突出显示变化部分。 #### 方法概述 1. 加载待比较的两张图片; 2. 将其转换为灰度模式以便简化后续处理过程; 3. 计算这两张灰度图间的绝对差值矩阵; 4. 对所得的结果施加适当范围内的二值化操作,从而获得清晰的变化边界; 5. 利用形态学操作去除噪声干扰项; 6. 绘制矩形框标注出所有被认定为新出现的目标对象位置。 下面是具体的 Python 实现代码: ```python import cv2 import numpy as np def find_new_regions(image_path_1, image_path_2): # 读取输入图像 img1 = cv2.imread(image_path_1) img2 = cv2.imread(image_path_2) # 如果任意一张图片为空,则返回None表示失败 if img1 is None or img2 is None: print('无法加载其中至少一幅图像') return # 转换成灰色调 gray_img1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)[^1] gray_img2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY) # 获取两个图像大小的一致性 h,w=gray_img1.shape[:2] # 缩放到相同尺寸 (如果必要的话) resized_gray_img2=cv2.resize(gray_img2,(w,h))[^3] # 计算绝对差值 diff = cv2.absdiff(resized_gray_img2, gray_img1) # 应用自适应阈值分割得到二值图像 _, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY) # 执行膨胀腐蚀消除噪点 kernel = np.ones((5,5),np.uint8) dilated = cv2.dilate(thresh,kernel,iterations=2) eroded = cv2.erode(dilated,kernel,iterations=2) # 寻轮廓 contours,_ = cv2.findContours(eroded.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2:] # 在原图上绘制矩形标记新增物体的位置 for contour in contours: x,y,w,h = cv2.boundingRect(contour) cv2.rectangle(img1,(x,y),(x+w,y+h),(0,255,0),2) # 显示最终结果 cv2.imshow("Detected New Regions",img1) cv2.waitKey(0) cv2.destroyAllWindows() ``` 此段程序能够有效地定位到第二张照片相对于第一张所增加的新目标或改变过的区域,并且会在原始的第一张图片中标记出来这些变动之处。需要注意的是,在实际应用场景中可能还需要考虑更多因素比如光照条件的影响等,因此上述参数设置应当依据具体情况进行调整优化。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值