文章目录
- 一、什么是伽马校正?
- 二、伽马校正的由来
- 三、Matlab实现伽马校正
-
- [3.1 matlab代码](#3.1 matlab代码)
- [3.2 matlab结果](#3.2 matlab结果)
- 四、Verilog实现伽马校正
-
- [4.1 生成初始化ROM文件](#4.1 生成初始化ROM文件)
- [4.2 Verilog代码](#4.2 Verilog代码)
- [4.3 仿真结果](#4.3 仿真结果)
一、什么是伽马校正?
Gamma校正是图像处理中用以调整图像的亮度和对比度来改善图像质量的。Gamma校正是基于人眼对亮度的感知非线性,人眼对亮度的敏感度随着亮度的增加而减少,也就是人眼在图像亮度较低时,人眼对亮度的变换更敏感。例如:人眼在夜晚很容易看见萤火虫,而在白天不容易看到天空中飞翔的鸟。伽马曲线如下所示:
二、伽马校正的由来
早期的显示设备(如CRT显示器)在处理光信号时表现出非线性特性。CRT显示器的亮度输出与输入信号的电压之间存在幂律关系:
O = I Y O=I^{Y} O=IY
Y就是所说的伽马值,例如:给 CRT 显示器输入一个 0.5(I=0.5), CRT 显示器的输出O输出 0.218,输入与输出间存在一个指数大概为 2.2 的幂次关系(这是人们根据实践总结出来的值)。
不同的Y对于的曲线不一样:
- 当伽马值小于1时,会拉伸图像中灰度较低的区域,同时压缩图像中灰度较高的区域,使得图像的暗部变亮,亮度变暗。
- 当伽马值大于1时,会拉伸图像中灰度较高的区域,同时压缩图像中灰度较低的区域,使得图像的暗部变暗,亮度变亮。
三、Matlab实现伽马校正
伽马校正就涉及到幂函数运算,直接使用运算就可以了:
3.1 matlab代码
matlab
clear all; close all; clc;
% 读取图像
img = imread('...\....\....\....\......\....\.....\dark.bmp');
grayImg = rgb2gray(img); % 转换为灰度图像
% 选择伽马值
gamma1 = 2.2; % 例如,使用伽马值2.2
gamma2 = 0.5; % 例如,使用伽马值0.5
% 归一化像素值
normalizedImg = double(grayImg) / 255;
% 应用伽马校正
correctedImg1 = normalizedImg .^ gamma1;
correctedImg2 = normalizedImg .^ gamma2;
% 反归一化像素值
correctedImg1 = uint8(correctedImg1 * 255);
correctedImg2 = uint8(correctedImg2 * 255);
% 显示原始和校正后的图像
figure;
subplot(1, 3, 1);
imshow(grayImg);
title('原始图像');
subplot(1, 3, 2);
imshow(correctedImg1);
title('伽马2.2校正后的图像');
subplot(1, 3, 3);
imshow(correctedImg2);
title('伽马0.5校正后的图像');
3.2 matlab结果
可以看到,伽马值2.2使得图像画面亮度部分更亮,暗部部分更暗了,伽马值为0.5使得图像画面亮度部分变暗,暗部部分变亮了。我们不显示灰度图像,直接显示彩色图片:
这样也非常的明显看到伽马值对图像亮部暗部的变化。
四、Verilog实现伽马校正
4.1 生成初始化ROM文件
我们从公式可以看到伽马校正涉及到的是幂函数,但是fpga不擅长处理幂函数,因此我们可以使用一个rom来提前存放好0-255灰阶的幂函数,这样我们输入一个灰度值作为rom的读地址,就能直接得到新的灰度值,ROM的初始文件用Matlab生成,代码如下:
matlab
clear all; close all; clc;
% 设定伽马值
gammaValue = 2.2; % 替换为你想要的伽马值
% 生成伽马校正表
LUT = zeros(256, 1);
for i = 0:255
LUT(i + 1) = round((i / 255) ^ gammaValue * 255);
end
% 生成MIF文件
mifFileName = 'gamma_correction.mif'; % MIF文件名
fileID = fopen(mifFileName, 'w');
% 写入MIF文件头
fprintf(fileID, 'DEPTH = 256;\n');
fprintf(fileID, 'WIDTH = 8;\n');
fprintf(fileID, 'ADDRESS_RADIX = HEX;\n');
fprintf(fileID, 'DATA_RADIX = HEX;\n');
fprintf(fileID, 'CONTENT BEGIN\n');
% 写入LUT数据
for i = 0:255
fprintf(fileID, '%02X : %02X;\n', i, LUT(i + 1));
end
fprintf(fileID, 'END;\n');
% 关闭文件
fclose(fileID);
生成的coe文件如下:
4.2 Verilog代码
代码很简单,就例化一个256深度,8位宽的ROM,然后把COE文件烧录进去,输入的灰度图像数据作为ROM的读地址,其他的信号都打一拍输出即可,代码如下:
c
`timescale 1ns / 1ps
module gamma_map(
input clk ,
input rst ,
input i_hsync ,
input i_vsync ,
input i_data_valid ,
input [23:0] i_data ,
output o_hsync ,
output o_vsync ,
output o_data_valid ,
output [23:0] o_data
);
/***************reg*******************/
reg ro_hsync ;
reg ro_vsync ;
reg ro_data_valid;
/***************wire******************/
wire [7:0] rom_data ;
/***************component*************/
gammp_map_rom u0_gamma_rom (
.clka (clk ), // input wire clka
.addra(i_data[23:16] ), // input wire [7 : 0] addra
.douta(rom_data ) // output wire [7 : 0] douta
);
/***************assign****************/
assign o_hsync = ro_hsync ;
assign o_vsync = ro_vsync ;
assign o_data_valid = ro_data_valid ;
assign o_data = {rom_data,rom_data,rom_data} ;
/***************always****************/
always @(posedge clk) begin
if(rst == 1'b1)
ro_data_valid <= 'd0;
else if(i_data_valid == 1'b1)
ro_data_valid <= i_data_valid;
else
ro_data_valid <= 'd0;
end
always @(posedge clk) begin
if(rst == 1'b1)
ro_hsync <= 1'b0;
else
ro_hsync <= i_hsync;
end
always @(posedge clk) begin
if(rst == 1'b1)
ro_vsync <= 1'b0;
else
ro_vsync <= i_vsync;
end
endmodule
4.3 仿真结果
仿真输入一个彩色图像,然后生成灰度图像以及伽马矫正后的图像命名为new_img:
c
rgb2gray u_rgb2gray(
.clk ( clk ),
.rst ( reset ),
.i_data_valid ( valid_i ),
.i_hsync ( img_hs ),
.i_vsync ( img_vs ),
.i_data_r ( img_data_i[23:16] ),
.i_data_g ( img_data_i[15:8] ),
.i_data_b ( img_data_i[7:0] ),
.o_data_valid ( valid_o ),
.o_hsync ( o_img_hs ),
.o_vsync ( o_img_vs ),
.o_data_r ( img_data_o[23:16] ),
.o_data_g ( img_data_o[15:8] ),
.o_data_b ( img_data_o[7:0] )
);
gamma_map u_gamma_map(
.clk ( clk ),
.rst ( reset ),
.i_hsync ( o_img_hs ),
.i_vsync ( o_img_vs ),
.i_data_valid ( valid_o ),
.i_data ( img_data_o ),
.o_hsync ( ),
.o_vsync ( ),
.o_data_valid ( o_post_cal_gray_data_valid ),
.o_data ( o_post_cal_gray_data )
);
可以看到gamma值2.2矫正后的图像,亮部区域更亮,暗部区域更暗,和matlab的一致。