简易零钱分类程序

6b0409107fa3322c222ffc4ea700c42e.jpeg

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

预处理

使用函数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

83b5b81a66fc6a8b462ed9e4cbdbcfc2.jpeg

确认分类情况

把输出的数字利用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, (0, 255, 255), 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)
00293364f47feada261b909259ed4d68.jpeg

关于颜色分类的测试

先截取硬币的部分面积进行分析,产生同时分别有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)))
d687a637fdfa7ba674fcdf184a442433.jpeg

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)
c2512b265067be17878e815b6e04c800.jpeg

改进与愿景

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

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

☆ END ☆

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

扫描二维码添加小编↓

8e06a96465c97858286fdfbed0554802.jpeg

相关推荐

  1. 简易C语言词法分析程序

    2024-03-23 09:02:04       40 阅读
  2. HTML程序大全(1):简易计算器

    2024-03-23 09:02:04       60 阅读
  3. C++案例四:简易记事本程序

    2024-03-23 09:02:04       24 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-23 09:02:04       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-23 09:02:04       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-23 09:02:04       87 阅读
  4. Python语言-面向对象

    2024-03-23 09:02:04       96 阅读

热门阅读

  1. Python 很简单。 Go 很简单。简单!=简单。

    2024-03-23 09:02:04       43 阅读
  2. S29GL064S的数据手册

    2024-03-23 09:02:04       34 阅读
  3. String类(一)

    2024-03-23 09:02:04       51 阅读
  4. 深入解析Oracle数据库的Buffer Cache

    2024-03-23 09:02:04       35 阅读
  5. [C语言]memcpy memmove的模拟实现 memcmp memset解析

    2024-03-23 09:02:04       43 阅读
  6. 查找DNS解析记录

    2024-03-23 09:02:04       40 阅读
  7. Unity 获取鼠标滚轮信息的一些方法

    2024-03-23 09:02:04       44 阅读