【FPGA】中值滤波处理BMP图片

news2024/11/17 18:27:30

文章目录

  • 一、中值滤波
  • 二、BMP图片格式
  • 三、功能实现
      • 1.代码设计思路
      • 2.shift IP核
      • 3.代码实现
  • 四、结果测试
  • 参考博客

一、中值滤波

中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。
中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近真实值,从而消除孤立的噪声点。

二、BMP图片格式

bmp文件的存储格式是Windows系统中广泛使用的图像文件格式,对图像不做任何程度的压缩处理,主要分为位图头文件,位图信息头,调色板信息,像素数据四大部分,由于通常是处理RBG图像,因此仅讨论RGB的情况

位图头文件 :文件的格式、大小等信息,前14Byte;主要关心的是图像尺寸,像素数据开始位置。
位图信息头:提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息,前40Byte;主要关心的是图像宽度,图像高度。
调色板信息:保留字,不关心
像素数据 :像素数据,8bit一个像素数据,即1Byte。

三、功能实现

1.代码设计思路

在这里插入图片描述

第一步:对3x3窗口的每一行进行排序,得到每行max,mid,min数
第二步:对第一步排序得到的第一列3个max排序取min,第二列3个mid排序取mid,第三列 3个min排序取max
第三步:对第二步产生的三个数进行排序,取mid得到中值

2.shift IP核

altera提供了矩阵的IP核,我们设置好位宽8、两路输出、每行640个深度(图像长度),这样就能生成一个3x3的矩阵
在这里插入图片描述shift ip核仿真图:

3.代码实现

在这里插入图片描述
我们首先把输入的数据放进filter_3x3模块,然后通过shift IP核生成一个3x3的窗口,然后再通过sort_3模块对窗口里9个数进行排序得到中值并输出。

median_filter顶层模块

module median_filter(
    input               clk     ,
    input               rst_n   ,
    
    input               iValid  ,
    input       [7:0]   iData   ,

    output      [7:0]   oData
);

//参数定义
wire    [7:0]filter_11;
wire    [7:0]filter_12;
wire    [7:0]filter_13;

wire    [7:0]filter_21;
wire    [7:0]filter_22;
wire    [7:0]filter_23;

wire    [7:0]filter_31;
wire    [7:0]filter_32;
wire    [7:0]filter_33;
																																															
wire    [7:0]max1;
wire    [7:0]max2;
wire    [7:0]max3;

wire    [7:0]mid1;
wire    [7:0]mid2;
wire    [7:0]mid3;

wire    [7:0]min1;
wire    [7:0]min2;
wire    [7:0]min3;

wire    [7:0]min_of_max;
wire    [7:0]max_of_min;
wire    [7:0]mid_of_mid;

filter_3x3 inst_filter_3x3(
    .clk      (clk),
    .rst_n    (rst_n),
    .iValid   (iValid),
    .iData    (iData),

    .oData_11 (filter_11), 
    .oData_12 (filter_12), 
    .oData_13 (filter_13),

    .oData_21 (filter_21), 
    .oData_22 (filter_22), 
    .oData_23 (filter_23),

    .oData_31 (filter_31), 
    .oData_32 (filter_32), 
    .oData_33 (filter_33)
);

//第一步:对3x3窗口的每一行进行排序,得到每行max,mid,min数
sort_3 inst_sort_3_11(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (filter_11),
    .data2 (filter_12),
    .data3 (filter_13),
    .max   (max1),
    .mid   (mid1),
    .min   (min1)
);
sort_3 inst_sort_3_12(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (filter_21),
    .data2 (filter_22),
    .data3 (filter_23),
    .max   (max2),
    .mid   (mid2),
    .min   (min2)
);
sort_3 inst_sort_3_13(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (filter_31),
    .data2 (filter_32),
    .data3 (filter_33),
    .max   (max3),
    .mid   (mid3),
    .min   (min3)
);

//第二步:对第一步排序得到的第一列3个max排序取min,第二列3个mid排序取mid,第三列 3个min排序取max
sort_3 inst_sort_3_21(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (max1),
    .data2 (max2),
    .data3 (max3),
    .max   (),
    .mid   (),
    .min   (min_of_max)
);
sort_3 inst_sort_3_22(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (mid1),
    .data2 (mid2),
    .data3 (mid3),
    .max   (),
    .mid   (mid_of_mid),
    .min   ()
);
sort_3 inst_sort_3_23(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (min1),
    .data2 (min2),
    .data3 (min3),
    .max   (max_of_min),
    .mid   (),
    .min   ()
);

//第三步:对第二步产生的三个数进行排序,取mid得到中值
sort_3 inst_sort_3_3(
    .clk   (clk),
    .rst_n (rst_n),
    .data1 (min_of_max),
    .data2 (mid_of_mid),
    .data3 (max_of_min),
    .max   (),
    .mid   (oData),
    .min   ()
);
endmodule

fitlet_3x3模块

module filter_3x3(
    input               clk         ,
    input               rst_n       ,


    input       [7:0]   iData       ,
    input               iValid      ,

    output  reg [7:0]   oData_11    ,
    output  reg [7:0]   oData_12    ,
    output  reg [7:0]   oData_13    ,

    output  reg [7:0]   oData_21    ,
    output  reg [7:0]   oData_22    ,
    output  reg [7:0]   oData_23    ,

    output  reg [7:0]   oData_31    ,
    output  reg [7:0]   oData_32    ,
    output  reg [7:0]   oData_33    
);

    reg     [7:0]   row3_data   ;
    wire    [7:0]   row2_data   ;
    wire    [7:0]   row1_data   ;

     // shift_ram实现2行缓存
    line_shift_ram inst_line_shift_ram(
        .clock    (clk),
        .clken    (iValid),
        .shiftin  (row3_data),
        .taps0x   (row2_data),
        .taps1x   (row1_data),
        .shiftout ()
    );

    // 将输入数据寄存作为窗口第三行起始数据,同时也作为行缓存的输入
    always @(posedge clk, negedge rst_n) begin
        if(!rst_n)
            row3_data <= 0;
        else if(iValid)
            row3_data <= iData;
        else 
            row3_data <= 0;
    end

    // 获取3x3模板
    always @(posedge clk, negedge rst_n) begin
        if(!rst_n) begin
            {oData_11, oData_12, oData_13} <= 3'b000;
            {oData_21, oData_22, oData_23} <= 3'b000;
            {oData_31, oData_32, oData_33} <= 3'b000;
        end else if(iValid) begin
            {oData_11, oData_12, oData_13} <= {oData_12, oData_13, row1_data};
            {oData_21, oData_22, oData_23} <= {oData_22, oData_23, row2_data};
            {oData_31, oData_32, oData_33} <= {oData_32, oData_33, row3_data};
        end
    end

endmodule

sort_3模块

//排序模块,对三个数进行排序
module sort_3(
    input               clk     ,
    input               rst_n   ,
    input       [7:0]   data1   ,
    input       [7:0]   data2   ,
    input       [7:0]   data3   ,
    output reg  [7:0]   max     ,
    output reg  [7:0]   mid     ,
    output reg  [7:0]   min
);

//max最大数
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        max <= 1'b0 ;
    else if(data1 >= data2 && data1 >= data3)
        max <= data1;
    else if(data2 >= data1 && data2 >= data3)
        max <= data2;
    else
        max <= data3;
end

//mid中间数
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        mid <= 1'b0 ;
    else if((data1 >= data2 && data1 <= data3) || (data1 >= data3 && data1 <= data2))
        mid <= data1;
    else if((data2 >= data1 && data2 <= data3) || (data2 >= data3 && data2 <= data1))
        mid <= data2;
    else
        mid <= data3;
end

//min最小数
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        min <= 1'b0 ;
    else if(data1 <= data2 && data1 <= data3)
        min <= data1;
    else if(data2 <= data1 && data2 <= data3)
        min <= data2;
    else
        min <= data3;
end
endmodule

tb文件

`timescale 1ns / 1ns

module bmp_tb;
reg				clk		;
reg				rst_n	;
reg				iValid	;
reg		[7:0]	iData	;
wire	[7:0]	oData	;


//图像属性:图像宽度 图像高度 图像尺寸 图像像素点起始位
integer bmp_width;
integer bmp_high;
integer bmp_size;
integer start_index;

//bmp file id
integer bmp_file_id;
integer bmp_dout_id;
integer dout_txt_id;

//文件句柄
integer h;
//文件bmp文件数据
reg		[7:0]	rd_data  [0:307200];//根据自己图片大小
reg		[7:0]	dout_data  [0:307200];

//写操作
reg		[23:0]	wr_data;
integer i = 0;
integer index,index0;



median_filter median_filter_inst(
    .clk	(clk	),
    .rst_n	(rst_n	),

    .iValid	(iValid	),
    .iData	(iData	),

    .oData	(oData	)
);


//时钟周期设置
parameter CYCLE =20;
initial begin
	clk = 1;
	forever
	#(CYCLE/2)
	clk=~clk;
end
//复位设置
initial begin
	rst_n = 1;
	#(CYCLE*2);
	rst_n = 0;
	#(CYCLE*3);
	rst_n = 1;
end

initial
begin
	iValid = 0;
	#(6*CYCLE)
	//打开原始图像
	bmp_file_id = $fopen("D:\\desktop\\in_img.bmp","rb");
	//打开输出图像
	bmp_dout_id = $fopen("D:\\desktop\\out_img.bmp","wb");
	//打开输出数据
	dout_txt_id = $fopen("D:\\desktop\\out_img.txt","w+");

	//读取bmp文件
	h = $fread(rd_data,bmp_file_id);

    // 图像宽度
	bmp_width = {rd_data[21], rd_data[20], rd_data[19], rd_data[18]};
	// 图像高度
	bmp_high = {rd_data[25], rd_data[24], rd_data[23], rd_data[22]};
	// 像素起始位置
	start_index = {rd_data[13], rd_data[12], rd_data[11], rd_data[10]};
	// 图像尺寸
	bmp_size = {rd_data[5], rd_data[4], rd_data[3], rd_data[2]};
	// bmp_size = 307200;
	$fclose(bmp_file_id);

	index = start_index;
	repeat(646)begin
	#(CYCLE);
	iData = rd_data[index];
	iValid = 1;
	index = index + 1;
	end
	repeat(bmp_size-646)begin
	#(CYCLE);
	dout_data[index-646] = oData;
	iData = rd_data[index];
	index = index + 1;
	end
	iValid = 0;
	repeat(646)begin
	#(CYCLE);
	dout_data[index-646] = oData;
	iData = rd_data[index];
	index = index + 1;
	end

	//输出BMP
	for(i = 0; i < bmp_size; i = i + 1)begin
		if(i < start_index)
             $fwrite(bmp_dout_id, "%c", rd_data[i]);//注意参数%c
		else 
			 $fwrite(bmp_dout_id, "%c", dout_data[i]);
    end
    $fclose(bmp_dout_id);

	//输出txt,只存像素点
    for(index0 = start_index; index0 < bmp_size-2; index0 = index0 + 3)begin
        wr_data = {dout_data[index0 + 2], dout_data[index0 + 1], dout_data[index0]};
        $fwrite(dout_txt_id, "%d,", wr_data[7:0]);
        $fwrite(dout_txt_id, "%d,", wr_data[15:8]);
        $fwrite(dout_txt_id, "%d\n", wr_data[23:16]);
    end
    $fclose(dout_txt_id);
   
end

endmodule

四、结果测试

代码完成后,在tb文件里的对应路径创建好所需要输出图片的bmp和txt文件,然后进行仿真
在这里插入图片描述

在这里插入图片描述
仿真完成后可以看到得到了滤波后的图片在这里插入图片描述

原图与滤波后图对比
在这里插入图片描述在这里插入图片描述

参考博客

中值滤波代码参考:
http://t.csdn.cn/XnTAc
http://t.csdn.cn/JWYsX
bmp图片格式:
http://t.csdn.cn/enoq8
shift IP核
http://t.csdn.cn/zbWdU

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

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

相关文章

【GO】K8s 管理系统项目[API部分--Ingress]

K8s 管理系统项目[API部分–Ingress] 1. 接口实现 service/dataselector.go import ("sort""strings""time"appsv1 "k8s.io/api/apps/v1"corev1 "k8s.io/api/core/v1"nwv1 "k8s.io/api/networking/v1" )// Ing…

JavaScript client screen offset scroll

文章目录JavaScript client screen offset scrollclientX和clientY、offsetX和offsetY、screenX和screenY、pageX和pageYclientWidth、offsetWidth、scrollWidthwindow.outerWidth、window.innerWidth、document.documentElement.clientWidthJavaScript client screen offset s…

【开发工具】Gradle的安装 与 配置环境变量

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Gradle安装配置教程一、安装Gradle二、配置环境…

C++: Essential C++ 读书笔记:面向过程编程:调用函数。

1&#xff1a;传值和传址区别 按值传递&#xff1a; 在调用函数中将原函数的值拷贝一份过去给被调用的函数&#xff0c;在被调用函数中对该值的修改&#xff0c;不会影响原函数的值。值传递&#xff0c;变量赋值&#xff0c;修改变量的值------修改的是新地址&#xff08;复制地…

智能家居加速落地,景联文科技提供数据采集标注服务

“以AI驱动智能家居&#xff0c;智能家庭助手和智能家居安防同向发展的智能物联网是目前主流趋势。高质量的标注数据能够高效训练算法&#xff0c;加速应用落地。景联文科技为相关企业提供、智能语音助手、人脸识别、指纹识别门禁系统、非法闯入检测、扫地机器人智能终端控制等…

临床资料研究中的风险因素评估相关指标

前言 写这篇文章是因为最涉及的医学相关的项目比较多&#xff0c;有些常常遇到的概念容易混淆&#xff0c;在这里着重区分一下。&#xff08;感谢广大学霸的分享&#xff09; 1. Ratio 与Rate 的区别 Ratio&#xff1a;表示相对比&#xff0c;简单理解为一个数值相对于另一个…

【1】高危漏洞利用工具 (2023.1.6更新)-- Apt_t00ls

0x01 工具介绍增加CNVD-2023-00895包括&#xff1a;泛微、蓝凌、用友、万户、致远、通达、中间件、安全设备等多个高位漏洞。泛微: e-cology workrelate_uploadOperation.jsp-RCE (默认写入冰蝎4.0.3aes) e-cology page_uploadOperation.jsp-RCE (暂未找到案例 仅供检测poc) e-…

Vivado综合属性之ASYNC_REG

本文验证了综合属性ASYNC_REG对寄存器位置的影响。 ASYNC_REG用于单bit信号采用双&#xff08;或多&#xff09;触发器实现异步跨时钟域的场合&#xff0c;此时所有用于同步的触发器都要标记ASYNC_REG。标记方式为&#xff1a; (* ASYNC_REG "TRUE" *) reg sync_0…

想在2023 年成为前端 Web 开发人员的分步指南

当我开始成为一名前端开发人员时&#xff0c;这是我希望拥有的路线图我想出了这个路线图&#xff0c;它有助于实现成为全能开发人员的目标。让我们开始吧。谁是前端开发人员&#xff1f;好的&#xff0c;现在谁是后端开发人员&#xff1f;那么如何成为一名前端开发人员呢&#…

Java 集合练习题

SourceURL:file:///home/windstorm/Documents/JAVA/JavaCoursePractise/Java 集合练习题.docx 答案&#xff1a; import java.lang.reflect.Array; import java.security.cert.CollectionCertStoreParameters; import java.util.*; public class Main { public static voi…

promise和async用法及区别(详解)

一、promisepromise的概念Promise 是异步编程的一种解决方案&#xff0c;是一个构造函数&#xff0c;自身有all、reject、resolve方法&#xff0c;原型上有then、catch等方法。特点&#xff1a;对象的状态不受外界影响。Promise对象代表一个异步操作&#xff0c;有三种状态&…

【django】模型类中数据的增删改查操作总结

文章目录一、数据库数据操作二、创建对象三、批量创建对象方法一&#xff1a;for循环迭代方法二&#xff1a;bulk_create()四、更新对象save()默认更新所有的字段指定要更新的字段一次性更新多个对象五、查询对象1、管理器2、QuerySet3、检索全部对象a、要注意&#xff1a;4、过…

01 踏上python之旅

Python是一种跨平台的、开源的、免费的、解释型的高级编程语言。它具有丰富和强大的库&#xff0c;能够把用其他语言制作的各种模块很轻松地连接在一起。所以被称为胶水语言。 python的应用领域&#xff1a; Web开发大数据处理人工智能自动化运维开发云计算爬虫游戏开发 解释…

【C语言】详解#define,#ifdef,#ifndef,#elif,#undef,以及相关运算符

1.明示常量 #define 预处理指令结尾不带&#xff1b;&#xff08;分号&#xff09;&#xff0c;在预编译的过程中使用宏的地方会进行展开&#xff0c;是用多少次就展开多少次&#xff0c;但是只替换 不计算&#xff0c;预处理器在发现程序中的宏后&#xff0c;会用宏等价的替换…

生物化学 SY002实验 最常用的酸spiric acid+阿司匹林Aspirin+从柳树皮得到水杨苷

阿司匹林已应用百年&#xff0c;成为医药史上三大经典药物之一。 小知识点&#xff1a;水杨酸的作用和阿司匹林的作用不同之处(抗凝)&#xff0c;使用时的胃损伤等 使用历史 埃及埃伯斯纸莎草纸中关于使用白柳树叶制成的混合物治疗发炎伤口的建议。&#xff08;因为柳叶和树…

软著申请你还不会?我是这样申请的

大家好&#xff0c;我是小悟 兄弟姐妹们&#xff0c;关于软著申请的话题&#xff0c;早前已经写过几篇文章的介绍了&#xff0c;包括软著的申请流程攻略和踩到被打回补正的坑&#xff0c;有兴趣的可以翻翻之前的文章&#xff0c;搜关键字【软著】就有。 私信的小伙伴来自各行…

9.Isaac教程-- Laikago 四足机器人的自主导航

Laikago 四足机器人的自主导航 开发智能机器人系统是一项多学科的工作&#xff0c;集成了动力学、控制、计算机视觉、人工智能等。 很难掌握所有这些领域。 即使你掌握了所有这些&#xff0c;也需要花费大量时间才能正确和稳健。 为了帮助机器人专家加速智能机器人的开发&…

笔试强训(12)

算法题1:计算日期到天数转换: 我们假设用例输入的是2022 1 1&#xff0c;那么我们对应的天数就是1天&#xff0c;我们就不应该在输出1月份的所有月数 public class Main {public static void main(String[] args) {Scanner scannernew Scanner(System.in);int yearscanner.next…

【uniapp小程序】上传图片

文章目录&#x1f34d;前言&#x1f34b;正文1、首先看官网uni.chooseImage(OBJECT) API 介绍2、案例代码演示3、效果展示&#x1f383;专栏分享&#xff1a;&#x1f34d;前言 本篇文章我们研究一下&#xff0c;在移动端开发过程中经常使用到的图片上传功能。在大多数小程序或…

ArcGIS基础实验操作100例--实验68注记符号化表达

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验68 注记符号化表达 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;1&am…