使用opencv查找两张图片不同的部分
2017-11-02 23:52
676 查看
简介
有一款游戏叫《大家一起来找茬》不知道大家有没有玩过,就是给出2张相似图片,在规定的时间内找出图片上有几处不同并标记出来。本文将介绍如何通过opencv替代肉眼快速找出准确的答案。材料准备
通过搜索引擎,找出要比较的素材。如下将素材裁剪成2张图片
// ubuntu 系统命令裁剪 convert -crop 50%x100% image01.jpg image01.png上面命令将生成
image01-0.png和
image01-1.png两张图片,至今素材准备完毕
环境
python3ubuntu
暴力匹配
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 aa1a # 用四边形圈出不同部分 _, 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线性混合(适用于两张不同尺寸的图片)
- ios--OpenCV--cvCompareHist使用直方图模型(CvHistogram)比对两张图片
- OpenCV入门九:使用findContours()查找图片轮廓线,并将轮廓线坐标点输出
- OpenCV在明暗不同或光线不均的图片上查找轮廓-应用在Android NDK
- 如何使用OPENCV实现两张图片的混合(PS中的图层不透明度)
- c++提取两张相同背景的bitmap的不同部分 -->找茬游戏其实很简单,自动提取不同图片部分就OK了
- 使用OpenCV合成两张图片
- 利用TBDBitmapData对象查找两张图片上的不同
- [置顶] 使用opencv人脸识别对比两张人脸图片
- OpenCV 两张大小不同图片的叠加
- 两张图片叠加成一张图片后使用
- 在ASP.NET的母版页中使用图片和超链接,HTML标记和ASP.NET标记的不同
- 不同服务器不同数据库两张表连接查询使用经验 数据库基础教程
- 使用Jmagick将图片压缩成各种不同大小的图片
- opencv实现不同格式图片的转换(jpg<-->bmp)
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解
- 用c#怎么比较两张图片的不同
- J2ME图片半透明处理(使用图片像素)(仅部分手机支持)
- Jtree不同节点使用不同图片实现