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

问题描述:

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

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 我在做什么错?

可分离滤波器的计算方法是有效两次通过。 (通道可以是交错的,但是如果按照该顺序执行,则垂直滤波器使用的所有值必须已经由水平滤波器计算)。在注释//then here I do the vertical multiplication的右下方,对像素X和像素Y的访问实际上是第二遍可分离式过滤器。前面已经计算了x的负值所访问的值,并且x的正值的值尚未通过水平通过计算。

结帐Halide。它使这种代码更容易和更高效。 (性病::载体的双重嵌套是不是一个很好的路要走。)

+0

好吧,如果我理解正确,我再次通过图像,并进行垂直乘法? – Vipoon

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

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的其余部分的计算,并且我循环。所以,我创建了另一个矢量矢量,并将它推到了X和Y的位置,这就解决了我的问题。

+0

啊应该已经意识到Sobel并不像2D卷积。同样的问题,垂直计算中的一半值来自水平计算,一半来自原始图像。修正是让他们都从原来的而不是我的建议,把他们全部从水平计算.. –