Verilog HDLに基づくTrue Color画像のグレースケール処理モジュールの設計



序章

FPGA は、固定小数点整数演算、つまり小数部分を含む乗算や加算演算を行うのに適しています。一般に、最初に数回拡張し、次に演算結果を数回削減して達成することを選択します。

応用事例、トゥルーカラー画像をグレースケール画像に変換するための心理計算式:

グレー = 0.299R + 0.587G + 0.114B

この記事では、具体的なデザインとシミュレーションのソース コード (Verilog HDL) を示します。MATLAB プラットフォームと組み合わせて、結果の精度を検証します。

Verilog コンパイル シミュレーション プラットフォーム: Vivado 2018.3

MATLAB バージョン: 2022a


デザイン

// ==============================================================================
// 功能描述:真彩图 转 灰度图
// 作 	 者:Xu Y. B.
// 计算公式:Gray = 0.299R + 0.587G + 0.114B
// 思	 路:采用定点运算,先将系数扩大若干倍,最后的结果在缩小若干倍
// ==============================================================================

`timescale 1ns / 1ps

module RGB_2_GRAY_MDL #(
// ---- ---- ---- ---- 模块可重载参数 ---- ---- ---- ---- 
parameter		P_PIXEL_DATA_WIDTH 		= 		24,    //像素数据位宽 ,RGB 分量等位宽
parameter		P_SCALE_FACTOR     		= 		1024,  //系数缩放因子
parameter		P_GRAY_DATA_WIDTH 		=		8      //输出灰度数据位宽
)(
// ---- ---- ---- ----     模块端口    ---- ---- ---- ----
input 											I_OPR_CLK,
input 											I_OPR_RSTN,
input 											I_PIXEL_VAL,
input			[P_PIXEL_DATA_WIDTH-1:0]		I_PIXEL_DATA,// R:MSB B:LSB

output 	reg										O_GRAY_VAL,
output 			[P_GRAY_DATA_WIDTH-1:0]			O_GRAY_DATA

    );
// ---- ---- ---- ----     内部参数    ---- ---- ---- ----
localparam 		LP_RIGHT_SHIFT_VALUE 	=		$clog2(P_SCALE_FACTOR);
integer 		INT_COEF_R				=		0.299*P_SCALE_FACTOR;
integer 		INT_COEF_G				=		0.587*P_SCALE_FACTOR;
integer 		INT_COEF_B				=		0.114*P_SCALE_FACTOR;
localparam 		LP_GRAY_RES_WIDTH 		=		FUNC_CAL_GRAY_RES_WIDTH(P_SCALE_FACTOR,P_PIXEL_DATA_WIDTH);

// ---- ---- ---- ----     内部信号    ---- ---- ---- ----
reg 			[LP_GRAY_RES_WIDTH-1:0] 		R_GRAY_RES;
// ---- ---- ---- ----     内部逻辑    ---- ---- ---- ----
always @ (posedge I_OPR_CLK)
begin
	if(~I_OPR_RSTN)
	begin
		O_GRAY_VAL <= 1'b0;
		R_GRAY_RES <= {LP_GRAY_RES_WIDTH{1'b0}};
	end
	else
	begin
		if(I_PIXEL_VAL)
		begin
			O_GRAY_VAL <= I_PIXEL_VAL;
			R_GRAY_RES <= (I_PIXEL_DATA[P_PIXEL_DATA_WIDTH-1-:8] * INT_COEF_R
						  +I_PIXEL_DATA[P_PIXEL_DATA_WIDTH/3+:8] * INT_COEF_G
						  +I_PIXEL_DATA[0+:8] * INT_COEF_B)>>LP_RIGHT_SHIFT_VALUE;//此处组合逻辑延迟较大 , 待优化
		end
		else
		begin
			O_GRAY_VAL <= 1'b0;
			R_GRAY_RES <= {LP_GRAY_RES_WIDTH{1'b0}};			
		end
	end
end
assign O_GRAY_DATA = R_GRAY_RES[0+:P_GRAY_DATA_WIDTH];

// ---- ---- ---- ----     函数/任务   ---- ---- ---- ----
// 计算最终结果的右移数值
function integer FUNC_CAL_GRAY_RES_WIDTH;
	input integer SCALE_FACTOR;
	input integer PIXEL_DATA_WIDTH;

	begin
		FUNC_CAL_GRAY_RES_WIDTH = PIXEL_DATA_WIDTH/3 + $clog2(SCALE_FACTOR) + 1 + 1;
	end
endfunction 

endmodule

設計ソースコードはパラメトリックプログラミングの仕様に従い、スケーリングファクターや出力ビット幅を設定できます。使用時には内部ロジックやパラメータを調整することなく直接呼び出すことができます。

3 つの乗算および加算演算のロジックには、例として、より高い周波数クロックでのセットアップ タイム/ホールド タイムが含まれる場合があることに注意してください。

ここでは、パイプライン構造を使用して計算するアイデアを示します。つまり、最初に 3 項目の乗算を計算し、次に 3 項目の加算を計算します。加算を計算する場合は、加数の数に注意が必要です。加算される は 2 の整数乗に等しくないため、2 つの加算値の合計を計算し、3 番目の加算値を 1 拍遅らせてから合計に加算して、最終結果を取得します。このようにして、タイミングの問題は軽減できますが、その結果、計算遅延が増加します。 

シミュレーション

// ==============================================================================
// 功能描述:测试 RGB_2_GRAY_MDL 模块
// 作 	 者:Xu Y. B.
// 计算公式:像素数据激励
// 思	 路:
// ==============================================================================


`timescale 1ns / 1ps
module TB_RGB_2_GRAY_MDL();

parameter		P_PIXEL_DATA_WIDTH 		= 		24;    //像素数据位宽 ,RGB 分量等位宽
parameter		P_SCALE_FACTOR     		= 		1024;  //系数缩放因子
parameter		P_GRAY_DATA_WIDTH 		=		8;     //输出灰度数据位宽


reg											I_OPR_CLK;
reg											I_OPR_RSTN;
reg											I_PIXEL_VAL;
reg			[P_PIXEL_DATA_WIDTH-1:0]		I_PIXEL_DATA;// R:MSB B:LSB

wire 										O_GRAY_VAL;
wire 		[P_GRAY_DATA_WIDTH-1:0]			O_GRAY_DATA;

reg 		[P_PIXEL_DATA_WIDTH-1:0] 		R_PIXEL_DATA[24366:1];


// 产生激励时钟
initial I_OPR_CLK = 1'b0;
always #5 I_OPR_CLK = ~I_OPR_CLK;

// 数据读取
initial
begin
	$readmemb("D:/A_Vivado_WorkSpace/DSP_BASIC_STUDY/MAT_FILE/IMAGE_PIXEL_DATA.txt",R_PIXEL_DATA);
end

// 复位、数据控制
initial
begin
	I_OPR_RSTN = 1'b0;
	// I_PIXEL_VAL  = 0;
	// I_PIXEL_DATA = 0;
	#109;
	I_OPR_RSTN = 1'b1;
	// @(posedge I_OPR_CLK)
	// I_PIXEL_VAL  <= 1;
	// I_PIXEL_DATA <= {8'd121,8'd99,8'd230};
	// @(posedge I_OPR_CLK)
	// I_PIXEL_VAL  <= 1;
	// I_PIXEL_DATA <= {8'd101,8'd90,8'd210};
	// @(posedge I_OPR_CLK)
	// I_PIXEL_VAL  <= 1;
	// I_PIXEL_DATA <= {8'd151,8'd69,8'd240};
	// @(posedge I_OPR_CLK)
	// I_PIXEL_VAL  <= 1;
	// I_PIXEL_DATA <= {8'd221,8'd109,8'd20};
	@(negedge O_GRAY_VAL)
	I_PIXEL_VAL  <= 0;
	#290;
	$finish;	
end

integer K=1;

always @ (posedge I_OPR_CLK)
begin
	if(~I_OPR_RSTN)
	begin
		I_PIXEL_VAL  <= 0;
		I_PIXEL_DATA <= 0;
	end
	else if(K<=24366)
	begin
		I_PIXEL_VAL  <= 1;
		I_PIXEL_DATA <= R_PIXEL_DATA[K];
		K <= K+1;		
	end
	else
	begin
		K = K;
		I_PIXEL_VAL  <= 0;
		I_PIXEL_DATA <= 0;		
	end
end

integer FILE_ID ;


initial
begin
	FILE_ID = $fopen("D:/A_Vivado_WorkSpace/DSP_BASIC_STUDY/MAT_FILE/GRAY_DATA.txt","w+");
	while(~O_GRAY_VAL | ~I_OPR_RSTN) @(posedge I_OPR_CLK);

	while(O_GRAY_VAL)
	begin
		$fdisplayb(FILE_ID,O_GRAY_DATA);
		@(posedge I_OPR_CLK);
	end
	$fclose(FILE_ID);
end

RGB_2_GRAY_MDL #(
		.P_PIXEL_DATA_WIDTH(P_PIXEL_DATA_WIDTH),
		.P_SCALE_FACTOR    (P_SCALE_FACTOR),
		.P_GRAY_DATA_WIDTH (P_GRAY_DATA_WIDTH)
	) INST_RGB_2_GRAY_MDL (
		.I_OPR_CLK    (I_OPR_CLK),
		.I_OPR_RSTN   (I_OPR_RSTN),
		.I_PIXEL_VAL  (I_PIXEL_VAL),
		.I_PIXEL_DATA (I_PIXEL_DATA),
		.O_GRAY_VAL   (O_GRAY_VAL),
		.O_GRAY_DATA  (O_GRAY_DATA)
	);

endmodule

この部分の検証には 2 つの方法があります。

1. 注釈が付けられた部分は、計算の精度を検証するためにいくつかのデータをモジュールに送信するだけです。

2. txt ファイル内のピクセル データを読み取り、計算のためにモジュールに送信し、計算結果を別の txt ファイルに保存して、MATLAB と FPGA によって計算された誤差を比較します。(この部分の具体的な実装については以下を参照してください) 

比較して検証する

Matlab は、分析と比較のためのテスト データとソース コードを生成します。

%% ==================== 像素数据读取存储 ====================
% 作者:Xu Y. B.
% 说明:
%       -1- 读取真彩图的RGB数据,拼接为24位二进制数,存入txt文件
%       -2- 对真彩图作灰度处理,并与FPGA处理结果作对比
% =============================================================

%% CLEAR
clc;
clearvars;
close all;

%% 图片读取
FILE_PATH = "C:\Users\XYB\Pictures\高清壁纸Z\wallhaven-5758y8.jpg";
IMAGE_DATA = imread (FILE_PATH,"jpg");
figure;
imshow(IMAGE_DATA);
title("原真彩图")
% 图片截取
PIXEL_DATA = IMAGE_DATA(240:425,868:998,:);
figure;
subplot(121)
imshow(PIXEL_DATA);
title("截取的真彩图")
subplot(122)
IM2GRAY = im2gray(PIXEL_DATA);
imshow(IM2GRAY)
title("截取的真彩图转灰度图")

%% 数据转化存储
PIXEL_DATA_R = PIXEL_DATA(:,:,1);
PIXEL_DATA_G = PIXEL_DATA(:,:,2);
PIXEL_DATA_B = PIXEL_DATA(:,:,3);

PIXEL_DATA_R_BIN = dec2bin(reshape(PIXEL_DATA_R,[],1));
PIXEL_DATA_G_BIN = dec2bin(reshape(PIXEL_DATA_G,[],1));
PIXEL_DATA_B_BIN = dec2bin(reshape(PIXEL_DATA_B,[],1));

PIXEL_DATA_BIN   = strcat(strcat(PIXEL_DATA_R_BIN,PIXEL_DATA_G_BIN),PIXEL_DATA_B_BIN);

WRITE_PATH = "D:\A_Vivado_WorkSpace\DSP_BASIC_STUDY\MAT_FILE\IMAGE_PIXEL_DATA.txt";
writematrix(PIXEL_DATA_BIN,WRITE_PATH,"WriteMode","overwrite","FileType","text")

%% FPGA处理结果读取
READ_PATH = "D:\A_Vivado_WorkSpace\DSP_BASIC_STUDY\MAT_FILE\GRAY_DATA.txt";
GRAY_DATA_FPGA = uint8(bin2dec(readmatrix(READ_PATH,"OutputType","string")));
GRAY_IMAG = reshape(GRAY_DATA_FPGA,186,[]);
figure;
subplot(121)
imshow(GRAY_IMAG)
title("FPGA处理结果")
subplot(122)
imshow(IM2GRAY)
title("MATLAB处理结果")
GRAY_PROC_ERR = uint8(abs(double(GRAY_IMAG)-double(IM2GRAY)));
figure;
mesh(GRAY_PROC_ERR);
title("FPGA MATLAB处理结果差异三维图")
figure;
imagesc(GRAY_PROC_ERR)
title("FPGA MATLAB处理结果差异平面")

元の画像:

MATLAB の画像インターセプトとグレースケール処理:

FPGA 処理結果と MATLAB 処理結果の比較:

エラー分析:

上記の分析と検証の結果に基づいて、Verilog HDL に基づいて設計されたモジュールはトゥルー カラー画像をグレースケール画像に正確に変換でき、MATLAB 計算結果との最大差は 1 であり、これはおそらく丸め精度の問題によるものであると考えられます。 。この問題は、スケーリング係数を 1024 から 2048 に変更するなど、スケーリング係数を増やすことによってのみ軽減できます。

説明する

上記のすべてのコード内の対応するファイル パスは個人用に設定する必要があり、直接コピーして貼り付けることはできません。そうしないと、パスに対応するファイルが見つからないというエラーが報告されます。

私の能力は限られているため、より良いアイデアがある場合、または使用中に問題が発生した場合は、コメント欄にメッセージを残して連絡してください~~~

おすすめ

転載: blog.csdn.net/qq_43045275/article/details/130182104