最近冒出来个想法,想要翻译下计算机视觉相关的博客。我觉着是够呛能做到。今天先总结一篇PyImageSearch一篇有意思的博客Pokemon识别。原博客提供了完整的代码,因此本文只附上核心代码。
作者将OpenCV应用到了一个很有意思的场景。假设有如下的一张照片,照片用有一个游戏机,游戏机的屏幕里是Pokemon游戏(这个游戏没玩过),屏幕的的右上角是一只小精灵。现在我们想做的就是给定一张类似这样的图像,识别出右上角的小精灵。概括来说,需要两步:找到小精灵,然后识别就完事了。
找到小精灵
找到屏幕
对于我们人来说,这个任务是非常简单的,但是对于计算机来说却相对较难。在博客中,作者采取的方法是根据图形的形状来找:游戏机的屏幕是矩形的,找到图形中的矩形区域即找到了屏幕。(如果有疑问先忍着,往下看)
通常情况下,寻找轮廓首先需要对图形进行灰度化处理、二值化处理,并进行边缘检测,代码如下所示。
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.bilateralFilter(gray, 11, 17, 17)
edged = cv2.Canny(gray, 30, 200)
得到如下结果:
边缘检测完了之后调用findContours
寻找轮廓:
cnts = cv2.findContours(edged.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
之后用多边形拟合曲线approxPolyDP
,这个函数利用多个点去拟合一条曲线,这里的想法是,如果用四个点可以拟合一条闭合曲线,则说明这条曲线是矩形的,核心代码如下。
for c in cnts:
peri = cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, 0.015 * peri, True)
if len(approx) == 4:
screenCnt = approx
break
以上步骤达到的效果如下。至此,已经找到了屏幕。我相信大家肯定有对以上做法的很多怀疑,还是先忍一忍。
找到小精灵
找到屏幕了怎么找小精灵呢?我们知道小精灵在屏幕中的位置上固定的。那么我们只需要把屏幕“摆正”,那么屏幕的右上角就是小精灵了。
要摆正屏幕,首先需要获取屏幕原来的四点坐标,注意顺序是从左上开始,顺时针旋转。左上点和右下点的坐标值特点是它们的和最小或最大,而右上点和左下点点坐标值特点是它们的差(高度坐标减宽度坐标)最小或最大。代码如下所示。
s = pts.sum(axis = 1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
有了点的坐标,自然可以计算矩形的宽高,就可以把他们进行角度转化。在未转化之前,矩形可能是倾斜的,例如左上点和右上点的高度坐标可能不相等,转化之后则不存在这种情况。
dst = np.array([
[0, 0],
[maxWidth - 1, 0],
[maxWidth - 1, maxHeight - 1],
[0, maxHeight - 1]], dtype = "float32")
M = cv2.getPerspectiveTransform(rect, dst)
warp = cv2.warpPerspective(orig, M, (maxWidth, maxHeight))
摆正之后,按照比例关系将小精灵截取出来即可,效果如下所示。
至此,我们已经实现了将想要识别的目标小精灵从包含无用信息的图像中截取出来,也就是获取感兴趣区域ROI。下一步要做的是识别小精灵。
识别小精灵
在简单的图像识别中,常使用图像距来描述图像信息,这里使用Zernike矩描述目标的形状。对于图像距我现在还没有完全理清,大家可以自行查阅资料。本文对它的理解就是较为浅显,认为它类似于哈希,给它一个图像,它就可以计算出一个“哈希值”,那么两个相似的图像的“哈希”值就较为接近,反之,差距较大两个图像的“哈希”值相差较大。
原博客首先利用爬虫在Pokemon网站上下载了小精灵们的图像,然后对每个图像做了“哈希”并存储在文件中。识别时,打开文件找到与目标最为接近的即可。
总结
小精灵识别是OpenCV的应用,在系列博客中,作者介绍了如何利用OpenCV找到ROI,以及如何利用形状判断两个目标是否相同。在阅读过程中,相信大家可能会有很多疑惑,例如“怎么矩形的区域就一定是屏幕呢?”“怎么右上角的就是小精灵呢?”等等。
我想,首先如题所述,这只是OpenCV的一个简单应用,是应用于一个较为简答的场景中的,例如图像中就只有一个矩形区域即游戏机屏幕;其次,计算机视觉的问题解决是较为复杂的(特别是对于我这种菜鸡),面对问题时如果我们可以通过分析图像找到类似“矩形的就是屏幕”“右上角就是小精灵”这样的特点,或许就可以简化问题;最后,人工辅助对于计算机视觉问题的解决会有很大帮助。