写在前面
- 关于参考材料:本系列博客参考学习经典教材《Digital Image Processing Using MATLAB》所总结的笔记,如有侵权,还请麻烦联系作者删除。
- 关于使用建议:本系列博客与教材相似,自成体系。同时加入了作者学习所遇到的困惑与心得。可以作为图像处理、计算机视觉爱好者的辅助指南。也竭力让其更易懂,从而帮助广大读者更好地掌握传统的图像处理技术。
- 关于实验平台:本系列博客基于Matlab2013(Window7)以上的版本做实验。
- 关于提问与反馈:在本系列博客阅读中,读者若产生相关疑问,可在评论中提问,本人非常荣幸能与大家共同探讨。我也将实时更新博客,如有错误,欢迎大家批评指正。
Matlab语言简洁表示+IPT(理想的软件原型环境):大量图像处理操作可按简洁明了的编码方式进行。
本博客为后续内容的基础,重要内容有
- Matlab表示法的基本知识
- IPT(扩展Matlab数值计算能力的函数集/图像处理工具箱)基本属性和函数
- 增强IPT的程序设计概念
图像定义:二维函数 f ( x , y ) f(x, y) f(x,y)。其中 x x x和 y y y是空间(平面)坐标, f f f在任何坐标点 ( x , y ) (x, y) (x,y)处的振幅,也就是图像在该点的亮度(或是黑白图像中的灰度)。【连续的二维函数】
其中,彩色图像的组成元素是单个二维图像 f ( x , y ) f(x, y) f(x,y)。如RGB彩色图像由三幅独立的分量二维图像(红、绿、蓝)组成。
数字图像定义:当图像 f f f的坐标 x x x和 y y y分量和振幅都是有限且离散的量。【二维数组(实数矩阵)----也及后续表示为二维数组的都为数字图像】
因为图像关于 x x x和 y y y坐标以及振幅连续,所以需要通过取样(坐标值数字化),量化(振幅数字化),将图像装换成数字图像。
1) 坐标约定
数据图像表示为一个实数矩阵如下图2.1所示(主要两种不同的坐标约定)。
其中每个坐标点 ( x , y ) (x, y) (x,y)(或 ( r , c ) (r, c) (r,c))不是图像在取样时的实际物理坐标值,只表示第几行的第几个取样。
还有一种较少用的IPT坐标约定,与 ( x , y ) (x, y) (x,y)正好相反,表示为 ( y , x ) (y, x) (y,x),其中 y y y表示行, x x x表示列。
2) 图像的矩阵表示
数字图像的数据化图像函数表示如下:
其中等式右边是由定义给出的一幅数字图像。该数组的每一个元素都称为像元、图元或像素。(为了便捷,默认称数字图像及其元素为图像和像素)
同样,数字图像在Matlab中可表示为矩阵如下所示:
>> f=imread('bk.png');
>> size(f)
ans =
279 253 3
>> whos f
Name Size Bytes Class Attributes
f 279x253x3 211761 uint8
显示在Matlab桌面上的图像:imshow
常用的选项如下所示:
例子:加载一个灰度图tree.png,并按照如下命令执行。
>> tree = imread('tree.png');
>> whos tree
Name Size Bytes Class Attributes
tree 467x533 248911 uint8
>> imshow(tree),figure,imshow(tree, [98 100]),figure,imshow(tree,[])
最后一行命令所显示的结果如下所示(配合使用逗号和命令figure可同时不覆盖地显示多幅图片):
-将Matlab桌面上的图像写到磁盘上:imwrite
不同的文件格式有不同的参数,常用的选项如下所示:
>> imwrite(tree, './tree50.jpg', 'quality', 50)
>> imwrite(tree, './tree25.jpg', 'quality', 25)
>> imwrite(tree, './tree15.jpg', 'quality', 15)
>> imwrite(tree, './tree5.jpg', 'quality', 5)
>> imwrite(tree, './tree0.jpg', 'quality', 0)
>> imwrite(tree, './tree.jpg')
>> imfinfo tree.jpg %了解所实现的压缩并获得图像文件的其它详细信息
ans =
Filename: 'D:\demo\tree.…'
FileModDate: '02-Jul-2020 11:07:09'
FileSize: 34873
Format: 'jpg'
FormatVersion: ''
Width: 533
Height: 467
BitDepth: 8
ColorType: 'grayscale'
FormatSignature: ''
NumberOfSamples: 1
CodingMethod: 'Huffman'
CodingProcess: 'Sequential'
Comment: {}
>>%使用imfinfo计算图像压缩比
>> K = imfinfo('tree.jpg') ;
>> image_bytes = K.Width*K.Height*K.BitDepth/8;
>> compressed_bytes = K.FileSize;
>> compression_ratio = image_bytes/compressed_bytes
compression_ratio =
7.1376
按照不同的q值输出的结果如下所示(q=15或q=0时,图像退化严重): >> tree= imread('tree.jpg');
>> colres = round(467/1);
>> rowres = round(533/1.5);
>> imwrite(tree, 'tree.tif', 'compression', 'none', 'resolution', [colres, rowres])
原图与写出后的图像如下所示:数字图像的像素值用Matlab、IPT程序表示可用的数据类(数据类型)。
其中,像素的坐标都是整数的。
其中double类最常用;
unit8也常用(特别是从存储设备读取数据时);
logical和使用较少的unit16构成本书集中讨论的基础数据类。
工具箱支持的图像类型有:
1)亮度图像(Intensity images)
表示为一个数据矩阵,规定双精度型归一化的像素取值范围是[0, 1]。
2)二值图像(Binary images)
表示为一个取值只有0和1的逻辑数组。在Matlab中具有特殊意义,仅仅包含0和1的其他类型数组不认为是二值图像的表示。
将其他类型数组转化为逻辑数组,可使用 logical() 函数(非零数值变为逻辑1)。通过 islogical() 来判断数组是否为逻辑数组。
#注意#大多数单色图像的处理运算通过以上两种图像类型来进行。以下两类图像见后续博客。
3)索引图像(Indexed images)
4)RGB图像(RGB images)
#注意#一幅数字图像由图像类型和数据类表征。如“unit 8 亮度图像”,“double 亮度图像”。
数据类的转换遵循编程语言类型转换的一贯做法,通过数据类名,直接转换为想要的类型。
例如:常见将unit8类数组A转换为双精度数组B,可通过简单命令B=double(A)。
#注意# 记住2.5中数据类表2.2的取值范围。若将取值范围大的数据类转换为小的,一般先进行缩放。
释义:一个图像采用一种图像类型表示时,可以输入为一种或多种数据类的数组。可以使用本节提供的函数,进行数组的数据类转换。这个操作有时不会改变图像类型, 有时会。
表2.3列举了IPT中进行单色图像类和类型间的转换函数(彩色图像见后续博客)
im2uint8(f):检测出输入的图像数据类,并进行所有必要的缩放,将输入转换为uint8类。
im2uint16(f):类比于im2uint8(f)。
mat2gray(f, [fmin, fmax]):把一个double类的任意图像数组分f转换成取值范围为[0,1](0为黑色,1为白色)的归一化double数组。参数fmin和fmax是为了在转换时,将f中小于fmin的值转换为0,将f中大于fmax的值转换为1。如果不填写fmin和fmax,则默认f中最小值为fmin,最大值为fmax。
im2double(f):将输入转换为范围[0, 1]间的double类。若输入的已经是double类的,则返回相同的数组(不改变取值范围,此时建议用mat2gray方法)。
im2bw(f, T):将一幅亮度图像f进行所有必要的缩放(如输入为uint8,默认将所有元素值除255),转换为一幅二值图像。T为阈值(必须取值在0与1之间,不人为指定T时,默认为0.5),f中小于T的转换为0,其它转换为1。输入类型为logical的则输出相同的数组。将二值图像转为亮度图像则可使用以上四个函数。
例子:
>> f = [1, 2 ; 3, 4] %默认为double类型
f =
1 2
3 4
>> g = mat2gray(f) %将f的取值范围变为[0, 1]
g =
0 0.3333
0.6667 1.0000
>> gb = im2bw(g, 0.6)%去阈值为0.6,达到将f中1,2转为0的二值图像gb
gb =
0 0
1 1
>> gb = f > 2 %直接使用关系运算符生成二值数组
gb =
0 0
1 1
>> gbv = islogical(gb) %使用islogical判断gb是否为二值数组
gbv =
1
>> gbd = im2double(gb) %将gb转换为值为0和1的double类数组
gbd =
0 0
1 1
主要关注一维和二维数组(向量和矩阵)的基本索引操作。
行向量rV,列向量cV,则常用向量索引操作有。
基础索引rV(i)/cV(i):提取行向量rV(或列向量cV)第i个元素。i取值从1开始。
向量转置(.’): rV.’ = cV
向量切片rV(start:step:end):在rV中,从索引start到索引end处,每隔step步,提取一个。
linspace(x1, x2, n): 以坐标(1,x1)与(n,x2)建立一条直线函数 f ( x ) f(x) f(x),并分别提取 f ( x ) , x = [ 1 , 2 , . . . , n ] f(x), x=[1,2, ... , n] f(x),x=[1,2,...,n]的值。当输入n=1,返回x2;输入n=2,返回x1,x2。
向量以向量为索引rV([i, j, k]):提取行向量rV第i,第j,第k个元素。
>> rV = [1 2 3 4 5]
rV =
1 2 3 4 5
>> rV(3) %基础索引rV(i)/cV(i)
ans =
3
>> cV = rV.' %向量转置(.')
cV =
1
2
3
4
5
>> rV(2:4) %向量切片
ans =
2 3 4
>> rV(2:end) %end为内置变量,表示最后一个元素索引
ans =
2 3 4 5
>> rV(:) %不论rV(:)、cV(:),全部返回所有元素组成的列向量
ans =
1
2
3
4
5
>> rV(1:end) %行向量返回行向量,列向量返回列向量
ans =
1 2 3 4 5
>> rV(1:2:end) %正序隔步提取元素
ans =
1 3 5
>> rV(end:-2:1) %逆序隔步提取元素
ans =
5 3 1
>> x = linspace(1, 10, 3) %线性返回值
x =
1.0000 5.5000 10.0000
>> rV([1, 3, 4]) %向量以向量为索引,不论传入的是行向量,还是列向量,都会转置后在索引
ans =
1 3 4
矩阵索引操作就要是对向量索引操作的扩展,分别对矩阵A(row, col)分别作行向量索引和列向量索引操作。两种区别于向量索引的矩阵操作形式为:
以逻辑矩阵D作为矩阵A的索引矩阵A(D):提取逻辑矩阵D中非0元素对应位置的矩阵A中的元素。逻辑矩阵D的大小要和矩阵A相等。
A矩阵的冒号(:)运算:A(: )、A(8)等都是先将矩阵以每列拼接成一个列向量,而后,进行列向量切片操作。A(2:3)、A(1:end)等都是先将矩阵以每列拼接成一个行向量,而后,进行行向量切片操作。
主要操作如代码所示:
>> A = [1 2 3; 4 5 6; 7 8 9] %矩阵的声明,封号(;)表示本行的截止
A =
1 2 3
4 5 6
7 8 9
>> A(2, 1) %提取第2行第1列的元素
ans =
4
>> cV2 = A(:, 2) %获取矩阵A的第2列元素,获取行类似rV2 = A(2, :)
cV2 =
2
5
8
>> A(end, end) %内置end的使用
ans =
9
>> A([1 3], [2 3]) %以向量作为索引
ans =
2 3
8 9
>> D = logical([1 0 0; 0 0 1; 0 0 0]) %以逻辑矩阵作为索引,找出非零元素对应元素的位置
D =
1 0 0
0 0 1
0 0 0
>> A(D)
ans =
1
6
>> A(:) %矩阵的冒号(:)运算
ans =
1
4
7
2
5
8
3
6
9
>> A(2:5)
ans =
4 7 2 5
>>
任意的Matlab任何变量A(标量、向量、矩阵、多维数组等)都表示为数组。
ndims(A):返回数组A的维数(值必大于等于2,标量也是1x1的数组)。
size(A, dim):返回数组A第dim个维度的大小。当dim大于实际维数时,返回1。
>> A = [1 2 3; 4 5 6; 7 8 9] %矩阵的声明,
A =
1 2 3
4 5 6
7 8 9
>> ndims(A) %获取矩阵A的维
ans =
2
>> size(A, 1) %获取矩阵A的第一维大小(行数)
ans =
3
以下列出7种常用数组生成函数(更便于模拟数字图像,验证数字图像处理算法等)。
zeros(M, N):生成一个大小为M x N的double类矩阵,元素均为0。
注意:zeros(M) 等效于zeros(M, M), 生成一个大小为M x M的方阵。如下函数类似。
ones(M, N):生成一个大小为M x N的double类矩阵,元素均为1。
true(M, N):生成一个大小为M x N的logical类矩阵,元素均为1。
false(M, N):生成一个大小为M x N的logical类矩阵,元素均为0。
magic(M):生成一个大小为M x M的“魔术方阵”,其中每行、每列和主对角线中的元素之和均相等,且元素均为整数。
rand(M, N):生成一个大小为M x N的矩阵,每个元素都是在区间[0,1]中均匀分布的随机数。
randn(M, N):生成一个大小为M x N的矩阵,其元素是正态分布的随机数,均值为0,方差为1。
>> 5*ones(3) %等效于5*ones(3, 3)
ans =
5 5 5
5 5 5
5 5 5
>> rand(2, 3)
ans =
0.7922 0.6557 0.8491
0.9595 0.0357 0.9340
>> randn(2)
ans =
0.4889 0.7269
1.0347 -0.3034