前言
本篇文章讲述图像的基础知识,主要包括灰度、通道等基础概念,同时还包括部分操作基于Opencv的代码实现。本系列文章并未涉及到图像处理所有的知识,若有不足之处,请多多包含!
像素
像素是构成位图的最基本的单位,像素的多少决定了图像的尺寸,同时也是分辨率的单位。如图所示,可以看到图片由许多小方格组成,每一个小方格就是一个像素点
分辨率(解析度)
图像的分辨率是单位英寸内的像素点个数,单位为PPI(Pixels Per Inch)。由上图可知,因为在单位面积内的像素点少,所以图像看起来模糊,因此,图像分辨率越高,图像越逼真。图像的分辨率与图像内的像素点个数没有必然联系,不能误认为图像分辨率就是图像中像素点个数,图像分辨率=像素点个数/图像尺寸
灰度
灰度是用来表示像素明暗程度的数值,数值越大,像素点越亮,数值越小,像素点越暗;灰度也就是“黑白图像”中点的颜色深度(说黑白图像不太准确,并不是真正意义上的非黑即白,故加了引号,较为准确的应该灰度图),对于8位图而言,其范围为0~255,最大数值为255,最亮,表现为白色;最小数值为0,最暗,表现为黑色。如图所示,左边图从上往下逐渐变亮,对应右边像素值逐渐变大
通道
通道,是数字图像中存储不同类型信息的灰度图像。根据数字图像的通道数可以分为以下几种:
- 单通道 。简单来说就是图像仅由一个通道组成,即每个像素点只有一个灰度值表示, 如二值图,灰度图。
- 三通道。这里指的是RGB模式,把数字图像分为红绿蓝三个通道,可以表示彩色。
- 四通道。即在RGB的基础上增加了一个alpha通道,表示透明度,alpha值越大,不透明度越高,alpha值越小,透明度越高。
- 多通道。
下面谈一下对通道的理解:
上课的时候老师类比过,说三通道就类似于三张纸的叠加,然后图片就显示为各种不同的颜色,再结合下图(不同深浅程度的颜色叠加就表现为另外一种颜色,图中仅仅表示了其中一种情况,因为红色还可以分为深红、浅红……,),我就在想是不是每个通道对应一种颜色的图像,然后经过计算机合成就显示为彩色图。
其实事实并非如此,通道的定义指出通道就是灰度图像,下面代码验证:
实验一
- 读取图片并进行缩放:
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img = cv.imread('input.png') #读取图片
height, width, channel = img.shape #获取图片属性
print('height=',height, ' width=',width, ' channel=', channel)
"""输出为height= 1080 width= 1620 channel= 3"""
result = cv.resize(img, (1620//4, 1080//4)) #将图片缩小为原来的四分之一
# result = cv.resize(img, (int(1620/4), int(1080//4)))
"""cv.resize(src, dsize),函数中dsize只能为整数,'/'运算结果为float型,故需要进行类型转换"""
"""此处resize函数中图片尺寸为(width,height),与img.shape输入恰好相反"""
print(result.shape[0],result.shape[1], result.shape[2]) #缩小后图片尺寸(270, 405, 3)
- 分离各个通道:
"""分离每个通道的图片,opencv是是按照B、G、R读取和存储"""
result_b = result[:, :, 0]
result_g = result[:, :, 1]
result_r = result[:, :, 2]
# result_b = cv.split(result)[0]; result_g = cv.split(result)[1]; result_r = cv.split(result)[2]
#上述函数同样可以实现三通道图像分离
- 显示图像:
"""把图片和图片名称存入list中方便进行数据操作"""
result_set= [result, result_b, result_g, result_r]
result_set_title = ['result','result_b', 'result_g', 'result_r']
"""matplot按照R、G、B读取图片,而opencv是按照B、G、R读取图片, 故应将BGR => RGB"""
for j in range(4):
result_set[j] = cv.cvtColor(result_set[j], cv.COLOR_BGR2RGB)
"""matplot显示2*2的图"""
for i in range(4):
plt.subplot(2, 2, i+1) #确定子图大小(2*2),当前是第i+1个图
plt.imshow(result_set[i]) #对图像进行处理,并显示其格式
plt.title(result_set_title[i]) #显示标题
plt.xticks([]) #不显示X坐标
plt.yticks([]) #不显示Y坐标
plt.show() #显示处理完的图片
- 运行结果:
- 结果分析:
第一幅图是原图,后面三幅图依次对应B、G、R通道的图,由上可知,每个通道对应的确实是灰度图像。我们可以看到每个通道对应的灰度图的亮暗程度都不一样,R通道的灰度图偏亮,灰度值偏大,其余通道的灰度图都偏暗,灰度值偏小;而原图的整体色彩偏红,恰好R通道的灰度值最大,是巧合吗?我们能来看下一个代码验证:
实验二
- 将分离的三个通道合并并显示:
result_merger_1 = cv.merge([result_b, result_g, result_r]) #把三个通道的图片按B、G、R格式存储并显示
result_merger_2 = cv.merge([result_r, result_g, result_b]) #把三个通道的图片按R、G、B格式存储并显示
result_merger = [result_merger_1, result_merger_2]
result_merger_title = ['result_merger_1', 'result_merger_2']
for j in range(2):
result_merger[j] = cv.cvtColor(result_merger[j], cv.COLOR_BGR2RGB)#BGR => RGB
for i in range(2):
plt.subplot(1, 2, i+1) #确定子图大小(1*2),当前是第i+1个图
plt.imshow(result_merger[i]) #对图像进行处理,并显示其格式
plt.title(result_merger_title[i]) #显示标题
plt.xticks([]) #不显示X坐标
plt.yticks([]) #不显示Y坐标
plt.show() #显示处理完的图片
- 运行结果:
- 结果分析:
图一是经BGR通道合并得到(原图), 图二经RGB通道合并得到,在代码第二行我们可以看到,我们把原图像分离得到的R通道的图像放在B通道进行合并,最后图像整体表现为蓝色,因为R通道的图像对应的灰度值最大,把它放在R通道图像表现为红色,因此把它放在B通道就应该表现为蓝色。
结合实验一和实验二,我们可以得出通道就是数字图像中存储不同类型信息的灰度图像,而真正转化为有颜色的图像的过程是在计算机中对应的函数进行(简单来说就是一个通道相当于一个数,自变量, 而计算机中的函数就相当于一个函数映射(正相关),作用就是把灰度图映射到彩色图),可以由下列代码得到验证:
- 验证代码
b1 = cv.split(result)[0] #分离得到B通道图像
g1 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #G通道为0
r1 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #R通道为0
merger_b = cv.merge([b1, g1, r1]) #合并三通道
b2 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #B通道为0
g2 = cv.split(result)[0] #分离得到G通道图像
r2 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #R通道为0
merger_g = cv.merge([b2, g2, r2]) #合并三通道
b3 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #B通道为0
g3 = np.zeros([result.shape[0], result.shape[1]], dtype=np.uint8) #G通道为0
r3 = cv.split(result)[0] #分离得到R通道图像
merger_r = cv.merge([b3, g3, r3]) #合并三通道
merger_set = [result, merger_b, merger_g, merger_r]
merger_set_title = ['result','merger_b', 'merger_g', 'merger_r']
for j in range(4):
merger_set[j] = cv.cvtColor(merger_set[j], cv.COLOR_BGR2RGB) #BGR => RGB
for i in range(4):
plt.subplot(2, 2, i+1) #确定子图大小(2*2),当前是第i+1个图
plt.imshow(merger_set[i]) #对图像进行处理,并显示其格式
plt.title(merger_set_title[i]) #显示标题
plt.xticks([]) #不显示X坐标
plt.yticks([]) #不显示Y坐标
plt.show() #显示处理完的图片
- 运行结果:
[Until:2020年12月22日17时,路漫漫而求索,求索,求索……]