python opencv学习笔记之数米粒,并返回每一个米粒的位置面积及总个数平均面积

之前曾经写过一道数米粒的作业,当时用的是c++中的opencv,这次用python试了一下。

原图及效果图

咦?水印怎么去啊
python opencv学习笔记之数米粒,并返回每一个米粒的位置面积及总个数平均面积_第1张图片
python opencv学习笔记之数米粒,并返回每一个米粒的位置面积及总个数平均面积_第2张图片
python opencv学习笔记之数米粒,并返回每一个米粒的位置面积及总个数平均面积_第3张图片

程序流程


程序的大致流程为:

1.读取图片
2.灰度化
3.二值化
4.膨胀、腐蚀等
5.边缘检测
6.输出

图片读取

用imread加上绝对路径进行读取

# 读取
img_rice = cv2.imread("d:/Python/rice/rice2.jpg")
cv2.imshow('rice', img_rice)

灰度化

基本的灰度化函数

# 灰度化
img_gray = cv2.cvtColor(img_rice, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', img_rice)

二值化

这个最好画出直方图,从直方图中选取合适的阈值,需要调整

# 二值化
ret,thresh1 = cv2.threshold(img_gray, 123, 255, cv2.THRESH_BINARY)
cv2.imshow('thresh', thresh1)

膨胀、腐蚀

矩阵的结构元素,以及腐蚀、膨胀的迭代次数要注意

# 腐蚀和膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(2,2))         #定义矩形结构元素

img_erode = cv2.erode(thresh1, kernel, iterations=3)
# cv2.imshow('erode', img_erode)

img_dilated = cv2.dilate(img_erode, kernel)

边缘检测

在边缘检测中对面积进行筛选,如果面积小于20,则认为不是米粒,如果面积大于150,则认为两个粘连,没有分开,具体的参数选取可以输出全部的面积之后再定,比如函数中加入

print(area)

用count统计个数
用ave_area统计面积

# 边缘检测
contours, hierarchy = cv2.findContours(img_dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

count = 0
ave_area = 0
for i in range(len(contours)):
    area = cv2.contourArea(contours[i])
    if area > 20:
        
        count = count + 1
        ave_area = ave_area + area
        rect = cv2.boundingRect(contours[i]) #提取矩形坐标

        print("number:{} x:{} y:{} area:{}".format(count,rect[0],rect[1], area))#打印坐标

        cv2.rectangle(img_rice,rect,(0,255,0),1)#绘制矩形
        if area > 150:
            count = count + 1
            cv2.putText(img_rice,str({count,count-1}), (rect[0], rect[1]), cv2.FONT_HERSHEY_COMPLEX, 0.4, (0, 255, 0), 1) #在米粒左上角写上编号
        else:

            cv2.putText(img_rice,str(count), (rect[0], rect[1]), cv2.FONT_HERSHEY_COMPLEX, 0.4, (0, 255, 0), 1) #在米粒左上角写上编号

    

输出

输出总个数和平均面积

ave_area = ave_area / count
# 输出
print('总个数是:{},平均面积是:{}'.format(count,ave_area))
cv2.imshow("Contours", img_rice)

完整代码

完整代码如下:

from cv2 import cv2

# 读取
img_rice = cv2.imread("d:/Python/rice/rice2.jpg")
cv2.imshow('rice', img_rice)
# 灰度化
img_gray = cv2.cvtColor(img_rice, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', img_rice)
# 二值化
ret,thresh1 = cv2.threshold(img_gray, 123, 255, cv2.THRESH_BINARY)
cv2.imshow('thresh', thresh1)

# 腐蚀和膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(2,2))         #定义矩形结构元素

img_erode = cv2.erode(thresh1, kernel, iterations=3)
# cv2.imshow('erode', img_erode)

img_dilated = cv2.dilate(img_erode, kernel)
# 边缘检测
contours, hierarchy = cv2.findContours(img_dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

count = 0
ave_area = 0
for i in range(len(contours)):
    area = cv2.contourArea(contours[i])
    if area > 20:
        
        count = count + 1
        ave_area = ave_area + area
        rect = cv2.boundingRect(contours[i]) #提取矩形坐标

        print("number:{} x:{} y:{} area:{}".format(count,rect[0],rect[1], area))#打印坐标

        cv2.rectangle(img_rice,rect,(0,255,0),1)#绘制矩形
        if area > 150:
            count = count + 1
            cv2.putText(img_rice,str({count,count-1}), (rect[0], rect[1]), cv2.FONT_HERSHEY_COMPLEX, 0.4, (0, 255, 0), 1) #在米粒左上角写上编号
        else:

            cv2.putText(img_rice,str(count), (rect[0], rect[1]), cv2.FONT_HERSHEY_COMPLEX, 0.4, (0, 255, 0), 1) #在米粒左上角写上编号

    
ave_area = ave_area / count
# 输出
print('总个数是:{},平均面积是:{}'.format(count,ave_area))
cv2.imshow("Contours", img_rice)

cv2.waitKey(0)
cv2.destroyAllWindows()

总结


对于一些米粒粘连严重的图片,这个方法不是很好。但是对于一般的还是可以的,不仅可以用于数米粒,还可以数一些其他的东西,比如玉米粒、芝麻粒、小麦。。。

你可能感兴趣的:(python opencv学习笔记之数米粒,并返回每一个米粒的位置面积及总个数平均面积)