主题
首先我们先来看下我们的原图:
步骤1:加载图片,转成灰度图
image = cv2.imread("1.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
执行完这一步,得到的图像如下:
步骤2:用Sobel算子计算x,y方向上的梯度,之后在x方向上减去y方向上的梯度,通过这个减法,我们留下具有高水平梯度和低垂直梯度的图像区域。
gradX = cv2.Sobel(gray, ddepth=cv2.cv.CV_32F, dx=1, dy=0, ksize=-1)
gradY = cv2.Sobel(gray, ddepth=cv2.cv.CV_32F, dx=0, dy=1, ksize=-1)
#用y方向上的梯度减去x方向上的梯度
gradient = cv2.subtract(gradX, gradY)
gradient = cv2.convertScaleAbs(gradient)
执行完这一步,得到的图像如下:
步骤3:去除图像上的噪声。首先使用低通滤泼器平滑图像(9 x 9内核),这将有助于平滑图像中的高频噪声。低通滤波器的目标是降低图像的变化率。如将每个像素替换为该像素周围像素的均值。这样就可以平滑并替代那些强度变化明显的区域。 然后,对模糊图像二值化。梯度图像中不大于90的任何像素都设置为0(黑色)。 否则,像素设置为255(白色)。
#这里我们采用平均滤波的方式去处理这个图像
blurred = cv2.blur(gradient, (9, 9))
ret, thresh = cv2.threshold(blurred, 90, 255, cv2.THRESH_BINARY)
执行完这一步,得到的图像如下:
步骤4:在上图中我们看到甲壳虫身体区域有很多黑色的空余,我们要用白色填充这些空余,使得后面的程序更容易识别昆虫区域,这需要做一些形态学方面的操作。
#这里我们采用25*25的卷积核进行闭运算操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
处理之后的图像如下:
步骤5:从上图我们发现图像上还有一些小的白色斑点,这会干扰之后的昆虫轮廓的检测,要把它们去掉。分别执行4次形态学腐蚀与膨胀。
#进行四次形态学腐蚀与膨胀
closed = cv2.erode(closed, None, iterations=4)
closed = cv2.dilate(closed, None, iterations=4)
执行完这步,得到的图形如下
步骤6:现在我们需要找出昆虫区域的轮廓。cv2.findContours()函数第一个参数是要检索的图片,必须是为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图,我们在第三步用cv2.threshold()函数已经得到了二值图。第二个参数表示轮廓的检索模式,有四种,这里我们采用cv2.RETR_EXTERNAL只找最外层的轮廓。第三个参数我们选择只取特征点来节约计算空间,所以为cv2.CHAIN_APPROX_SIMPLE。然后我们得到了一个轮廓列表,调用sorted函数(或者max函数)来获得最大的那个轮廓,然后调用cv2.drawContour()函数来画出轮廓:
contours,hierarchy=cv2.findContours(closed,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnt=sorted(contours,key=cv2.contourArea,reverse=True)[0]#面积最大的那个
img=cv2.drawContours(img,[cnt],-1,(0,255,0),3)
执行完这步得到的图形如下:
步骤7:运用矩形拟合画出边界矩形
x,y,w,h=cv2.boundingRect(cnt)
img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意:在运行这步的时候记得把上面的cv2.drawContours()注释掉不然会画两条轮廓出来
步骤8:裁剪。x,y为左上角的像素坐标,w是矩形的width,h是矩形的height,所以我们的图片就是:
crop = img[y1:y1+h, x1:x1+w]
cv2.imshow(“crop”,crop)
裁剪出的图片如下:
总结
(本系列每周不定期更新,谢谢大家支持!)