本代码是用于硬币识别
可以看到左图中共有三个五元硬币,一个一元硬币,以及三个两元硬币,Rs为22
当右图中新加入一个五元硬币,可以看到Rs变为28
接下来将简述该代码的各个部分。
cap = cv2.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)
cap = cv2.VideoCapture(0)
VideoCapture()中参数是0,表示打开笔记本的内置摄像头
若想打开指定视频,则cap = cv2.VideoCapture(“视频路径”)
cv2.set(propId, value)
用于设置摄像头
propId:设置的视频参数,类型:整数,
参数详情可参考(85条消息) cv2.VideoCapture.get、set详解_videocapture set_液压姬的博客-CSDN博客
value: 设置的参数
返回值:bool值:true:不能确保摄像头已接受属性值// flase:摄像头未接受属性值
该处使用的
cap.set(3, 640)指把视频流的帧(图片)的宽度调成480,3在视频流的帧的宽度,480为高度数值
cap.set(4, 480)指把视频流的帧(图片)的高度调成480,4在视频流的帧的高度,480为宽度的数值
while True:
success, img = cap.read()
cv2.imshow("Image", imgStacked)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
该段表示读取cap视频,并且利用循环持续遍历视频帧,
cap.read()
该函数有两个返回值,success指读取是否成功,img存储读取到的序列。
cv2.waitKey(1)在有按键按下的时候返回按键的ASCII值,否则返回-1
& 0xFF的按位与操作只取cv2.waitKey(1)返回值最后八位,因为有些系统cv2.waitKey(1)的返回值不止八位,ord(‘q’)表示q的ASCII值
该段用于按下q键后break
def preProcessing(img):
imgPre = cv2.GaussianBlur(img, (5, 5), 3)
thresh1 = cv2.getTrackbarPos("Threshold1", "Settings")
thresh2 = cv2.getTrackbarPos("Threshold2", "Settings")
imgPre = cv2.Canny(imgPre, thresh1, thresh2)
kernel = np.ones((3, 3), np.uint8)
imgPre = cv2.dilate(imgPre, kernel, iterations=1)
imgPre = cv2.morphologyEx(imgPre, cv2.MORPH_CLOSE, kernel)
return imgPre
该函数对img进行处理,返回值为imgPre,首先对imgPre进行高斯去噪
可参考(85条消息) 机器视觉——图像平滑处理_几乎几乎的博客-CSDN博客
cv2.GaussianBlur(img, (5, 5), 3)
指对img进行处理,高斯矩阵长宽都为5,标准差取3
cv2.getTrackbarPos("Threshold1", "Settings")
用于读取滑动条,通过滑动滑块,改变 getTrackbarPos的值,并赋值给参数,该处第一个参数为创建的 Trackbar 名称,第二个参数为运行时打开的窗口名称,窗口创建下面再讲,
cv2.Canny(imgPre, thresh1, thresh2)
用于边缘检测,第一个参数为输入的图像,后两个参数分别为处理过程中的第一二的参数
不难看出,当thresh1, thresh2数值较小时,可以捕获更多的边缘信息
np.ones((3, 3), np.uint8)
dilate(imgPre, kernel, iterations=1)
morphologyEx(imgPre, cv2.MORPH_CLOSE, kernel)
以上函数代表对图像进行腐殖操作,具体使用以及介绍可参见(85条消息) 计算机视觉-腐殖&膨胀操作_几乎几乎的博客-CSDN博客(85条消息) 计算机视觉--开闭运算,梯度运算,黑帽礼帽_几乎几乎的博客-CSDN博客
def empty(a):
pass
cv2.namedWindow("Settings")
cv2.resizeWindow("Settings", 640, 240)
cv2.createTrackbar("Threshold1", "Settings", 219, 255, empty)
cv2.createTrackbar("Threshold2", "Settings", 233, 255, empty)
创建窗口与滑动条
如图,创建了一个名为Settings的窗口,并且该窗口拥有两个滑动条,每个滑动条的数值上限为255,默认值分别为219,233,窗口大小为640*240,回调参数为empty即跳过,empty中的参数a为滑动条的当前值。
while True:
success, img = cap.read()
imgPre = preProcessing(img)
imgContours, conFound = cvzone.findContours(img, imgPre, minArea=20)
totalMoney = 0
imgCount = np.zeros((480, 640, 3), np.uint8)
if conFound:
for count, contour in enumerate(conFound):
peri = cv2.arcLength(contour['cnt'], True)
approx = cv2.approxPolyDP(contour['cnt'], 0.02 * peri, True)
if len(approx) > 5:
area = contour['area']
x, y, w, h = contour['bbox']
imgCrop = img[y:y + h, x:x + w]
# cv2.imshow(str(count),imgCrop)
imgColor, mask = myColorFinder.update(imgCrop, hsvVals)
whitePixelCount = cv2.countNonZero(mask)
# print(whitePixelCount)
if area < 2050:
totalMoney += 5
elif 2050 < area < 2500:
totalMoney += 1
else:
totalMoney += 2
# print(totalMoney)
cvzone.putTextRect(imgCount, f'Rs.{totalMoney}', (100, 200),scale=10,offset=30,thickness=7)
imgStacked = cvzone.stackImages(0.5,([img, imgPre],[imgContours,imgCount]))#把图像拼接到一起
cvzone.putTextRect(imgStacked, f'Rs.{totalMoney}', (50, 50))
cv2.imshow("Image", imgStacked)
cv2.findContours()
用于轮廓检测,其两个返回值分别代表轮廓本身及每条轮廓所对应的属性
关于函数介绍可参见
(85条消息) cv2.findContours() 轮廓检测_cv2轮廓检测_Easennn的博客-CSDN博客
通过轮廓检测,当该轮廓切割线条大于五即认定目标,而后计算其面积,通过面积判断硬币面值,最后以Rs值作为结果输出。
myColorFinder = ColorFinder(False)
# Custom Orange Color
hsvVals = {'hmin': 0, 'smin': 0, 'vmin': 145, 'hmax': 63, 'smax': 91, 'vmax': 255}
用于颜色检测,当硬币面值不同,大小相同时可用。
详情可见(88条消息) HSV颜色空间中颜色(红、黄、绿、 青、蓝、紫、 粉红、 砖红、 品红)对应的灰度范围_hsv颜色对照表_胖子工作室的博客-CSDN博客
最后附上完整代码
# -*- coding: utf-8 -*-
"""
Created on Tue May 23 17:27:19 2023
@author: Victor
"""
import cv2
import cvzone
import numpy as np
from cvzone.ColorModule import ColorFinder
cap = cv2.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)
totalMoney = 0
myColorFinder = ColorFinder(False)
# Custom Orange Color
hsvVals = {'hmin': 0, 'smin': 0, 'vmin': 145, 'hmax': 63, 'smax': 91, 'vmax': 255}
def empty():
pass
cv2.namedWindow("Settings")
cv2.resizeWindow("Settings", 640, 240)
cv2.createTrackbar("Threshold1", "Settings", 219, 255, empty)
cv2.createTrackbar("Threshold2", "Settings", 233, 255, empty)
def preProcessing(img):
imgPre = cv2.GaussianBlur(img, (5, 5), 3)
thresh1 = cv2.getTrackbarPos("Threshold1", "Settings")
thresh2 = cv2.getTrackbarPos("Threshold2", "Settings")
imgPre = cv2.Canny(imgPre, thresh1, thresh2)
kernel = np.ones((3, 3), np.uint8)
imgPre = cv2.dilate(imgPre, kernel, iterations=1)
imgPre = cv2.morphologyEx(imgPre, cv2.MORPH_CLOSE, kernel)
return imgPre
while True:
success, img = cap.read()
imgPre = preProcessing(img)
imgContours, conFound = cvzone.findContours(img, imgPre, minArea=20)
totalMoney = 0
imgCount = np.zeros((480, 640, 3), np.uint8)
if conFound:
for count, contour in enumerate(conFound):
peri = cv2.arcLength(contour['cnt'], True)
approx = cv2.approxPolyDP(contour['cnt'], 0.02 * peri, True)
if len(approx) > 5:
area = contour['area']
x, y, w, h = contour['bbox']
imgCrop = img[y:y + h, x:x + w]
# cv2.imshow(str(count),imgCrop)
imgColor, mask = myColorFinder.update(imgCrop, hsvVals)
whitePixelCount = cv2.countNonZero(mask)
# print(whitePixelCount)
if area < 2050:
totalMoney += 5
elif 2050 < area < 2500:
totalMoney += 1
else:
totalMoney += 2
# print(totalMoney)
cvzone.putTextRect(imgCount, f'Rs.{totalMoney}', (100, 200),scale=10,offset=30,thickness=7)
imgStacked = cvzone.stackImages(0.5,([img, imgPre],[imgContours,imgCount]))#把图像拼接到一起
cvzone.putTextRect(imgStacked, f'Rs.{totalMoney}', (50, 50))
cv2.imshow("Image", imgStacked)
# cv2.imshow("imgColor", imgColor)
#cv2.waitKey(1)
if cv2.waitKey(1) & 0xFF == ord('q'):
break