来自opencv和Matlab的Sobel滤波器输出不同

Posted

技术标签:

【中文标题】来自opencv和Matlab的Sobel滤波器输出不同【英文标题】:Sobel filter output from opencv and Matlab different 【发布时间】:2013-09-04 12:05:48 【问题描述】:

我正在将一些代码从 matlab 转换为 opencv。我尝试在 opencv 中使用 Sobel,但 opencv 和 matlab 的输出完全不同,这可能是原因。如何使opencv的输出与matlab相同?我的 MATLAB 代码是:

 [sobel_edges,T,V,H] = edge(rgb2gray(im),'sobel',0.03);
  sobel_angles = atan2(V,H); 
  sobel_weights = (V.*V+H.*H).^0.5;

其中 0.03 是阈值。在 opencv 中,当我使用预建的 Sobel 滤波器时,输出与 matlab 完全不同,即使在 openc 中计算的角度和幅度也不同。 opencv代码为:

Mat gray_img=Mat::zeros(img.size(),CV_8U);
Mat gradientX=Mat::zeros(gray_img.size(),CV_64F);
Mat gradientY=Mat::zeros(gray_img.size(),CV_64F);
Mat sobel_edge=Mat::zeros(gray_img.size(),CV_64F);
cvtColor(img, gray_img, CV_BGR2GRAY);
Sobel(gray_img, gradientX, gradientX.type(), 1, 0, 3);
Sobel(gray_img, gradientY, gradientY.type(), 0, 1, 3);
Sobel(gray_img,sobel_edge,sobel_edge.type(),1,1,3);
sobel_edge.convertTo(sobel_edge,CV_8U);
sobel_edge.convertTo(sobel_edge,CV_64F);
sobel_edge=sobel_edge/255.0; //I divided this my 255 becuz in MATLAB the output is between 0 to 1
imshow("Sobel",sobel_edge);

   Mat magnitude(gray_img.size(), CV_64F, cv::Scalar(0.0));
    Mat angles=Mat::zeros(gradientX.size(),CV_64F);
    bool anglesInDegrees = true;
    cartToPolar(gradientX, gradientY, magnitude, angles, anglesInDegrees);

sobel 边缘本身不同,幅度和角度也不同,我尝试通过查看 matlab 中的边缘函数来手动转换 opencv 中的 sobel,但输出仍然不同,因为结果是 opencv 和 imfilter 的 filter2D在 matlab 中返回不同的输出。如何在matlab和opencv中得到sobel相同的输出???matlab的sobel手动转换为opencv的代码是:

Mat gray_img=Mat::zeros(img.size(),CV_32FC1);
  cvtColor(img, gray_img, CV_RGB2GRAY);
  double minVal,maxVal;
  cv::Mat gray = cv::Mat(gray_img.size(),CV_32FC1);
  gray_img.convertTo(gray_img,CV_32FC1);
  gray=gray_img/255.0;
  cout<<gray<<endl<<"End";
  double data[]=1,2,1,0,0,0,-1,2,-1;
  Mat op=Mat(3,3,CV_64F,data).clone();
  op=op/8;
  Mat x_mask;
  transpose(op,x_mask);
  cout<<x_mask<<endl;
  Mat y_mask=op.clone();
  int scale=4;
  int offset[]=0,0,0,0;
  double sobel_thresh=0.03;
  Mat bx,by,bx_mul,by_mul,b;
  Point anchor(0,0);
  float delta = 0.0;
  cv::filter2D(gray, bx, CV_32FC1, x_mask, anchor, delta, BORDER_REPLICATE);
   bx=abs(bx);
   imshow("f1",bx);

  cv::filter2D(gray, by, CV_32FC1, y_mask, anchor, delta, BORDER_REPLICATE);
   by=abs(by);
  imshow("by",by);

  pow(bx,2,bx_mul);
      imshow("f2",bx_mul);
  pow(by,2,by_mul);
  b= bx_mul+by_mul;
   imshow("f3",b);

  double cut_off;
  cut_off=pow(sobel_thresh,2);
  Mat sobel_edge(gray.size(),CV_32FC1);
    for(int i=0;i<b.rows;i++)
    
        for(int j=0;j<b.cols;j++)
        
            if((b.at<float>(i,j))>cut_off)
            
                sobel_edge.at<float>(i,j)=1;
            
            else
            
               sobel_edge.at<float>(i,j)=0;
            
        
    
    imshow("Sobel_edge",sobel_edge);

【问题讨论】:

(我刚刚阅读了您的主题行)一个潜在的问题是 opencv 和 MATLAB 中的行优先与列优先矩阵排序。我建议从具有简单图案的 3x3 或 5x5 小图像开始尝试解决这个问题。 为什么将sobel_edge(CV_64F 类型)转换为CV_8U 格式而不是转换回CV_64F? 我也试过删除它,但没有用 【参考方案1】:

这段代码给了我与 MATLAB 代码相同的结果:

int main(int argc, char* argv[])

    namedWindow("result");
    Mat img=imread("D:\\ImagesForTest\\1.tiff",0);
    img.convertTo(img,CV_32FC1,1.0/255.0);
    Mat h,v,g;
    cv::Sobel(img,h,-1,1,0,3,1.0/8.0);
    cv::Sobel(img,v,-1,0,1,3,1.0/8.0);
    cv::magnitude(h,v,g);

    // Check extremums
    double m,M;
    cv::minMaxLoc(g,&m,&M);
    cout << m << ":" << M << endl;
    cv::minMaxLoc(h,&m,&M);
    cout << m << ":" << M << endl;
    cv::minMaxLoc(v,&m,&M);
    cout << m << ":" << M << endl;
    imshow("result",g);
    cv::waitKey(0);

OpenCV 从不缩放卷积结果,所以要小心。

【讨论】:

以上是关于来自opencv和Matlab的Sobel滤波器输出不同的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV-Laplacian和Sobel滤波器的实现

学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

opencv入门之九Opencv边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

OpenCV实战: SobelLaplacianCanny 边缘检测

OpenCV——边缘检测(sobel算子Laplacian算子scharr滤波器)

图像梯度