RGB转Gray算法的Matlab实现
0赞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. 效果图
可见大小变成了原来的1/3。系统直接存储为灰度格式的BMP图像。这对于后期自己实现Gray转换太有用了!
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
1.3.3. 效果图
如下图所示,实现Gray = (R*75 + G*147 + B*36) >>8的的灰度转换,灰度大小为RGB的一半,属性啥的都OK了。
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如下所示:
如此通过查找表来实现,只要一个加法便能得到最后的结果,如下:
% -----------------------------------------------------------------------
% 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中就完全不用浮点运算,加速逻辑的实现。