100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > OpenCV+Python简单实践之硬币检测以及条形码检测

OpenCV+Python简单实践之硬币检测以及条形码检测

时间:2023-10-07 00:59:58

相关推荐

OpenCV+Python简单实践之硬币检测以及条形码检测

目录标题

一、简单图片格式1.位图2.文件压缩比二、用奇异值分解(SVD)对一张图片进行特征值提取(降维)处理1.代码2.效果三、采用图像的开闭运算(腐蚀-膨胀),检测出2个样本图像中硬币、细胞的个数1.硬币检测代码读取图片转为灰度图片图片二值化腐蚀膨胀找到硬币中心标识硬币显示结果最终结果源码2.细胞检测四、 采用图像梯度、开闭、轮廓运算等,对图片中的条形码进行定位提取;再调用条码库获得条码字符读取图片转为灰度图片高斯滤波处理Sobel算子计算梯度差均值方波消除高频噪声二值化闭运算填充空隙开运算得到最终区域绘制结果结果源码四、总结五、参考

一、简单图片格式

1.位图

把一张彩色图片分别保存为 32位、16位彩色和256色、16色、单色的位图

notepad打开位图

img1.bmp单色位图

文件头如图

img16.bmp16色位图

img256.bmp256色位图

img16rgb16位彩图

img32rgb32位彩图

位图大小计算公式为;长×高×位深度

比如下面的图,可以计算得大小约为(220×220×16)/8/1024=94.53125kb,不包括文件头等其他信息。

0~1 两个字节为文件类型,0x4d42为固定BM

2~5 四个字节为文件大小,0x184e,即6222

6~9 四个字节为保留字段,全0

a~d 四个字节为从文件头到实际的位图数据的偏移字节数

12~15 四个字节表示图片宽度,0xdc为220

16~19 四个字节表示图片高度,0xdc为220

1a~1b 两个字节,恒定为0x1

1c~1d 两个字节表示像素占的比特,这里为0x1即两种颜色,16色为0x4即16种颜色,256色为0x8即256种颜色

1e~21 四个字节表示图片是否压缩,0x0表示不压缩

22~25 四个表示图像大小,0x1810为6160

26~29 四个字节表示水平分辨率

2a~2d 四个字节表示垂直分辨率

23~31 四个字节表示实际使用的颜色索引数

32~35 四个字节表示重要的颜色索引数

可以发现文件头一共占40个字节,为十六进制。

对于不同的图片,文件大小、长、宽、像素占比都不同。

2.文件压缩比

分别保存jpg,png,gif,bmp四种格式的图片,原图为24位img.bmp,大小为468kb。

经过jpg转换后大小变为22.6kb,压缩率在5%

经过gif转换后大小变为10.9kb,压缩率在3%

经过png转换后大小变为74.1kb,压缩率在16%

经过256色位图转换后大小变为157kb,压缩率在36%

当然,这里的图片空白部分偏多,压缩率很低。

二、用奇异值分解(SVD)对一张图片进行特征值提取(降维)处理

1.代码

import numpy as npimport osfrom PIL import Imageimport matplotlib.pyplot as pltimport matplotlib as mplfrom pprint import pprintdef restore1(sigma, u, v, K): # 奇异值、左特征向量、右特征向量m = len(u)n = len(v[0])a = np.zeros((m, n))for k in range(K):uk = u[:, k].reshape(m, 1)vk = v[k].reshape(1, n)a += sigma[k] * np.dot(uk, vk)a[a < 0] = 0a[a > 255] = 255# a = a.clip(0, 255)return np.rint(a).astype('uint8')def restore2(sigma, u, v, K): # 奇异值、左特征向量、右特征向量m = len(u)n = len(v[0])a = np.zeros((m, n))for k in range(K+1):for i in range(m):a[i] += sigma[k] * u[i][k] * v[k]a[a < 0] = 0a[a > 255] = 255return np.rint(a).astype('uint8')if __name__ == "__main__":A = Image.open("./lena.jpg", 'r')print(A)output_path = r'./SVD_Output'if not os.path.exists(output_path):os.mkdir(output_path)a = np.array(A)print(a.shape)K = 50u_r, sigma_r, v_r = np.linalg.svd(a[:, :, 0])u_g, sigma_g, v_g = np.linalg.svd(a[:, :, 1])u_b, sigma_b, v_b = np.linalg.svd(a[:, :, 2])plt.figure(figsize=(11, 9), facecolor='w')mpl.rcParams['font.sans-serif'] = ['simHei']mpl.rcParams['axes.unicode_minus'] = Falsefor k in range(1, K+1):print(k)R = restore1(sigma_r, u_r, v_r, k)G = restore1(sigma_g, u_g, v_g, k)B = restore1(sigma_b, u_b, v_b, k)I = np.stack((R, G, B), axis=2)Image.fromarray(I).save('%s\\svd_%d.png' % (output_path, k))if k <= 12:plt.subplot(3, 4, k)plt.imshow(I)plt.axis('off')plt.title('奇异值个数:%d' % k)plt.suptitle('SVD与图像分解', fontsize=20)plt.tight_layout()# plt.subplots_adjust(top=0.9)plt.show()

2.效果

随着奇异值的减少图片变得模糊

三、采用图像的开闭运算(腐蚀-膨胀),检测出2个样本图像中硬币、细胞的个数

1.硬币检测代码

读取图片

#读取图片src = cv2.imread("img_1.png")img = src.copy()

原图

转为灰度图片

#灰度img_1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

图片二值化

#二值化ret, img_2 = cv2.threshold(img_1, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

腐蚀

腐蚀主要为了把每个硬币区分开。过大会造成缺失,过低会无法区分开。参数可以自己设置以达到合适。

#腐蚀kernel = np.ones((25, 25), int)img_3 = cv2.erode(img_2, kernel, iterations=1)

膨胀

膨胀到合适的值,这样每一个白色区域就是一个硬币。

#膨胀kernel = np.ones((10, 10), int)img_4 = cv2.dilate(img_3, kernel, iterations=1)

找到硬币中心

#找到硬币中心contours, hierarchy = cv2.findContours(img_4, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2:]

标识硬币

#标识硬币cv2.drawContours(img, contours, -1, (0, 0, 255), 5)

显示结果

#显示图片cv2.putText(img, "count:{}".format(len(contours)), (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(src, "src", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_1, "gray", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_2, "thresh", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_3, "erode", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_4, "dilate", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)imgStack = stackImages(0.7, ([src, img_1, img_2], [img_3, img_4, img]))cv2.imshow("imgStack", imgStack)cv2.waitKey(0)

最终结果

源码

import cv2import numpy as npdef stackImages(scale, imgArray):"""将多张图像压入同一个窗口显示:param scale:float类型,输出图像显示百分比,控制缩放比例,0.5=图像分辨率缩小一半:param imgArray:元组嵌套列表,需要排列的图像矩阵:return:输出图像"""rows = len(imgArray)cols = len(imgArray[0])rowsAvailable = isinstance(imgArray[0], list)width = imgArray[0][0].shape[1]height = imgArray[0][0].shape[0]if rowsAvailable:for x in range(0, rows):for y in range(0, cols):if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)else:imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]),None, scale, scale)if len(imgArray[x][y].shape) == 2: imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)imageBlank = np.zeros((height, width, 3), np.uint8)hor = [imageBlank] * rowshor_con = [imageBlank] * rowsfor x in range(0, rows):hor[x] = np.hstack(imgArray[x])ver = np.vstack(hor)else:for x in range(0, rows):if imgArray[x].shape[:2] == imgArray[0].shape[:2]:imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)else:imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)hor = np.hstack(imgArray)ver = horreturn ver#读取图片src = cv2.imread("img_1.png")img = src.copy()#灰度img_1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#二值化ret, img_2 = cv2.threshold(img_1, 127, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)#腐蚀kernel = np.ones((20, 20), int)img_3 = cv2.erode(img_2, kernel, iterations=1)#膨胀kernel = np.ones((3, 3), int)img_4 = cv2.dilate(img_3, kernel, iterations=1)#找到硬币中心contours, hierarchy = cv2.findContours(img_4, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[-2:]#标识硬币cv2.drawContours(img, contours, -1, (0, 0, 255), 5)#显示图片cv2.putText(img, "count:{}".format(len(contours)), (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(src, "src", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_1, "gray", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_2, "thresh", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_3, "erode", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)cv2.putText(img_4, "dilate", (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 3)imgStack = stackImages(1, ([src, img_1, img_2], [img_3, img_4, img]))cv2.imshow("imgStack", imgStack)cv2.waitKey(0)

2.细胞检测

和硬币检测原理和过程一致

四、 采用图像梯度、开闭、轮廓运算等,对图片中的条形码进行定位提取;再调用条码库获得条码字符

读取图片

#读取图片src = cv2.imread("img_3.jpg")img = src.copy()

转为灰度图片

#灰度img_1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

高斯滤波处理

#高斯滤波img_2 = cv2.GaussianBlur(img_1, (5, 5), 1)

Sobel算子计算梯度差

#Sobel算子sobel_x = cv2.Sobel(img_2, cv2.CV_64F, 1, 0, ksize=3)sobel_y = cv2.Sobel(img_2, cv2.CV_64F, 0, 1, ksize=3)sobel_x = cv2.convertScaleAbs(sobel_x)sobel_y = cv2.convertScaleAbs(sobel_y)img_3 = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)

均值方波消除高频噪声

#均值方波img_4 = cv2.blur(img_3, (5, 5))

二值化

#二值化ret, img_5 = cv2.threshold(img_4, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

闭运算填充空隙

#闭运算kernel = np.ones((100, 100), int)img_6 = cv2.morphologyEx(img_5, cv2.MORPH_CLOSE, kernel)

开运算得到最终区域

#开运算kernel = np.ones((200, 200), int)img_7 = cv2.morphologyEx(img_6, cv2.MORPH_OPEN, kernel)

绘制结果

#绘制条形码区域contours = cv2.findContours(img_7, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)contours = imutils.grab_contours(contours)c = sorted(contours, key = cv2.contourArea, reverse = True)[0]rect = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(rect) if imutils.is_cv2() else cv2.boxPoints(rect)box = np.int0(box)cv2.drawContours(img, [box], -1, (0,255,0), 20)#显示图片信息cv2.putText(img, "results", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_1, "gray", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_2, "GaussianBlur",(200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_3, "Sobel", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_4, "blur", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_5, "threshold", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_6, "close", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_7, "open", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)#输出条形码barcodes = pyzbar.decode(src)for barcode in barcodes:barcodeData = barcode.data.decode("utf-8")cv2.putText(img, barcodeData, (200, 600), cv2.FONT_HERSHEY_SIMPLEX, 5.0, (0, 255, 0), 30)#显示所有图片imgStack = stackImages(0.1, ([img_1, img_2,img_3,img_4],[img_5,img_6,img_7,img]))cv2.imshow("imgStack", imgStack)cv2.waitKey(0)

结果

源码

import cv2import numpy as npimport imutilsfrom pyzbar import pyzbardef stackImages(scale, imgArray):"""将多张图像压入同一个窗口显示:param scale:float类型,输出图像显示百分比,控制缩放比例,0.5=图像分辨率缩小一半:param imgArray:元组嵌套列表,需要排列的图像矩阵:return:输出图像"""rows = len(imgArray)cols = len(imgArray[0])rowsAvailable = isinstance(imgArray[0], list)width = imgArray[0][0].shape[1]height = imgArray[0][0].shape[0]if rowsAvailable:for x in range(0, rows):for y in range(0, cols):if imgArray[x][y].shape[:2] == imgArray[0][0].shape[:2]:imgArray[x][y] = cv2.resize(imgArray[x][y], (0, 0), None, scale, scale)else:imgArray[x][y] = cv2.resize(imgArray[x][y], (imgArray[0][0].shape[1], imgArray[0][0].shape[0]),None, scale, scale)if len(imgArray[x][y].shape) == 2: imgArray[x][y] = cv2.cvtColor(imgArray[x][y], cv2.COLOR_GRAY2BGR)imageBlank = np.zeros((height, width, 3), np.uint8)hor = [imageBlank] * rowshor_con = [imageBlank] * rowsfor x in range(0, rows):hor[x] = np.hstack(imgArray[x])ver = np.vstack(hor)else:for x in range(0, rows):if imgArray[x].shape[:2] == imgArray[0].shape[:2]:imgArray[x] = cv2.resize(imgArray[x], (0, 0), None, scale, scale)else:imgArray[x] = cv2.resize(imgArray[x], (imgArray[0].shape[1], imgArray[0].shape[0]), None, scale, scale)if len(imgArray[x].shape) == 2: imgArray[x] = cv2.cvtColor(imgArray[x], cv2.COLOR_GRAY2BGR)hor = np.hstack(imgArray)ver = horreturn ver#读取图片src = cv2.imread("img_3.jpg")img = src.copy()#灰度img_1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#高斯滤波img_2 = cv2.GaussianBlur(img_1, (5, 5), 1)#Sobel算子sobel_x = cv2.Sobel(img_2, cv2.CV_64F, 1, 0, ksize=3)sobel_y = cv2.Sobel(img_2, cv2.CV_64F, 0, 1, ksize=3)sobel_x = cv2.convertScaleAbs(sobel_x)sobel_y = cv2.convertScaleAbs(sobel_y)img_3 = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)#均值方波img_4 = cv2.blur(img_3, (5, 5))#二值化ret, img_5 = cv2.threshold(img_4, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)#闭运算kernel = np.ones((100, 100), int)img_6 = cv2.morphologyEx(img_5, cv2.MORPH_CLOSE, kernel)#开运算kernel = np.ones((200, 200), int)img_7 = cv2.morphologyEx(img_6, cv2.MORPH_OPEN, kernel)#绘制条形码区域contours = cv2.findContours(img_7, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)contours = imutils.grab_contours(contours)c = sorted(contours, key = cv2.contourArea, reverse = True)[0]rect = cv2.minAreaRect(c)box = cv2.cv.BoxPoints(rect) if imutils.is_cv2() else cv2.boxPoints(rect)box = np.int0(box)cv2.drawContours(img, [box], -1, (0,255,0), 20)#显示图片信息cv2.putText(img, "results", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_1, "gray", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_2, "GaussianBlur",(200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_3, "Sobel", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_4, "blur", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_5, "threshold", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_6, "close", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)cv2.putText(img_7, "open", (200, 200), cv2.FONT_HERSHEY_SIMPLEX, 10.0, (255, 0, 0), 30)#输出条形码barcodes = pyzbar.decode(src)for barcode in barcodes:barcodeData = barcode.data.decode("utf-8")cv2.putText(img, barcodeData, (200, 600), cv2.FONT_HERSHEY_SIMPLEX, 5.0, (0, 255, 0), 30)#显示所有图片imgStack = stackImages(0.1, ([img_1, img_2,img_3,img_4],[img_5,img_6,img_7,img]))cv2.imshow("imgStack", imgStack)cv2.waitKey(0)

四、总结

学会使用OpenCV对于处理图像有很大的帮助

五、参考

/qq_43279579/article/details/120782545

/qq_43279579/article/details/120766454

/qq_43279579/article/details/120785076

/weixin_45602979/article/details/108831760

/yl_best/article/details/90666104

/qq_47281915/article/details/121640725?spm=1001..3001.5501

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。