软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

11.1 概述

本章向大家介绍了如何利用HLS来实现快速角点检测算法,快速角点检测可以用于特征提取,因此具有很大的实用性,最后利用我们的开发板对其进行了验证,通过本章,大家应该掌握利用HLS来进行基本的算法开发,这也将大大的节省我们的开发时间。

11.2 角点定义

角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。

角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。

现有的角点检测算法并不是都十分的鲁棒。很多方法都要求有大量的训练集和冗余数据来防止或减少错误特征的出现。角点检测方法的一个很重要的评价标准是其对多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。

在我们解决问题时,往往希望找到特征点,“特征”顾名思义,指能描述物体本质的东西,还有一种解释就是这个特征微小的变化都会对物体的某一属性产生重大的影响。而角点就是这样的特征。

观察日常生活中的“角落”就会发现,“角落”可以视为所有平面的交汇处,或者说是所有表面的发起处。假设我们要改变一个墙角的位置,那么由它而出发的平面势必都要有很大的变化。所以,这就引出了图像角点的定义,“如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点”

特征检测与匹配是Computer Vision 应用中重要的一部分,这需要寻找图像之间的特征建立对应关系。点,也就是图像中的特殊位置,是很常用的一类特征,点的局部特征也可以叫做“关键特征点”(keypoint feature),或“兴趣点”(interest point),或“角点”(conrner)。

关于角点的具体描述可以有几种:

一阶导数(即灰度的梯度)的局部最大所对应的像素点;

两条及两条以上边缘的交点;

图像中梯度值和梯度方向的变化速率都很高的点;

角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

11.3 角点检测算法

11.3.1 Moravec角点检测算法

Moravec角点检测算法是最早的角点检测算法之一。该算法将角点定义为具有低“自相关性”的点。算法会检测图像的每一个像素,将像素周边的一个邻域作为一个patch,并检测这个patch和周围其他patch的相关性。这种相关性通过两个patch间的平方差之和(SSD)来衡量,SSD值越小则相似性越高。

如果像素位于平滑图像区域内,周围的patch都会非常相似。如果像素在边缘上,则周围的patch在与边缘正交的方向上会有很大差异,在与边缘平行的方向上则较为相似。而如果像素是各个方向上都有变化的特征点,则周围所有的patch都不会很相似。Moravec会计算每个像素patch和周围patch的SSD最小值作为强度值,取局部强度最大的点作为特征点。

11.3.2 Harris角点检测

当一个窗口在图像上移动,在平滑区域如图(a),窗口在各个方向上没有变化。在边缘上如图(b),窗口在边缘的方向上没有变化。在角点处如图(c),窗口在各个方向上具有变化。Harris角点检测正是利用了这个直观的物理现象,通过窗口在各个方向上的变化程度,决定是否为角点。

将图像窗口平移[u,v]产生灰度变化E(u,v)

11.3.3 FAST角点检测算法

Smith 和 Brady在1997年提出了一种完全不同的角点提取方法,即“SUSAN (Smallest UnivalueSegment AssimilatingNucleus)”提取算子。SUSAN 提取算子的基本原理是,与每一图像点相关的局部区域具有相同的亮度。如果某一窗口区域内的每一像元亮度值与该窗口中心的像元亮度值相同或相似,这一窗口区域将被称之为“USAN”。计算图像每一像元的“USAN”,为我们提供了是否有边缘的方法。位于边缘上的像元的“USAN”较小,位于角点上的像元的“USAN”更小。因此,我们仅需寻找最小的“USAN”,就可确定角点。该方法由于不需要计算图像灰度差,因此,具有很强的抗噪声的能力。

Edward Rosten and TomDrummond 在2006年提出了一种简单快速的角点探测算法,该算法检测的角点定义为在像素点的周围邻域内有足够多的像素点与该点处于不同的区域。应用到灰度图像中,即有足够多的像素点的灰度值大于该点的灰度值或者小于该点的灰度值。

考虑下图中p点附近半径为3的圆环上的16个点,一个思路是若其中有连续的12个点的灰度值与p点的灰度值差别超过某一阈值,则可以认为p点为角点。

这一思路可以使用机器学习的方法进行加速。对同一类图像,例如同一场景的图像,可以在16个方向上进行训练,得到一棵决策树,从而在判定某一像素点是否为角点时,不再需要对所有方向进行检测,而只需要按照决策树指定的方向进行2-3次判定即可确定该点是否为角点。

在本章节的HLS实现中我们主要介绍FAST角点检测,很多传统的算法都很耗时,而且特征点检测算法只是很多复杂图像处理里中的第一步,得不偿失。FAST特征点检测是公认的比较快速的特征点检测方法,只利用周围像素比较的信息就可以得到特征点,简单,有效。

FAST特征检测算法来源于corner的定义,这个定义基于特征点周围的图像灰度值,检测候选特征点周围一圈的像素值,如果候选点周围领域内有足够多的像素点与该候选点的灰度值差别够大,则认为该候选点为一个特征点。

其中I(x)为圆周上任意一点的灰度,I(p)为圆心的灰度,Ed为灰度值差得阈值,如果N大于给定阈值,一般为周围圆圈点的四分之三,则认为p是一个特征点。

11.4 HLS实现

11.4.1 工程创建

Step1:打开HLS,按照之前介绍的方法,创建一个新的工程,命名为fast_corner。

Step2:右单击Source选项,选择New File,创建一个名为Top.cpp的文件。

Step3:在打开的编辑区中,把下面的程序拷贝进去:

#include "top.h"

void hls_fast_corner(AXI_STREAM& INPUT_STREAM, AXI_STREAM& OUTPUT_STREAM,introws,intcols,intthrehold)

{

//Create AXI streaming interfaces for the core

#pragmaHLS INTERFACE axis port=INPUT_STREAM

#pragmaHLS INTERFACE axis port=OUTPUT_STREAM

#pragmaHLS RESOURCE core=AXI_SLAVE variable=rows metadata="-bus_bundle CONTROL_BUS"

#pragmaHLS RESOURCE core=AXI_SLAVE variable=cols metadata="-bus_bundle CONTROL_BUS"

#pragmaHLS RESOURCE core=AXI_SLAVE variable=threhold metadata="-bus_bundle CONTROL_BUS"

#pragmaHLS RESOURCE core=AXI_SLAVE variable=returnmetadata="-bus_bundle CONTROL_BUS"

#pragmaHLS INTERFACE ap_stable port=rows

#pragmaHLS INTERFACE ap_stable port=cols

#pragmaHLS INTERFACE ap_stable port=threhold

RGB_IMAGE      _src(rows,cols);

RGB_IMAGE      _dst(rows,cols);

RGB_IMAGE      src0(rows,cols);

RGB_IMAGE      src1(rows,cols);

GRAY_IMAGE     mask(rows,cols);

GRAY_IMAGE     dmask(rows,cols);

GRAY_IMAGE     gray(rows,cols);

#pragmaHLS dataflow

#pragmaHLS stream depth=20000 variable=src1.data_stream

hls::AXIvideo2Mat(INPUT_STREAM, _src);

hls::Scalar<3,unsigned char> color(255,0,0);

hls::Duplicate(_src,src0,src1);

hls::CvtColor(src0,gray);

hls::FASTX(gray,mask,threhold,true);

hls::Dilate(mask,dmask);

hls::PaintMask(src1,dmask,_dst,color);

hls::Mat2AXIvideo(_dst, OUTPUT_STREAM);

}

Step4:再在Source中添加一个名为Top.h的库函数,并添加如下程序:

#ifndef_TOP_H_

#define_TOP_H_

#include "hls_video.h"

// maximum image size

#defineMAX_WIDTH  1920

#defineMAX_HEIGHT 1080

// I/O Image Settings

#defineINPUT_IMAGE"test_1080p.bmp"

#defineOUTPUT_IMAGE"result.bmp"

#defineOUTPUT_IMAGE_GOLDEN"result_golden.bmp"

// typedef video library core structures

typedefhls::stream >AXI_STREAM;

typedefhls::Scalar<3,unsigned char>RGB_PIXEL;

typedefhls::MatRGB_IMAGE;

typedefhls::MatGRAY_IMAGE;

// top level function for HW synthesis

void hls_fast_corner(AXI_STREAM& src_axi,AXI_STREAM& dst_axi,introws,intcols,intthrehold);

#endif

Step5:在Test Bench中,用同样的方法添加一个名为Test.cpp的测试程序。添加如下代码:

#include "hls_opencv.h"

#include "top.h"

using namespacecv;

int main(intargc,char** argv) {

IplImage* src =cvLoadImage(INPUT_IMAGE);

IplImage* dst =cvCreateImage(cvGetSize(src), src->depth, src->nChannels);

cvShowImage("hls_src", src);

//HLS视频库处理

AXI_STREAMsrc_axi, dst_axi;

IplImage2AXIvideo(src, src_axi);

hls_fast_corner(src_axi, dst_axi, src->height, src->width, 20);

AXIvideo2IplImage(dst_axi, dst);

cvShowImage("hls_dst", dst);

cvSaveImage(OUTPUT_IMAGE,dst);

waitKey(0);

return0;

}

Step6:在Test Bench中添加一张名为test_1080P.bmp的测试图片,图片可以在我们提供的源程序中的Image文件夹中找到。完整的工程如下图所示:

11.4.2 仿真及优化

Step1:单击Project settings快捷键。

Step2:选择Synthesis选项,然后点击Browse..指定一个顶层函数。

Step3:选定hls_fast_corner为顶层函数,然后点击OK。

Step4:再次单击OK,完成工程的修改。

综合报告如下:

11.5 硬件工程创建

11.5.1 硬件平台搭建

本章的硬件平台与sobel算子的实现几乎是一样的,只是在这里需要把sobel实现的HLS IP替换成角点检测的IP 。系统整体硬件电路如下图所示:

11.5.2 导入到SDK

硬件平台搭建完成之后,让工程重新生成Bit文件,之后记得删除之前的SDK工程,以便HLS IP的驱动文件能正确的产生。

Step1:在工程文件夹中删除原来工程的sdk文件夹。

Step2:单击File-Export-Export Hardware。

Step3:单击File-Launch SDK。

Step4:新建一个名为Fast_Corner的空白工程。

Step5:复制我们提供的SDK驱动文件,然后在SDK中,选中工程,在Src下直接按Ctrl

+V将其复制到工程中来。

Step6:双击main.c,用如下程序进行替换。

#include "xaxivdma.h"

#include "xaxivdma_i.h"

#include "xhls_fast_corner.h"

#include "sleep.h"

#defineDDR_BASEADDR        0x00000000

#defineDISPLAY_VDMA       XPAR_AXI_VDMA_0_BASEADDR + 0

#defineSOBEL_VDMA XPAR_AXI_VDMA_1_BASEADDR + 0

#defineDIS_X            1280

#defineDIS_Y            720

#defineSOBEL_ROW 512

#defineSOBEL_COL 512

#definepi 3.14159265358

#defineCOUNTS_PER_SECOND (XPAR_CPU_CORTEXA9_CORE_CLOCK_FREQ_HZ)/64

#defineSOBEL_S2MM 0x08000000

#defineSOBEL_MM2S 0x0A000000

#defineDISPLAY_MM2S 0x0C000000

u32*BufferPtr[3];

u32threhold=20;

static XHls_fast_cornerfast;

//函数声明

void Xil_DCacheFlush(void);

//所有数据格式 为RGBA,低位的透明度暂不起作用

extern const unsigned chargImage_lena[1048584];

extern const unsigned chargImage_logo[284008];

void SOBEL_VDMA_setting(unsigned intwidth,unsigned intheight,unsigned ints2mm_addr,unsigned intmm2s_addr)

{

//S2MM

Xil_Out32(SOBEL_VDMA + 0x30, 0x4);//reset   S2MM VDMA Control Register

usleep(10);

Xil_Out32(SOBEL_VDMA + 0x30, 0x0);//genlock

Xil_Out32(SOBEL_VDMA + 0xAC,   s2mm_addr);//S2MM Start Addresses

Xil_Out32(SOBEL_VDMA + 0xAC+4, s2mm_addr);

Xil_Out32(SOBEL_VDMA + 0xAC+8, s2mm_addr);

Xil_Out32(SOBEL_VDMA + 0xA4, width*4);//S2MM Horizontal Size

Xil_Out32(SOBEL_VDMA + 0xA8, width*4);//S2MM Frame Delay and Stride

Xil_Out32(SOBEL_VDMA + 0x30, 0x3);//S2MM VDMA Control Register

Xil_Out32(SOBEL_VDMA + 0xA0, height);//S2MM Vertical Size  start an S2M

// Xil_DCacheFlush();

//MM2S

Xil_Out32(SOBEL_VDMA + 0x00,0x00000003);// enable circular mode

Xil_Out32(SOBEL_VDMA + 0x5c,mm2s_addr);// start address

Xil_Out32(SOBEL_VDMA + 0x60,mm2s_addr);// start address

Xil_Out32(SOBEL_VDMA + 0x64,mm2s_addr);// start address

Xil_Out32(SOBEL_VDMA + 0x58,(width*4));// h offset

Xil_Out32(SOBEL_VDMA + 0x54,(width*4));// h size

Xil_Out32(SOBEL_VDMA + 0x50,height);// v size

//Xil_DCacheFlush();

}

void DISPLAY_VDMA_setting(unsigned intwidth,unsignedheight,unsigned intmm2s_addr)

{

Xil_Out32((DISPLAY_VDMA + 0x000), 0x00000003); // enable circular mode

Xil_Out32((DISPLAY_VDMA + 0x05c), mm2s_addr); // start address

Xil_Out32((DISPLAY_VDMA + 0x060), mm2s_addr); // start address

Xil_Out32((DISPLAY_VDMA + 0x064), mm2s_addr); // start address

Xil_Out32((DISPLAY_VDMA + 0x058), (width*4)); // h offset (640 * 4) bytes

Xil_Out32((DISPLAY_VDMA + 0x054), (width*4)); // h size (640 * 4) bytes

Xil_Out32((DISPLAY_VDMA + 0x050), height); // v size (480)

}

void SOBEL_DDRWR(unsigned intaddr,unsigned intcols,unsigned intlows)

{

u32i=0;

u32j=0;

u32r,g,b;

for(i=0;i

{

for(j=0;j

{

b= gImage_lena[(j+i*cols)*4+2];

g= gImage_lena[(j+i*cols)*4+1];

r= gImage_lena[(j+i*cols)*4];

Xil_Out32((addr+(j+i*cols)*4),((r<<16)|(g<<8)|(b<<0)|0x0));

}

}

Xil_DCacheFlush();

}

void SOBEL_Setup()

{

//const int cols= 512;

//const introws = 512;

XHls_fast_corner_SetRows(&fast, SOBEL_COL);

XHls_fast_corner_SetCols(&fast, SOBEL_ROW);

XHls_fast_corner_SetThrehold(&fast, threhold);

XHls_fast_corner_DisableAutoRestart(&fast);

XHls_fast_corner_InterruptGlobalDisable(&fast);

SOBEL_VDMA_setting(SOBEL_ROW,SOBEL_COL,SOBEL_S2MM,SOBEL_MM2S);

SOBEL_DDRWR(SOBEL_MM2S,SOBEL_ROW,SOBEL_COL);

//init_hls_sobel_dma(cols,rows, VIDEO_BASEADDR, HLS_VDMA_MM2S_ADDR);

//DDRVideoWr(HLS_VDMA_MM2S_ADDR,cols,rows);

XHls_fast_corner_Start(&fast);

}

void Set_blackground(u32size_x,u32size_y,u32disp_addr)

{

u32i=0;

u32j=0;

//u32 r,g,b;

for(j=0;j

{

for(i=0;i

{

Xil_Out32((disp_addr+(i+j*size_x)*4),0);

}

}

Xil_DCacheFlush();

}

void show_img(u32x,u32y,u32disp_base_addr,const unsigned char* addr,u32size_x,u32size_y)

{

//计算图片 左上角坐标

u32i=0;

u32j=0;

u32r,g,b;

u32start_addr=disp_base_addr;

start_addr = disp_base_addr + 4*x + y*4*DIS_X;

for(j=0;j

{

for(i=0;i

{

//if(type==0)

//{

//b = *(addr+(i+j*size_x)*4+2); //08

//g = *(addr+(i+j*size_x)*4+1); //60

//r = *(addr+(i+j*size_x)*4); //01

//}

//else

//{

b = *(addr+(i+j*size_x)*4);//08

g = *(addr+(i+j*size_x)*4+1);//60

r = *(addr+(i+j*size_x)*4+2);//01

//}

Xil_Out32((start_addr+(i+j*DIS_X)*4),((r<<16)|(g<<8)|(b<<0)|0x0));

}

}

Xil_DCacheFlush();

}

int main(void)

{

//Xil_DCacheFlush();

xil_printf("Starting the first VDMA \n\r");

intstatus = XHls_fast_corner_Initialize(&fast, XPAR_HLS_FAST_CORNER_0_S_AXI_CONTROL_BUS_BASEADDR);

if(0 != status)

{

xil_printf("XHls_Sobel_Initialize failed \n");

}

SOBEL_Setup();

DISPLAY_VDMA_setting(DIS_X,DIS_Y,DISPLAY_MM2S);

Set_blackground(1280,720,DISPLAY_MM2S);

/******************************

for(i=0;i<614400;i++)

{

Xil_Out32(VIDEO_BASEADDR0+i,0);

}

*******************************/

while(1)

{

//show_img(0,0,VIDEO_BASEADDR0,&gImage_beauty[0],563,600);

//sleep(5);

//show_img(0,0,VIDEO_BASEADDR0,&gImage_miz702_rgba[0],375,400);

//sleep(5);

show_img(0,0,DISPLAY_MM2S,(void*)SOBEL_S2MM,512,512);

show_img(522,0,DISPLAY_MM2S,(void*)SOBEL_MM2S,512,512);

//show_img(0,513,DISPLAY_MM2S,&gImage_logo[0],355,200);

}

return0;

}

Step8:下载程序,打开系统自带的窗口调试助手,点击运行按钮开始运行程序。

程序运行之后,显示屏上的输出如下图所示:

11.6 程序分析

本章节的程序与第六章SOBEL的程序基本上是一致的,这是因为HLS产生的IP大多驱动方式是一样的,本章程序中快速角点检测IP的驱动函数如下图所示:

可以看出,这与第七章的程序相比较只是函数名改了个名字而已,驱动方式是一样的,大家在以后的设计中就可以仿照这里对HLS生成的IP进行驱动。

fast角点检测 java_米联客 ZYNQ/SOC 精品教程 S04-CH11 快速角点检测之硬件实现相关推荐

  1. 米联客 ZYNQ/SOC 精品教程 S02-CH24 利用AXI VDMA 实现MT9V034摄像头采集

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  2. 米联客 ZYNQ/SOC精品教程 S01-CH06 FPGA按钮去抖实验

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  3. 米联客 ZYNQ/SOC 精品教程 S02-CH25 利用OSD实现双目摄像头字幕叠加

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  4. 米联客 ZYNQ/SOC精品教程 S01-CH07 FPGA多路分频器实验

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  5. 米联客 ZYNQ/SOC精品教程 S02-CH13 CAN总线通信实验

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  6. 米联客 ZYNQ/SOC 精品教程 S02-CH19 利用BRAM进行PS与PL间数据交互

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  7. 米联客 ZYNQ/SOC精品教程 S01-CH04 VIVADO创建工程之流水灯

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  8. 米联客 ZYNQ/SOC 精品教程 S02-CH15 AXI_Lite 总线详解

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  9. 基于zynq的千兆网udp项目_米联客 ZYNQ/SOC 精品教程 S05-CH05 PS 千兆 UDP 加速

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

最新文章

  1. Linux(CentOS)安装分区方案
  2. 深入浅出WPF——附加事件(Attached Event)
  3. boost::counting_range相关的测试程序
  4. 【Git】切换分支,以及git stash的使用
  5. 思科路由器debug基本操作和简单配置
  6. 如何在 SAP BTP 平台 ABAP 编程环境里消费基于 SOAP 的 Web Service
  7. 基于CompletableFuture并发任务编排实现
  8. BZOJ 2738: 矩阵乘法 [整体二分]
  9. python 课程设计扫雷报告_扫雷游戏课程设计报告
  10. 谷歌浏览器保存网页为PDF
  11. 3A算法—自动曝光(AE)
  12. vue3中使用Web Worker多线程
  13. 总结归纳erf与erfc
  14. 使用 Jenkins 创建微服务应用的持续集成
  15. 解决Linux下无法利用shell脚本启动conda虚拟环境问题
  16. 诺基亚Symbian算不算智能手机?
  17. Leetcode_80_Remove Duplicates from Sorted Array II
  18. 11-27 概率论两种收敛方式
  19. PHP八字强弱计算,八字强弱的数学计算方法
  20. feign 接口请求405

热门文章

  1. mysql8.0安装32位的_安装MySQL8.0
  2. 如何查看centos7系统的服务器ip地址
  3. 出现身份验证错误。 要求的函数不受支持, 远程计算机 这可能是由于CredSSP加密数据库修正
  4. CodeForces - 1244E
  5. 数据采集卡采样率M Sa/s 与G Sa/s是什么意思
  6. 灌注桩如何计算机械台班,钢护筒造价计算及套定额
  7. 实现html页面的倒计时
  8. 自学Java如何入门?看完教你秒懂Java接口 抽象类区别!
  9. Linux vim/vi下backspace(退格键)出现^? 或^H
  10. Python数据分析面试实战