利用OTSU阈值算法在ZYNQ上实现浒苔识别
文章目录
- 前言
- 一、软件安装
- 二、算法实现
- 1.图片数据读入
- 2.数据处理
- 1.Matlab仿真
- 2.利用Matlab Coder将Matlab代码转为C代码
- 3.利用Vitis HLS将C代码转为Verilog代码
- 3.图像显示
- 3.完整FPGA工程代码:
这里是引用
前言
近年来,青岛附近海域的藻华现象越来越严重,针对这一问题,我们暑期实践选择了对藻华图像的处理,利用FPGA识别出图像中的浒苔。
一、软件安装
我们选用的板卡是xilinx中的ZYNQ-z7-20,软件需要使用VIVADO,同时使用vitis HLS将阈值计算部分的C代码转为Verilog代码。VIVADO和HLS的安装步骤网上有很详细的步骤,下面是我安装时参考的博客。
参考博客–最详细的Vivado安装教程
二、算法实现
1.图片数据读入
我们选择将图片数据由Matlab转化为coe文件后导入FPGA的rom中,在后续的数据处理中读取rom中的图片数据。
Matlab将PNG文件转为coe文件代码如下:
%读入的图片是灰度图,如果是RGB格式需要先转换为灰度图。
src = imread('19.png');
[m,n] = size( src );%
N = m*n;
word_len = 8;
data = reshape(src, 1, N);fid=fopen('19.coe', 'wt');%打开文件
fprintf(fid, 'MEMORY_INITIALIZATION_RADIX=16;\n');
fprintf(fid, 'MEMORY_INITIALIZATION_VECTOR=\n');
for i = 1 : N-1fprintf(fid, '%x,\n', data(i));%使用%x表示十六进制数
end
fprintf(fid, '%x;\n', data(N));
fclose(fid);
FPGA中ROM的使用可以借助IP核,ROM核的使用教程可以参考以下博客:
片内ROM读写测试实验
FPGA中ROM的使用部分代码如下:
wire [7:0] rom_data;
reg [17:0] rom_addr; rom_ip rom_ip_inst
(.clka (pixclk), //inoput clka.addra (rom_addr), //input [4:0] addra.douta (rom_data) //output [7:0] douta
);
always@(posedge pixclk)
beginif((x_cnt >= 740) && (x_cnt < 1240) && (y_cnt >= 164) && (y_cnt < 828 - 164)) rom_addr <= rom_addr +1'b1;else if(rom_addr == 18'd250000)//图片为500x500格式,若图片尺寸不同,这一行和上一行需要根据图片的尺寸进行修改。rom_addr <=18'b0; elserom_addr <=rom_addr;
end
2.数据处理
根据图片中浒苔的灰度值更高这一特点,我们选择利用阈值算法对导入的数据进行二值化,将图片中的浒苔识别出来。由于某些图片中存在大气干扰、浒苔数量过多、过少等区别,一个固定的阈值并不能满足所有数据的需要,识别效果很差。因此我们在对图像数据进行预处理后,利用OTSU这一阈值算法进行阈值计算。
OTSU部分我们先用Matlab仿真,无误后利用Matlab中的app将Matlab代码转为C代码,之后利用Vitis HLS将C代码转为Verilog代码,封装成一个IP核导入到工程中进行使用。
1.Matlab仿真
Matlab中OTSU的代码如下:
im=imread("19.png");
m=500;n=500;
num=zeros(1,256);
sum=0;
start=1;
End=256;
for i = 1:mfor j = 1:nk=im(i,j);k=k+1;num(k)=num(k)+1;sum=sum+1;end
end
p=zeros(1,256);
for i = 1:256p(i)=num(i)/(m*n);
end
M=zeros(1,256);
pa=zeros(1,256);
pb=zeros(1,256);
ma=zeros(1,256);
mb=zeros(1,256);
for k = 1:256for i = 1:kpa(k)=pa(k)+p(i);M(k)=M(k)+(i-1)*p(i);end
end
for k = 1:256ma(k)=M(k)/pa(k);mb(k)=(M(256)-M(k))/(pa(256)-pa(k));
end
max_variance=0;
for k = 1:256variance=pa(k)*(pa(256)-pa(k))*(ma(k)-mb(k))^2;%variance=pa(k)*(ma(k)-M(255))^2+pb(k)*(mb(k)-M(255))^2;if(max_variance<variance)max_variance=variance;threshold=k-1;end
end
threshold
2.利用Matlab Coder将Matlab代码转为C代码
转化后代码如下:
/** File: otsu.c** MATLAB Coder version : 5.2* C/C++ source code generated on : 29-Jun-2022 15:57:35*//* Include Files */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "otsu.h"
/* Function Definitions */
/** Arguments : const unsigned char im[250000]* Return Type : double*/unsigned int finish;
unsigned int pix_num;
double num[255];int otsu(unsigned int im,int threshold)
{#pragma HLS INTERFACE mode=ap_hs port=threshold
#pragma HLS INTERFACE mode=ap_hs port=im
#pragma HLS INTERFACE mode=ap_ctrl_hs port=returnpix_num=pix_num+1;if(pix_num!=250000){if(im<120) im = 120U;num[im-1]=num[im-1]+1;return 0;}double M[255];double pa[255];double pb[255];double resum[255];double max_variance;double variance;int b_i;int b_k;int i;int j;int start;unsigned char k;memset(&resum[0], 0, 255U * sizeof(double));start = 0;for (i = 0; i < 254; i++) {resum[253 - i] = resum[254 - i] + num[253 - i];}if (resum[120] - resum[169] > 10000.0) {start = 169;}for (i = 0; i < 255; i++) {resum[i] = num[i] / 250000.0;M[i] = 0.0;pa[i] = 0.0;pb[i] = 0.0;}for (b_k = 0; b_k < 255; b_k++) {for (i = 0; i <= b_k; i++) {variance = resum[i];pa[b_k] += variance;M[b_k] += ((double)i + 1.0) * variance;}b_i = 253 - b_k;for (i = 0; i <= b_i; i++) {pb[b_k] += resum[(b_k + i) + 1];}}for (b_k = 0; b_k < 255; b_k++) {resum[b_k] = M[b_k] / pa[b_k];num[b_k] = (M[254] - M[b_k]) / pb[b_k];}max_variance = 0.0;threshold = 200.0;b_i = 254 - start;for (b_k = 0; b_k <= b_i; b_k++) {j = start + b_k;variance = resum[j] - num[j];variance = pa[j] * pb[j] * (variance * variance);/* variance=pa(k)*(ma(k)-M(255))^2+pb(k)*(mb(k)-M(255))^2; */if (max_variance < variance) {max_variance = variance;threshold = j + 1.0;}}return threshold;
}/** File trailer for otsu.c** [EOF]*/
3.利用Vitis HLS将C代码转为Verilog代码
Vitis具体的使用步骤可以参考以下博客:
Vitis HLS 构建项目并生成IP核
FPGA中生成的OTSU例化部分代码如下:
otsu_0 otsu_cal
(.im_ap_vld (1'b1),.im_ap_ack (im_ap_ack),.threshold_ap_vld (1'b1),.threshold_ap_ack (threshold_ap_ack),.ap_clk (pixclk),.ap_rst (1'b0),.ap_start (1'b1),.ap_done (done),.ap_idle (idle),.ap_ready (ready),.ap_return (threshold_otsu),.im (rom_data),.threshold (threshold_start)
);
3.图像显示
zynq板卡上有HDMI输出接口,使用一根HDMI连接线,将板卡连接到显示器上,板卡发送数据即可显示。显示部分使用HDMI的IP核。
FPGA中HDMI例化代码如下:
HDMI_FPGA_ML_0 u_HDMI
(.PXLCLK_I (pixclk),.PXLCLK_5X_I (serclk),.LOCKED_I (lock),.RST_N (1'b1),.VGA_HS (HS),.VGA_VS (VS),.VGA_DE (DE),.VGA_RGB (RGB),.HDMI_CLK_P (HDMI_CLK_P),.HDMI_CLK_N (HDMI_CLK_N),.HDMI_D2_P (HDMI_D2_P),.HDMI_D2_N (HDMI_D2_N),.HDMI_D1_P (HDMI_D1_P),.HDMI_D1_N (HDMI_D1_N),.HDMI_D0_P (HDMI_D0_P),.HDMI_D0_N (HDMI_D0_N)
);
FPGA中HDMI显示代码如下:
`timescale 1ns / 1ps
module hdmi_data_gen(input pix_clk,input turn_mode,input wire[7:0] data,input wire[11:0] x_cnt,input wire[11:0] y_cnt,input wire[7:0] threshold,output reg[3:0]led,output [7:0] VGA_R,output [7:0] VGA_G,output [7:0] VGA_B,output VGA_HS,output VGA_VS,output VGA_DE);parameter H_Total = 1680; //e
parameter H_Sync = 136; //a
parameter H_Back = 200; //b
parameter H_Active = 1280; //c
parameter H_Front = 64; //d
parameter H_Start = 336;
parameter H_End = 1616;parameter V_Total = 828;
parameter V_Sync = 3;
parameter V_Back = 24;
parameter V_Active = 800;
parameter V_Front = 1;
parameter V_Start = 27;
parameter V_End = 827;reg[11:0] x_cnt;
reg[7:0] pix_data;
reg[7:0] pix_data_two;
reg[23:0] color_bar;
always @(posedge pix_clk )
beginif(threshold>8'd160)led[0]<=1'b1;
endalways @(posedge pix_clk)
beginif(threshold<9'd180)led[1]<=1'b1;
endreg [7:0]threshold_cal;
always@(posedge pix_clk)
beginif(threshold>threshold_cal)threshold_cal<=threshold;end
always@(posedge pix_clk)
beginif((x_cnt >= 740) && (x_cnt < 1240) && (y_cnt >= 164) && (y_cnt < 828 - 164)) beginpix_data <= data;endelse pix_data <= 24'hffffff;end
always@(posedge pix_clk)
beginif((x_cnt >= 740) && (x_cnt < 1240) && (y_cnt >= 164) && (y_cnt < 828 - 164)) beginif(data>threshold_cal) beginpix_data_two<= 24'hffffff;endelse beginpix_data_two<=2'b0;endendelsepix_data_two <= 24'hffffff;end
reg[3:0] dis_mode=0;
always @(posedge turn_mode)beginif(dis_mode<2'b11)dis_mode<= dis_mode + 1'b1;elsedis_mode<=1'b0;endreg[7:0] VGA_R_reg;
reg[7:0] VGA_G_reg;
reg[7:0] VGA_B_reg;
always @(posedge pix_clk)
begin if(1'b0) begin VGA_R_reg<=0; VGA_G_reg<=0;VGA_B_reg<=0; endelsecase(dis_mode)4'd0:beginVGA_R_reg<=0; //LCD显示全黑VGA_G_reg<=0;VGA_B_reg<=0;end4'd1:beginVGA_R_reg<=pix_data; //LCD显示原图VGA_G_reg<=pix_data;VGA_B_reg<=pix_data;end4'd2:beginVGA_R_reg<=pix_data_two; //LCD显示结果图VGA_G_reg<=pix_data_two;VGA_B_reg<=pix_data_two; end default:beginVGA_R_reg<=8'hff; //LCD显示全白VGA_G_reg<=8'hff;VGA_B_reg<=8'hff;end endcase
endwire hs_de = (x_cnt<H_Start)? 0:(x_cnt<=H_End)?1:0;
wire vs_de = (y_cnt<V_Start)? 0:(y_cnt<=V_End)?1:0;
reg [7:0] grid_data;assign VGA_HS = (x_cnt==1'b0)? 1:(x_cnt<H_Sync)?0:1;
assign VGA_VS = (y_cnt==1'b0)? 1:(y_cnt<V_Sync)?0:1;assign VGA_DE = hs_de & vs_de;
assign VGA_R = (hs_de & vs_de)?VGA_R_reg:8'h0;
assign VGA_G = (hs_de & vs_de)?VGA_G_reg:8'h0;
assign VGA_B = (hs_de & vs_de)?VGA_B_reg:8'h0;
endmodule
3.完整FPGA工程代码:
OTSU阈值算法进行图像二值化
利用OTSU阈值算法在ZYNQ上实现浒苔识别相关推荐
- TF之LSTM:利用多层LSTM算法对MNIST手写数字识别数据集进行多分类
TF之LSTM:利用多层LSTM算法对MNIST手写数字识别数据集进行多分类 目录 设计思路 实现代码 设计思路 更新-- 实现代码 # -*- coding:utf-8 -*- import ten ...
- OpenCV —— 阈值分割(直方图技术法,熵算法,Otsu,自适应阈值算法)
阈值分割 1. 全局阈值分割 直方图技术法 熵算法 Otsu算法 2. 局部阈值分割 自适应阈值 阈值的分割的核心就是如何选取阈值,选取正确的阈值时分割成功的关键.可以使用手动设置阈值,也可以采用直方 ...
- 【图像分割】利用粒子群算法与遗传算法实现图像的自适应多阈值的快速分割
文章目录 前言 一.自适应多阈值分割 1.最大类间差方法 2.最大熵方法 二.代码部分(以粒子群算法与遗传算法优化自适应双阈值分割为例) 1. 利用粒子群算法优化最大类间差双阈值分割 1.1 概述 1 ...
- python实现Otsu双阈值算法
最近在做双阈值的对比实验需要用到Otsu,发现网上没有python的实现,所以写下来记录一下. Otsu双阈值算法的思想与单阈值的思想类似,单阈值的思想为: g = w0(u0-u)^2+w1(u1- ...
- 【MATLAB教程案例23】基于MATLAB图像分割算法仿真——阈值分割法、Otsu阈值分割法、K均值聚类分割法等
FPGA教程目录 MATLAB教程目录 目录 1.软件版本 2.通过二值图实现图像分割 3.通过Otsu阈值分割实现图像分割
- 基于MATLAB改进Otsu阈值分割的车道线检测
基于MATLAB改进Otsu阈值分割的车道线检测 摘要:在判断车道偏离以防止车辆碰撞等危害时,车道标线检测需要通过图像处理来进行,检测方法是否适用于各种背景环境条件以及检测的及时性至关重要传统的Ots ...
- C#,图像二值化(24)——局部阈值算法的NiBlack算法及源程序
1.局部阈值算法的NiBlack算法 摘要-医学图像的处理最为复杂人和计算机.磁性捐赠的脑组织共振成像(MRI)在许多领域是非常重要的问题例如手术和治疗.最常见的分割图像的最简单方法是使用阈值.在这项 ...
- OTSU图像分割算法(python实现)
OTSU图像分割算法使用[最大类间方差]作为标准,利用图像直方图的分布信息,计算出一个阈值,根据像素是否超过阈值将图像分为前景与背景. (而实际上只是分割亮部与暗部而已,这种简单粗暴的单阈值分割无法真 ...
- win10+Python3.7.3+OpenCV3.4.1入门学习(十二 图像轮廓)————12.7 利用形状场景算法比较轮廓
Python版本是Python3.7.3,OpenCV版本OpenCV3.4.1,开发环境为PyCharm 文章目录 12.7 利用形状场景算法比较轮廓 12.7.1 计算形状场景距离 12.7.2 ...
最新文章
- delete archivelog all 无法彻底删除归档日志?
- vue中实现双向数据绑定原理,使用了Object.defineproperty()方法,方法简单
- zoj 3747 (DP)(连续至多,连续至少)
- Oracle常用sql操作总结
- 复古风格海报设计欣赏|蒸汽波了解下
- 蒸汽朋克简单图形免扣PNG素材,让设计艺术变得简单
- 天池学习赛:工业蒸汽量预测2——特征工程
- WPE封包外挂教程(下)
- npn三种波形失真_RF测试笔记:三阶交调失真概述及测试
- python3.6 pillow,【Pillow】Python图像处理
- 福建2021高考成绩查询是什么时间,2021年福建高考成绩排名及成绩公布时间什么时候出来...
- JQuery EasyUI 教程
- 【Python】列表生成式应用的八重境界
- 吉首 - 超超的自闭意思(素筛+暴力)
- 如何添加Burp Suite添加https证书
- NLP基础-wangdong
- 「人物特写」清华大学教授、IEEE Fellow王志华:几乎所有的AI,到现在为止都是胡扯...
- #1082 : 然而沼跃鱼早就看穿了一切
- 计算机文件共享xp,两台XP怎么共享文件
- C#连接sqlserver数据库,插入数据,并且读取数据库数据画折线图。
热门文章
- 关于Vuforia扫描识别图片,最简单的设置识别区域
- 《2016年度中国智库大数据报告》发布 哪些智库进入TOP20榜单
- QQ登录报错:redirect uri is illegal(100010)解决方案
- 图形处理(九)点云重建(下)法矢求取、有向距离场等值面提取
- Rhinoceros 7 for Mac(犀牛7 mac版)
- html聚焦标签,HTML
- Centos7解除自动锁屏及修改主机名
- linux 系统被入侵之后你要做什么
- 商品期货策略 之 Python 精简多品种 MACD 趋势策略框架(注释版)
- 电脑的wifi天线原理_无线网络WIFI天线原理