FPGA 上使用 SVM 进行图像处理

8b5057b102520417c3fa6a3f1d132e17.jpeg

SVM简介

面部识别是一个经常讨论的计算机科学话题,并且由于计算机处理能力的指数级增长而成为人们高度关注的话题。面部识别在机器人、生物安全和汽车工业等许多领域都有广泛的应用,涉及对输入图像应用数学算法,提取不同的特征,表明所提供的图片中是否存在人脸。方向梯度直方图(HOG)是一种传统算法,用于提取图像特征,例如像素方向,并且可以与线性支持向量机(SVM)一起使用来将输入图像识别为人脸或不是人脸。

1cde0d63a41927801c713afaf7720613.jpeg

我们将使用下面图像作为参考和测试:

0649e71fcc42afdfa047b56779209327.png

图像处理

卷积

两个函数的卷积是一种重要的数学运算,在信号处理中广泛应用。在计算机图形和图像处理领域,我们通常使用离散函数(例如图像)并应用离散形式的卷积来消除高频噪声、锐化细节或检测边缘。

卷积是对两个信号 f 和 g 的数学运算,定义为:

2d2a97481e923824d6cbb2d0e8ab08dc.png

在图像领域,我们可以将卷积想象为单个像素与其相邻像素之间的关系。这种关系主要应用搜索颜色变化、亮度差异和像素周期性等独特特征检测。

下图说明了使用小型 3 x 3 内核的卷积滤波器。滤波器被定义为一个矩阵,其中中心项对中心像素进行加权,其他项定义相邻像素的权重。我们也可以说 3×3 核的半径为 1,因为在卷积过程中只考虑“一环”邻域。在图像边界要定义卷积的行为,其中内核映射到图像外部未定义的值。

122c4887170aa7abf7283e964d58f821.png

使用 3 x 3 窗口和 3 x 3 内核的卷积运算可以定义如下:

static int convolve(unsigned int window[3][3], int kernel[3][3])
{
    int result = 0;

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            result+= window[i][j] * kernel[i][j];
        }
    }

    return result;
}

为了对整个图像进行卷积运算,可以应用滑动窗口技术。从第一个像素开始,每 8 个临近像素被分组为一个方形窗口,窗口内的输入像素与内核进行卷积,产生一个像素值放置在输出图像中。重复此步骤直到图像结束。

6f0e5cd082df7a82fddff63a4adfcb3a.png

Sobel-索贝尔

边缘检测是检测灰度图像中不连续性的最常见方法。边缘被定义为位于两个区域之间的特定边界上的一组连接的像素。

如果输入图像是彩色图像,则在应用卷积运算之前,将其转换为灰度图像。

假设每个像素都使用 32 位无符号整数表示,则 RGB 转换为灰度的代码如下所示:

#define R(pixel)    (((pixel) >> 16) & 0xFF)
#define G(pixel)    (((pixel) >> 8)  & 0xFF)
#define B(pixel)    (((pixel)      ) & 0xFF)

float rgb2gray(unsigned int pixel)
{
    return (R(pixel) * 0.2989 + G(pixel) * 0.5870 + B(pixel) * 0.1440);
}

运行后,测试图像将如下所示:

43e04c28d7bcd3d8b19320df846eea6b.png

Sobel 算子是边缘检测中最常用的算子之一。Sobel 算子使用两个 3×3 内核与原始图像进行卷积来计算导数的近似值 - 一个用于水平变化,另一个用于垂直变化。如果我们将 A 定义为源图像,G x和 G y是两个图像,每个点分别包含水平和垂直导数近似值,则计算如下:

0aec741fff13bdb76c73b55698e70611.png

通过前面的卷积函数,我们可以使用以下代码计算输出图像:

int dx = convolve(window, kernel_x);
int dy = convolve(window, kernel_y);

其中窗口定义为 3 x 3 滑动窗口,内核是 Sobel 算子使用的内核:

static int kernel_x[3][3] = {
    { 1,  2,  1},
    { 0,  0,  0},
    {-1, -2, -1}
};

static int kernel_y[3][3] = {
    { 1,  0, -1},
    { 2,  0, -2},
    { 1,  0, -1}
};

卷积计算后得到的图像如下:

29568a0596da700d617461c2a5f3148d.png

正如所看到的,垂直和水平细节得到增强并且更易于观察。尽管它有帮助,但我们需要一个更独特的特征图像,仅代表边缘。

下一步将组合这两个图像并获得双向变化图。我们可以通过计算每个像素值的大小或强度以及当前像素与边缘线中的另一个像素链接的方向或角度来做到这一点。

在图像中的每个点,可以使用以下方法组合所得的近似值来给出幅度:

5234dac2bac74ddd911ba731c95e7031.png

以及使用的角度:

49d410a7c24e80cb42fec0595ddef03e.png

squareroot 和 atan2 函数都已在 HLS 命名空间中实现:

unsigned int magnitude = hls::sqrt(dx*dx + dy*dy);
int angle = hls::atan2(dx,dy);

结果是:

a818b39b487edf4cd82c5bddc2e295ec.png幅度 356c6550bae20436c5e81dd59017e2e3.png角度

我们已经得到边缘更加集中的图像。尽管如此,在多种形式的领域,边缘会变得更宽。我们需要使用一种称为非极大值抑制的技术来抑制这些错误边缘:

unsigned int nms(unsigned int mag[3][3], int ang) {
    unsigned int q,r;
    
    q = r = 255;
    
    if ((0 <= ang < 23) || (158 < ang <= 180)) {
        q = mag[1][2];
        r = mag[1][0];
    } else if (223 <= ang < 68) {
        q = mag[2][0];
        r = mag[0][2];
    } else if ( 68 <= ang < 113) {
        q = mag[0][1];
        r = mag[2][1];
    } else if ( 113 <= ang < 158) {
        q = mag[0][0];
        r = mag[2][2];
    }

    if (mag[1][1] >= q && mag[1][1] >= r)
        return mag[1][1];

    return 0;
}

现在边缘更薄、更简洁。

055a2a15d3c7b3e6ee53349615873a5e.png

实施

如前所述,输入图像以数据流的形式逐像素输入。为了应用卷积运算,我们需要将数据打包在 3 x 3 窗口下。可以使用具有两个缓冲区的架构来实现这一点,其中元素数量等于宽度,如果我们的输入图像:

3254e660f27ce4474117f0afb563fc02.png

这里将有两个辅助函数用于移动行缓冲区和滑动窗口:

static void shift_w(unsigned int window[3][3], unsigned int v1, unsigned int v2,
                    unsigned int v3)
{
    window[0][0] = window[0][1];
    window[0][1] = window[0][2];
    window[0][2] = v1;
    window[1][0] = window[1][1];
    window[1][1] = window[1][2];
    window[1][2] = v2;
    window[2][0] = window[2][1];
    window[2][1] = window[2][2];
    window[2][2] = v3;
}

static void shift_b(unsigned int line_buffer[2][1280], int pos,
                    unsigned int val)
{
    line_buffer[0][pos] = line_buffer[1][pos];
    line_buffer[1][pos] = val;
}

最后,我们可以将整个过程打包成一个 HLS 函数(代码见附件)。

得到了代码后,还应该对其进行测试。GIMP (https://www.oschina.net/p/gimp?hmsr=aladdin1e1)有一个非常酷的功能,可以直接将图像导出为头文件。假设我们将测试图像导出到文件 image.h 下,就可以利用如下代码实现我们要测试的功能(代码见文末)。

验证 HLS IP 的另一种方法是直接在 FPGA 上进行验证。

第一步是创建block design并将合成的 Sobel IP 添加到存储库:

026dafeb6af45fc899b87c9da1952fa1.png

添加已实现的 IP,其中一个 DMA 向其提供数据,另一个读取输出:

70f18d3da1ada67c21ed8812691ef888.png 27a4d63c90cfa3e44bb42554c025bde7.png 6a6aaeee44c506f8a51feba73ead780d.png

生成比特流后就可以验证功能。

生成的图像应与模拟图像相似。

现在我们需要实现一个直接从相机输入的架构。

第一个组件是 Znyq 处理系统和用于配置相机接口的 i2c 控制器:

794c64daf3d20615ebe039df4063938f.png 63cf37b6865f61c0eee1283ad37043a0.png d71ad1568c44fd63a6f1a0088da2564e.png

在图像流方面,需要一个 MIPI 控制器和一个 Demosaic IP 将流转换为 RGB24:

cb6b1ffb1b3a4514ad9df9c5e18475ab.png 4864cad5a92d8c5d70fb32fb30ef60d7.png 1a0291092c3d5236dea9fd9375b1a985.png

最后添加我们的图像处理IP和VDMA:

a220fe225c97e58c4bf67fc3d299f0e7.png b4e2c110dfafc0f06f29b2bd9fee24e0.png

HOG

后续单独文章介绍,敬请关注~

SVM-支持向量机

机器学习中,支持向量机(SVM,也称为支持向量网络)是具有相关学习算法的监督学习模型,用于分析用于分类和回归分析的数据。给定一组训练样本,每个样本都标记为属于两个类别中的一个或另一个,SVM 训练算法会构建一个模型,将新样本分配给一个类别或另一个类别,使其成为非概率二元线性分类器(尽管方法例如 Platt 缩放可以在概率分类设置中使用 SVM)。SVM 模型将示例表示为空间中的点,进行映射,以便将不同类别的示例划分为尽可能宽的清晰间隙。然后,新的示例被映射到同一空间,并根据它们所在的间隙一侧预测属于某个类别。

代码

https://github.com/cuciureansergiu/kv260_svm


http://www.niftyadmin.cn/n/5438873.html

相关文章

[python] ETL 工作流程 Prefect

Prefect 是一个用于构建、调度和监控数据流程的 Python 库。它提供了一种简单而强大的方式来管理 ETL&#xff08;Extract, Transform, Load&#xff09;工作流程。下面是一个简单的示例&#xff0c;演示了如何使用 Prefect 来创建和运行一个简单的任务&#xff1a; 首先&…

阿里云2025届春招实习生招聘

投递时间&#xff1a;2024年2月1日-2026年3月1日 岗位职责 负责大型客户“上云”&#xff0c;"用云"技术平台开发。 开发云迁移运维技术工具&#xff0c;帮助阿里云服务团队&&企业客户和服务商自主、高效的完成云迁移。 开发云运维技术工具&#xff0c;帮助…

SpringAOP(控制反转)【看这一片文章就够了】

目录 一、SpringAOP 1.概述 1 什么是AOP 2 AOP的作用 3 AOP的底层 4 AOP相关概念 5 AOP开发前要明确的事情 2. AOP入门 小结&#xff1a; 3. AOP详解-通知类型 1 通知类型 2 通知方法里获取目标方法信息(备用) 3 小结 4. AOP详解-切入点表达式 1 execution 2 an…

轻松解锁微博视频:基于Perl的下载解决方案

引言 随着微博成为中国最受欢迎的社交平台之一&#xff0c;其内容已经变得丰富多彩&#xff0c;特别是视频内容吸引了大量用户的关注。然而&#xff0c;尽管用户对微博上的视频内容感兴趣&#xff0c;但却面临着无法直接下载这些视频的难题。本文旨在介绍一个基于Perl的解决方…

网络工程师练习题3

网络工程师 在Cisco Catalyst 3548以太网交换机上建立一个名为lib105的VLAN&#xff0c;下列正确的配置是&#xff08;&#xff09;。 A.Switch-3 548#vlan 1 name lib 105 Switch-3548#exitB.Switch-3548&#xff08;valn&#xff09; 1 name lib 105C. Switch-3548&#xf…

Unity发布webgl之后打开PDF文件,不使用js,不和浏览器交互

创建一个按钮&#xff0c;然后点击就会打开 在webgl下要使用这样的路径拼接&#xff0c;不然就会报错。 btnBook.onClick.AddListener(() >{var uri new System.Uri(Path.Combine(Application.streamingAssetsPath "/Books", "文档.pdf"));Debug.Log…

解决由于历史原因解析tflite失败的问题

文章目录 0. 背景1. tflite 历史遗留问题2. schema3. flatbuffers 编译器3.1 安装 FlatBuffers 编译器3.2. 编译 FlatBuffers schema 文件3.3 使用生成的 Python 文件 4 问题未解决终极解决方案 写在最前面&#xff1a;解决方法是升级tensorflow版本&#xff0c;重新生成tflite…

RSA加密解密签名加签验签RsaUtils工具类

RSA加密解密RsaUtils工具类题 引言一、RsaUtils工具类代码二、优点三、缺点四、声明 引言 RSA算法基于大数因子分解难题&#xff0c;提供了公钥加密和私钥解密的能力。公钥用于加密&#xff0c;私钥则负责解密。这种特性使得RSA成为保证数据传输安全的理想选择。 公钥加密私钥…