基于 Verilog HDL 设计真彩图的灰度处理模块

news2024/11/17 15:28:59



引言

FPGA比较擅长的是作定点数整数运算,那么对于带有小数部分的乘加运算。一般都选择先扩大若干倍,而后将运算结果缩小若干倍实现。

应用案例,真彩图转灰度图的心理学计算公式:

Gray = 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的整数次幂,故可计算两个加数的和,然后将第三个加数延迟一拍后再与和相加,得到最终的结果。如此一来,时序的问题可以缓解,但是带来的后果就是计算延迟增大。 

仿真

// ==============================================================================
// 功能描述:测试 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

此部分的验证提供了两种方式:

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。

说明

以上所有代码中对应的文件路径都需要个性化更改,不可以直接复制粘贴使用,否则会报错:找不到路径对应的文件。

由于本人能力有限,如果有更好的想法或者在使用中遇到问题,都可以在评论区里留言交流~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/419663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring boot基础学习之(十八):通过shiro框架使用Mybatis实现用户的认证完整的认证流程

在上几篇文章的基础上&#xff0c;实现本次案例 注意&#xff1a;本篇文章的实现代码在几篇文章都已经详细的讲过了&#xff0c;所以在此篇文章&#xff0c;将不再有理论知识的陈述&#xff0c;更过的流程&#xff0c;如何通过代码实现连接数据库进行认证 添加本次案例所需要的…

【并发编程】ConcurrentHashMap源码分析(二)

addCount 统计元素个数 private transient volatile long baseCount; //初始化大小为2,如果竞争激烈,会扩容 2->4 private transient volatile CounterCell[] counterCells;如果竞争不激烈的情况下&#xff0c;直接用cas (baseCount1)如果竞争激烈的情况下&#xff0c;采用…

项目管理的三要素:时间、成本和质量

项目管理的三要素&#xff1a;时间、成本和质量&#xff0c;他们作为衡量一个项目的成功失败的指标&#xff0c;贯穿项目整个过程。 时间&#xff1a; 项目时间管理包括使项目按时完成必须实施的各项过程。 项目计划按照逻辑关系安排计划活动顺序时&#xff0c;需要考虑进度…

C#,码海拾贝(16)——求行列式值的全选主元高斯消去法,《C#数值计算算法编程》源代码升级改进版

1 高斯消去法 数学上&#xff0c;高斯消元法&#xff08;或译&#xff1a;高斯消去法&#xff09;&#xff0c;是线性代数规划中的一个算法&#xff0c;可用来为线性方程组求解。但其算法十分复杂&#xff0c;不常用于加减消元法&#xff0c;求出矩阵的秩&#xff0c;以及求出…

利好消息不断原油价格大幅走高

​几个OPEC成员国将在年底前将全球产量再削减116万桶/天&#xff0c;这将进一步给央行遏制全球通胀的努力带来负担&#xff0c;但关键是保护该联盟更广泛的产量策略免受政治压力的影响。 华盛顿介入批评了上周日的声明&#xff0c;8个OPEC生产国&#xff08;包括组织的领导国沙…

Java中jar包的创建和使用

Java中jar包的创建和使用 jar包的基本概念 jar包的全称是java archive。jar包本质就是一种压缩包。在Java开发中一般是用来压缩类的一个包。类似C/C中的静态库和动态库&#xff0c;但是又不完全是。 C/C中的静态库和动态库是对中间文件&#xff08;*.o&#xff09;打包成一个…

【电路原理】电路元件基本知识详解

博主简介&#xff1a;努力学习的22级计科生一枚~博主主页&#xff1a; 是瑶瑶子啦所属专栏: 电路理论 前言1.电阻元件2.电容元件3.电感元件4.独立电源4.1&#xff1a;电压源4.2&#xff1a;电流源5.受控电源6.符号补充&#xff1a;7.总结本专栏文章主要总结、归纳电路原理、电路…

数据结构-排序(2)

前言&#xff1a; 上一章节介绍了 排序中的插入排序和选择排序&#xff0c; 分别复盘了插入排序中的直接插入排序和希尔排序以及选择排序中的选择排序和堆排序。今天继续复盘交换排序。 目录 2.3交换排序 2.3.1冒泡排序 2.3.2快速排序 2.3.2快速排序非递归 2.3交换排序 基…

HTML5 <figure> 标签、HTML5 <footer> 标签

HTML5 <figure> 标签 实例 使用 <figure> 元素标记文档中的一个图像&#xff1a; <figure><img src"img_pulpit.jpg" alt"The Pulpit Rock" width"304" height"228"> </figure>尝试一下 浏览器支持 …

在proteus中仿真arduino实现矩阵键盘程序

矩阵键盘是可以解决我们端口缺乏的问题&#xff0c;当然&#xff0c;如果我们使用芯片来实现矩阵键盘的输入端口缺乏的问题将更加划算了&#xff0c;本文暂时不使用芯片来解决问题&#xff0c;而使用纯朴的8根线来实现矩阵键盘&#xff0c;目的是使初学者掌握原理。想了解使用芯…

Lua脚本

目录说明什么是Lua脚本为什么要使用Lua脚本Lua脚本的安装Lua脚本的使用Lua的变量Lua脚本的算术运算符Lua脚本的关系运算符Lua脚本的逻辑运算符Lua脚本不同的操作Lua脚本的函数和标准库Redis整合Lua脚本&#xff08;重点&#xff09;在Java集成Lua在SpringBoot项目中使用Redis集…

前端PC端适配,网页端适配

问题背景 由于我司是使用的大屏&#xff0c;且设计稿尺寸为19201080。但是需要适配各种分辨率&#xff0c; 比如12801024(5:4)、1366768(16&#xff1a;10)、16801050&#xff08;16&#xff1a;10&#xff09;。在尝试了多种方法之后&#xff0c;最终确定主要的适配方法为rem…

【vue3】04-vue基础语法补充及阶段案例

文章目录vue基础语法补充vue的computedvue的watch侦听书籍购物车案例vue基础语法补充 vue的computed computed&#xff1a;用于声明要在组件实例上暴露的计算属性。&#xff08;官方文档描述&#xff09; 我们已经知道&#xff0c;在模板中可以直接通过插值语法显示一些data中…

科学的演变:从笛卡尔到生成式人工智能

编者按&#xff1a;本文主要介绍了科学的演变历史&#xff0c;从笛卡尔到生成式人工智能。文章探讨了数学在验证科学原理中的作用&#xff0c;并介绍了新机器学习工具如何验证新的科学。 文中提到&#xff0c;将生成式人工智能与Excel或iPhone进行比较是低估了这一新技术的潜在…

【AI】PaddlePaddle实现自动语音识别

文章目录文档背景安装环境Python版本pip环境安装模型需要的环境项目目录结构数据准备生成数据字典数据预处理训练模型创建模型构建模型的目的模型黑盒在模型中充当什么角色解码方法总结文档背景 学习AI的过程中&#xff0c;难免会出现各种各样的问题。比如&#xff0c;什么样的…

制造业生产管理系统(500强制造企业数字化实践)

前言 制造业是国民经济的支柱产业之一&#xff0c;随着科技和数字化的发展&#xff0c;制造业正在经历着一场新的变革。传统的制造模式已经无法满足市场的快速变化和客户的多样化需求&#xff0c;制造企业急需通过数字化和智能化转型升级&#xff0c;提高生产效率和质量水平&a…

第十四届蓝桥杯嵌入式详解

目录 第一部分 客观试题&#xff08;15 分&#xff09; 不定项选择&#xff08;1.5 分/题&#xff09; 第二部分 程序设计试题&#xff08;85 分&#xff09; 2.1 STM32CubeMX初始化配置 2.1.1 配置GPIO 2.1.2 配置ADC 2.1.3 配置RCC 2.1.4 配置定时器TIM 2.1.5 配置ADC1、AD…

【从零开始学Skynet】基础篇(二):了解Skynet

1、节点和服务 在下图所示的服务端系统中&#xff0c;每个Skynet进程&#xff08;操作系统进程&#xff09;都称为一个节点&#xff0c;每个节点都可以开启数千个Lua服务&#xff0c;每个服务都是一个Actor。不同节点可以部署在不同的物理机上&#xff0c;提供分布式集群的能力…

Velocity入门到精通(上篇)

最近自己所做的项目使用到这个Velocity模板引擎&#xff0c;分享一下在互联网找的学习资料。 目录 一. velocity简介 1. velocity简介 2. 应用场景 3. velocity 组成结构 二. 快速入门 1. 需求分析 2. 步骤分析 3. 代码实现 3.1 创建maven工程 3.2 引入坐标 3.3 编…

Redis锁的租约问题

目录Redis的租约问题Redis租约问题的想法Redis租约问题的解决方案Redis的租约问题 首先我们先来说一说什么是Redis的租约问题。   在我们实现Redis分布式锁的时候&#xff0c;我们会出现Redis锁的时间<业务执行执行时间&#xff0c;这其实就是一个典型的租约问题&#xf…