识别硬币和细胞数量+条形码检测(python+opencv)

如愿

  • 一、准备工作
  • 二、硬币和细胞数量识别
  • 三、条形码定位和识别
  • 四、总结
  • 五、参考资料

一、准备工作

  • 所用图片
    识别硬币和细胞数量+条形码检测(python+opencv)_第1张图片
    识别硬币和细胞数量+条形码检测(python+opencv)_第2张图片
    识别硬币和细胞数量+条形码检测(python+opencv)_第3张图片
  • python版本以及opencv版本

python 3.8.12 opencv 3.4.11

二、硬币和细胞数量识别

  • 原理
  1. 用opencv读取图片,读取之后并进行灰度化和二值化
  2. 二值化之后存储图片的二维列表里的值全为0和1,进行膨胀和腐蚀等操作使图像的轮廓更明显
  3. 较为明显之后使用findContours,发现的轮廓数就是我们要求的数量
  • 开始代码操作,导入库并定义文件路径
#导入相关包
import cv2
import numpy as np
import os
#定义文件路径
source_path='..\\source\\AI_digital_image\\'
cell_file="cell.png"
coin_file="coin.png"
  • 构建完整路径并读取图片,图片我就不放了,自己运行看看就知道了,算了图片还是放代码后面,自己看看
#得到完整路径
cell_path=source_path+cell_file
coin_path=source_path+coin_file  
#读取文件
cell_read=cv2.imread(cell_path)
coin_read=cv2.imread(coin_path)
cv2.imshow("cell",cell_read)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第4张图片

  • 先进行细胞数量提取,这里进行了灰度化,而且手动调了一波亮度,因为这张图片上下的亮度不一致,不调整的话二值化得出来的效果不太好
#进行灰度化
cell_gauss=cv2.GaussianBlur(cell_read,(5,5),0)#高斯降噪
cell_gray=cv2.cvtColor(cell_gauss,cv2.COLOR_BGR2GRAY)#灰度化
cell_att=cell_gray
cv2.waitKey(0)
#上半部分亮度太低,手动增加
for j in range(3,342):
    low=int(sum(cell_gray[j]))
    high=int(sum(cell_gray[335]))
    add=(high-low)/len(cell_read[3])
    for i in range(len(cell_read[3])):
        if int(cell_att[j][i])+add>255:
             cell_att[j][i]=255
        else :
            cell_att[j][i]+=add
cv2.imshow("cell",cell_att)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第5张图片

识别硬币和细胞数量+条形码检测(python+opencv)_第6张图片

  • 二值化
thre,cell_bw=cv2.threshold(cell_att,170,255,cv2.THRESH_BINARY_INV)#二值化
cv2.imshow("cell",cell_bw)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第7张图片

  • 细胞的图片感觉应该是血液的样本,不然为啥这么多血红细胞,血红细胞中间是空的,灰度化之后会有小空洞,先用闭运算来填补这些空的地方
#闭运算,填充空洞
#构造一个全1的5*5的矩阵
kernel=np.ones((3,3),int)#设置形态学操作卷积的大小
cell_close=cv2.morphologyEx(cell_bw,cv2.MORPH_CLOSE,kernel)
cv2.imshow("cell",cell_close)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第8张图片

  • 开运算作用:用来消除小的物体,平滑形状边界,并且不改变其面积。可以去除小颗粒噪声,断开物体间的粘连
#开运算
#构造一个全1的5*5的矩阵
kernel=np.ones((11,11),int)#设置形态学操作卷积的大小
cell_open=cv2.morphologyEx(cell_close,cv2.MORPH_OPEN,kernel)
cv2.imshow("cell",cell_open)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第9张图片

  • 开运算之后再进行腐蚀,将两个细胞之间的间隔再拉大一点,同时把那些重叠的地方再细化
#腐蚀运算
#构造一个全1的5*5的矩阵
kernel=np.ones((20,20),int)#设置形态学操作卷积的大小
cell_corr=cv2.erode(cell_open,kernel,iterations=1)
cv2.imshow("cell",cell_corr)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第10张图片

  • 再进行开运算,把细化的重叠部分也断掉
#开运算
#构造一个全1的5*5的矩阵
kernel=np.ones((10,10),int)#设置形态学操作卷积的大小
cell_close2=cv2.morphologyEx(cell_corr,cv2.MORPH_OPEN,kernel)
cv2.imshow("cell",cell_close2)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第11张图片

  • 利用opencv的findcontours获取轮廓,返回的cell_count就是轮廓的数组,长度就是细胞的数量,只要求求数量,绘图时的轮廓就偷懒了,表示个意思就行
image,cell_count,hir=cv2.findContours(cell_close2,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#检测所有轮廓,所有轮廓建立一个等级树结构。
print(len(cell_count))
cell_read=cv2.imread(cell_path)
result = cv2.drawContours(cell_read, cell_count, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第12张图片

  • 接下来就是硬币数量检测了,这个简单多了,刚刚读取了,这里进行灰度化和二值化
#进行灰度化和二值化
coin_gauss=cv2.GaussianBlur(coin_read,(5,5),0)#高斯降噪
coin_gray=cv2.cvtColor(coin_gauss,cv2.COLOR_BGR2GRAY)#灰度化
thre,coin_bw=cv2.threshold(coin_gray,150,255,cv2.THRESH_BINARY_INV)#二值化
cv2.imshow("coin",coin_bw)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第13张图片

  • 开始以为还要一次开运算,这里直接腐蚀效果就很好了
#腐蚀运算
#构造一个全1的5*5的矩阵
kernel=np.ones((20,20),int)#设置形态学操作卷积的大小
coin_corr=cv2.erode(coin_bw,kernel,iterations=1)
cv2.imshow("cell",coin_corr)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第14张图片

  • 获取数量
image,coin_count,hir=cv2.findContours(coin_corr,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#检测所有轮廓,所有轮廓建立一个等级树结构。
print(len(coin_count))
coin_read=cv2.imread(coin_path)
result = cv2.drawContours(coin_read, coin_count, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第15张图片

三、条形码定位和识别

  • 定位就不调用库了,用opencv实现
#导入库
import cv2
  • 读取文件
bar_code_path='..\\source\\picture\\bar_code\\code_bar.jpg'
bar_code=cv2.imread(bar_code_path)
bar_code=cv2.resize(bar_code,(500,300))
cv2.imshow('src',bar_code)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第16张图片

  • 转化为灰度图
#转化为灰度图
bar_code_gray=cv2.cvtColor(bar_code,cv2.COLOR_BGR2GRAY)
cv2.imshow('gray',bar_code_gray)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第17张图片

  • 高斯平滑滤波
# 高斯平滑滤波
bar_code_gauss=cv2.GaussianBlur(bar_code_gray,(3,3),0)
cv2.imshow('gauss',bar_code_gauss)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第18张图片

  • 求水平和垂直的梯度差,使用sobel算子,这里好像直接相减有些问题,可能是opencv在python里的存储类型和在c++里不一样,小于0的话就变成200+了

#求水平方向和垂直方向的梯度差,使用sobel算子
bar_code_h=cv2.Sobel(bar_code_gauss,cv2.CV_64F,1,0,ksize=3,scale=1,delta=0,borderType=4)
bar_code_v=cv2.Sobel(bar_code_gauss,cv2.CV_64F,0,1,ksize=3,scale=1,delta=0,borderType=4)
#从16位转化为8位
bar_code_x=cv2.convertScaleAbs(bar_code_h,alpha=1,beta=0)
bar_code_y=cv2.convertScaleAbs(bar_code_v,alpha=1,beta=0)
bar_code_xy=bar_code_x
for i in range(len(bar_code_x)):
    for j in range(len(bar_code_x[0])):
        if int(bar_code_x[i][j])-(bar_code_y[i][j])>=0:
            bar_code_xy[i][j]=bar_code_x[i][j]-bar_code_y[i][j]
        else:
            bar_code_xy[i][j]=0
cv2.imshow('x',bar_code_x)
cv2.waitKey(0)
cv2.imshow('y',bar_code_y)
cv2.waitKey(0)
cv2.imshow('xy',bar_code_xy)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第19张图片
识别硬币和细胞数量+条形码检测(python+opencv)_第20张图片
识别硬币和细胞数量+条形码检测(python+opencv)_第21张图片

  • 均值滤波
#均值滤波
bar_code_blur=cv2.blur(bar_code_xy,(3,3))
cv2.imshow('blur',bar_code_blur)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第22张图片

  • 二值化
#二值化
thr,bar_code_th=cv2.threshold(bar_code_blur,170,255,cv2.THRESH_BINARY)
cv2.imshow('threshold',bar_code_th)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第23张图片

  • 闭运算,填充条形码间隙
#闭运算,填充条形码间隙
import numpy as np
kernel=np.ones((7,7),int)#设置形态学操作卷积的大小
bar_code_close=cv2.morphologyEx(bar_code_th,cv2.MORPH_CLOSE,kernel)
cv2.imshow('close',bar_code_close)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第24张图片

  • 腐蚀,消除旁边的小白点
#腐蚀
kernel=np.ones((7,7),int)#设置形态学操作卷积的大小
bar_code_ero=cv2.erode(bar_code_close,kernel)
cv2.imshow('erode',bar_code_ero)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第25张图片

  • 膨胀使条码连起来
#膨胀
bar_code_dia=cv2.dilate(bar_code_ero,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
bar_code_dia=cv2.dilate(bar_code_dia,kernel)
cv2.imshow('dilate',bar_code_dia)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第26张图片

  • 定位,这偏差有点迷,可能使计算梯度差时造成的
image,barcode,hir=cv2.findContours(bar_code_dia,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#检测所有轮廓,所有轮廓建立一个等级树结构。
barcode_read=cv2.imread(bar_code_path)
result = cv2.drawContours(barcode_read, barcode, -1 ,(0, 255, 0), 1)
cv2.imshow('I',result)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第27张图片

  • 识别条形码的话可以自己手动排查,也可以调用库,这里就偷懒一下,调用pyzbar库实现
#调用条码库进行条码识别
import pyzbar.pyzbar as pyzbar
import cv2
bar_code_path='..\\source\\picture\\bar_code\\code_bar.jpg'
srcImg = cv2.imread(bar_code_path)
cv2.imshow("Image", srcImg)
barcodes = pyzbar.decode(srcImg)
for barcode in barcodes:
    barcodeData = barcode.data.decode("utf-8")
    print(barcodeData)
cv2.waitKey(0)

识别硬币和细胞数量+条形码检测(python+opencv)_第28张图片

四、总结

  • 经过上面这些例子,大概明白了对图像的操作都是提取出需要的元素,然后简化简化再简化,最后变为0和1,而0和1对应的就是黑和白,就十分方便处理

五、参考资料

Opencv:10个步骤检测出图片中条形码
python-opencv检测图片中鸡蛋个数/数量

你可能感兴趣的:(ai,opencv,python,计算机视觉)