CrazyBingo

RGB转Gray算法的Matlab实现

0
阅读(11125) 评论(2)

1. RGB转Gray算法实现

1.1. RGB转Gray概念

1.2. RGB2Gray实现方案1

使用MATLAB自带rgb2gray函数,实现bmp转Gray算法,这个适用于PC上的实现。

1.2.1. Matlab代码

clear all;

% --------------------------------------------------------------------------

% Read an RGB image and convert it to a gray image.

IMG1 = imread('PLMM.bmp');  % 读取RGB文件,输入当前目录下的图片

h = size(IMG1,1);         % 读取图像高度

w = size(IMG1,2);         % 读取图像宽度

%-----------------------------------------------

subplot(1,2,1);    % 分为1行2列的子图显示,并且显示原图

% figure(1);

imshow(IMG1);

title('Original Image');

%-----------------------------------------------

IMG2 = rgb2gray(IMG1);

subplot(1,2,2);    % 分为1行2列的子图显示,并且显示原图

% figure(2);

imshow(IMG2);

title('Processed Image');

imwrite(IMG2,'E:\Matlab_Information\Matlab_Project\RGB2Gray_Process\PLMM_Gray.bmp');  %保存重建后的BMP

whos IMG2;  %输出转换后Gray图像信息

IMG3 = imread('PLMM_Gray.bmp');  % 读取RGB文件,输入当前目录下的图片

whos IMG3;  %输出转换完的Gray图像信息

1.2.2. 效果图

wps_clip_image-13994

可见大小变成了原来的1/3。系统直接存储为灰度格式的BMP图像。这对于后期自己实现Gray转换太有用了!

wps_clip_image-7175

1.3. RGB2Gray实现方案2

1.3.1. RGB2Gray算法分析及改进

1) 方法1:Adobe Photoshop 里的公式

Adobe RGB (1998) [gamma=2.20]

Gray = (R^2.2 * 0.2973 + G^2.2 * 0.6274 + B^2.2 * 0.0753)^(1/2.2)

该方法运行速度稍慢,但是效果很好。

2) 原则上的灰度,就是让R=G=B,那顾名思义,可以直接求平均,如下:

GRAY = (RED+BLUE+GREEN)/3

(GRAY,GRAY,GRAY ) 替代 (RED,GREEN,BLUE)

不过这样会导致图像质量不好,这是必然的,因为也许图像的分量不均匀,再者肉眼对色彩的敏感程度也是不一样的。

3) 典型灰度转换公式

对于彩色转灰度,有一个很著名的心理学公式:

Gray = R*0.299 + G*0.587 + B*0.114

在此0.299+0.587+0.144=1,刚好是满偏,这是通过不同的敏感度以及经验总结出来的公式,一般直接用这个!

而实际应用时,希望避免低速的浮点运算,所以需要整数算法。注意到系数都是小数点后3位,我们可以将它们缩放1000倍来实现整数运算算法,如下

Gray = (R*299 + G*587 + B*114) / 1000

加上500是为了四舍五入。但是除法就是不爽,为了能在后续实现移位,将1000扩展到1024:

Gray = (R*299 + G*587 + B*114) / 1024 = Gray = (R*299 + G*587 + B*114) >>10

适当的还可以在精简,压缩到8位以内,现在变成这样子:

Gray = (R*75 + G*147 + B*36) >>8

到目前为止,整数算法已经很快了,但是完美是没有极限的,其实是可以更快的,观察原始式子

Gray = R*0.299 + G*0.587 + B*0.114

每一通道数据乘以一个常数,这三个变量可以实现算好,保存在矩阵中,这样就只是查找表的时间了,具体时间的提升,Matlab的实现上再看!

1.3.2. Matlab代码

% -----------------------------------------------------------------------

% Relized method 2:myself Algorithm realized

% Gray = (R*75 + G*147 + B*36) >>8

IMG1 = double(IMG1);    %将图片转换为双精度类型

IMG2 = zeros(h,w);      %灰度只需要二维数组就够了,因为只有一个通道

for i = 1 : h

    for j = 1 : w

        IMG2(i,j) = bitshift((IMG1(i,j,1)*75 + IMG1(i,j,2)*147 + IMG1(i,j,3)*36),-8);

    end

end

wps_clip_image-3475

1.3.3. 效果图

如下图所示,实现Gray = (R*75 + G*147 + B*36) >>8的的灰度转换,灰度大小为RGB的一半,属性啥的都OK了。

wps_clip_image-29563

1.3.4. Matlab加速运算

前面说了,这样还不够,浮点运算可以实现算好放数组里面,后期若移植FPGA直接放在ROM里面,爽半死,尤其像CPLD这种没有乘法器的,呵呵,试试看!

% -----------------------------------------------------------------------

% Gray = R*0.299 + G*0.587 + B*0.114

fp_red = fopen('RED_ARRAY.txt','w'); 

fp_green = fopen('GREEN_ARRAY.txt','w');

fp_blue = fopen('EBLUE_ARRAY.txt','w'); 

RED_ARRAY = zeros(1,256);  %存放R通道浮点运算后的数据

GREEN_ARRAY = zeros(1,256);  %存放G通道浮点运算后的数据

BLUE_ARRAY = zeros(1,256);  %存放B通道浮点运算后存放的数据

for i = 1 : 256

    RED_ARRAY(1,i) = ((i - 1) * 0.299); %Matlab从1开始,但Gray从0开始

    GREEN_ARRAY(1,i) = ((i - 1) * 0.587); %Matlab从1开始,但Gray从0开始

    BLUE_ARRAY(1,i) = ((i - 1) * 0.114); %Matlab从1开始,但Gray从0开始

    if(rem(i,16) == 0)      %取余为0,即以写入16个数据

        fprintf(fp_red,'%03d ...\n',uint8(RED_ARRAY(1,i)));  %写入到TXT文件中

        fprintf(fp_green,'%03d ...\n',uint8(GREEN_ARRAY(1,i)));  %写入到TXT文件中

        fprintf(fp_blue,'%03d ...\n',uint8(BLUE_ARRAY(1,i)));  %写入到TXT文件中

    else

        fprintf(fp_red,'%03d ',uint8(RED_ARRAY(1,i)));  %写入到TXT文件中

        fprintf(fp_green,'%03d ',uint8(GREEN_ARRAY(1,i)));  %写入到TXT文件中

        fprintf(fp_blue,'%03d ',uint8(BLUE_ARRAY(1,i)));  %写入到TXT文件中

    end

end

fclose(fp_red); %关闭文件

fclose(fp_green); %关闭文件

fclose(fp_blue); %关闭文件

以上功能可以实现三个LUT的生成,同时写入了TXT,实际运行中并不需要。此时在Matlab中填充3个数组,RED_ARRAY如下所示:

wps_clip_image-29643

如此通过查找表来实现,只要一个加法便能得到最后的结果,如下:

% -----------------------------------------------------------------------

% Relized method 3:Realized by LUT

% Gray = R*0.299 + G*0.587 + B*0.114

%      = RED_ARRAY + GREEN_ARRAY + BLUE_ARRAY

IMG1 = double(IMG1);    %将图片转换为双精度类型

IMG2 = zeros(h,w);      %灰度只需要二维数组就够了,因为只有一个通道

for i = 1 : h

    for j = 1 : w

        % 因为Matlab从1开始,所以+1

        IMG2(i,j) = RED_ARRAY(1,IMG1(i,j,1)+1) + GREEN_ARRAY(1,IMG1(i,j,2)+1) + BLUE_ARRAY(1,IMG1(i,j,3)+1);

    end

end

最终只消耗了0.196s,相对于前面的0.447s,提升了不少。关键是这样做的话,在FPGA中就完全不用浮点运算,加速逻辑的实现。

wps_clip_image-30637

  1. 原来近似的、
  2. lz也爱原干惠