这份笔记是对冈萨雷斯《数字图像处理第三版》的学习整理,编程语言选择MATLAB,笔记中有大量MATLAB中IPT的API介绍
一幅图像可以定义为一个向量值函数 f ( x , y ) f(x,y) f(x,y) , 其中 ( x , y ) (x, y) (x,y) 表示空间坐标(二维空间即为平面), f ( x , y ) f(x, y) f(x,y) 是一个向量,称为像素值,通常是一维或三维。如表示黑白图像时, f(x,y) 是一维的,此时也称为灰度,表示RGB图像时, f(x,y) 是三维,分量分别表示(红,绿,蓝)三个通道的值。
将一幅图像存储到计算机中时,需要对图像数字化,对空间坐标的数字化称为取样,对亮度的数字化称为量化,数字化后的图像仅由有限个离散值表示,称为数字图像。
数字图像处理就是用计算机处理图像。
图像处理与计算机视觉之间没有明显界限
粗略分类:
对一幅图像取样后,假设得到 M M M行 N N N列的图像,称图像大小为 M × N M\times N M×N.
通常采用如下两种约定:
类型 | 名称 | 描述 |
---|---|---|
数值型 | double | Matlab默认类型,双精度浮点数,- 1 0 308 10^{308} 10308~ 1 0 308 10^{308} 10308 (8字节每像素) |
数值型 | uint8 | 无符号8比特整数,[0, 255] (1字节每像素) |
数值型 | uint16 | 无符号16比特整数,[0, 65535] (2字节每像素) |
数值型 | uint32 | 无符号32比特整数,[0, 4294967295] (4字节每像素) |
数值型 | int8 | 有符号8比特整数,[-128, 127] (1字节每像素) |
数值型 | int16 | 有符号16比特整数,[-32768, 32767] (2字节每像素) |
数值型 | int32 | 有符号32比特整数,[-2147483648, 2147483647] (4字节每像素) |
数值型 | single | 单精度浮点数,- 1 0 38 10^{38} 1038~ 1 0 38 10^{38} 1038 (4字节每像素) |
字符型 | char | 字符(2字节每像素) |
逻辑型 | logical | 值为0或1(1字节每像素) |
一幅灰度图像是一个数据矩阵
像素的数据类型可以是uint8或uint16, 此时取值范围分别是[0,255]或[0, 65535]的整数值
也可以是double, single,此时像素值是浮点数,通常归一化为[0,1], 也可取其他范围值
二值图像是取值只有0,1的逻辑数组。取值为0,1的数值型数组在Matlab中不认为是二值图像
基本结构
map是 m × 3 m\times 3 m×3 的矩阵,元素是double类,取值在[0,1]之间,每行代表一个归一化的RGB三原值,m表示颜色总数
X存储颜色索引
如果X是double类,则小于或等于1的所有值对应map的第一行,所有等于2的值对应第二行,以此类推
如果X是uint8,uint16,则0对应第一行,1对应第二行,以此类推
基本结构
M × N × 3 M\times N\times 3 M×N×3 数组
数组每个元素的数据类型:
每个像素是一个三维向量[r,g,b],分别表示红,绿,蓝分量
色彩数: ( 2 b ) 3 (2^b)^3 (2b)3 ,b代表数组每个元素的比特数
术语:通常提到一幅图像时,是指 “data_class image_type 图像”。 data_class是MATLAB支持的数据类型,image_type是IPT支持的图像类型
语法: B = d a t a _ c l a s s _ n a m e ( A ) B = data\_class\_name(A) B=data_class_name(A)
data_class_name可以是MATLAB支持的任意一种数据类型,如:
B = d o u b l e ( A ) B = double(A) B=double(A)
会将A转换为double类型B
任何数值型转换为逻辑型时,非0值转换为逻辑值1,0值转换为逻辑值0
double是MATLAB的默认类型,double转换为整型时,小于该整型取值范围最小值的均转换为最小值,大于该整型取值范围最大值的均转换为最大值,小数部分直接舍去。如:
input:
a = int8(-129)
b = int8(3.23)
c = logical([0 1 2;1 2 3;3.2 0.0 -1])
output
a =
int8
-128
b =
int8
3
c =
3×3 logical 数组
0 1 1
1 1 1
1 0 1
语法: i s l o g i c a l ( A ) islogical(A) islogical(A)
input:
a = 7;
islogical(a)
output:
ans =
logical
0
input:
a = logical(7);
islogical(a)
output:
ans =
logical
1
语法: i m r e a d ( ′ f i l e n a m e ′ ) imread('filename') imread(′filename′)
f = imread('F:\Matlab\chapter1\rose_512.tif');
格式名称 | 描述 | 可识别扩展名 |
---|---|---|
TIFF | 加表识的图像文件格式 | .tif , .tiff |
JPEG | 联合图像专家组 | .jpg , .jpeg |
GIF | 图形交换格式 | .gif |
BMP | windows位图 | .bmp |
PNG | 可移植网络图形 | .png |
XWD | X windows 转储 | .xwd |
A = [5 6 7;1 2 3];
A(:,:,2) = [2 3 4; 5 6 7];
size(A)
output: ans =
2 3 2
f = [1 2 3; 4 5 6; 7 8 9];
whos f
output: Name Size Bytes Class Attributes
f 3x3 72 double
语法一: imshow( f, G)
语法二: imshow(f ,[low , high])
语法三: imshow(f, [ ])
这个形式相当于语法二中low取f的最小值,high取f的最大值
这个形式在显示一幅动态范围较小的图像或者既有正值又有负值的图像时有优势
input:
>> f = imread('D:\typora图片\Fig0203(a)(chest-xray).tif');
>> figure
>> subplot(1,2,1);imshow(f),title('imshow(f)');
>> subplot(1,2,2);imshow(f,[]),title('imshow(f,[])');
如果f为double型,一定要用这个形式
语法: imwrite(f, ‘filename’)
imwrite(f,'picture.tif')
imwrite(f,'picture1','tif')
q是0-100之间的整数,q越小,图像压缩越厉害,图像退化越严重
例:
input:
>> f = imread('D:\typora图片\Fig0204(a)(bubbles-q-100jpg).tif');
>> imwrite(f,'bubbles50.jpg','quality',50)
>> imwrite(f,'bubbles25.jpg','quality',25)
>> imwrite(f,'bubbles15.jpg','quality',15)
>> imwrite(f,'bubbles5.jpg','quality',5)
>> imwrite(f,'bubbles0.jpg','quality',0)
>> f100 = imread('bubbles-q-100.tif');
>> f50 = imread('bubbles50.jpg');
>> f25 = imread('bubbles25.jpg');
>> f15 = imread('bubbles15.jpg');
>> f5 = imread('bubbles5.jpg');
>> f0 = imread('bubbles0.jpg');
>> figure
>> subplot(2,3,1);imshow(f100),title('原图');
>> subplot(2,3,2);imshow(f50),title('q=50');
>> subplot(2,3,3);imshow(f25),title('q=25');
>> subplot(2,3,4);imshow(f15),title('q=15');
>> subplot(2,3,5);imshow(f5),title('q=5');
>> subplot(2,3,6);imshow(f0),title('q=0');
output:
压缩图像是为了降低存储量,减少传输时间,但压缩过大就会失真,通常判断压缩是否合理,就看有没有明显的伪轮廓线。
>> imfinfo bubbles25.jpg
output: ans =
包含以下字段的 struct:
Filename: 'F:\Matlab\chapter1\bubbles25.jpg'
FileModDate: '07-Jun-2019 12:50:34'
FileSize: 13354
Format: 'jpg'
FormatVersion: ''
Width: 720
Height: 688
BitDepth: 8
ColorType: 'grayscale'
FormatSignature: ''
NumberOfSamples: 1
CodingMethod: 'Huffman'
CodingProcess: 'Sequential'
Comment: {}
>> K = imfinfo('bubbles25.jpg');
>> image_bytes = K.Width*K.Height*K.BitDepth/8;
>> compressed_bytes = K.FileSize;
>> compression_ratio = image_bytes/compressed_bytes
output: compression_ratio =
37.0945
>> f = imread('D:\typora图片\2.10.jpg');
>> imwrite(f,'sf.tif','compression','none','resolution',[300,300])
>> g = imread('sf.tif');
>> figure
>> subplot(1,2,1);imshow(f),title('原图');
>> subplot(1,2,2);imshow(g),title('sf.tif');
格式名称 | 描述 | 可识别扩展名 |
---|---|---|
TIFF | 加表识的图像文件格式 | .tif , .tiff |
JPEG | 联合图像专家组 | .jpg , .jpeg |
XWD | X windows 转储 | .xwd |
BMP | windows位图 | .bmp |
PNG | 可移植网络图形 | .png |
im2uint8
语法: g = i m 2 u i n t 8 ( f ) g = im2uint8(f) g=im2uint8(f)
im2uint16
同im2uint8,只是255改成65535.
mat2gray
语法: g = m a t 2 g r a y ( A , [ A m i n , A m a x ] ) g = mat2gray(A, [Amin, Amax]) g=mat2gray(A,[Amin,Amax])
im2double
im2bw
语法: g = i m 2 b w ( f , T ) g = im2bw(f, T) g=im2bw(f,T)
>> v =[2 4 6 8 10 12 14 16];
>> v([2 4 6])
ans =
4 8 12
每个维度都支持向量索引的方式
使用向量做索引值
语法: A[u,v]
使用矩阵寻址的方式
例:用逻辑数组取出逻辑值1位置处的元素,返回一个列向量
A ( : ) 以逐列的顺序返回A所有元素构成 的列向量
使用数组索引进行简单的图像操作
>> f = imread('D:\typora图片\Fig0219(rose1024).tif');
>> fp = f(end:-1:1,:);
>> fc = f(233:666,233:666);
>> fs = f(1:2:end,1:2:end);
>> plot(f(512,:))
>> figure
>> subplot(1,4,1);imshow(f),title('原图');
>> subplot(1,4,2);imshow(fp),title('翻转');
>> subplot(1,4,3);imshow(fc),title('截取部分');
>> subplot(1,4,4);imshow(fs),title('二次取样');
一类操作: o p e r a t i o n ( A , d i m ) operation(A,dim) operation(A,dim)
>> A = 1;
>> B = [2 2];
>> C = [2 3;3 4];
>> D(:,:,1) = [2 3 ;4 5];
>> D(:,:,2) = [6 7;8 9];
>> ndims(A),ndims(B),ndims(C),ndims(D)
ans =
2
ans =
2
ans =
2
ans =
3
>> A = [1 2 3];
>> B = A;
>> A = [1 2 4];
>> B
B =
1 2 3
第二行命令只是记录了B=A,并不把数据复制给B,但第三行A要改变时,才将数据复制给BIPT支持的图像运算函数
逻辑函数
条件分支
通用形式语法:
if expression1
statements1
elseif expression2
statements2
...
else expressionk
statementsk
end
例:计算图像的平均亮度
function ave = average(A)
%AVERAGE computes the average value of an array
% av=average(A) computes the average value of input array,A, which must be
% 1-D or 2-D array
% check the validity of input
if ndims(A) > 2
error('The dimension of input can not exceed 2!')
end
%compute the average
ave = sum(A(:))/length(A(:));
for 循环
语法:
for index = start:step:endpoint
statements
end
while循环
语法:
while expresssion
statements
end
break
退出包含它的最内层循环
continue
直接进入包含它的循环的下一次迭代
switch
switch switch_expresssion
case case_expression1
statement(s)
case case_expression2
statement(s)
...
otherwise
statement(s)
end
function s = subim(f,m,n,rx,cy)
%SUBIM extracts a subimage s from a given image f
% The subimage is of size m_by_n, and the coordinates of its top_left
% conner are (rx,cy)
s = zeros(m,n);
rowhigh = rx + m - 1;
colhigh = cy + n - 1;
xcount = 0;
for r = rx:rowhigh
xcount = xcount + 1;
ycount = 0;
for c = cy:colhigh
ycount = ycount + 1;
s(rcount, ycount) = f(r,c);
end
end
向量化循环
原理:利用矩阵运算避免显式地使用循环
例:生成一个一维函数,函数形式是:
f ( x ) = A s i n ( x / 2 π ) f(x)=Asin(x/2\pi) f(x)=Asin(x/2π)
其中 x = 0 , 1 , . . . , M − 1 x=0,1,...,M-1 x=0,1,...,M−1
for x = 1:M
f(x) = A*sin(x/(2*pi));
end
x = 1:M;
f(x) = A*sin(x/(2*pi));
二维函数情形
meshgrid
语法: [C,R] = meshgrid(c,r)
>> r = [0 1 2];
>> c = [0 1];
>> [C,R] = meshgrid(c,r), h = R.^2+C.^2
output: C =
0 1
0 1
0 1
R =
0 0
1 1
2 2
h =
0 1
1 2
4 5
例:比较两种方式的计算速度
编写一个M文件,比较for循环与向量化代码的运算速度,所实现的二维函数:
f ( x , y ) = A s i n ( u 0 x + v 0 y ) f(x,y)=Asin(u_0 x+v_0 y) f(x,y)=Asin(u0x+v0y)
x = 0 , 1 , . . . , M − 1 , y = 0 , 1 , . . . , N − 1 x=0,1,...,M-1 , y=0,1,...,N-1 x=0,1,...,M−1,y=0,1,...,N−1
函数输入: A , u 0 , v 0 , M , N A,u_0,v_0,M,N A,u0,v0,M,N
函数输出:由两种方式生成的图像,以及所用时间之比
function [tratio, f, g] = two_method_sin(A, u0, v0, M, N)
%TWO_METHOD_SIN Compares for loops vs. vectorization
% The comparison is based on implementing the function
% f(x,y)=Asin(u0*x+v0*y) for x=0,1,...,M-1 and y=0,1,...N-1
% The inputs to the function are M and N and the constants in the
% function
% first implement using for loops
tic % start timing
for r = 1:M
u0x = u0*(r-1);
for c = 1:N
v0y = v0*(c-1);
f(r,c) = A*sin(u0x + v0y);
end
end
t1 = toc; % end timing
% now implement using vectorization
tic % start timing
r = 0:M-1;
c = 0:N-1;
[C,R] = meshgrid(c,r);
g = A*sin(u0*R + v0*C);
t2 = toc; % end timing
% compute the ratio of the two times
tratio = t1/(t2 + eps); % use eps in case t2 is close to 0
>> [rt,f,g] = two_method_sin(1, 1/(4*pi), 1/(4*pi), 512, 512);
>> rt
rt =
10.9560
提取图片中某一矩形区域
区域左上角坐标为 ( r x , r y ) (rx,ry) (rx,ry) , 大小为 m × n m\times n m×n , f 是将要提取的图像。
rowhigh = rx + m - 1;
colhigh = ry + n - 1;
s = f(rx:rowhigh, ry:colhigh);
预分配数组
>> f = zeros(1024);
交互式I/O
>> A = [1 2 3]
A =
1 2 3
>> disp(A)
1 2 3
>> disp('Hello MATLAB!')
Hello MATLAB!
>> t = input('enter some data:','s')
enter some data:1 2 3
t =
'1 2 3'
>> class t
ans =
'char'
>> size(t)
ans =
1 5
>> n = str2num(t)
n =
1 2 3
>> size(n)
ans =
1 3
>> class(n)
ans =
'double'
>> t = '2.3,hello,x';
>> [a,b,c] = strread(t,'%f%q%q','delimiter',',');
>> a,b,c
a =
2.3000
b =
1×1 cell 数组
{'hello'}
c =
1×1 cell 数组
{'x'}
单元数组与结构
单元数组
>> c = {'gauss',[1.0 3.0],3},c{1}
output: c =
1×3 cell 数组
{'gauss'} {1×2 double} {[3]}
ans =
'gauss'
结构
>> S.char_str = 'gauss';
>> S.matrix = [1.0 3.0];
>> S.scalar = 3;
>> S.matrix
output: ans =
1 3
《数字图像处理第三版》(冈萨雷斯)
《数字图像处理(matlab)》