目录标题
一、简单图片格式
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 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("./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 = 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()
# 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)