关于图像的二维卷积各种版本的实现(C++,Cuda和mex)

  卷积的相关知识本文不再描述,网上大把的资源,本文给出二维卷积的各种版本的实现。

C++版本

  首先是最常用的C++版本的卷积实现,代码如下:

void Conv2(int** filter, int** arr, int** res, int filterW, int filterH, int arrW, int arrH)  
{  
    int temp;  

    for (int i=0; i<filterH+arrH-1; i++)  
    {  
        for (int j=0; j<filterW+arrW-1; j++)  
        {  
            temp = 0;  
            for (int m=0; m<filterH; m++)  
            {  
                for (int n=0; n<filterW; n++)  
                {  
                    if ((i-m)>=0 && (i-m)<arrH && (j-n)>=0 && (j-n)<arrW)  
                    {  
                        temp += filter[m][n]*arr[i-m][j-n];  
                    }  
                }  
            }  
            res[i][j] = temp;  
        }  
    }  
} 

Matlab版本

quarters = single(imread('eight.tif'));
kernel = single([1 2 1; 0 0 0; -1 -2 -1]);
imagesc(quarters);
colormap(gray);

H = conv2(quarters, kernel, 'same');
imagesc(H);
colormap(gray);

Mex版本

  如何编写mex这里就不再描述了,直接上代码:

#include "mex.h"

void conv2Mex(float* src, float* dst, int numRows, int numCols, float* kernel)
{
    int boundCol = numCols - 1;
    int boundRow = numRows - 1;

    for (int c = 1; c < boundCol; c++)
    {
        for (int r = 1; r < boundRow - 1; r++)
        {
            int dstIndex = c * numRows + r;
            int kerIndex = 8;
            for (int kc = -1; kc < 2; kc++)
            {
                int srcIndex = (c + kc) * numRows + r;
                for (int kr = -1; kr < 2; kr++)
                    dst[dstIndex] += kernel[kerIndex--] * src[srcIndex + kr];
            }
        }
    }
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[])
{
    if (nrhs != 2)
        mexErrMsgTxt("Invaid number of input arguments");

    if (nlhs != 1)
        mexErrMsgTxt("Invalid number of outputs");

    if (!mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1]))
        mexErrMsgTxt("input image and kernel type must be single");

    float* image = (float*)mxGetData(prhs[0]);
    float* kernel = (float*)mxGetData(prhs[1]);

    int numRows = mxGetM(prhs[0]);
    int numCols = mxGetN(prhs[0]);
    int numKRows = mxGetM(prhs[1]);
    int numKCols = mxGetN(prhs[1]);

    if (numKRows != 3 || numKCols != 3)
        mexErrMsgTxt("Invalid kernel size. It must be 3x3");

    plhs[0] = mxCreateNumericMatrix(numRows, numCols, mxSINGLE_CLASS, mxREAL);
    float* out = (float*)mxGetData(plhs[0]);

    conv2Mex(image, out, numRows, numCols, kernel);
}

Cuda版本

#ifndef __CONV2D3X3_H__
#define __CONV2D3X3_H__

extern void conv2Mex(float* in, float* out, int numRows, int numCols, float* kernel);

#endif // __CONV2D3X3_H__
#include "conv2Mex.h"

__global__ void conv2MexCuda(float* src,
                             float* dst,
                             int numRows,
                             int numCols,
                             float* kernel)
{
    int row = blockIdx.x;
    if (row < 1 || row > numRows - 1)
        return;

    int col = blockIdx.y;
    if (col < 1 || col > numCols - 1)
        return;

    int dstIndex = col * numRows + row;
    dst[dstIndex] = 0;
    int kerIndex = 3 * 3 - 1;
    for (int kc = -1; kc < 2; kc++)
    {
        int srcIndex = (col + kc) * numRows + row;
        for (int kr = -1; kr < 2; kr++)
        {
            dst[dstIndex] += kernel[kerIndex--] * src[srcIndex + kr];
        }
    }
}

void conv2Mex(float* src, float* dst, int numRows, int numCols, float* ker)
{
    int totalPixels = numRows * numCols;
    float *deviceSrc, *deviceKer, *deviceDst;

    cudaMalloc(&deviceSrc, sizeof(float) * totalPixels);
    cudaMalloc(&deviceDst, sizeof(float) * totalPixels);
    cudaMalloc(&deviceKer, sizeof(float) * 3 * 3);

    cudaMemcpy(deviceSrc, src, sizeof(float) * totalPixels, cudaMemcpyHostToDevice);
    cudaMemcpy(deviceKer, ker, sizeof(float) * 3 * 3, cudaMemcpyHostToDevice);
    cudaMemset(deviceDst, 0, sizeof(float) * totalPixels);

    dim3 gridSize(numRows, numCols);
    conv2MexCuda<<<gridSize, 1>>>(deviceSrc, deviceDst, numRows, numCols, deviceKer);

    cudaMemcpy(dst, deviceDst, sizeof(float) * totalPixels, cudaMemcpyDeviceToHost);

    cudaFree(deviceSrc);
    cudaFree(deviceDst);
    cudaFree(deviceKer);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CreateAMind

paper:Multi-Level Discovery of Deep Options

10210
来自专栏落影的专栏

OpenGL ES实践教程(二)摄像头采集数据和渲染

教程 这一篇教程是摄像头采集数据和渲染,包括了三部分内容,渲染部分-OpenGL ES,摄像头采集图像部分-AVFoundation和图像数据创建纹理部分-G...

46950
来自专栏進无尽的文章

多媒体-图片、音频、视频压缩

很多时候我们需要把一些图片、音频、视频上传到服务器,于是就有了文件压缩这个问题了,这篇文章就小结一下具体的文件压缩实现吧。

31810
来自专栏移动开发面面观

iOS自动布局——Masonry详解

20620
来自专栏用户2442861的专栏

Python-OpenCV 处理图像(二):滤镜和图像运算

喜欢自拍的人肯定都知道滤镜了,下面代码尝试使用一些简单的滤镜,包括图片的平滑处理、灰度化、二值化等:

24610
来自专栏贾志刚-OpenCV学堂

教程 | OpenCV深度神经网络实现人体姿态评估

OpenCV自从发布了DNN模块之后,就开始以开挂的方式支持各种深度学习预训练模型的调用,DNN模块的全称为深度神经网络,但是并不是所有深度学习模型导出到Ope...

29520
来自专栏HansBug's Lab

算法模板——单个值欧拉函数

输入N,输出phi(N) 这样的单个值欧拉函数程序一般见于部分数论题,以及有时候求逆元且取模的数不是质数的情况(逆元:A/B=A*Bphi(p)-1 (mod ...

35850
来自专栏linux驱动个人学习

高通Audio中ASOC的machine驱动

ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的...

1.4K40
来自专栏DannyHoo的专栏

iOS开发中简单代码实现UITableView头视图拉伸效果

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

29330
来自专栏向治洪

iOS自动布局框架之Masonry

目前iOS开发中大多数页面都已经开始使用Interface Builder的方式进行UI开发了,但是在一些变化比较复杂的页面,还是需要通过代码来进行UI开发的。...

21960

扫码关注云+社区

领取腾讯云代金券