目录
二、对比不同文件格式的图片文件大小
三、基于奇异值分解(SVD)提取图片特征值
四、开闭运算检测图像中硬币和细胞的个数
一、位图文件分析
1. 什幺是位图
位图图像(bitmap)
,亦称为 点阵图像
或 栅格图像
,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增大单个像素,从而使线条和形状显得参差不齐。然而,如果从稍远的位置观看它,位图图像的颜色和形状又显得是连续的。用数码相机拍摄的照片、扫描仪扫描的图片以及计算机截屏图等都属于位图。位图的特点是可以表现色彩的变化和颜色的细微过渡,产生逼真的效果,缺点是在保存时需要记录每一个像素的位置和颜色值,占用较大的存储空间。
2. BMP位图文件
常见的图像文件格式有: BMP
、 JPG(JPE,JPEG)
、 GIF
等。
BMP
图像文件(Bitmap-File)格式是 Windows
采用的图像文件存储格式,在Windows环境下运行的所有图像处理软件都支持这种格式。 BMP
位图文件默认的文件扩展名是 .BMP
,有时它也会以 .DIB
或. RLE
作扩展名。
本文采用 SL.bmp(2880 x 1440)
示例:
3. BMP文件结构
BMP文件由4部分组成:
- 位图文件头(bitmap-file header)
- 位图信息头(bitmap-informationheader)
- 颜色表(color table)
- 颜色点阵数据(bits data)
4. 位图文件头
位图文件头分4部分,共 14字节 :
bfType:2字节,作为标识,就是“BM”二字。
bfSize:4字节,整个BMP文件的大小。
bfReserved1/2:4字节,保留字,没用。
bfOffBits:4字节,偏移数,即 位图文件头+位图信息头+调色板 的大小。
5. 位深度
看图像属性,位深度,如果是24,就说明图片是24位真彩色
单色位图:每个像素最多可以表示2种颜色,只需要使用长度为1的二进制位来表示,因此每个像素占1/8byte。
16色位图:每个像素最多可以表示16种颜色,所以只需要长度为4的二进制表示,因此每个像素占1/2byte。
256色位图:每个像素最多可以表示256中颜色,所以只需要长度是8的二级制位表示就可以了,因此每个像素占1byte。
24位位图:即RGB三原色位图每个像素占3个byte。
BMP图像大小计算公式: 大小= 分辨率*位深度/8
6. 不同位深度图像对比
将原图其分别保存为256色、16色、单色的位图(BMP)文件,并对比文件大小。
二、对比不同文件格式的图片文件大小
将原图其分别保存为为BMP、JPG、GIF和PNG格式,对比它们的文件大小。
三、基于奇异值分解(SVD)提取图片特征值
奇异值分解(Singular Value Decomposition,以下简称SVD)是一种重要的矩阵分解方法,也是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域。是很多机器学习算法的基石。
本文采用 SL.png(2880 x 1440)
示例:
代码准备:
# -*- coding: utf-8 -*- #!/usr/bin/python # -*- coding:utf-8 -*- import numpy as np import os from PIL import Image import matplotlib.pyplot as plt import matplotlib as mpl from pprint import pprint def 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] = 0 a[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] = 0 a[a > 255] = 255 return np.rint(a).astype('uint8') if __name__ == "__main__": A = Image.open("SL.png", '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 = 50 u_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'] = False for 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(0.3, rect=(0, 0, 1, 0.92)) # plt.subplots_adjust(top=0.9) plt.show()
运行结果:
四、开闭运算检测图像中硬币和细胞的个数
1. 检测硬币数量
代码准备:
#导入函数库 import cv2 import numpy as np #读取一张硬币图像 img=cv2.imread("coins2.jpg") #低通滤波处理 #对图像进行泛洪处理 h, w = img.shape[:2] #获取图像的长和宽 mask = np.zeros((h+2, w+2), np.uint8)#进行图像填充 cv2.floodFill(img, mask, (w-1,h-1), (255,255,255), (2,2,2),(3,3,3),8) #图像灰度化 gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #通过高斯滤波对图像进行模糊处理,可以理解为对图像硬币去噪 blur=cv2.cv2.GaussianBlur(gray,(29,29),0,0)#这里可以用中值滤波,具体视对图像效果选择 cv2.imshow("blur",blur) cv2.waitKey(0) #通过二进制阈值化对图像进行阈值化处理,将硬币轮廓与周围噪声区分开来 ret,thresh1=cv2.threshold(blur,127,255,cv2.THRESH_BINARY) cv2.imshow("thresh1",thresh1) cv2.waitKey(0) #进行闭运算,去除图像内部噪声 kernel = np.ones((7,7), np.uint8)#设置卷积核 close=cv2.morphologyEx(thresh1, cv2.MORPH_CLOSE, kernel)#闭运算 cv2.imshow("close",close) cv2.waitKey(0) #利用canny算法对图像进行轮廓提取 Canny = cv2.Canny(close, 20, 150) #显示图像轮廓提取图像 cv2.imshow("Canny",Canny) #等待键盘键值关闭 cv2.waitKey(0) #在提取出的轮廓图像中找出轮廓线条 (cnts1,_) =cv2.findContours(Canny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) #在终端打印出硬币个数 print("图像中的硬币共有:",len(cnts1),"个") #将硬币轮廓线条画在原图 coins1 = img.copy() cv2.drawContours(coins1, cnts1, -1, (0,255,0), 2) #显示在原图上面检测出来的硬币 cv2.imshow("coins",coins1) #等待键盘键值关闭 cv2.waitKey(0)
运行结果:
共24个硬币,识别正确。
2. 检测细胞数量
代码准备:
#导入函数库 import cv2 import numpy as np #读取一张硬币图像 img = cv2.imread("Cell1.jpg") #低通滤波处理 #对图像进行泛洪处理 h, w = img.shape[:2] # 获取图像的长和宽 mask = np.zeros((h+2, w+2), np.uint8) # 进行图像填充 cv2.floodFill(img, mask, (w-1, h-1), (255, 255, 255), (2, 2, 2), (3, 3, 3), 8) #图像灰度化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #通过高斯滤波对图像进行模糊处理,可以理解为对图像细胞去噪 blur = cv2.cv2.GaussianBlur(gray, (3, 3), 0, 0) # 这里可以用中值滤波,具体视对图像效果选择 #cv2.imshow("blur", blur) #cv2.waitKey(0) #通过二进制阈值化对图像进行阈值化处理,将细胞轮廓与周围噪声区分开来 ret, thresh1 = cv2.threshold(blur, 189, 255, cv2.THRESH_BINARY) #cv2.imshow("thresh1", thresh1) #cv2.waitKey(0) #进行闭运算,去除图像内部噪声 kernel = np.ones((7, 7), np.uint8) # 设置卷积核 close = cv2.morphologyEx(thresh1, cv2.MORPH_CLOSE, kernel) # 闭运算 #cv2.imshow("close", close) #cv2.waitKey(0) #利用canny算法对图像进行轮廓提取 Canny = cv2.Canny(close, 20, 150) #显示图像轮廓提取图像 cv2.imshow("Canny", Canny) #等待键盘键值关闭 cv2.waitKey(0) #在提取出的轮廓图像中找出轮廓线条 (cnts1, _) = cv2.findContours(Canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #在终端打印出细胞个数 print("图像中的细胞共有:", len(cnts1), "个") #将细胞轮廓线条画在原图 coins1 = img.copy() cv2.drawContours(coins1, cnts1, -1, (0, 255, 0), 2) #显示在原图上面检测出来的细胞 cv2.imshow("Cells", coins1) #等待键盘键值关闭 cv2.waitKey(0)
运行结果:
由于图片光线不均,识别结果具有一定误差。
五、图片条形码定位
代码准备:
import cv2 import pyzbar.pyzbar as pyzbar import numpy from PIL import Image, ImageDraw, ImageFont def decodeDisplay(img_path): img_data = cv2.imread(img_path) # 转为灰度图像 gray = cv2.cvtColor(img_data, cv2.COLOR_BGR2GRAY) barcodes = pyzbar.decode(gray) for barcode in barcodes: # 提取条形码的边界框的位置 # 画出图像中条形码的边界框 (x, y, w, h) = barcode.rect cv2.rectangle(img_data, (x, y), (x + w, y + h), (0, 255, 0), 2) # 条形码数据为字节对象,所以如果我们想在输出图像上 # 画出来,就需要先将它转换成字符串 barcodeData = barcode.data.decode("utf-8") barcodeType = barcode.type #不能显示中文 # 绘出图像上条形码的数据和条形码类型 #text = "{} ({})".format(barcodeData, barcodeType) #cv2.putText(imagex1, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX,5, (0, 0, 125), 2) #更换为: img_PIL = Image.fromarray(cv2.cvtColor(img_data, cv2.COLOR_BGR2RGB)) # 参数(字体,默认大小) font = ImageFont.truetype('msyh.ttc', 35) # 字体颜色(rgb) fillColor = (0, 255, 255) # 文字输出位置 position = (x, y-50) # 输出内容 str = barcodeData # 需要先把输出的中文字符转换成Unicode编码形式( str.decode("utf-8) ) draw = ImageDraw.Draw(img_PIL) draw.text(position, str, font=font, fill=fillColor) # 使用PIL中的save方法保存图片到本地 img_PIL.save('1.jpg', 'jpeg') # 向终端打印条形码数据和条形码类型 print("扫描结果==》 类别: {0} 内容: {1}".format(barcodeType, barcodeData)) if __name__ == '__main__': decodeDisplay("ma.jpg")
运行结果:
六、总结
本文简单介绍了位图,并对比了不同格式的图像的大小。并使用SVD对图像进行特征值提取,并识别了硬币和细胞的个数,最后对条形码进行得提取。
七、参考
https://blog.csdn.net/aidem_brown/article/details/80500637
https://blog.csdn.net/qq_42451251/article/details/108056501
Be First to Comment