使用 python3.8.x,opencv
问题描述
- 使用图像处理技术,从照片中识别硬币的个数,并判断总价值。
设计思路1
使用简单特征识别
- 使用颜色特征,识别出5角硬币
- 使用半径大小,判断出1角和1元硬币。
具体操作
- 将图片转换为HSV颜色模型
hsv = cv2.cvtColor(imgROI, cv2.COLOR_BGR2HSV)
lowerYellowHSV = np.array([11,43,46])
upperYellowHSV = np.array([34,255,255])
mask=cv2.inRange(hsv,lowerb=lowerYellowHSV,upperb=upperYellowHSV)/255
部分代码
def coinSimpleDetection(img,circlesVector):
# 简单识别,利用硬币的色彩和半径进行区分
circlesNum = circlesVector.shape[0]
# 将图片裁剪出来
candidateImage = {}
for i in range(circlesNum):
information = {"radius":0,"value":0}
col,row,radius = circlesVector[i,:]
imgTemp = img.copy()
imgROI = imgTemp[row-radius:row+radius,col-radius:col+radius,:]
information["radius"] = radius
# 识别5角硬币
hsv = cv2.cvtColor(imgROI, cv2.COLOR_BGR2HSV)
lowerYellowHSV = np.array([11,43,46])
upperYellowHSV = np.array([34,255,255])
mask=cv2.inRange(hsv,lowerb=lowerYellowHSV,upperb=upperYellowHSV)/255
if np.sum(np.array(mask))/((row+2*radius)*(col+2*radius)) > 0.05:
information["value"] = 0.5
# 根据半径判断1块,新旧1角硬币
if information["value"] == 0:
if information["radius"] > 180 and information["radius"] < 250:
information["value"] = 0.1
if information["radius"] > 250 and information["radius"] < 300:
information["value"] = 1.0
candidateImage.update({i:information})
cionsValue = np.sum([candidateImage[k]["value"] for k in range(circlesNum)])
return candidateImage,cionsValue
设计思路2
模板匹配
- 提取轮廓信息
cv2.findContours()
- 拟合椭圆,提取ROI
cv2.fitEllipse()
- 模板匹配
cv2.matchTemplate()
- 选取最优匹配
源码
模板制作
有同学说不知道如何制作模板,其实,只需要将上面所说的模板匹配过程执行一半,获取到ROI之后,分别保存下来即可。
我把模板制作代码完整地贴出来吧文章来源:https://www.toymoban.com/news/detail-786749.html
"""
模板制作
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 参数给定
numOfTimeToBlur = 3 # 去噪次数
blurKernelSize = 5 # 去噪核大小
cannyThreshold = 100 # canny 算子的低阈值
cannyThreshold2 = 2*cannyThreshold # canny 算子的高阈值,一般为低阈值的2~3倍
minAreaOfCircle = 800 # 最小圆形面积
numberOfTemplates = 8
threshold1=[50,50,50,50,20,30,40,30]
threshold2=[120,120,120,120,40,60,80,60]
# 图片路径
sourceImgPath = ".\\coin Image\\Test Image\\coin.jpg"
templateImgPath = ".\\coin Image\\Template Images\\"
if __name__ == "__main__":
# 0.1 图像读取
sourceImg = cv2.imread(sourceImgPath,cv2.IMREAD_COLOR)
contourFilledWithColorImg = sourceImg.copy()
# 1.1 转换为灰度图
sourceImgGray = cv2.cvtColor(sourceImg,cv2.COLOR_BGR2GRAY)
# 1.2 图像去噪
for i in range(0,numOfTimeToBlur):
sourceImgGray = cv2.GaussianBlur(sourceImgGray,(blurKernelSize,blurKernelSize),2.0,2.0)
# 1.3 Canny 边缘检测
sourceImgCanny = cv2.Canny(sourceImgGray,cannyThreshold,cannyThreshold2)
# 1.4 膨胀canny图像
dilationKernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3),(1,1))
cv2.dilate(sourceImgCanny,dilationKernel,sourceImgCanny)
# 1.5 在边缘中找轮廓
# CV_RETR_EXTERNAL只检测最外围轮廓
# CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息
contours, _ = cv2.findContours(sourceImgCanny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# 2 遍历每一个找到的轮廓
matchingContours = []
for currentContour in range(0,len(contours)):
# 2.1 轮廓拐点小于5或者小于最小面积限制,跳过
if len(contours[currentContour]) < 5 or cv2.contourArea(contours[currentContour])<= minAreaOfCircle:
continue
# 2.2 创建形状包围轮廓,得到轮廓的边界矩形的顶点和其相反点
# boundingRectVals = cv2.boundingRect(contours[currentContour]) # x y w h
boundingRect_x,boundingRect_y,boundingRect_w,boundingRect_h = cv2.boundingRect(contours[currentContour])
p1 = (boundingRect_x,boundingRect_y)
p2 = (boundingRect_x+boundingRect_w,boundingRect_y+boundingRect_h)
bottom = (boundingRect_x,boundingRect_y + boundingRect_h + 50)
# 2.3 求轮廓的外接椭圆
ellipse = cv2.fitEllipse(contours[currentContour]) # [ (x, y) , (a, b), angle ] 椭圆中心位置,长短轴,旋转角度
# 2.4 用红色绘制外接椭圆
# 【这里进行绘制,会导致patch中有红色线,故将其移动到保存patch之后】
# cv2.ellipse(sourceImg,ellipse,(0,0,255),3,cv2.LINE_AA)
# 3 模板匹配
# 3.1 创建与轮廓周围的边界矩形大小相同的patch
patch = np.zeros((boundingRect_h,boundingRect_w,3),np.uint8)
# 3.2 为轮廓区域填充颜色
cv2.ellipse(contourFilledWithColorImg,ellipse,(111,222,111),cv2.FILLED,cv2.LINE_AA)
# 3.3 创建填充的patch,用于从图像中提取硬币而忽略背景
patchFilled = patch.copy()
# 3.4 提取轮廓范围内的像素到patch
sourceRow = boundingRect_y
for patchRow in range(patch.shape[0]):
sourceCol = boundingRect_x
for patchCol in range(patch.shape[1]):
patchFilled[patchRow,patchCol,:] = contourFilledWithColorImg[sourceRow,sourceCol,:]
if patchFilled[patchRow,patchCol,0] == 111 and patchFilled[patchRow,patchCol,1] == 222 and patchFilled[patchRow,patchCol,2] == 111:
patch[patchRow,patchCol,:] = sourceImg[sourceRow,sourceCol,:]
sourceCol += 1
sourceRow += 1
# 3.5 保存每一个patch为模板
fpath = templateImgPath + "{}.jpg".format(currentContour)
print(fpath)
cv2.imwrite(fpath,patch)
# 用红色绘制外接椭圆
cv2.ellipse(sourceImg,ellipse,(0,0,255),3,cv2.LINE_AA)
cv2.namedWindow("sourceImg",cv2.WINDOW_NORMAL|cv2.WINDOW_KEEPRATIO)
cv2.imshow("sourceImg",sourceImg)
cv2.waitKey(0)
完整代码
链接
https://download.csdn.net/download/weixin_44545174/87391095文章来源地址https://www.toymoban.com/news/detail-786749.html
到了这里,关于【python-opencv】硬币检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!