FPGA与Matlab图像处理之伽马校正

文章目录


一、什么是伽马校正?

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的一致。

相关推荐
ThreeYear_s21 分钟前
基于FPGA 的4位密码锁 矩阵键盘 数码管显示 报警仿真
fpga开发·矩阵·计算机外设
禁默4 小时前
2024年图像处理、多媒体技术与机器学习
图像处理·人工智能·microsoft
Anin蓝天(北京太速科技-陈)6 小时前
252-8路SATAII 6U VPX高速存储模块
fpga开发
发呆小天才O.oᯅ8 小时前
YOLOv8目标检测——详细记录使用OpenCV的DNN模块进行推理部署C++实现
c++·图像处理·人工智能·opencv·yolo·目标检测·dnn
如何学会学习?9 小时前
2. FPGA基础了解--全局网络
fpga开发
Anin蓝天(北京太速科技-陈)9 小时前
271-基于XC7V690T的12路光纤PCIe接口卡
嵌入式硬件·fpga开发
stm 学习ing9 小时前
HDLBits训练3
c语言·经验分享·笔记·算法·fpga·eda·verilog hdl
机器学习之心10 小时前
Bayes-GRU-Attention的数据多特征分类预测Matlab实现
matlab·分类·gru
叶庭云10 小时前
Matlab 和 R 语言的数组索引都是从 1 开始,并且是左闭右闭的
matlab·编程语言·r·数组索引·从 1 开始
tiger11911 小时前
制造研发企业与IPD管理体系
项目管理·制造·fpga·芯片·半导体·ipd