继上一篇:opencv-python打开摄像头定位车牌之后,我发现摄像头有时会比较卡顿,显然这不是我想要的效果。
产生卡顿的原因在于:摄像头读取到的有很多帧,但是如果每一帧我们都对其做各种滤波、腐蚀、膨胀等操作,那显然计算是跟不上摄像头捕捉的速率的。
那么我们就引入了多线程。
想法如下:把摄像头显示的部分放在主线程,然后开启一个线程去处理图像。
实现代码如下:
import cv2
import threading
cap = cv2.VideoCapture(1) # 创建一个 VideoCapture 对象
# 新线程执行的代码:
def deal(frame):
# 高斯去噪
image = cv2.GaussianBlur(frame, (3, 3), 0)
# 灰度处理
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# sobel算子边缘检测(做了一个y方向的检测)
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
# Sobel_y = cv2.Sobel(image, cv2.CV_16S, 0, 1)
absX = cv2.convertScaleAbs(Sobel_x) # 转回uint8
image = absX
# 自适应阈值处理
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
# 闭运算,是白色部分练成整体
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5))
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX, iterations=3)
# 去除一些小的白点
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (20, 1))
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 19))
# 膨胀,腐蚀
image = cv2.dilate(image, kernelX)
image = cv2.erode(image, kernelX)
# 腐蚀,膨胀
image = cv2.erode(image, kernelY)
image = cv2.dilate(image, kernelY)
# 中值滤波去除噪点
image = cv2.medianBlur(image, 15)
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
image1 = frame.copy()
cv2.drawContours(image1, contours, -1, (0, 255, 0), 5)
# 筛选出车牌位置的轮廓
# 这里我只做了一个车牌的长宽比在3:1到4:1之间这样一个判断
for item in contours:
# cv2.boundingRect用一个最小的矩形,把找到的形状包起来
rect = cv2.boundingRect(item)
x = rect[0]
y = rect[1]
weight = rect[2]
height = rect[3]
# 440mm×140mm
if (weight > (height * 2.5)) and (weight < (height * 4)):
# image = frame[y:y + height, x:x + weight]
cv2.rectangle(frame, (x, y), (x + weight, y + height), (0, 0, 255), 2) # 画出矩形
cv2.imshow('rawImage', frame)
while cap.isOpened(): # 循环读取每一帧
ret_flag, frame = cap.read() # 返回两个参数,第一个是bool是否正常打开,第二个是照片数组,如果只设置一个则变成一个tuple包含bool和图片
# 主线程
cv2.imshow('rawImage', frame)
t = threading.Thread(target=deal, name='funThread', args=(frame,))
# 子线程
t.start() # 启动线程
t.join() # 调用join方法,主线程等待t线程结束
if cv2.waitKey(1) == 27: # Esc退出
break
cap.release() # 释放摄像头
cv2.destroyAllWindows() # 删除建立的全部窗口
画面其实比之前流畅了很多,基本是实时的。