openCV 简单物体识别

2019-09-04 16:38:19 浏览数 (2)

本篇的例子介绍使用numpy和 OpenCV ,仅根据识别对象的尺寸和颜色进行简单的物体识别。专业的图像识别须借助机器学习(含神经网络即深度学习),本篇不做介绍。

下图截屏于支付宝登山赛小游戏,我们的任务是识别一系列截图中的小鸡和金币,并给出其各自中心位置的大概坐标(原点在图像的左上角)。

首先是抠掉不动的背景。上篇已有介绍,不再赘述。

接着将图像上部小鸡和金币不可能去的位置像素置零。

代码语言:javascript复制
img[0: int(0.38*H),:, :] =0 #上边部分没有待检测目标,不参与计算, 置零

再分离通道:

代码语言:javascript复制
B,G,R = cv2.split(img) # 分离三个颜色通道
#cv2.imshow("B", cv2.resize(B ,(int(0.3*W),int(0.3*H))))
#cv2.imshow("G", cv2.resize(G ,(int(0.3*W),int(0.3*H))))
#cv2.imshow("R", cv2.resize(R ,(int(0.3*W),int(0.3*H))))

然后分离小鸡等白色的部分:

小鸡的红色分量和蓝色分量都很亮。我们将图片红色通道稍暗的部分对应的蓝色通道置零,即分离出来了包含小鸡的白色部分。

代码语言:javascript复制
B_ = B.copy() #深拷贝,防止串扰
B_[np.where(R<240)] =0 #红色通道稍暗的像素在蓝色通道置零
cv2.imshow("B_0", cv2.resize(B_ ,(int(0.3*W),int(0.3*H))))

然后转二值图,蓝色通道亮度小的部分置零以降噪。

代码语言:javascript复制
B_ = np.where(B_<230,0,255).astype(np.uint8)  #亮度小的置零
cv2.imshow("B_", cv2.resize(B_ ,(int(0.3*W),int(0.3*H))))

有了二值图,我们就可以对其进行轮廓检测,加以尺寸限制,在原始图上画出矩形框。这些命令我写在函数drawRect()中:

代码语言:javascript复制
#画矩形框且标记文本
def drawRect(src, dst, minW, minH, text='',maxW=np.inf, maxH= np.inf, RectColor=(0,0,255 ), textColor=(255,0,0)):
    contours, hierarchy = cv2.findContours(src, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if contours is not None:
        for c in contours: #对于每一个轮廓
            x, y, w, h = cv2.boundingRect(c) #矩形框
            if minW<w and w< maxW and minH<h and h<maxH:  #按宽、高的大小过滤
                print(w,h)
                cv2.rectangle(dst, (x,y), (x w, y h), RectColor, 4) # 颜色均为(B,G,R)模式
                #putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]])
                cv2.putText(dst,text,(x int(0.2*w),y int(0.5*h)), cv2.FONT_HERSHEY_COMPLEX, 1, textColor, 2, 4,False)
                print("{text} 坐标:{x}, {y}".format(text =text, x=x int(0.5*w), y= y int(0.5*h)))
               
drawRect(B_, img1st, 0.12*W, 0.05*H, text='chick')#识别小鸡

金币识别的方法也相似:

代码语言:javascript复制
#金币在红色通道最明显
#cv2.imshow("B", cv2.resize(B ,(int(0.3*W),int(0.3*H))))
R_ = R.copy()#深拷贝,防止串扰
R_[np.where(B>150)] =0 #蓝色通道稍亮的 在红色通道置零
cv2.imshow("R_0", cv2.resize(R_ ,(int(0.3*W),int(0.3*H))))
R_ = np.where(R_<200,0,255).astype(np.uint8) #亮度小的置零
#cv2.imshow("R_", cv2.resize(R_ ,(int(0.3*W),int(0.3*H))))
drawRect(R_, img1st, W/200.0, H/60.0, 'gold',H/28.0, H/28.0) #识别金币

最后,我们就得到了识别的结果:

代码语言:javascript复制
cv2.imshow("detection", cv2.resize(img1st ,(int(0.3*W),int(0.3*H))))
cv2.waitKey()
cv2.destroyAllWindows()

小鸡和分数圈混到一起,有些瑕疵,需引入更细致的条件加以区分。

0 人点赞