简易零钱分类程序

本程序主要利用影像处理,以及影像色彩统计并加以分析的方式,对台币进行分类标记。

预处理

使用函数HoughCircles 来侦测圆边,其中大多数数值都需要手动调整来提高标记的正确率,进行消除噪声的前处理可以减少误判的情况。

关于函数使用可参考以下官方网址:

https://docs.opencv.org/master/da/d53/tutorial_py_houghcircles.html

cv2.HoughCircles(image,method,dp,minDist[, circles[,param1, param2[,minRadius[,maxRadius]]]])

image:输入矩阵

method:cv2.HOUGH_GRADIENT 霍夫圆检测,梯度法

dp:计数器的分辨率图像像素分辨率与参数空间分辨率的比值

minDist:圆心之间最小距离,如果距离太小,会产生很多相交的圆,如果距离太大,则会漏掉正确的圆

param1:canny检测的双阈值中的高阈值,低阈值是它的一半

param2:最小投票数(基于圆心的投票数)

minRadius:需要检测圆的最小半径

maxRadius:需要检测圆的最大半径

import numpy as np              #處理list跟數值的常用模組
import cv2 as cv
from google.colab.patches import cv2_imshow #colab所使用的imshow
import matplotlib.pyplot as plt       #畫圖用
from PIL import Image

img = cv.imread('coins.jpg')
imgGlay = cv.imread('coins.jpg',0)      #載入灰階圖片

imgGlay = cv.medianBlur(imgGlay,5)      #消除噪訊
cimg = cv.cvtColor(imgGlay,cv.COLOR_GRAY2BGR)
circles = cv.HoughCircles(imgGlay,cv.HOUGH_GRADIENT,1,25,param1=30,param2=40,minRadius=30,maxRadius=70#偵測圓圈
circles = np.uint16(np.around(circles))

统计硬币的半径

利用硬币半径先将硬币大致进行分类,本次测试只有1 5 10 元,因此只从图表中间进行切割,当然如果有50元的话也可以利用类似比例切割的方法,因为在固定比例的情况下相机的误差有限。

其中输出的数值xy 为图片上坐标,r 为半径单位像素。

array = []
for i in circles[0,:]:
  array.append(i[2])
  print('x = {:>4d} y = {:>4d} r = {:>3d}'.format(i[0],i[1],i[2]))  #數值整形

mid = (max(array)+min(array))/2
print("mid = {:.2f}".format(mid))

import matplotlib.pyplot as plt    #直方圖繪製
plt.hist(array,10)            #只有10條的模糊直方圖
plt.xlabel('coins size (pt)')   #標籤
plt.ylabel('amount')
plt.title('Coins size and amount')
plt.show()

x = 94 y = 410 r = 58
x = 212 y = 552 r = 57
x = 260 y = 96 r = 53 x =
244 y = 324 r = 56
x = 242 y = 198 r = 44 x
= 224 y = 428 r = 44
x = 408 y = 236 r = 46
x = 334 y = 470 r = 44
x = 116 y = 280 r = 43
x = 376 y = 136 r = 42
x = 352 y = 318 r = 41
x = 108 y = 110 r = 44
mid = 49.50

确认分类情况

把输出的数字利用for的方式绘制在图片上,为了方便人工侦错把list序号也标记上去。

imgd = cv.imread('coins.jpg')
flag = 0
for i in circles[0,:]:  #直接迭代資料
  text = str(flag)  #產生文字編號

  #繪制文字
  cv.putText(imgd, text, (i[0]-5, i[1]+5), cv.FONT_HERSHEY_SIMPLEX, .7, (0255255), 1, cv.LINE_AA)

  #繪制圓圈
  if i[2] > mid:
    cv.circle(imgd,(i[0],i[1]),i[2],(0,255,0),2)
  else :
    cv.circle(imgd,(i[0],i[1]),i[2],(255,0,0),2)
  flag += 1

cv2_imshow(imgd)

关于颜色分类的测试

先截取硬币的部分面积进行分析,产生同时分别有RGB统计的直方图(这跟Photoshop上的直方图功能是同一个原理)。

可以发现蓝色绿色的总量,在1元铜色的情况下比例会比5元或是10元银色的比例低,所以可以利用这项特性来分类两种颜色的硬币。

这边是用中位数找比值,可以修改flag数值观察。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
src= Image.open('coins.jpg')
flag = 8
cropPict = src.crop((circles[0,flag][0]-30, circles[0,flag][1]-30, circles[0,flag][0]+30, circles[0,flag][1]+30)) #截取
r,g,b=cropPict.split()

# 統計RGB總量直方圖
ar=np.array(r).flatten()
plt.hist(ar, bins=256, density=True,facecolor='r',edgecolor='r')
ag=np.array(g).flatten()
plt.hist(ag, bins=256, density=True, facecolor='g',edgecolor='g')
ab=np.array(b).flatten()
plt.hist(ab, bins=256, density=True, facecolor='b',edgecolor='b')
plt.show()

print(np.median(np.array(r)))
print(np.median(np.array(g)))
print(np.median(np.array(b)))

143.0
116.0
101.0

开始分类

利用前述之方式进行分类,公式只是很简单的除比例。

这边只使用了手工的方式输入分类比例为1.3,并产生一个手动计算的list。

coinCategory = []

for i in circles[0,:]:
  cropPict = src.crop((i[0]-30, i[1]-30, i[0]+30, i[1]+30)) #截取
  r,g,b=cropPict.split()

  #統計中位數
  medR = np.median(np.array(r))
  medG = np.median(np.array(g))
  medB = np.median(np.array(b))
  #print(medR, medG, medB)

  rate = medR /((medG + medB) / 2)  #比例
  if rate < 1.3 :
    coinCategory.append(1)  #白銀色就 1
    print('{:.2f} , it is white'.format(rate))
  else :
    coinCategory.append(0)  #銅色就 0
    print('{:.2f}'.format(rate))

print('coinCategory {}'.format(coinCategory))

1.09 , it is white
1.25 , it is white
1.08 , it is white
1.19 , it is white
1.34
1.47
1.08 , it is white
1.15 , it is white
1.32
1.33
1.49
1.31
coinCategory [1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0]

成品

利用同样的绘图方式,把分类好的数字画上去就完成分类了!

imgd = cv.imread('coins.jpg')
flag = 0
for i in circles[0,:]:
  if i[2] > mid: #判斷半徑中值
    cv.putText(imgd, '10', (i[0]-5, i[1]+5), cv.FONT_HERSHEY_SIMPLEX, .7, (0,255,0), 1, cv.LINE_AA) #繪制文字
    cv.circle(imgd,(i[0],i[1]),i[2],(0,255,0),2)  #繪制圓圈
  else :
    text = str(1 + coinCategory[flag] * 4)  #判斷顏色
    cv.putText(imgd, text, (i[0]-5, i[1]+5), cv.FONT_HERSHEY_SIMPLEX, .7, (255,coinCategory[flag]*255,0), 1, cv.LINE_AA)  #繪制文字
    cv.circle(imgd,(i[0],i[1]),i[2],(255,coinCategory[flag]*255,0),2#繪制圓圈
  flag += 1
cv2_imshow(imgd)

改进与愿景

HoughCircles并不是一个「聪明的」函数,它只能应付一些比较干净没有太多杂物的图片。如果图片受到光线影响可能又会严重影响精度,所以目前本程序的应用能力有限。

颜色怎么判断也是值得再深入研究的部分,比如利用寻找峰值函数peak去处理,甚至寻找特征来提高程序的鲁棒性,这样,程序就可能可以不再限于某一两种货币而是一个通用的工具了。


☆ END ☆如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文扫描二维码添加小编↓

相关推荐

  • 国产大模型Kimi爆火到「宕机」;李想发内部信反思MEGA失利;Stable Diffusion核心团队被曝集体离职|极客头条
  • 突发!告 iPhone 垄断,美国政府起诉苹果
  • 年度问卷 | 智能推荐系统用户调研
  • 新版 Redis 将不再“开源”引争议:本想避免云厂商“白嫖”,却让开发者遭到“背刺”!
  • Redis不再 “开源”
  • Kimi,今年的VC之光
  • 马斯克的星舰项目到底哪里伟大了?
  • LLM、RAG虽好,但XGBoost更香!
  • 宋东桓:Sora可能会颠覆好莱坞,但优秀更取决于想象力 |T前线
  • 股票涨停、泼天流量,Kimi受宠若惊到宕机:预计25日恢复,200万无损窗口实测:好用!不失优秀、免费的国产大模型产品!
  • 分库分表设计及常见问题
  • 全网独家“Java面试+进阶学习”资源合集,手慢则无!
  • 今日代码 PK | 使用 try-with-resources 关闭资源
  • 面试被拷打,真面不动了。。。
  • 我们公司的春招来啦!
  • 从 AI 和数据要素角度聊聊“新质生产力”对企业数字化转型的影响
  • openEuler 学习赛等你来战:解锁开源之力,赢取丰厚奖品!| Q推荐
  • 打造一个成本优先的技术架构,可以分几步?| ArchSummit
  • 我用十几年时间自创了两门编程语言,它们都还挺知名
  • 新一代“汽车人”不智能,汽车怎么智能?| 极客时间