可分离的sobel过滤器实现openCV C ++

时间:2017-10-12 22:42:49

标签: c++ opencv image-processing

我正在创建自己的可分离sobel过滤器实现的实现。我的函数输入kernelSize,梯度Y的水平滤波器作为像素Y1,梯度Y的垂直滤波器作为像素Y2,梯度X的水平滤波器作为像素X1,梯度X的垂直滤波器作为像素X2。

X1的输入为[1,0,-1](水平)

X2的输入是[1,2,1](垂直)

Y1的输入为[1,2,1](水平)

Y2的输入为[1,0 -1](垂直)

void gradientFilter1D(Mat& img, int kernelSize, vector<double> pixelsY1, vector<double> pixelsY2, vector<double> pixelsX1, vector<double> pixelsX2)
{
    int sumMin = INT_MAX, sumMax = INT_MIN;
    //gradient X
    vector<vector<int>> pixelsX(img.rows, vector<int>(img.cols, 0));
    //gradient Y
    vector<vector<int>> pixelsY(img.rows, vector<int>(img.cols, 0));
    vector<vector<int>> sumArray(img.rows, vector<int>(img.cols, 0));

    for (int j = kernelSize / 2; j < img.rows - kernelSize / 2; j++)
    {
        for (int i = kernelSize / 2; i < img.cols - kernelSize / 2; i++)
        {
            double totalX = 0;
            double totalY = 0;
            //this is the horizontal multiplication
            for (int x = -kernelSize / 2; x <= kernelSize / 2; x++)
            {
                totalY += img.at<uchar>(j, i + x) * pixelsY1[x + (kernelSize / 2)];
                totalX += img.at<uchar>(j, i + x) * pixelsX1[x + (kernelSize / 2)];
                //cout << int(img.at<uchar>(j, i + x)) << " " << pixelsY1[x + (kernelSize / 2)] << endl;
            }
            pixelsX[j][i] = totalX;
            pixelsY[j][i] = totalY;     
        }
    }
    for (int j = kernelSize / 2; j < img.rows - kernelSize / 2; j++)
    {
        for (int i = kernelSize / 2; i < img.cols - kernelSize / 2; i++)
        {
            double totalX = 0;
            double totalY = 0;
            //this is the vertical multiplication
            for (int x = -kernelSize / 2; x <= kernelSize / 2; x++)
            {
                totalY += pixelsY[j + x][i] * pixelsY2[x + (kernelSize / 2)];
                totalX += pixelsX[j + x][i] * pixelsX2[x + (kernelSize / 2)];
                //cout << int(img.at<uchar>(j, i + x)) << " " << pixelsY1[x + (kernelSize / 2)] << endl;
            }
            pixelsX[j][i] = totalX;
            pixelsY[j][i] = totalY;
        }
    }
    for (int j = 0; j < img.rows; j++)
    {
        for (int i = 0; i < img.cols; i++)
        {
            int sum;
            sum = sqrt(pow(pixelsX[j][i], 2) + pow(pixelsY[j][i], 2));
            sumArray[j][i] = sum;
            sumMin = sumMin < sum ? sumMin : sum;
            sumMax = sumMax > sum ? sumMax : sum;
        }
    }
    //normalization
    for (int j = 0; j < img.rows; j++)
        for (int i = 0; i < img.cols; i++)
        {
            sumArray[j][i] = (sumArray[j][i] - sumMin) * ((255.0 - 0) / (sumMax - sumMin)) + 0;
            img.at<uchar>(j, i) = sumArray[j][i];
        }
}

输入图片:  Input Image 输出图像: Output Image 我做错了什么?

2 个答案:

答案 0 :(得分:0)

可分离滤波器的计算结果实际为两次。 (传递可以是交错的,但如果按顺序执行,则垂直滤波器使用的所有值都必须由水平滤波器计算。)在注释//then here I do the vertical multiplication的正下方,可以访问pixelsX和pixelsY这实际上是可分离滤波器的第二遍。之前已经计算了x的负值所访问的值,并且尚未通过水平传递计算x的正值的值。

结帐Halide。它使这种代码更容易,更高效。 (std :: vector的双重嵌套不是一个好方法。)

答案 1 :(得分:0)

好的,所以我的错误实际上是在这个

for (int j = kernelSize / 2; j < img.rows - kernelSize / 2; j++)
    {
        for (int i = kernelSize / 2; i < img.cols - kernelSize / 2; i++)
        {
            double totalX = 0;
            double totalY = 0;
            //this is the vertical multiplication
            for (int x = -kernelSize / 2; x <= kernelSize / 2; x++)
            {
                totalY += pixelsY[j + x][i] * pixelsY2[x + (kernelSize / 2)];
                totalX += pixelsX[j + x][i] * pixelsX2[x + (kernelSize / 2)];
                //cout << int(img.at<uchar>(j, i + x)) << " " << pixelsY1[x + (kernelSize / 2)] << endl;
            }
            pixelsX[j][i] = totalX; <---- I overwrite the old values
            pixelsY[j][i] = totalY; <--- I overwrite the old values
        }
    }

因此,pixelsX [j] [i] = totalX等等是错误的,因为我需要旧值才能在j的其余部分完成计算,并且i循环。所以,我创建了另一个向量向量,并在其中推送了totalX&#39; s和Y&#39; s,这解决了我的问题。