背景
应某个老友的要求,想要从一个图片中,搜索出指定的图片元素。
因为当前正好在学习CV方面的知识,所以感觉这个需求比较有趣,所以研究了一下。
正文
查了下cv2库的这方面资料,有个matchTemplate模板匹配的方法,通过cv2的归一化相关系数匹配法(TM_CCOEFF_NORMED),来从原图片中匹配到目标图片。
然后通过numpy.where来筛选出图片中符合条件的部分(矩阵元素)的坐标。
关于cv2的安装或者基本引用等方法,就不在这里述说了。本文适合用过一次以上的pythonopencv-python 库的小伙伴。
1.首先打开图片,这里统一进行了一步去色的处理:
# 1.读入原图和模板
img_src = Image.open("main2.jpg")
img_src_gray = np.asarray(img_src.convert('L')) # 黑白
img_src = cv2.cvtColor(np.asarray(img_src), cv2.COLOR_RGB2BGR)
# 目标图
img_aim = np.asarray(Image.open("aim2.jpg").convert('L'))
2.cv2模板匹配
# 2.模板匹配.cv2.TM_CCOEFF_NORMED=归一化相关系数匹配法.也可采用TM_CCORR_NORMED-归一化相关匹配法
res = cv2.matchTemplate(img_src_gray, img_aim, cv2.TM_CCOEFF_NORMED)
3.获取匹配后的坐标
# 3.匹配程度大于THRESHOLD阈值坐标.格式y,x
loc = np.where(res >= THRESHOLD)
4.遍历结果,并显示
# 目标的高、宽
aim_h, aim_w = img_aim.shape[:2]
# 4.遍历符合条件的img数组
# 利用 * 号操作符,可以将元组解压为列表
for point_ in zip(*loc[::-1]): # 倒序,对应着转为x,y的坐标
# 按目标的高、宽,做标记
flag_point = (point_[0] + aim_w, point_[1] + aim_h)
# 绘制矩形框:cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)
# 绘制矩形框-参数:img是原图;(x,y)是矩阵的左上点坐标;(x+w,y+h)是矩阵的右下点坐标;(0,255,0)是画线对应的rgb颜色;2是所画的线的宽度
x1 = cv2.rectangle(img_src, point_, flag_point, (0, 0, 255), 2)
# 显示结果图片
cv2.imshow('out', x1)
cv2.waitKey(0)
原图:
目标图:
效果图:
总结
cv2.matchTemplate 匹配的使用:
- CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
- CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
- CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
- CV_TM_SQDIFF_NORMED 归一化平方差匹配法
- CV_TM_CCORR_NORMED 归一化相关匹配法
- CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
- python基础:
zip 中利用 * 号操作符,可以将元组解压为列表,这个之前用的不多,所以蛮有新鲜感;
numpy.where(condition, x, y) 的使用:满足条件(condition),输出x,不满足则输出y。emmm话说对numpy还没系统学习过,只是用到了什么就记下来;
- 另外,稍微思考了下,想起之前见过的一个连连看类型的游戏外挂,用的是切割图片,来完全匹配,然后判断是否可进行连接等等;
想来可以基于此方式来实现优化;可以直接检测目标图片的坐标,暴力找到其匹配的另一个图片,也无需判断是否可连接,直接移动鼠标强制点击连接~
|