Python opencv 实现玉米粒计数

Python笔记(一)

(本文用来记录自己学习python的笔记,公开可看,共同学习)

PS:思路就是采用距离变换和找轮廓来实现玉米粒计数和标记优良差

一、调用opencv,numpy库

import cv2
import numpy as np

首先调用两个常见的库opencv和numpy,下面会用到

这两个库需要自行安装:

  1. 安装opencv:命令行输入pip insatll opencv-python
  2. 安装numpy:命令行输入pip install numpy

二、 读入图片

img=cv2.imread(r'C:\Users\30362\Desktop/Corn.jpg')
cv2.imshow('原图',img)

 Python opencv 实现玉米粒计数_第1张图片

cv2.imread('路径'):路径中不能含有中文(如果你使用中文的话python不会报错,但是一但用到这个图片就会立马报错),注意我的路径格式

cv2.imshow():正常图片显示,(图片名称“原图”在python可能显示的是乱码,是因为还需要配置其他库才行)

三、灰度处理

gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度处理
cv2.imshow('gray_img',gray_img)

 

 cv2.cvtColor():色彩空间转换 RGB转GRAY(图像上的灰度值范围为0~255)

四、二值化 

ret,th1=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY)
cv2.imshow('th1',th1)

 Python opencv 实现玉米粒计数_第2张图片

th1为二值化处理后的图像(图像上的像素点值只有0,255两种) 

120为阈值,大于这个阈值像素点为255(即白色),小于阈值则为0(即黑色),这是默认的,可改;

 

 五、腐蚀变换

erosion = cv2.erode(th1,kernel,iterations = 1)#腐蚀
cv2.imshow('erosion',erosion)

 Python opencv 实现玉米粒计数_第3张图片

cv2.erdoe():对图像进行腐蚀,kernel为卷积核(需自己定义,例kernel = np.ones((7,7),np.uint8))

腐蚀变换的目的是消除噪点(开运算也可以,只是此处要比较是否腐蚀后图上的各个轮廓是否分离,通过上图可以发现仍有粘连,所以就有了下一步——距离变换)

 六、距离变换

dist_img = cv2.distanceTransform(erosion, cv2.DIST_L1, cv2.DIST_MASK_3)#距离变换
cv2.imshow('距离变换',dist_img)
dist_output = cv2.normalize(dist_img, 0, 1.0, cv2.NORM_MINMAX)#归一化
cv2.imshow('dist_output',dist_output*80)

 Python opencv 实现玉米粒计数_第4张图片

cv2.distanceTransform:距离变换(计算图像中像素点到最近零像素点的距离距离变换后得到轮廓的骨架,通过二值化可以有效的去除重叠部分) 

cv2.normalize:归一化(归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。)

经过归一化得到的图像dist_output灰度值在0~1.0

此处dist_output*80是因为归一化之后灰度值在0~1.0,不容易观察

七、 二值化+开运算

ret,th2=cv2.threshold(dist_output*80,0.3,255,cv2.THRESH_BINARY)
cv2.imshow('th2',th2)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(th2, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening',opening)

 Python opencv 实现玉米粒计数_第5张图片

灰度处理之后成二值化图像 ,可以发现原本重叠的部分不再重叠,那下面便可以寻找轮廓

八、找轮廓 

opening = np.array(opening,np.uint8)
contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#轮廓提取

 cv2.findContours:轮廓提取,它可以根据你提供的边界点绘制任何形状(注意要寻找的物体为白色背景为黑色)

此函数得到的轮廓集存储在contours里,下面我们进行遍历

九、判断种子优良差 

for cnt in contours:
    (x,y),radius = cv2.minEnclosingCircle(cnt)
    center = (int(x),int(y))
    radius = int(radius)
    circle_img = cv2.circle(opening,center,radius,(255,255,255),1)
    area = cv2.contourArea(cnt)
    area_circle=3.14*radius*radius
    #print(area/area_circle)
    if area/area_circle <=0.5:
        #img = cv2.drawContours(img, cnt, -1, (0,0,255), 5)#差(红色)
        img=cv2.putText(img,'bad',center,font,0.5,(0,0,255))
    elif area/area_circle >=0.6:
        #img = cv2.drawContours(img, cnt, -1, (0,255,0), 5)#优(绿色)
        img=cv2.putText(img,'good',center,font,0.5,(0,0,255))
    else:
        #img = cv2.drawContours(img, cnt, -1, (255,0,0), 5)#良(蓝色)
        img=cv2.putText(img,'normal',center,font,0.5,(0,0,255))
    count+=1
img=cv2.putText(img,('sum='+str(count)),(50,50),font,1,(255,0,0))
cv2.imshow('circle_img',img)
print('玉米粒共有:',count)

 遍历每一个轮廓(for cnt in contours),得到每个轮廓最小外接圆的圆心和半径((x,y),radius = cv2.minEnclosingCircle(cnt))

判断玉米粒优良差标准为每个玉米粒轮廓的面积( area = cv2.contourArea(cnt))与最小外接圆的面积之比

cv2.putText()在指定坐标上写字

最后贴出完整代码 

import cv2
import numpy as np
font=cv2.FONT_HERSHEY_COMPLEX
kernel = np.ones((7,7),np.uint8)
img=cv2.imread(r'C:\Users\30362\Desktop/Corn.jpg')
cv2.imshow('原图',img)
gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度处理
cv2.imshow('gray_img',gray_img)
ret,th1=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY)
cv2.imshow('th1',th1)
erosion = cv2.erode(th1,kernel,iterations = 1)#腐蚀
cv2.imshow('erosion',erosion)
dist_img = cv2.distanceTransform(erosion, cv2.DIST_L1, cv2.DIST_MASK_3)#距离变换
cv2.imshow('距离变换',dist_img)
dist_output = cv2.normalize(dist_img, 0, 1.0, cv2.NORM_MINMAX)#归一化
cv2.imshow('dist_output',dist_output*80)


ret,th2=cv2.threshold(dist_output*80,0.3,255,cv2.THRESH_BINARY)
cv2.imshow('th2',th2)

kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(th2, cv2.MORPH_OPEN, kernel)
cv2.imshow('opening',opening)
opening = np.array(opening,np.uint8)
contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#轮廓提取
count=0
for cnt in contours:
    (x,y),radius = cv2.minEnclosingCircle(cnt)
    center = (int(x),int(y))
    radius = int(radius)
    circle_img = cv2.circle(opening,center,radius,(255,255,255),1)
    area = cv2.contourArea(cnt)
    area_circle=3.14*radius*radius
    #print(area/area_circle)
    if area/area_circle <=0.5:
        #img = cv2.drawContours(img, cnt, -1, (0,0,255), 5)#差(红色)
        img=cv2.putText(img,'bad',center,font,0.5,(0,0,255))
    elif area/area_circle >=0.6:
        #img = cv2.drawContours(img, cnt, -1, (0,255,0), 5)#优(绿色)
        img=cv2.putText(img,'good',center,font,0.5,(0,0,255))
    else:
        #img = cv2.drawContours(img, cnt, -1, (255,0,0), 5)#良(蓝色)
        img=cv2.putText(img,'normal',center,font,0.5,(0,0,255))
    count+=1
img=cv2.putText(img,('sum='+str(count)),(50,50),font,1,(255,0,0))
cv2.imshow('circle_img',img)
print('玉米粒共有:',count)

先写到这,若有错误或者不足可以提出,共同进步嘻嘻

你可能感兴趣的:(Python opencv 实现玉米粒计数)