加速卷积函数C ++

时间:2016-06-17 13:54:35

标签: c++ image opencv filtering convolution

我正在尝试实现用于图像过滤的“自适应”卷积,其将输出像素的最大或最小可能值限制预定界限。我还没有在opencv中找到任何允许我这样做的函数,所以我写了自己的函数来完成我想要的东西。 (可能有不同的库吗?)唯一的问题是这个函数需要大约0.9秒,而cv :: filter2D过滤图像需要大约0.005秒(两者都使用相同的内核)。有谁知道如何加快我的方法?

关于我的内核的一些评论:它是一个9x9自定义锐化过滤器,内核不可分离。我尝试重新设计我的过滤器是可分离的,但我无法达到预期的效果。有什么想法吗?下面是我用于代码的函数:

Mat& adaptive_convolution(Mat& img)
{

    fstream in("kernel.txt");
    string line;

    float v[9][9];
    int i = 0, k = 0;

    while (getline(in, line))
    {
        float value;
        int k = 0;
        stringstream ss(line);

        while (ss >> value)
        {
            v[i][k] = value;
            ++k;
        }
        ++i;
    }


    clock_t init, end;
    double minVal;
    double maxVal;
    Point minLoc;
    Point maxLoc;

    int pad_fact = 4;
    int top, left, bottom, right;

    Mat new_image = img;
    top = pad_fact; bottom = pad_fact;
    left = pad_fact; right = pad_fact;

    copyMakeBorder(img, new_image, top, bottom, left, right, BORDER_CONSTANT, 0);

    minMaxLoc(img, &minVal, &maxVal, &minLoc, &maxLoc);
    new_image / 2^8;
    init = clock();
    double temp = 0;

    for (int i = pad_fact; i < img.rows + pad_fact; i++)
    {
        for (int j = pad_fact; j < img.cols + pad_fact; j++)
        {
            for (int ii = -pad_fact; ii <= pad_fact; ii++)
            {
                for (int jj = -pad_fact; jj <= pad_fact; jj++)
                {
                    //temp = double(v[ii + 2*pad_fact][jj + 2*pad_fact]); 
                    temp = temp + double(v[ii + pad_fact][jj + pad_fact] * float(new_image.at<uchar>(i - jj, j - ii)));
                    //temp = double(new_image.at<uchar>(i - jj, j - ii));
                }
            }
            if (temp > maxVal)
            {
                temp = maxVal;
            }
            else
            {
                if (temp < minVal)
                {
                    temp = minVal;
                }
            }
            new_image.at<uchar>(i, j) = temp;
            temp = 0;
        }
    }



    img = new_image;
    end = clock();
    cout << float(end - init)/1000 << endl;
    return img;
}

编辑:

我能够使用Numba在我使用的python脚本中加速卷积约0.2秒。我仍然需要使用c ++看到这种改进。我是否通过使用opencv帮助回来了?

import numba as nb
import numpy as np

@nb.autojit
def custom_convolve(image,kernel,pad_fact):
    pad_fact = int(pad_fact)
    filt_im = np.zeros(image.shape)
    rows = image.shape[0]
    columns = image.shape[1]
    glob_max = np.max(image)
    glob_min = np.min(image)

    for x in range(pad_fact,columns-pad_fact,1):
        for y in range(pad_fact,rows-pad_fact,1):
            pix_sum = 0
            for k in range(-pad_fact,pad_fact,1):
                for j in range(-pad_fact,pad_fact,1):
                    pix_sum = pix_sum + kernel[k+pad_fact,j+pad_fact]*image[y-j,x-k]

            if pix_sum > glob_max:
                pix_sum = glob_max
            elif pix_sum < glob_min:
                pix_sum = glob_min

            filt_im[y,x] = pix_sum
    return filt_im

1 个答案:

答案 0 :(得分:0)

大多数基本的OpenCV实现都使用SSE function,它允许使用128位变量进行两个进程加法等。另一个技巧是,如果过滤器内核是separable,可以按如下方式组成:

K = D * D'

其中*表示卷积算子,D是矢量,例如[1 2 1],K是最终内核。您可以将图像A的过滤替换为图像B:

B = A * K;

B = A * D(*)(A'* D)'

这里(*)表示逐像素乘法,A'表示转置图像,即转置符号。