opencv入门之数米粒:给出一幅米粒图数出图中米粒数目以及最大米粒位置。在原图上画出最大米粒的位置。并输出最大米粒的面积和最大米粒的周长。使用pycharm编码,亲测功能强大。
首先利用opencv轮廓检测函数来分别提取每一个米粒,并计算出每个米粒的面积,然后对最大米粒求周长,最后在原图上标记最大米粒的位置,并且输出米粒信息。
opencv轮廓检测函数所需要的图像为二值化图片,所以在进行轮廓检测前,需要对图像进行预处理。预处理过程为:
(1).对图片进行灰度化:
(2)获取去背景的米粒图
利用腐蚀膨胀,对原图进行5次腐蚀,然后进行5次膨胀,得到背景图
原图减去背景图可以得到去背景的米粒图
import import cv2
import numpy as np
#打开图片
img=cv2.imread('Img/rice.jpg',0)
#构造模板,5次腐蚀
kernel=np.ones((5,5),np.uint8)#构造5x5卷积核
erosion=cv2.erode(img,kernel,iterations=5)#进行5次腐蚀
dilation=cv2.dilate(erosion,kernel,iterations=5) #进行5次膨胀
#原图减去背景得到米粒形状
backImg=dilation
rice=img-backImg
去背景米粒效果图:
(3)图像二值化
简单阈值
与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素 赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。 这个函数就是 cv2.threshhold()。这个函数的第一个参数就是原图像,原图 像应该是灰度图。第二个参数就是用来对像素值进行分类的阈值。第三个参数 就是当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。OpenCV 提供了多种不同的阈值方法,这是有第四个参数来决定的。这些方法包括:
cv2.THRESH_BINARY
cv2.THRESH_BINARY_INV
cv2.THRESH_TOZERO
cv2.THRESH_TOZERO_INV
OSTU全局阈值
这里用到到的函数还是 cv2.threshold(),但是需要多传入一个参数 (flag):cv2.THRESH_OTSU。这时要把阈值设为 0。然后算法会找到最 优阈值,这个最优阈值就是返回值 retVal。如果不使用 Otsu 二值化,返回的 retVal 值与设定的阈值相等。
#OSTU二值化,th1返回阈值,ret1返回二值化的结果图像
th1,ret1=cv2.threshold(rice,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
二值化效果图如下
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同 的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。 python3.x-opencv开发指导用书
(1) 轮廓提取
**#轮廓检测,注意输出结果应有3个,其他著作上为2个输出结果,亲测错误**
ret1,contours,hierarchy=cv2.findContours(ret1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
(2)轮廓数据
cv2.contourArea(cnt)
cv2.arcLength(cnt,True)
(3)输出结果
遍历所有轮廓,比较轮廓数据,得出最大轮廓,并在原图上标注。
函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供 的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一 个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设 置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
#遍历得到最大面积的米粒
maxC=-1
maxS=-1
for cnt in contours:
tempS=cv2.contourArea(cnt)
if maxS<tempS:
maxS=tempS
maxC=tempC=cv2.arcLength(cnt,True)
contour=cnt
#在img中画出最大面积米粒
cv2.drawContours(img,[contour],-1,(0,0,255,),1)
改变参数可以获取更好的效果
整体代码
import cv2
import numpy as np
#打开图片
img=cv2.imread('Img/rice.jpg',0)
#构造模板,5次腐蚀,5次膨胀,得到背景
kernel=np.ones((5,5),np.uint8)
erosion=cv2.erode(img,kernel,iterations=5)
dilation=cv2.dilate(erosion,kernel,iterations=5)
#原图减去背景得到米粒形状
backImg=dilation
rice=img-backImg
#OSTU二值化
th1,ret1=cv2.threshold(rice,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#轮廓检测
ret1,contours,hierarchy=cv2.findContours(ret1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#遍历得到最大面积的米粒
maxC=-1
maxS=-1
for cnt in contours:
tempS=cv2.contourArea(cnt)
if maxS<tempS:
maxS=tempS
maxC=tempC=cv2.arcLength(cnt,True)
contour=cnt
#在img中画出最大面积米粒
cv2.drawContours(img,[contour],-1,(0,0,255,),1)
cv2.imshow('image',rice)
print('面积最大:',maxS)
print('对应米粒周长:',maxC)
cv2.waitKey(0)
cv2.destroyAllWindows()
cs