FPGA/图像处理/创业/职场
关注
基于FPGA的灰度图像处理之幂律(伽马)变化
1 背景知识
幂律变换的基本形式为:
----------------------------------------------------------------------------------------(1)
其中c和r为正常数。有时考虑到偏移量 可将式(1)写为
------------------------------------------------------------------------------------(2)
偏移量一般是显示标定问题,作为一个结果,通常在式(1)中忽略不计。对于不同的值,s与r的关系如图1所示。
图1 r变换曲线
与对数变换的情况类似,部分r值的幂律曲线将较窄范围的暗色输入值映射为较宽范围的输出值,相反的,对于输入高灰度级值时也成立。然而与对数函数不同的是,随着r值的变化,将简单地得到一簇可能的变化曲线。如图1所示,r>1的值所生成的曲线和r<1的值所生成的曲线的效果完全相反。当c=r=1时简化成了恒等变换。
用于图像获取,打印和显示的各种设备根据幂律来产生响应。习惯上,幂律方程中的指数称为伽马。用于校正这些幂律响应现象的处理称为伽马校正。
图2 航拍图幂律变换
如图2所示,a航拍原图b~d令c=1且分别等于3.0,4.0和5.0时应用式(1)给出的变换的结果(此例的原图像由NASA提供)。
2 FPGA实现
图3 FPGA实现幂律变换框架图
由图2可知对于灰度图像直接经过幂律变换就可以得到幂律变换图像,但是对于FPGA直接实现对数公式显然难度很大。在FPGA中我们采用基于查找表的方式进行幂律变换。
ROM表的制作:
Matlab源码:
clear all
close all
clc
depth = 256;
width =8;
r = [0:1:255];
x = r; %恒等变换
y =16*sqrt(r);%开根
%z = round(y);
m = (1/256)*r.^2; %r平方
z = round(m);
fid = fopen('E:\matlab_project\log\square.mif','w');%路径
fprintf(fid,'depth= %d; \n',depth);
fprintf(fid,'width= %d; \n',width);
fprintf(fid,'address_radix=uns;\n');
fprintf(fid,'data_radix = uns;\n');
fprintf(fid,'Content Begin \n');
for(k=1:depth)
fprintf(fid,'%d: %d; \n',k-1,z(k));
end
fprintf(fid,'end;');
hold on
plot(x);
plot(y);
plot(m);
hold off
FPGA源码:
//------------------------------------------
// power law
//------------------------------------------
wire [7:0] sqrt_data; //root
wire [7:0] square_data;//square
rom_sqrt rom_sqrt_inst(
.address(o_y_8b),
.clken(TFT_de),
.clock(TFT_clk),
.q(sqrt_data)
);
rom_square rom_square_inst(
.address(o_y_8b),
.clken(TFT_de),
.clock(TFT_clk),
.q(square_data)
);
//assign TFT_rgb = {sqrt_data[7:3],sqrt_data[7:2],sqrt_data[7:3]}; //Y
assign TFT_rgb = {square_data[7:3],square_data[7:2],square_data[7:3]}; //Y
//assign TFT_rgb = {o_y_8b[7:3],o_y_8b[7:2],o_y_8b[7:3]}; //Y
实验结果:
图4 原图
图5原图灰度显示
图6整体变暗
图7整体变亮
结果分析:
图6、图7和图5相比,图6明显变暗,图7明显变亮。此技术可以应用在图像采集系统上,当拍摄的光线较暗时,我们可以采取亮变换;当光线过强时,我们可以采取暗变化,从而达到人眼更适合的效果。
3 基于ov5640的图像采集系统的幂律变换移植
verilog源码:
//------------------------------------------
// power law
//------------------------------------------
wire [7:0] sqrt_data; //root
wire [7:0] sqrt_r_data; //root
wire [7:0] sqrt_g_data; //root
wire [7:0] sqrt_b_data; //root
wire [7:0] square_data;//square
wire [7:0] square_r_data;//square
wire [7:0] square_g_data;//square
wire [7:0] square_b_data;//square
rom_sqrt rom_sqrt_r_inst(
.address({rgb[15:11],3'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(sqrt_r_data)
);
rom_sqrt rom_sqrt_g_inst(
.address({rgb[10:5],2'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(sqrt_g_data)
);
rom_sqrt rom_sqrt_b_inst(
.address({rgb[4:0],3'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(sqrt_b_data)
);
rom_square rom_square_r_inst(
.address({rgb[15:11],3'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(square_r_data)
);
rom_square rom_square_g_inst(
.address({rgb[10:5],2'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(square_g_data)
);
rom_square rom_square_b_inst(
.address({rgb[4:0],3'b0}),
.clken(TFT_DE),
.clock(TFT_VCLK),
.q(square_b_data)
);
assign TFT_RGB = {square_r_data[7:3],square_g_data[7:2],square_b_data[7:3]};
//Y The image darker
//assign TFT_RGB = {sqrt_r_data[7:3],sqrt_g_data[7:2],sqrt_b_data[7:3]};
//Y Image brighter
源码解释:
通过对R,G,B三个通道进行square处理后合成新的16bitRGB数据整个图像彩色相比较原RGB图像变暗;通过对R,G,B三个通道进行root处理后合成新的16bitRGB数据整个图像彩色相比较原RGB图像变亮。
有兴趣的同学可以将square数据和sqrt数据线性叠加来输出彩色图像或者与RGB原通道数据进行线性叠加。结果将是下图:
我们可以调整彩色的不同明亮度来达到不同的效果。
请欣赏视频: