opencv边缘检测的方法

部分边缘检测仅提供主要实现代码工程需要自己补充完整

1、Robert

原理:

任意一对互相垂直方向上的差分可以看成求梯度的近似方法

优缺点:

边缘定位精度较高,对于陡峭边缘且噪声低的图像效果较好,但没有进行平滑处理,没有抑制噪声能力

应用

具有陡峭的低噪声的图像处理效果较好

/*****************************Robert*******************************/

Mat roberts(cv::Mat srcImage)

{

  cv::Mat dstImage = srcImage.clone();

  int nRows = dstImage.rows;

  int nCols = dstImage.cols;

  for (int i = 0; i < nRows-1; i++)

  {

    for (int j = 0; j < nCols-1; j++)

    {

      int t1 = (srcImage.at<uchar>(i, j) -

          srcImage.at<uchar>(i+1, j+1)) *

          (srcImage.at<uchar>(i, j) -

          srcImage.at<uchar>(i+1, j+1));

      int t2 = (srcImage.at<uchar>(i+1, j) -

          srcImage.at<uchar>(i, j+1)) *

          (srcImage.at<uchar>(i+1, j) -

           srcImage.at<uchar>(i, j+1));

      dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);

    }

  }

  return dstImage;

}

2、Sobelprewwitt

进行了平滑处理,对噪声具有一定的抑制能力,但容易出现多像素宽度。

应用

检测方法对灰度渐变和噪声较多的图像处理效果较好

/*****************************prewwitt*******************************/

Mat prewitt(Mat imageP)

{

    cvtColor(imageP,imageP,CV_RGB2GRAY);

    float prewittx[9] =

    {

        -1,0,1,

        -1,0,1,

        -1,0,1

    };

    float prewitty[9] =

    {

        1,1,1,

        0,0,0,

        -1,-1,-1

    };

    Mat px=Mat(3,3,CV_32F,prewittx);

    Mat py=Mat(3,3,CV_32F,prewitty);

    Mat dstx=Mat(imageP.size(),imageP.type(),imageP.channels());

    Mat dsty=Mat(imageP.size(),imageP.type(),imageP.channels());

    Mat dst=Mat(imageP.size(),imageP.type(),imageP.channels());

    filter2D(imageP,dstx,imageP.depth(),px);

    filter2D(imageP,dsty,imageP.depth(),py);

    float tempx,tempy,temp;

    for(int i=0;i<imageP.rows;i++)

    {

        for(int j=0;j<imageP.cols;j++)

        {

            tempx=dstx.at<uchar>(i,j);

            tempy=dsty.at<uchar>(i,j);

            temp=sqrt(tempx*tempx+tempy*tempy);

            dst.at<uchar>(i,j)=temp;

        }

    }

    return dst;

}

/*****************************sobel*******************************/

   Mat src, src_gray;

    Mat grad;

    string window_name = "Sobel Demo - Simple Edge Detector";

    int scale = 1;//默认值

    int delta = 0;//默认值

    int ddepth = CV_16S;//防止输出图像深度溢出

    int c;

    src = imread( "lena.jpg" );

    if( !src.data )

      { return -1; }

    //高斯模糊

    GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );

    //变换为灰度图

    cvtColor( src, src_gray, CV_RGB2GRAY );

    //创建窗口

    namedWindow( window_name, CV_WINDOW_AUTOSIZE );

    //生成 grad_x and grad_y

    Mat grad_x, grad_y;

    Mat abs_grad_x, abs_grad_y;

    // Gradient X x方向梯度 1,0:x方向计算微分即导数

    Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );

    convertScaleAbs( grad_x, abs_grad_x );

    // Gradient Y y方向梯度 0,1:y方向计算微分即导数

    Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );

    convertScaleAbs( grad_y, abs_grad_y );

    //近似总的梯度

    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );

    imshow( window_name, grad );

    waitKey(0);

3、Laplacian

对噪声较为敏感,使噪声能力成分得到加强,容易丢失部分边缘方向信息,造成一些不连续的检测边缘,同时抗噪声能力较差。所以很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。

4、Laplacian

(自己加载一张图片就好,img加载图像名,补充完main函数)

/*****************************Laplacian*******************************/

    cv::Mat srcImage=cv::imread("lena.jpg", 0);

     if (!srcImage.data)

          return -1;

    // 高斯平滑  加上高斯平滑效果边缘检测效果更好     

    GaussianBlur(srcImage, srcImage, cv::Size(3,3),0, 0, cv::BORDER_DEFAULT);

     cv::Mat dstImage;

     // 拉普拉斯变换

     Laplacian(srcImage, dstImage, CV_16S, 3);

     convertScaleAbs( dstImage, dstImage);

     cv::imshow("srcImage", srcImage);

     cv::imshow("dstImage", dstImage);

     cv::waitKey(0);

5、Log

抗噪声能力较强,但会造成一些尖锐的边缘无法检测到。(自己加载一张图片就好,img加载图像名,补充完mainh)

/*****************************Log*******************************/

    Mat img_G0,img_G1;

     GaussianBlur(img,img_G0,Size(3,3),0);

     GaussianBlur(img_G0,img_G1,Size(3,3),0);

     Mat img_DoG = img_G0 - img_G1;

     normalize(img_DoG,img_DoG,255,0,CV_MINMAX);

     imshow("img_DoG",img_DoG);

     cv::waitKey(0);

6、Canny

最优化思想的边缘检测算子,同时采用高斯函数对图像进行平滑处理,但会造成将高频边缘平滑掉,造成边缘丢失,采用双阈值算法检测和链接边缘。

/*****************************Canny*******************************/

#include"./opencv2/opencv.hpp"

#include <iostream>  

using namespace cv;  

using namespace std;  

Mat src, src_gray;  

Mat dst, detected_edges;  

int edgeThresh = 1;  

int lowThreshold;  

int const max_lowThreshold = 100;  

int ratio = 3;  

int kernel_size = 3;  

const char* window_name = "Edge Map";   

static void CannyThreshold(int, void*)  

{  

    Canny( src_gray, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );  

    dst = Scalar::all(0);  

    src.copyTo( dst, detected_edges);  

    imshow( window_name, dst );  

}  

int main( int, char** argv )  

{  

  src = imread("D:\\lena.jpg",CV_LOAD_IMAGE_COLOR);  

  if( !src.data )  

    { return -1; }  

  dst.create( src.size(), src.type() );  

  cvtColor( src, src_gray, CV_BGR2GRAY );  

  namedWindow( window_name, CV_WINDOW_AUTOSIZE );  

  createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );  

  CannyThreshold(0, 0);  

  waitKey(0);  

  return 0;  

}

7、形态学边缘检测

利用形态学梯度保留边缘检测morphgrad(src)=dilate(src)erode(src)

/***********************dilate-erode  Edge detection****************************/

#include "core/core.hpp"

#include "highgui/highgui.hpp"

#include "imgproc/imgproc.hpp"

using namespace cv;

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

{

Mat image,imageGray,imageDilate,imageErode,imageBorder;

image=imread(argv[1]);

resize(image,image,Size(400,400));

cvtColor(image,imageGray,CV_RGB2GRAY);

//enum { MORPH_RECT=0, MORPH_CROSS=1, MORPH_ELLIPSE=2 };

Mat element=getStructuringElement(1,Size(3,3),Point(-1,-1));

//效果等同与imageDilate-imageErode

   //morphologyEx(imageGray,imageGray, MORPH_GRADIENT, element); 

dilate(imageGray,imageDilate,element,Point(-1,-1));

erode(imageGray,imageErode,element,Point(-1,-1));

imageBorder=imageDilate-imageErode;

imshow("Source image",image);

imshow("Dilate",imageDilate);

imshow("Erode",imageErode);

imshow("Border",imageBorder);

waitKey(0);

}

猜你喜欢

转载自blog.csdn.net/qq_34510308/article/details/79497992