美文网首页
Neon指令应用---图像腐蚀和膨胀加速

Neon指令应用---图像腐蚀和膨胀加速

作者: 教训小磊 | 来源:发表于2022-05-05 00:22 被阅读0次

最近在项目开发的过程中需要使用到形态学中的腐蚀膨胀算法,以获得图像中的边缘信息。腐蚀和膨胀原始的C代码运行一帧320x180x1的图像需要8ms左右,经过neon指令加速后的运行时间只需0.5ms,差不多是16倍的加速。
ps:由于项目的需要,我这边使用的是5x1的卷积核,用来提取图像中的横条信息,所以下面的加速方法并不适合卷积核是3x3或5x5这种的情况。同时为了方便加速,去除了算法开头的一些判断,所以结果会有几个像素的差异。

1.腐蚀和膨胀原始C代码

#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "stdio.h"
#include "stdlib.h"
#include "vector"
//腐蚀
void MorphErosion(unsigned char* src, unsigned char* dst, int width, int height, int strutWidth, int structHeight)
{
    if (width - strutWidth < 0 && height - structHeight < 0)return;
    int midY = (structHeight + 1) / 2 - 1;
    unsigned char val = 255;
    for (int i = midY; i < height - midY; i++)
    {
        for (int j = midY; j < width - midY; j++)
       {
                for (int n = 0; n < strutWidth; n++)
                {
                    val &= src[i * width + j + n];
                }
            dst[i * width + j] = val;
            val = 255;
        }
    }
}
//膨胀
void MorphDilition(unsigned char* src, unsigned char* dst, int width, int height, int strutWidth, int structHeight)
{
    if (width - strutWidth < 0 && height - structHeight < 0)return;
    int midY = (structHeight + 1) / 2 - 1;
    unsigned char val = 0;
    for (int i = midY; i < height - midY; i++)
    {
        for (int j = midY; j < width - midY; j++)
        {
            for (int n = 0; n < strutWidth; n++)
            {
                val |= src[i * width + j + n];
            }
            dst[i * width + j] = val;
            val = 0;
        }
   }
}
void MorphOpen(unsigned char* src, unsigned char* tmp, int width, int height, int strutWidth, int structHeight)
{
    MorphErosion(src, tmp, width, height, strutWidth, structHeight);
    MorphDilition(tmp, tmp, width, height, strutWidth, structHeight);
}
int main()
{
    int iRet = 0;
    IplImage * src, *dst;
    src = cvLoadImage("./sad_pic/6_R.jpg", 0);
    if (src == NULL)
    {
        printf("open image failed\n");
        exit(1);
    }
    IplImage* s = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
    cvThreshold(src, src, 180, 255, CV_THRESH_BINARY);
    dst = cvCloneImage(src);
    MorphOpen((unsigned char*)src->imageData, (unsigned char*)dst->imageData, src->widthStep, src->height, 5, 1);
    cvShowImage("src", src);
    cvShowImage("dst", dst);
    cvWaitKey(0);
    cvReleaseImage(&src);
    cvReleaseImage(&dst);
    return iRet;
}

2.腐蚀和膨胀Neon指令加速代码

具体思路:去除了卷积核的概念,直接通过对每一排相邻的5个元素进行and或or操作,所以代码中设置了5个相邻的寄存器p0~p4。

//腐蚀
void MorphErosion(unsigned char* src, unsigned char* dst, int width, int height, int strutWidth, int structHeight)
{
    uint8x16_t p0_8x16;
    uint8x16_t p1_8x16;
    uint8x16_t p2_8x16;
    uint8x16_t p3_8x16;
    uint8x16_t p4_8x16;
    uint8x16_t val_8x16;

    int erosion_loop = width / 16;
    if (width - strutWidth < 0 && height - structHeight < 0)return;
    for (int i = 0; i < height; i++)
    {
        int steph = i * width;
        for (int k = 0; k<erosion_loop; k++)
        {
            int stepw = 16 * k;
            p0_8x16 = vld1q_u8(src + steph + stepw);
            p1_8x16 = vld1q_u8(src + steph + stepw + 1);
            p2_8x16 = vld1q_u8(src + steph + stepw + 2);
            p3_8x16 = vld1q_u8(src + steph + stepw + 3);
            p4_8x16 = vld1q_u8(src + steph + stepw + 4);
            val_8x16 = vandq_u8(vandq_u8(vandq_u8(vandq_u8(p0_8x16, p1_8x16), p2_8x16), p3_8x16), p4_8x16);
            vst1q_u8(dst + steph + stepw, val_8x16);
        }
    }
}
//膨胀
void MorphDilition(unsigned char* src, unsigned char* dst, int width, int height, int strutWidth, int structHeight)
{
    uint8x16_t p0_8x16;
    uint8x16_t p1_8x16;
    uint8x16_t p2_8x16;
    uint8x16_t p3_8x16;
    uint8x16_t p4_8x16;
    uint8x16_t val_8x16;

    int dilition_loop = width / 16;
    if (width - strutWidth < 0 && height - structHeight < 0)return;
    for (int i = 0; i < height; i++)
    {
        int steph = i * width;
        for (int k = 0; k<dilition_loop; k++)
        {
            int stepw = 16 * k;
            p0_8x16 = vld1q_u8(src + steph + stepw);
            p1_8x16 = vld1q_u8(src + steph + stepw + 1);
            p2_8x16 = vld1q_u8(src + steph + stepw + 2);
            p3_8x16 = vld1q_u8(src + steph + stepw + 3);
            p4_8x16 = vld1q_u8(src + steph + stepw + 4);
            val_8x16 = vorrq_u8(vorrq_u8(vorrq_u8(vorrq_u8(p0_8x16, p1_8x16), p2_8x16), p3_8x16), p4_8x16);
            vst1q_u8(dst + steph + stepw, val_8x16);
        }
    }
}
效果图

相关文章

  • Neon指令应用---图像腐蚀和膨胀加速

    最近在项目开发的过程中需要使用到形态学中的腐蚀和膨胀算法,以获得图像中的边缘信息。腐蚀和膨胀原始的C代码运行一帧3...

  • 图片处理-opencv-5.图像形态学(腐蚀,膨胀,开运算,闭运

    图像腐蚀与图像膨胀 图像的膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,主要用来寻找图像...

  • OpenCV (iOS)中的腐蚀和膨胀(9)

    膨胀和腐蚀 如实对膨胀和腐蚀不了解需要先看一下这篇文章,了解图像处理 腐蚀 膨胀 细化 膨胀和腐蚀这两种操作是形态...

  • 22、图像形态学:膨胀与腐蚀

    注:都是基于黑白像素而言,无论是彩色图像还是二值化图像。膨胀是趋于白色的区域膨胀;腐蚀是基于白色区域腐蚀 腐蚀 膨胀

  • 第 5 章 用形态学运算变换图像

    本章包括以下内容: 用形态学滤波器腐蚀和膨胀图像; 用形态学滤波器开启和闭合图像; 在灰度图像中应用形态学运算; ...

  • opencv2(2017.5.5)

    1.图像的腐蚀和膨胀 前提:输入的是二值图像腐蚀:用该像素周围像素集合中最小像素替换当前像素;膨胀:用该像素周围像...

  • [CV]图像的开运算、闭运算

    所谓开运算图像开运算是图像依次经过腐蚀、膨胀处理后的过程。图像被腐蚀后,去除了噪声,但是也压缩了图像;接着对腐蚀过...

  • 图像膨胀腐蚀——opencv

    图像腐蚀: 图像二值化,将图像的灰度值根据阈值进行0,1处理得到的图像; 卷积核,对应信号处理中的高低频滤波器。常...

  • 图像膨胀腐蚀--膨胀部分优化

    针对输入图像为灰度图,而非二值图出现的问题进行优化,主要针对膨胀部分进行了优化,同时解决了膨胀后图像四周出现黑框的问题。

  • C++开发技术人脸识别实战,年薪40W起步 !

    C++ 人脸识别,图像处理有:光线补偿、皮肤颜色建模、膨胀、腐蚀、去掉假区域、再次膨胀、再次腐蚀、得到人脸区域、C...

网友评论

      本文标题:Neon指令应用---图像腐蚀和膨胀加速

      本文链接:https://www.haomeiwen.com/subject/nmtnyrtx.html