Matlab图像处理常用函数汇总与注意事项

Aug 9,2020   4589 words   17 min

Tags: Others

最近这段时间用Matlab比较多,作为用惯了Python+OpenCV+Numpy的我来说,或多或少还是有些不太习惯,尤其是在Matlab对图像的输入输出以及类型转换上。这篇博客就简单总结整理一下Matlab中相关的常用工具函数,以方便以后查阅。

1.图片读取相关

(1)imread()

Matlab中图片读取和OpenCV是类似的,都是imread()函数。传入的参数也很类似,都是影像的路径。需要注意的是与OpenCV不同的是Matlab在读取的时候并不要指定一个FLAG(比如cv2.IMREAD_GRAYSCALE)来说明读取灰度还是RGB。 Matlab会自己根据影像所包含的通道数来读取影像内容。比如下面的代码:

% 影像读取
img_rgb = imread('img_rgb.png');
img_gray = imread('img_gray.png');

可以看到,分别读取了两个uint8类型的470×470的影像,一个是只有一个通道的灰度影像,一个是有三个通道的RGB影像。

(2)ndims()

这是一个很常用的函数,可以用来判断读取的图片有多少个通道,如果是1个那就是灰度影像,如果是3个那就是RGB影像。如果只需要处理灰度影像,那就是用rgb2gray()(后面会介绍)将其转为灰度即可。

(3)histogram()

从字面意思就可以知道它是用来计算影像的灰度直方图的,直接使用即可,十分方便。

2.图片像素值访问与操作

(1)单个像素操作

图片可以看作是矩阵,所以直接通过索引就可以获取对应灰度值。不过有两点需要注意:1.Matlab中都是用小括号表示索引的,而不是Python或C++中的中括号。2.Matlab中索引是从1开始,而不是从0开始。 对于单波段影像,I(x,y)获取得到的就是(x,y)处的灰度值;而对于多波段影像,需要用I(x,y,c)的方式获取某一波段c(x,y)处的灰度值。

(2)块操作

与Python类似,图片的块操作依然是用冒号的方式,比如对某个单波段灰度影像,I(a:b,c:d)即表示获取从a到b,c到d这个范围内的所有元素。 有两个需要注意的细节:1.第一维表示竖直方向,对应图像的高;第二维表示水平方向,对应图像的宽。2.Matlab中a:b左右边界都包含

(3)灰度越界处理

Matlab中,对于灰度越界的情况处理策略是,大于最大值(如8bit的255)的全部赋成最大值,小于最小值(如8bit的0)的全部赋成最小值。这一点需要注意一下。如下代码演示了这种效果。

img_gray = imread('img_gray.png');

img_gray_plus = img_gray + 100;
img_gray_minus = img_gray - 100;

subplot(1,3,1);imshow(img_gray_minus);title('img - 100');
subplot(1,3,2);imshow(img_gray);title('img gray');
subplot(1,3,3);imshow(img_gray_plus);title('img + 100');

上面分别是对应的图片与灰度直方图。

(4)最值获取

在Matlab中并没有像Python中那样方便的max()函数可用。要想获取一个二维矩阵的最值,需要写成这样:max(max(I))min(min(I))。原因在于最值函数都是针对一维数据的,如果你只写了一个,比如max(I),那么你获取到的就是每一列的最大值。

3.图片类型转换

(1)数据类型转换

顾名思义就是对读取影像的数据类型进行转换。比如一般8bit的影像,读入以后元素的数据类型都是uint8,如果后续基于这个类型进行运算的话,可能会无法得到正确的结果,尤其运算涉及到小数、负数或者超出0到255范围的情况下。 这时候就需要对数据类型进行转换。一般而言,都是转换为double类型。在Matlab中提供了多种方式,比如常用的两种是double()im2double()

a.double()

其实这类似于Python或C++里的强制类型转换,就是将每个元素的类型强制转换成double,不改变数据内容本身。比如120变成120.0。

b.im2double()

Matlab提供的函数,同样用于将读取的影像转换为double类型。但这里一定需要注意的是,这个函数会把灰度归一化。最后得到的结果是0到1之间的小数。 说是归一化,但这里需要注意的是并不是对原始灰度进行拉伸到0到1之间,就是简单的归一化。 它并不是将当前影像中的最大、最小灰度值线性拉伸到0到1,而是简单的除法,将每个灰度值除以当前量化等级的最大灰度值。 举个例子。例如某8bit影像的实际灰度范围为0到214,经过im2double()函数归一化之后,灰度范围为0到0.839。因为214/255=0.839。

c.im2uint8()

这个函数其实与上面的类似,但不同之处在于将数据转换为uint8类型。这一般在保存图片成8bit影像的时候用的比较多一些。 但在使用时也有需要注意的地方。这个输入的矩阵的数值范围必须要在0到1之间。如果小于0,会被赋为0;如果大于1,会被赋为1。而在0到1之间的小数,则会被乘以255,得到最后的灰度值。 这点要切记,使用前记得对数据进行归一化。

(2)变量类型转换
a.rgb2gray()

在前面简单提到过,它的作用是将读取的RGB影像转换成对应的灰度影像,转换之后的数据类型和原图相同。例如uint8的RGB影像,转换后是uint8的灰度影像。

b.mat2gray()

顾名思义,用于将矩阵转换为灰度值在0到1之间的灰度影像。具体而言,它按照如下公式进行计算:gray = (gray-min)*(max-min)。 也就是说它会找到原始矩阵中的最大和最小值,分别将它们作为1和0,其余值都根据它们进行计算。 根据它的这个特性,在使用时就需要格外小心了。比如处理了一个8bit影像,最终的结果灰度在0到200之间,你想把它保存下来。 然后你用了mat2gray()这个函数,它就会将现在0到200的灰度拉伸到0到255之间,结果就是转换后的灰度范围在0到1,这时再保存,就已经不是你处理的原始结果了。 所以在使用之前一定需要考虑清楚。

4.图片显示

(1)imshow()

Matlab中的图像显示和OpenCV中是一样的,都是imshow()函数,可以显示RGB或灰度影像,比如如下所示。 但在使用过程中也有一些需要注意的地方,否则可能show出来的和真实的数据是有差异的。 首先对于uint8类型的影像而言,基本没有什么大问题,正常使用就好。 问题在于对于一些double类型的影像。因为经过一系列处理,不可避免会使用到浮点型运算。它在显示浮点型影像的时候需要特别注意。 简单一句话总结就是对于浮点型影像,在show之前一定要归一化到0到1之间,不然显示的都是一片白(全部大于1)或一片黑(全部小于0)。 比如下面的代码演示了这种效果。

img_gray = imread('img_gray.png');

img_gray_d = im2double(img_gray);
img_gray_d_minus = img_gray_d - 2.0;
img_gray_d_plus = img_gray_d + 2.0;

subplot(1,3,1);imshow(img_gray_d_minus);title('img - 2.0');
subplot(1,3,2);imshow(img_gray_d);title('img double');
subplot(1,3,3);imshow(img_gray_d_plus);title('img + 2.0');

效果如下。 可以看到,只要是小于0或大于1的灰度都无法正常显示。左边图中灰度值为-1.69的被显示为0,右边2.733的显示为1。 这样可能会带来的一种结果就是本来对比度很强的结果,被他显示的没那么强了。 比如一个矩阵的最小值为-10,最大值为10。但它一显示,所有负数全都是黑色了,而所有大于1的都是白色,对比度显然就降低了。 如果这种情况的话,不妨考虑先对矩阵利用mat2gray()函数进行归一化,然后再用imshow()会好一些。比如下面的代码演示了这种情况。

img_gray = imread('img_gray.png');

img_gray_d = im2double(img_gray);
img_gray_d_minus = img_gray_d - 0.4;
img_gray_d_norm = mat2gray(img_gray_d);

subplot(1,3,1);imshow(img_gray_d);title('img double');
subplot(1,3,2);imshow(img_gray_d_minus);title('img - 0.4');
subplot(1,3,3);imshow(img_gray_d_norm);title('img - 0.4 norm');

(2)imagesc()

在Matlab中,还有imagesc()函数(是image scale的缩写)专门用来可视化二维矩阵,将矩阵中的元素数值按照大小转化为不同颜色。在很多实验中也是个非常常用的函数,尤其是需要查看原始的结果的时候。相比于用imshow()mat2gray()把矩阵归一化到0到1之间显示,它可以直接显示任意范围的原始数据。如下所示。

5.图片保存

同样的,与OpenCV中的函数名称一样,为imwrite()。需要注意的同样是数据的范围问题,其实和imshow()基本上是一致的,它在保存的时候并不会主动地对灰度进行拉伸。 对于uint8类型的数据,只要注意最大值不超过,一般没什么问题。对于double类型的数据,则必须要是归一化到0到1之间的,不然小于0的全部为黑色,大于1的全部为白色。0到1之间的则直接乘以当前量化等级的最大灰度值(默认为8bit)。

另外就是在保存结果时对于精度的考虑。如果你对精度要求很高,结果也是double类型的,保存的8bit的影像满足不了你,那还是建议你以mat文件的形式保存原始数据。可以保存uint8的作为预览图。 可以直接使用Matlab的save()load()保存或加载mat文件。不过需要注意它们的用法。下面的代码演示了批量保存数据。

A = [1,2,3;4,5,6];

for i = 1:10
    A = A * i;
    name = [sprintf('%03d',i),'.mat'];
    save(name,'A');
end

6.总结对比

最后把上面提到的几个函数总结如下表,表中函数都是以8bit为例。表格内容只是个人理解,如果有错误的地方也欢迎提出。

本文作者原创,未经许可不得转载,谢谢配合

返回顶部