概述
基于opencv实现玉米排种株距检测,从而对排种器排种性能进行检测;
实现原理
1.调用摄像头
2.识别到种子,并记录当前时间
3.获取两次识别到种子的时间戳
4.由 传送带速度 * 两粒种子时间间隔 = 株距,得出株距
5.硬件:JPS-12试验台(传送带)、电脑、摄像头、排种器
完整代码
"""
1.调用摄像头
2.识别种子,并记录当前时间
3.获取两次识别到种子的时间戳
4.由传送带速度,计算出株距
author : 南栀北辰
Q:1761630764
start_date :2022-11-08
end_date :2022-11-12
"""
# 加载库
import cv2
import cv2 as cv
import numpy as np
import time
from matplotlib import pyplot as plt
# 定义调参变量
Speed = 3.3 # 传送带速度,单位 : m/s
Distance = [] # 种子间距, 单位: m
W_multiple = 1 # 摄像头捕捉的宽度倍数,大于1放大捕捉范围,小于1缩小捕捉范围
H_multiple = 1 # 摄像头捕捉的长度倍数,大于1放大捕捉范围,小于1缩小捕捉范围
Interval = 10 # 每间隔 interval ms,捕捉一帧
Appear_time = [] # 临时变量,存储每次种子出现的时间戳
Sowing_time = [] # 种子间隔时间 s
# 临时变量
time1 = [] # 临时变量,每一次黑白变化清空一次
# 获取时间函数 单位s,小数点后6位有效数据
def get_time():
# noinspection PyShadowingNames
use_time = time.time()
# print("时间戳 :", time_stamp) # 秒级
# print(int(round(time_stamp * 1000))) # 毫秒级
return use_time
# 写入文本函数
def save_write(path, mode, content):
file = open(path, mode) # 打开现有文件,或创建文件
file.write(content) # 写入内容
content = file.readlines() # 读出内容
file.close()
return content
# 1.调用摄像头
camera = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 摄像头
# cap = cv2.VideoCapture('F:/Python_Learn_Source/02.OpenCV_DATE/English.mp4')
width, height = camera.get(3), camera.get(4) # 获取摄像头的宽和高
# 以原分辨率的一倍来捕获,用来该改变摄像头捕捉的范围,
camera.set(cv.CAP_PROP_FRAME_WIDTH, width * W_multiple)
camera.set(cv.CAP_PROP_FRAME_HEIGHT, height * H_multiple)
history = 300 # 用于训练背景的帧数,默认为500帧,如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
learningRate = 0 # 值为0-1,为0时背景不更新,为1时逐帧更新,默认为-1,即算法自动更新;
varThreshold = 70 # 用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
mog = cv2.createBackgroundSubtractorMOG2(history=history, detectShadows=False, varThreshold=varThreshold) # 应用MOG2模型
se = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) # 构造全是1的扫描核,用于形态学操作
time.sleep(0.5)
# 2.判断是否读取成功
while camera.isOpened():
# 3.获取每一帧图像
success, img = camera.read() # 从摄像头读取照片
# 4.获取成功显示图像
if success:
cv2.imshow('frame', img)
fg_mark = mog.apply(img) # 对图像进行混合高斯模型
cv2.imshow('fg_mark', fg_mark)
ret, thresh = cv.threshold(fg_mark, 0, 250, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# binary = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, se)
bg_image = mog.getBackgroundImage() # 背景图像
cv2.imshow('bg_image', bg_image)
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# contours, hierarchy = cv.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
print('轮廓个数为', len(contours)) # 轮廓个数
# print(hierarchy)
# print(len(contours[0])) # 轮廓包含多少像素点
# cnt = contours[0] # 第几个轮廓
cv.drawContours(img, contours, -1, (0, 255, 0), 1)
cv.imshow("frame", img)
# 4.1判断轮廓个数,有种子轮廓层次总数为2
# if len(contours) == 1 or len(contours) == 2 or len(contours) == 3 or len(contours) == 4: # 获取当前时间,给时间变量1
if (len(contours) >= 8) and (len(contours) <= 30000): # 获取当前时间,给时间变量1
use_time = get_time()
time1.append(use_time)
# print(time1)
# time1[0]
else: # 将time1[0]先写入Appear_time = []保存,再进行清空time1列表
if len(time1) != 0:
Appear_time.append(time1[0]) # 写入time1[0]
print("种子每出现一次的时间戳", Appear_time)
time1.clear() # 对列表清空
# 5.每间隔 interval ms,捕捉一帧
if cv.waitKey(Interval) & 0xFF == ord('0'): # 按下数字0 ,关闭摄像头
break
print('.................数据采集完毕,进行数据处理中..................')
# 6.利用时间戳和传送带的速度计算株距,并保存在“株距.txt”文件中
# 6.1 计算种子间隔时间,并记录在文本 ‘播种间隔时间.txt’中
# print(len(Appear_time))
for i in range(len(Appear_time)):
if i == (len(Appear_time)-1):
break
else:
D_value = Appear_time[i+1] - Appear_time[i] # 相邻种子间的时间差
Sowing_time.append(D_value)
save_write('播种间隔时间.txt', 'w+', str(Sowing_time))
# 6.2 计算株距,并记录到文本‘株距.txt’
for j in range(len(Sowing_time)):
Jian_Ju = Sowing_time[j] * Speed
Distance.append(Jian_Ju)
save_write('株距.txt', 'w+', str(Distance))
print('...................数据处理和保存完成..........................')
for t in range(3):
print(f'{3-t}秒后程序结束')
time.sleep(1)
print('程序结束')
# 7.释放视频对象
camera.release() # 关闭摄像头
cv.destroyAllWindows() # 销毁进程
检测结果
问题
由于排种过程中,玉米和传送带会发生碰撞回弹,导致少量数据明显异常,去除明显异常数据即可;