来源:https://blog.csdn.net/zhuiyuanzhongjia/article/details/79621813
1、显示RGB图像
相同点:这三个函数都是把m*n*3的矩阵中的数值当做RGB值来显示的。
区别:imshow将图像以原始尺寸显示,image和imagesc则会对图像进行适当的缩放(显示出来的尺寸大小)。
2、显示灰度图像
说明:先搞明白什么是索引图像?(灰度图像也是索引图像的一种)
当用Matlab中的imread函数将图像读入并存入矩阵时,我们知道如果是RGB图像,得到是m*n*3的矩阵,但如果是索引图像,得到就是m*n的矩阵,这个矩阵的每个元素只是1个数值,那么怎么确定它的RGB值来显示图像呢?这就需要colormap了,colormap是一个m*3的矩阵,每一行有3列元素构成RGB组,也就是一种颜色,一个m*3的colormap中有m中颜色,而索引图像存储的数值和colormap中的行号对应起来就可以像RGB那样显示图片了,至于对应方法,可以直接对应(比如1对应1,2对应2)也可以是线性映射对应(比如[-128,128]映射到[1,256])。还有一点要说明的是,默认情况下每一个figure都有且仅有一个colormap,而且默认的是 jet(64),可在figure窗口通过,edit->colormap...查看,另外在弹出的窗口colormap editor中,可通过Tools->Standard colormap来修改当前figure的colormap,这里是Matlab已经做好的一些colormap。
(1)当灰度图像转化成矩阵后,矩阵中的元素都介于[0,255],下面我们结合具体实例来看看这三个函数的调用效果,并解释原因。代码:
- clear all;clc;close all;
- img = imread('lenna.bmp');
- % my picture is named lenna.bmp while yours may be not
- I = rgb2gray(img);
- % Attention: we use the axis off to get rid of the axis.
- figure(1),image(I); %equals to imagesc(I,[1 64]);you can try it.
- colorbar,title('show by image in figure1');axis off;
- figure(2),imagesc(I);
- %equals to imagesc(I,[min(I(:)) max(I(:))]);you can try it.
- colorbar,title('show by imagesc in figure2');axis off;
- %colormap(gray) %use this statement you can get a gray image.
- figure(3),imshow(I),colorbar,title('show by imshow in figure3');
显示效果:
我们看到现象是image 和imagesc 显示出来是彩色的,只有imshow显示出来是灰度图像,为什么会出现这种情况呢?还记得前面所说的吗,索引图像是矩阵和colormap配合起来显示的,而每个figure默认使用的colormap 是jet(64),而不是gray(gray和gray(64)是一样的),这个jet(64)就使得figure1和figure2中显示出来时是彩色的,当然你也可以修改当前figure的colormap使用colormap(gray)(使用64个等级的灰度色图),或者colormap(gray(256))(使用256个等级的灰度色图,这就是调用imshow函数时使用的colormap,后面有讲解)。而figure3为什么会是灰度图像呢,这是因为当调用imshow来显示索引图像时,这个函数就会把当前的figure的colormap设置成gray(256),这下明白为什么会出现这种情况了吧。我们再仔细观察一下figure1和figure2会发现,figure2中人物的轮廓显示的还算可以,而figure1中则出现了大面积的红色的区域,人物的轮廓被抹掉了很多。
为什么会出现这样的情况呢?这就要说说索引图像矩阵中的数(以下简称矩阵中的数)和colormap中的索引(index)的对应关系了。
image:这个函数,直接把矩阵中的数当做索引值(我称为直接映射),例如colormap中索引为1的是颜色RGB1,索引为2的是颜色RGB2,……,索引为64的是颜色RGB64。那么矩阵中为1的数就显示成颜色RGB1,矩阵中为2的数就显示成颜色RGB2,……,矩阵中为64的数就显示成颜色RGB64,值得注意的是当矩阵中的数小于1时,此时该数也将被显示成颜色RGB1,同样,而矩阵中大于64的数将被显示成颜色RGB64(类似于信号处理里面的限幅,也可以认为是削顶或者削底了),这下我们就能明白为什么figure1中会出现大面积的红色区域,这说明这些地方的数值都大于等于64。
imagesc: 在figure2中我们用imagesc来显示图像与figure1相比能较好的显示出来,同样我们也得搞明白调用imagesc时矩阵的数和colormap中索引的对应关系,与image不同的是imagesc采用的不是直接映射而是线性映射,至于什么是线性映射,我粗略的说一下,比如把区间A = [0,a]映射到区间B = [0,b]我们对A中的元素做A/a*b就可以了,矩阵的数到colormap索引的线性映射大概就是这样,Matlab会自动获取矩阵中数的最小值和最大值,并把区间[Cmin,Cmax]映射到colormap的[最小索引,最大索引]比如[1,64],然后再根据这个对应关系把图像显示出来,具体的算法细节是Matlab确定的,当然也可以自己指定显示范围,比如一副索引图像I范围为[27,218],而我只想显示[1 64 ],使用命令imagesc(I,[1 64])就可以了,如果你把上面程序中的imagesc(I)换成imagesc(I,[1,64]),那么figure2中的效果就和figure1中一样了,因为只是把[1,64]这个范围映射到色图,超过的都被认为是64。关于映射,我截图Matlab中imagesc的help页给大家看看,这里要自己慢慢体会哦,使用imagesc(I)这种线性映射就可以用到整个色图从而将图像较好的显示出来,这就是figure2中的显示效果比figure1中好的原因。
imshow:调用这个函数会把当前figure的colormap设置成gray(256),这个前面也有提到,我们先讨论矩阵元素是uint8型(范围:0~255,整数,一般使用imread和 rgb2gray返回的都是uint8型的),同样我们也要搞明白矩阵中的数和colormap中颜色索引的对应关系,imshow的功能是比较全的,它即可使用像image那样的直接映射,也可使用像imagesc那样的线性映射,当我们使用imshow(I),即只有一个矩阵作为参数,这时采用的是直接映射,比如矩阵中元素0就显示成colormap中索引为1的颜色也就是黑色,矩阵中元素255就显示成colormap中索引为256的颜色也就是白色,(注意:uint8范围是0~255,而gray(256)的索引是1:256,当然这些我们只要了解就可以了,编程并不会用到,因为这些对应的细节Matlab已经帮我们做好了)如果这样调用imshow(I,[ ]),此时矩阵中的数和颜色表就是线性映射,为什么会这样,我解释一下,我们看这种调用方式和imagesc(I,[1 64])很相似,其实原理是一样的,第二个参数是一个向量,这个向量指定了矩阵中映射到颜色表的数的范围,也就是显示范围(Matlab里叫做display range)前面已经介绍了,Matlab中imshow的help中说如果采用imshow(I,[low high])调用imshow的话而且你用[ ]代替[low high]那么imshow会使用[min(I(:)) max(I(:))]作为显示范围,也就说I中的最小值会显示成黑色,最大值会显示成白色,这其实就是整个范围的线性映射(没有削顶也没有削底),此时的imshow(I,[ ])函数就相当于imagesc(I);
为了说明imshow不仅具有image的功能也具有imagesc的功能,同时体会一下直接映射和线性映射的区别,我们来写一段小程序来测试一下,程序如下:
- clear all;clc;close all;
- img = imread('lenna.bmp');
- I = rgb2gray(img);
- figure(1),image(I); colormap(gray(256));
- colorbar,title('show by image in figure1');axis off;
- figure(2),imagesc(I);colormap(gray(256));
- % We can see that the image showed in figure(2) is a little bright
- % than in figure(1).
- colorbar,title('show by imagesc in figure2');axis off;
- % When we use the imshow, we do not need to set the colormap,
- % because the imshow set the colormap to gray(256) automatically.
- figure(3),imshow(I),colorbar,title('show by imshow(I) in figure3');
- % The effectiveness in figure(3) is the same as in figure(1).
- figure(4),imshow(I,[]),colorbar,title('show by imshow(I,[]) in figure3');
- % The effectiveness in figure(4) is the same as in figure(2).
显示效果:
我们可以看出figure2中的图像比figure1中的图像要亮一些,而且,figure3中的显示效果和figure1中是一样的,figure4中的显示效果和figure2中是一样的,为什么会这样呢?这是因为image(I)和imshow(I)是将I中的值直接作为colormap(gray(256))中的索引,也就是我所说的直接映射,我这里读到的索引图像矩阵也就是I中的数值的范围是[27,218],也就是说直接映射显示I,只用到的色图(colormap)上[27,218]范围的颜色,(比如表示白色的索引255就没有用到),从右边的colorbar也可以看出来。但线性映射就不一样了,imagesc(I),和imshow(I,[ ])采用的就是线性映射,线性映射把[27,218]按照线性算法(Matlab写的)映射到色图索引[1,256]然后再显示出来,这样整个色图的颜色都被用到了,这里也可以认为把[27,218]放大到[1,256],这就是figure2中显示效果比figure1中亮的原因。
小结:直接映射和线性映射的区别在于映射到色图的数值范围,如果是[min(I(:)) max(I(:))]就是线性映射,如果是0-255或者1-64或者0-1就是直接映射。这个数值范围就叫做显示范围(display range)。
3、最后再说说image,imagesc,imshow 在显示double型数据时的用法,
我们做图像处理就会对图像进行运算,使用uint8型数据精度不高,因为当运算结果超过255时会被认为是255,而负数就会被认为是0(注意在Matlab中数据默认采用double型(64位)进行存储和运算)所以,我们读到灰度图像后一般都会将图像转换成double型(I = double(I))然后再参与运算,运算的结果有正有负,也有小数,正的还可能超过255,比如我经过运算后的得到图像矩阵I,假如I的范围是[-187,152],当然你也可以用max(I(:))和min(I(:))去获取,这时怎么显示图像呢?image,imagesc,imshow 都可以用来显示double型数据的图像矩阵,主要区别如下:
image:将double型数据取整(正数取整就是把小数部分舍掉)然后使用直接映射的方法按照颜色表显示。
imagesc:这个函数很好,会对数据进行缩放再显示,也就是把显示范围自动设置成[min(I(:)) max(I(:))],也就是线性 映射。
imshow:这个函数调用方式不同,显示效果也不同,如下:
imshow(I):直接调用,因为当图像为double型时imshow函数会把显示范围设置成[0 , 1],这样小于0的就变成黑色了,大于1的就变成白色了,所以处理不当就会出现全白的情况。
imshow( I/(max(I(:))):针对直接调用imshow函数出现的问题,用max(I(:) ) 对图像矩阵进行归一化再显示,这样负数部分会变黑,正数部分还可以正常显示,但有一部分信息丢失了。
imshow(uint8(I)):这种方式把I转化成uint8,负数会被归零,超过255的被置为255,而且小数也会被round(四舍五入),当参数为uint8型时,imshow函数把显示范围设置成[0,255],这样图像虽然也能显示出来,但与原始数据相比来说,丢掉很多信息,但有时可能却是想要的结果,这个要看具体情况。
imshow(I,[ ]):这种方式就是把imshow的显示范围设置成[min(I(:)) max(I(:))],也就是线性映射,相当于imagesc(I),colormap(gray(256))可以将整幅图像的信息显示出来。
综上所述,大家根据自己实际需要选用显示函数和对应的参数,这些是我自己研究学习的心得,表述难免有些疏漏,有发现严重错误的,可以给我留言,但可以给大家一个感性的认识,从云里雾里的困境里走出来。