文章目录
- 一:数字图像的生成与表示
- (1)图像信号的数字化
- (2)数字图像类型
- 二:数字图像的数值描述
- (1)常用坐标系
- (2)数字图像的数据结构
- (3)常用图像格式
- A:JPEG格式
- B:GIF格式
- C:TIFF格式
- D:PNG格式
- E:BMP格式
- (4)BMP位图文件
- A:位图文件头(BITMAPFILEHEADER)
- B:位图信息头(BITMAPINFOHEADER)
- C:调色板(RGBQUAD)
- D:图像数据(DATA)
- E:读取并显示图像
- ①:目前可做程序
- ②:实例
- (5)综合案例
- A:分析
- B:肤色分布
- C:程序设计
一:数字图像的生成与表示
数字图像的生成与表示:对于自然界中的物体,通过某些成像设备,将物体表面的反射光或者通过物体的透射光,转换成电压,在成像平面生成图像。图像中目标的亮度取决于投影成目标的景物所受到的光照度、景物表面对光的反射程度以及成像系统的特性
(1)图像信号的数字化
图像信号的数字化:模拟图像转换为数字图像,方能被计算机处理,这一过程称为图像信号的数字化,包括:采样和量化
-
采样:对空间坐标x和y离散化,即确定水平和垂直方向上的像素数
- 图像分辨率:采样所获得的图像总像素的多少,以水平和垂直像素数表示(p用M×N表示,M列N行,如2560×1920),分辨率不一样,数字图像的质量也不一样
- 图像分辨率:采样所获得的图像总像素的多少,以水平和垂直像素数表示(p用M×N表示,M列N行,如2560×1920),分辨率不一样,数字图像的质量也不一样
-
量化:将各个像素所含的明暗信息离散化
-
一般的量化值为整数,量化层数取为2的n次幂
-
8位量化:也即 2 8 2^{8} 28,充分考虑到人眼的识别能力。非特殊用途的图像均为8bit量化,用[0 255]描述“从黑到白”,0和255分别对应亮度的最低和最高级别
-
在3bit以下的量化,会出现伪轮廓现象
-
如果要求更高精度,可以增大量化分层,但编码时占用位数也会增多,数据量加大
-
下图为数字化的灰度图像
下图为数字化的彩色图像
(2)数字图像类型
灰度图像: 每个像素只有一个强度值,呈现黑、灰、白等色
二值图像: 每个像素值要么为0要么为1的数字图像,一般为黑白两色
彩色图像: 每个像素值为三维向量,也即组成该色彩的RGB值
动态图像: 多帧位图的有序组合,使用动态原理,也即 Δ t ≤ 1 24 s \Delta t \leq \frac{1}{24}s Δt≤241s(视觉暂留时间), 产生连续活动视觉效果
索引图像: 索引图像实际上不是一种图像类型,而是图像的一种存储方式,牵涉到数据编码的问题。p具体的颜色数据存放在调色板中,图像数据区中存放对应每一个像素点的颜色索引值
二:数字图像的数值描述
数字图像的数值描述:所谓的数字图像的描述是指如何用一个数值方式来表示一幅图像。因为矩阵是二维的,所以可以用矩阵来描述数字图像。同时,前面我们已经提到,量化值是整数,因此描述数字图像的矩阵一定是整数矩阵
(1)常用坐标系
常用坐标系:如下图为矩阵坐标系、直角坐标系和像素坐标系对比
(2)数字图像的数据结构
数字图像的数据结构:
- 文件头: 图像的自我说明,应包含图像的维数、类型、创建日期和某类标题,也可以包含用于解释像素值的颜色表或编码表,甚至历史段(包含如何建立和处理图像的信息)
- 图像数据: 像素颜色值或压缩后的数据
(3)常用图像格式
A:JPEG格式
JPEG格式:中文名为联合图片专家组开发,用于彩色图像的存储和网络传送
- 特点: 采用有损压缩编码,数据量小
- 核心技术: DCT、量化、熵编码
- 使用要点:
- 用于保存表现自然景观的图像
- 用于网络传送
- 不适于表现有明显边界的图形
- 不适用于高质量印刷文件
B:GIF格式
GIF格式:CompuServe公司开发,用于屏显和网络
- 特点:
- 具有87a、89a两种格式
- 87a描述单一静止图像
- 89a描述多帧图像
- 采用改进的LZW压缩算法
- 彩色模式: 2 8 2^{8} 28
- 分辨率96dpi
- 具有87a、89a两种格式
- 使用要点:
- 屏显图像和电脑动画
- 用于网络传送
- 不适于保存高质量印刷文件
C:TIFF格式
TIFF格式:标记图像文件格式,Aldus公司开发,用于精确描述图像的场合
- 特点:
- 文件描述单一(静止)图像
- 彩色模式: 21 (单色)~ 232
- 支持多平台(PC & Macintosh)
- 可采用多种压缩数据格式
- 使用要点:
- 平面设计作品的最佳表现形式
- 用于提供印刷文件
- 不适于网络传送
D:PNG格式
PNG格式:中文名便携式网络图形格式
- 特点:
- 支持索引、灰度、RGB三种颜色方案以及Alpha通道
- 灰度图像的深度可多到16位,彩色图像的深度可多到48位,可存储多到16位的α通道数据
- 采用无损压缩
- 使用要点:
- 用于平面设计
- 用于网络传送
E:BMP格式
BMP格式:Bitmap,Microsoft公司开发,用于Windows环境
- 特点:
- 文件描述单一(静止)图像
- 彩色模式: 24 ~ 232
- 调色板RGB数据顺序反向排列
- 以图像左下角为起点排列数据
- 一般采用非压缩数据格式
- 使用要点:
- 用于表现打印、显示用图像
- 不适于网络传送
- 不适于提供印刷文件
(4)BMP位图文件
A:位图文件头(BITMAPFILEHEADER)
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; //文件类型,必是”BM” 0x4D42
DWORD bfSize; //指定文件大小(单位:字节)
WORD bfReserved1; //保留字,不考虑
WORD bfReserved2; //保留字,不考虑
DWORD bfOffBits;
//从文件头到位图数据的偏移字节数
//sizeof(fileheader)+sizeof(infoheader)+sizeof(RGBQUAD)
} BITMAPFILEHEADER
B:位图信息头(BITMAPINFOHEADER)
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; //本结构的长度,40个字节
DWORD biWidth; //图像宽,单位是像素
DWORD biHeight; //图像高,单位是像素
WORD biPlanes; //必须是1(位平面)
WORD biBitCount ;//颜色位数,1,4,8,24
DWORD biCompression; //压缩类型
DWORD biSizeImage; //实际位图数据占用的字节数
DWORD biXPelsPerMeter; //水平分辨率
DWORD biYPelsPerMeter; //垂直分辨率
DWORD biClrUsed; //实际使用的颜色数
DWORD biClrImportant; //重要的颜色数
} BITMAPINFOHEADER;
如下为256色的图像文件头及信息头
如下为真彩色24位的图像文件头及信息头
C:调色板(RGBQUAD)
RGBQUAD结构指的是一种颜色的构成,调色板中有多少种颜色就有多少种这种结构。例如:图像只有纯红和纯蓝两种颜色,调色板数据为:0 0 255 0 | 255 0 0 0
typedef struct tagRGBQUAD
{
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值,不考虑
} RGBQUAD;
D:图像数据(DATA)
- 图像中的颜色少于或等于256时,数据是颜色在调色板中的索引
- 图像为真彩色24位或更多,没有调色板,图像数据直接是每一个像素的颜色值B、G、R
- 位图的存储顺序:从左到右、从下到上;即图像数据中的第一个数是图像的最左下角的像素值
- 存储图像一行所用的字节理论上:
W=biWidth*biBitCount/8
,但实际上p要求W是4的倍数,不足的补0
如下图为灰度Lena图像调色板及图像数据
如下图为彩色Bird图像数据
E:读取并显示图像
①:目前可做程序
MATLAB
- 打开并显示图像
imread
imshow
imwrite
- 灰度化
rgb2gray
- 色彩空间变换
rgb2hsv
rgb2ycbcr
Python:
imread
:使用OpenCV读取图像,可以使用cv2.imread()
函数。imshow
:使用OpenCV显示图像,可以使用cv2.imshow()
函数。imwrite
:使用OpenCV保存图像,可以使用cv2.imwrite()
函数。rgb2gray
:将RGB彩色图像转换为灰度图像,可以使用cv2.cvtColor()
函数与cv2.COLOR_RGB2GRAY
参数来进行转换。rgb2hsv
:将RGB彩色图像转换为HSV图像,可以使用cv2.cvtColor()
函数与cv2.COLOR_RGB2HSV
参数来进行转换。rgb2ycbcr
:将RGB彩色图像转换为YCbCr图像,可以使用cv2.cvtColor()
函数与cv2.COLOR_RGB2YCrCb
参数来进行转换
②:实例
MATLAB:
①:打开图像取反并显示和存储
I=imread('cameraman.jpg');
J=255-I;
subplot(121),imshow(I),title('原始图像');
subplot(122),imshow(J),title('反色图像');
imwrite(J,'cameraman反色.jpg');
②:打开彩色图像,灰度化和二值化
Image1=im2double(imread('lotus.jpg'));
r=Image1(:,:,1);
g=Image1(:,:,2);
b=Image1(:,:,3);
Y=0.299*r+0.587*g+0.114*b;
subplot(131),imshow(Y),title('亮度图Y');
I=(r+g+b)/3;
subplot(132),imshow(I),title('亮度图I');
BW=zeros(size(Y));
BW(Y>0.3)=1;
subplot(133),imshow(BW),title('二值化图');
Python OpenCV:
注意
- 在 Python 中,我们需要指定图像的读取方式(灰度或彩色),因此在
imread()
函数调用时需要将第二个参数设置为cv2.IMREAD_GRAYSCALE
- Matplotlib 默认的颜色映射是彩色的,因此需要将
imshow()
函数中的cmap
参数设置为'gray'
才能正确地显示灰度图像 - OpenCV 默认使用 BGR 顺序读取和显示图像
①:打开图像取反并显示和存储
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
I = cv2.imread('cameraman.jpg', cv2.IMREAD_GRAYSCALE)
J = 255-I
plt.subplot(121), plt.imshow(I, cmap='gray'), plt.title('原始图像')
plt.subplot(122), plt.imshow(J, cmap='gray'), plt.title('反色图像')
cv2.imwrite('cameraman反色.jpg', J)
plt.show()
②:打开彩色图像,灰度化和二值化
import cv2
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
img = cv2.imread('lotus.JPG').astype(np.float32)/255
b, g, r = cv2.split(img)
Y=0.299*r+0.587*g+0.114*b
plt.subplot(131), plt.imshow(Y, cmap='gray'), plt.title('亮度图Y'), plt.axis('off')
I=(r+g+b)/3
plt.subplot(132), plt.imshow(I, cmap='gray'), plt.title('亮度图I'), plt.axis('off')
_, BW = cv2.threshold(Y, thresh=0.3, maxval=1.0, type=cv2.THRESH_BINARY)
plt.subplot(133), plt.imshow(BW, cmap='gray'), plt.title('二值化图'), plt.axis('off')
plt.show()
(5)综合案例
打开人脸图像,利用色彩信息进行肤色检测
A:分析
- 在检测人脸、手等目标时,常采用肤色检测的方法,将相关区域从图像中分割出来
- 肤色分布的聚集性,即肤色的颜色分量一般聚集在某个范围内
- 通过大量的肤色样本进行统计,找出肤色颜色分量的聚集范围或用特殊的分布模型去模拟肤色分布,进而实现对任意像素颜色的判别
B:肤色分布
- 肤色在不同彩色空间均具有一定的聚集性。例如,据统计资料,肤色在YCbCr空间分布范围大约在: 77 ≤ C b ≤ 127 77\leq Cb\leq 127 77≤Cb≤127、 133 ≤ C r ≤ 173 133\leq Cr\leq 173 133≤Cr≤173
- 肤色模型
- 根据大量样本的统计数据建立,确定肤色的分布规律,进而判断像素的色彩是否属于肤色或与肤色相似程度的模型
- 常用的有阈值模型、高斯模型和椭圆模型
C:程序设计
MATLAB:
这段MATLAB代码是一个肤色检测的程序,它接受一张图片作为输入,通过分别在RGB、HSV和YCbCr三个颜色空间中检测像素点是否属于肤色,并输出相应的二值图。其中,对于YCbCr空间的检测,采用了高斯模型来对肤色的分布进行建模。具体实现过程如下:
- 清空MATLAB的工作空间。
- 使用 imread 函数读取名为 motheranddaughter.jpg 的图片文件,并将其显示出来。
- 将图像分离成红色通道 ®、绿色通道 (g) 和蓝色通道 (b),并获取图像的大小信息。
- 定义一个表示肤色在YCbCr空间下的高斯分布的均值 miu 和协方差矩阵 sigma。
- 初始化变量 cbcr、SkinCbCrG、SkinRGB、SkinHSV 和 SkinCbCr,并设定偏移参数 thresh。
- 对于每个像素点,分别进行 RGB、HSV 和 YCbCr 三种颜色空间的肤色检测,并更新对应像素点在三种检测空间下的二值图。
- 将得到的三种检测空间下的二值图保存为 skinrgb3.jpg、skinhsv3.jpg、skincbcr3.jpg 和 skinCbCrG3.jpg 四个文件。
clear,clc,close all;
Image=imread('motheranddaughter.jpg');
r=double(Image(:,:,1));
g=double(Image(:,:,2));
b=double(Image(:,:,3));
[N,M]=size(r);
miu=[117.4361 156.5599]'; % 定义肤色在YCbCr空间下的高斯分布的均值miu(行向量)
sigma=[160.1301 12.1430;12.1430 299.4574]; % 定义协方差矩阵(列向量)
cbcr=zeros(2,1);
SkinCbCrG=zeros(N,M); % 初始化一个与图像大小相同的矩阵 SkinCbCrG,用于表示 YCbCr 检测结果中检测到的肤色部分
SkinRGB=zeros(N,M); % 初始化一个与图像大小相同的矩阵 SkinRGB,用于表示 RGB 检测结果中检测到的肤色部分
SkinHSV=zeros(N,M); % 初始化一个与图像大小相同的矩阵 SkinHSV,用于表示 HSV 检测结果中检测到的肤色部分
SkinCbCr=zeros(N,M); % 初始化一个与图像大小相同的矩阵 SkinCbCr,用于表示 YCbCr 检测结果中检测到的肤色部分
thresh=0.35; % 设定YCbCr检测中的偏移参数
for i=1:M % 对于每一行
for j=1:N % 对于每一列
R=r(j,i);
G=g(j,i);
B=b(j,i);
if (R>95 && G>40 && B>20 && (R-G)>15 && R-B>15) || ...
(R>220 && G>210 && B>170 && R-B<=15 && R>B && G>B)
SkinRGB(j,i)=1; % 判断是否是肤色,如何是设置为1
end
maxRGB=max(max(R,G),B);
minRGB=min(min(R,G),B);
C=maxRGB-minRGB;
V=maxRGB;
if V==0
S=0;
else
S=C/V;
end
if maxRGB==R
H=60*mod((G-B)/C,6);
elseif maxRGB==G
H=60*((B-R)/C+2);
elseif maxRGB==B
H=60*((R-G)/C+4);
end
if ((H>=0 && H<=25) || (H>=335 && H<=360)) && (S>=0.2 && S<=0.6) && V>=0.4
SkinHSV(j,i)=1;
end
R=R/255;G=G/255;B=B/255;
Cb=224*(-0.1687*R-0.3313*G+0.5*B)+128;
Cr=224*(0.5*R-0.4187*G-0.0813*B)+128;
if Cb>=77 && Cb<=127 && Cr>=133 && Cr<=173
SkinCbCr(j,i)=1;
end
cbcr= [Cb Cr]';
p=exp(-0.5*((cbcr-miu)')*(inv(sigma))*(cbcr-miu));
if p>thresh
SkinCbCrG(j,i)=1;
end
end
end
subplot(151),imshow(Image),title('原图');
subplot(152),imshow(SkinRGB),title('RGB');
subplot(153),imshow(SkinHSV),title('HSV');
subplot(154),imshow(SkinCbCr),title('YCbCr');
subplot(155),imshow(SkinCbCrG),title('YCbCr');
imwrite(SkinRGB,'skinrgb3.jpg');
imwrite(SkinHSV,'skinhsv3.jpg');
imwrite(SkinCbCr,'skincbcr3.jpg');
imwrite(SkinCbCrG,'skinCbCrG3.jpg');