710官方网站平整处理时索要运用一个滤波器,开源中国

图像的平整处理

平整,也称 模糊, 平滑处理时索要运用一个滤波器
。滤波器想象成一个带有加权全面的窗口,这些加权周详也叫做核或者模版。

    // 图像平滑处理分而学之.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    using namespace std;
    using namespace cv;
    const int MAX_KERNEL_LENGTH = 31;
    int _tmain(int argc, _TCHAR* argv[])
    {
        Mat img = imread("D:\\lenargb.jpg", 1);
        if (img.empty())
        {
            cout << "无法读入图像" << endl;
            return -1;
        }
        Mat dest;

    #pragma region 归一化平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i++)
        {
            blur(img, dest, Size(i, i), Point(-1, -1));//size(i,i)内核大小,最小为(1,1);
            imshow("归一化平滑图像", dest);
            waitKey(100);

        }
    #pragma endregion
    #pragma region 高斯平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            GaussianBlur(img, dest, Size(i, i), 0, 0);//size的两个参数必须都为正奇数,第四个参数是x方向的标准差,第五个参数是y方向的标准差,如果是0,表示从内核大小计算得到;
            imshow("高斯平滑图像图像", dest);
            waitKey(100);
        }
    #pragma endregion

    #pragma region 中值平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            medianBlur(img, dest, i);//第三个参数为核的边长,必须为奇数,一般中值平滑用的都是正方形所以只用一个参数就好;
            imshow("中值平滑", dest);
            waitKey(100);
        }
    #pragma endregion

        //waitKey(0);
        return 0;
    }

图像的平缓处理

平整,也称 模糊, 平滑处理时索要动用一个滤波器
。滤波器想象成一个暗含加权周详的窗口,这一个加权周详也叫做核或者模版。

    // 图像平滑处理分而学之.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    using namespace std;
    using namespace cv;
    const int MAX_KERNEL_LENGTH = 31;
    int _tmain(int argc, _TCHAR* argv[])
    {
        Mat img = imread("D:\\lenargb.jpg", 1);
        if (img.empty())
        {
            cout << "无法读入图像" << endl;
            return -1;
        }
        Mat dest;

    #pragma region 归一化平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i++)
        {
            blur(img, dest, Size(i, i), Point(-1, -1));//size(i,i)内核大小,最小为(1,1);
            imshow("归一化平滑图像", dest);
            waitKey(100);

        }
    #pragma endregion
    #pragma region 高斯平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            GaussianBlur(img, dest, Size(i, i), 0, 0);//size的两个参数必须都为正奇数,第四个参数是x方向的标准差,第五个参数是y方向的标准差,如果是0,表示从内核大小计算得到;
            imshow("高斯平滑图像图像", dest);
            waitKey(100);
        }
    #pragma endregion

    #pragma region 中值平滑
        for (int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2)
        {
            medianBlur(img, dest, i);//第三个参数为核的边长,必须为奇数,一般中值平滑用的都是正方形所以只用一个参数就好;
            imshow("中值平滑", dest);
            waitKey(100);
        }
    #pragma endregion

        //waitKey(0);
        return 0;
    }

开源中国

图像阈值操作

为了从一副图像中领到出我们需要的片段,应该用图像中的每一个像素点的灰度值与选拔的阈值举办相比,并作出相应的论断。
假诺找到了亟需分割的实体的像素点,大家能够对这一个像素点设定一些一定的值来代表。(例如:可以将该物体的像素点的灰度值设定为:‘0’(粉色),其他的像素点的灰度值为:‘255’(白色);
OpenCV中提供了阈值(threshold)函数 有五种档次

  1. 二进制阈值化
    先要选定一个一定的阈值量,比如:120,这样,新的阈值发生规则可以分解为大于120的像素点的灰度值设定为最大值(如8位灰度值最大为255),灰度值小于120的像素点的灰度值设定为0。
  2. 反二进制阈值化
    该阈值化与二进制阈值化相似,先选定一个一定的灰度值作为阈值,不过最后的设定值相反。
  3. 截断阈值化
    一样首先需要选定一个阈值,图像中超越该阈值的像素点被设定为该阈值,小于该阈值的维系不变
  4. 阈值化为0
    第一需要选定一个阈值,像素点的灰度值大于该阈值的不开展其他改变;2
    像素点的灰度值小于该阈值的,其灰度值全体变为0
  5. 反阈值化为0
    规律类似于0阈值,但是在对图像做处理的时候相反,即:像素点的灰度值小于该阈值的不举办任何改动,而胜出该阈值的局部,其灰度值全体变为0。
    filter2D函数可以对图像遵照模版举行滤波

    // 基本阈值操作2.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    using namespace  std;
    using namespace cv;


    void respond(int, void*);
    const char * window_name = "图片";
    Mat src_gray;
    Mat dst;
    int threshhold_type = 5;
    const int max_type = 5;
    int threshhold_value = 0;
    int max_value = 255;
    int _tmain(int argc, _TCHAR* argv[])
    {
        namedWindow(window_name, WINDOW_AUTOSIZE);
        Mat src = imread("E:\\code\\test\\image\\tiantan.png", 1);
        if (src.empty())
        {
            cout << "无法正常载入图片" << endl; return -1;
        }
        //转换为灰度图;
        cvtColor(src, src_gray, CV_RGB2GRAY);
        imshow(window_name, src_gray);
        createTrackbar("阈值类型", window_name, &threshhold_type, max_type, respond);
        createTrackbar("阈值大小", window_name, &threshhold_value, max_value, respond);
        waitKey(0);
        return 0;
    }
    void respond(int, void*)
    {
        /* 0:二进制阈值
        1: 反二进制阈值
        2: 截断阈值
        3: 0阈值
        4: 反0阈值
        5:原灰度图;
        */
        if (threshhold_type==5)
        {
            imshow(window_name, src_gray);
        }
        else
        {
            threshold(src_gray, dst, threshhold_value, max_value, threshhold_type);
            imshow(window_name, dst);
        }
    }

图像阈值操作

为了从一副图像中领取出我们需要的局部,应该用图像中的每一个像素点的灰度值与接纳的阈值举行相比,并作出相应的判断。
假使找到了索要分割的实体的像素点,我们得以对这一个像素点设定一些特定的值来表示。(例如:可以将该物体的像素点的灰度值设定为:‘0’(粉色),其他的像素点的灰度值为:‘255’(白色);
OpenCV中提供了阈值(threshold)函数 有五系列型

  1. 二进制阈值化
    先要选定一个特定的阈值量,比如:120,这样,新的阈值产生规则可以分解为超出120的像素点的灰度值设定为最大值(如8位灰度值最大为255),灰度值小于120的像素点的灰度值设定为0。
  2. 反二进制阈值化
    该阈值化与二进制阈值化相似,先选定一个特定的灰度值作为阈值,可是最后的设定值相反。
  3. 截断阈值化
    同等首先需要选定一个阈值,图像中胜出该阈值的像素点被设定为该阈值,小于该阈值的维持不变
  4. 阈值化为0
    率先需要选定一个阈值,像素点的灰度值大于该阈值的不开展其他改动;2
    像素点的灰度值小于该阈值的,其灰度值全体改成0
  5. 反阈值化为0
    规律类似于0阈值,但是在对图像做处理的时候相反,即:像素点的灰度值小于该阈值的不开展任何改动,而胜出该阈值的部分,其灰度值全体变为0。
    filter2D函数可以对图像遵照模版举行滤波

     // 基本阈值操作2.cpp : 定义控制台应用程序的入口点。
     //
    
     #include "stdafx.h"
     #include <iostream>
     #include <opencv2/opencv.hpp>
     using namespace  std;
     using namespace cv;
    
    void respond(int, void*);
    const char * window_name = "图片";
    Mat src_gray;
    Mat dst;
    int threshhold_type = 5;
    const int max_type = 5;
    int threshhold_value = 0;
    int max_value = 255;
    int _tmain(int argc, _TCHAR* argv[])
    {
        namedWindow(window_name, WINDOW_AUTOSIZE);
        Mat src = imread("E:\\code\\test\\image\\tiantan.png", 1);
        if (src.empty())
        {
            cout << "无法正常载入图片" << endl; return -1;
        }
        //转换为灰度图;
        cvtColor(src, src_gray, CV_RGB2GRAY);
        imshow(window_name, src_gray);
        createTrackbar("阈值类型", window_name, &threshhold_type, max_type, respond);
        createTrackbar("阈值大小", window_name, &threshhold_value, max_value, respond);
        waitKey(0);
        return 0;
    }
    void respond(int, void*)
    {
        /* 0:二进制阈值
        1: 反二进制阈值
        2: 截断阈值
        3: 0阈值
        4: 反0阈值
        5:原灰度图;
        */
        if (threshhold_type==5)
        {
            imshow(window_name, src_gray);
        }
        else
        {
            threshold(src_gray, dst, threshhold_value, max_value, threshhold_type);
            imshow(window_name, dst);
        }
    }
#@date:         2014-06-20
#@author:       gerui
#@email:        forgerui@gmail.com

心想事成和谐的线性滤波器

OpenCV为我们提供了函数 filter2D ,来贯彻核卷积;

    // 实现自己的滤波器2.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    using namespace std;
    using namespace cv;
    void respond(int, void*);
    const char * window_name = "实现自己的滤波器";
    int value = 0;
    Mat src,dst,kernel;
    const int max_value = 100;

    int _tmain(int argc, _TCHAR* argv[])
    {
        src = imread("E:\\code\\test\\image\\lena.png", 1);
        if (src.data==NULL)
        {
            cout << "无法加载图片" << endl;
            return -1;
        }
        namedWindow(window_name, WINDOW_AUTOSIZE);
        imshow(window_name, src);
        createTrackbar("核的大小", window_name, &value, max_value, respond);
        while (true)
        {

            char c = waitKey(0);
            if (c==27)
            {
                return 0;
            }
        }

        return 0;
    }

    void respond(int, void*)
    {
        int kernel_size = 1 + value * 2;
        kernel = Mat::ones(kernel_size, kernel_size, CV_32F)/(float)(kernel_size*kernel_size);
        filter2D(src, dst, -1, kernel, Point(-1, -1));
        imshow(window_name, dst);
    }

心想事成协调的线性滤波器

OpenCV为我们提供了函数 filter2D ,来贯彻核卷积;

    // 实现自己的滤波器2.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include <iostream>
    #include <opencv2/opencv.hpp>
    using namespace std;
    using namespace cv;
    void respond(int, void*);
    const char * window_name = "实现自己的滤波器";
    int value = 0;
    Mat src,dst,kernel;
    const int max_value = 100;

    int _tmain(int argc, _TCHAR* argv[])
    {
        src = imread("E:\\code\\test\\image\\lena.png", 1);
        if (src.data==NULL)
        {
            cout << "无法加载图片" << endl;
            return -1;
        }
        namedWindow(window_name, WINDOW_AUTOSIZE);
        imshow(window_name, src);
        createTrackbar("核的大小", window_name, &value, max_value, respond);
        while (true)
        {

            char c = waitKey(0);
            if (c==27)
            {
                return 0;
            }
        }

        return 0;
    }

    void respond(int, void*)
    {
        int kernel_size = 1 + value * 2;
        kernel = Mat::ones(kernel_size, kernel_size, CV_32F)/(float)(kernel_size*kernel_size);
        filter2D(src, dst, -1, kernel, Point(-1, -1));
        imshow(window_name, dst);
    }

一、一阶微分边缘算子

  1. 一阶微分边缘检测算子也称梯度边缘算子。

  2.
梯度的模值大小提供了边缘的强度信息,梯度的方向提供了边缘趋势新闻,因为梯度方向始终是垂直于边缘的势头。

  3. 用单薄差分进行梯度近似。

Sobel导数

Sobel 算子是一个离散微分算子 (discrete differentiation operator)。
它用来测算图像灰度函数的近乎梯度。Sobel 算子结合了高斯平滑和微分求导。

    // Sobel导数.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>

    using namespace cv;

    /** @function main */
    int main(int argc, char** argv)
    {

        Mat src, src_gray;
        Mat grad;
        char* window_name = "Sobel Demo - Simple Edge Detector";
        int scale = 1;
        int delta = 0;
        int ddepth = CV_16S;

        //int c;

        /// 装载图像
        src = imread("E://code//test//image//lena.png",1);

        if (!src.data)
        {
            return -1;
        }

        GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
        /// 创建显示窗口
        namedWindow(window_name, CV_WINDOW_AUTOSIZE);
        imshow(window_name, src);
        waitKey(3000);
        /// 转换为灰度图
        cvtColor(src, src_gray, CV_RGB2GRAY);


        imshow(window_name, src_gray);
        waitKey(3000);
        /// 创建 grad_x 和 grad_y 矩阵
        Mat grad_x, grad_y;
        Mat abs_grad_x, abs_grad_y;

        /// 求 X方向梯度

        Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
        //Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
        convertScaleAbs(grad_x, abs_grad_x);

        /// 求Y方向梯度
        Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
        //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);

        return 0;
    }

//其实不简单也没有关系,因为只是相对大小,在图像的对比中,依然能够找到边界;

Sobel导数

Sobel 算子是一个离散微分算子 (discrete differentiation operator)。
它用来计量图像灰度函数的接近梯度。Sobel 算子结合了高斯平滑和微分求导。

    // Sobel导数.cpp : 定义控制台应用程序的入口点。
    //
    #include "stdafx.h"

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>

    using namespace cv;

    /** @function main */
    int main(int argc, char** argv)
    {

        Mat src, src_gray;
        Mat grad;
        char* window_name = "Sobel Demo - Simple Edge Detector";
        int scale = 1;
        int delta = 0;
        int ddepth = CV_16S;

        //int c;

        /// 装载图像
        src = imread("E://code//test//image//lena.png",1);

        if (!src.data)
        {
            return -1;
        }

        GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
        /// 创建显示窗口
        namedWindow(window_name, CV_WINDOW_AUTOSIZE);
        imshow(window_name, src);
        waitKey(3000);
        /// 转换为灰度图
        cvtColor(src, src_gray, CV_RGB2GRAY);


        imshow(window_name, src_gray);
        waitKey(3000);
        /// 创建 grad_x 和 grad_y 矩阵
        Mat grad_x, grad_y;
        Mat abs_grad_x, abs_grad_y;

        /// 求 X方向梯度

        Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
        //Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);
        convertScaleAbs(grad_x, abs_grad_x);

        /// 求Y方向梯度
        Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
        //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);

        return 0;
    }

//其实不简单也没有关系,因为只是相对大小,在图像的对比中,依然能够找到边界;

二、二阶微分边缘算子

  1.
二阶微分边缘检测算子,它是利用图像在边缘处的阶跃性导致图像二阶微分在边缘处出现零值这一特色开展检测。

  2. 二阶微分算子对噪声异常灵活。采纳LOG可以削减噪音对边缘的熏陶。

  3.
行使高斯函数对图像举办滤波并对图像滤波结果开展二阶微分运算的经过,可以转移为先对高斯函数举行二阶微分,再使用高斯函数的二阶微分结果对图像举办卷积运算。

Laplace 算子

一阶导数的极值地方,二阶导数为0。所以我们也足以用这么些特点来作为检测图像边缘的法子。
但是,
二阶导数的0值不仅仅出现在边缘(它们也说不定出现在架空的地点),但是大家得以过滤掉这一个点。
实际,由于 Laplacian使用了图像梯度,它其中调用了 Sobel 算子。

    // Laplace算子.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>

    using namespace cv;

    /** @函数 main */
    int main(int argc, char** argv)
    {
        Mat src, src_gray, dst;
        int kernel_size = 3;
        int scale = 1;
        int delta = 0;
        int ddepth = CV_16S;
        char* window_name = "Laplace Demo";

        int c;

        /// 装载图像
        src = imread("E://code//test//image//lena.png", 1);

        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);
        imshow(window_name, src);
        waitKey(2000);
        imshow(window_name, src_gray);
        waitKey(3000);

        /// 使用Laplace函数
        Mat abs_dst;

        Laplacian(src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);
        //ddepth: 输出图像的深度。 因为输入图像的深度是 CV_8U ,这里我们必须定义 ddepth = CV_16S 以避免外溢。
        //下面大概求绝对值;
        convertScaleAbs(dst, abs_dst);

        /// 显示结果
        imshow(window_name, abs_dst);

        waitKey(0);

        return 0;
    }

Laplace 算子

一阶导数的极值地方,二阶导数为0。所以我们也足以用这一个特点来作为检测图像边缘的法子。
可是,
二阶导数的0值不仅仅现身在边缘(它们也说不定出现在架空的职位),可是大家得以过滤掉那个点。
事实上,由于 Laplacian使用了图像梯度,它其中调用了 Sobel 算子。

    // Laplace算子.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>

    using namespace cv;

    /** @函数 main */
    int main(int argc, char** argv)
    {
        Mat src, src_gray, dst;
        int kernel_size = 3;
        int scale = 1;
        int delta = 0;
        int ddepth = CV_16S;
        char* window_name = "Laplace Demo";

        int c;

        /// 装载图像
        src = imread("E://code//test//image//lena.png", 1);

        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);
        imshow(window_name, src);
        waitKey(2000);
        imshow(window_name, src_gray);
        waitKey(3000);

        /// 使用Laplace函数
        Mat abs_dst;

        Laplacian(src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);
        //ddepth: 输出图像的深度。 因为输入图像的深度是 CV_8U ,这里我们必须定义 ddepth = CV_16S 以避免外溢。
        //下面大概求绝对值;
        convertScaleAbs(dst, abs_dst);

        /// 显示结果
        imshow(window_name, abs_dst);

        waitKey(0);

        return 0;
    }

三、Canny边缘检测算子

  1. 三条标准:高检测率;精确的定点;明确的响应。

  2. Canny算子重要四手续:

  1) 用高斯函数对图像举行平滑滤波。将高斯函数作成滤波模板,使用5 X
5的沙盘。
  2)
总结梯度值与方向角。分别求取x方向和y方向的梯度Mx和My。求梯度可以通过使用Sobel模板与图像举办卷积。归并到0,
45, 90, 135多少个趋势。
  3)
非最大值抑制。经过Sobel滤波后,图像中的边缘粗细不一。边缘的粗细重要在于跨越边缘密度分布。非最大值抑制是将梯度方向上最大梯度值保留,将其余像元删除。分为0,45,90,135度多个样子分别处理,如0度方向检查(x+1, y)、(x, y)、(x-1, y);45度方向检查(x+1, y+1)、(x, y)、(x-1, y-1)…相比这六个像元高低,将较小的六个删除。
  4)
滞后阈值化。由于噪声烦扰,本应当连续的边缘出现断裂。滞后阈值化设定五个阈值thigh,一个低阈值tlow,通过如下方法总结:

    a) 假如像元(x,
y)的梯度值大于thigh,则标记为边缘像元;
    b) 假若像元(x,
y)的梯度值小于tlow,则标记为非边缘像元;
    c) 即使像元(x,
y)值介于多少个阈值之间,则判断及3、5邻域内是否存在梯度大于thigh,如若有则标记为边缘,没有则标记为非边缘像元。

Canny 边缘检测

步骤

  1. 解除噪声。 使用高斯平滑滤波器卷积降噪。
  2. 计量梯度幅值和倾向。 此处,使用Sobel滤波器
  3. 非极大值 抑制。 这一步排除非边缘像素,
    仅仅保留了一部分细线条(候选边缘)。
  4. 落后阈值: 最后一步,Canny
    使用了落后阈值,滞后阈值需要七个阈值(高阈值和低阈值): Canny 推荐的
    高:低 阈值比在 2:1 到3:1里面。

    // Canny边缘检测.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h" 
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>

    using namespace cv;

    /// 全局变量

    Mat src, src_gray;
    Mat dst, detected_edges;

    //int edgeThresh = 1;
    int lowThreshold=1;
    int const max_lowThreshold = 100;
    int ratio = 3;
    int kernel_size = 3;
    char* window_name = "Edge Map";

    /**
    * @函数 CannyThreshold
    * @简介: trackbar 交互回调 - Canny阈值输入比例1:3
    */
    void CannyThreshold(int, void*)
    {
        /// 使用 3x3内核降噪
        blur(src_gray, detected_edges, Size(3, 3));

        /// 运行Canny算子
        Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
        //第一个参数是原图像,第二个参数是输出图像,支持本地计算,第三个参数是低阈值,第四个参数是高阈值,第五个参数是内部sobel算子使用的内核大小。
        /// 使用 Canny算子输出边缘作为掩码显示原图像
        dst = Scalar::all(0);
        //把dst填充为黑色
        src.copyTo(dst, detected_edges);
        //第一个参数为输出图像,第二个参数为掩码;即把第二个图像中非0的部分在src中的像素复制给dst;

        imshow(window_name, dst);
    }


    /** @函数 main */
    int main(int argc, char** argv)
    {
        /// 装载图像
        src = imread("E:\\code\\test\\image\\lena.png",1);

        if (!src.data)
        {
            return -1;
        }

        /// 创建与src同类型和大小的矩阵(dst)
        dst.create(src.size(), src.type());

        /// 原图像转换为灰度图像
        cvtColor(src, src_gray, CV_BGR2GRAY);

        /// 创建显示窗口
        namedWindow(window_name, CV_WINDOW_AUTOSIZE);

        /// 创建trackbar
        createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold);

        /// 显示图像
        CannyThreshold(0, 0);

        /// 等待用户反应
        waitKey(0);

        return 0;
    }

1.png

    /// 使用 3x3内核降噪
    blur(src_gray, detected_edges, Size(3, 3));

    /// 运行Canny算子
    Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
    //第一个参数是原图像,第二个参数是输出图像,支持本地计算,第三个参数是低阈值,第四个参数是高阈值,第五个参数是内部sobel算子使用的内核大小。
    /// 使用 Canny算子输出边缘作为掩码显示原图像

Canny 边缘检测

步骤

  1. 扫除噪声。 使用高斯平滑滤波器卷积降噪。
  2. 测算梯度幅值和自由化。 此处,使用Sobel滤波器
  3. 非极大值 抑制。 这一步排除非边缘像素,
    仅仅保留了部分细线条(候选边缘)。
  4. 败北阈值: 最终一步,Canny
    使用了落后阈值,滞后阈值需要六个阈值(高阈值和低阈值): Canny 推荐的 高:低
    阈值比在 2:1 到3:1以内。

     // Canny边缘检测.cpp : 定义控制台应用程序的入口点。
     //
    
     #include "stdafx.h" 
     #include "opencv2/imgproc/imgproc.hpp"
     #include "opencv2/highgui/highgui.hpp"
     #include <stdlib.h>
     #include <stdio.h>
    
     using namespace cv;
    
     /// 全局变量
    
     Mat src, src_gray;
     Mat dst, detected_edges;
    
     //int edgeThresh = 1;
     int lowThreshold=1;
     int const max_lowThreshold = 100;
     int ratio = 3;
     int kernel_size = 3;
     char* window_name = "Edge Map";
    
     /**
     * @函数 CannyThreshold
     * @简介: trackbar 交互回调 - Canny阈值输入比例1:3
     */
     void CannyThreshold(int, void*)
     {
         /// 使用 3x3内核降噪
         blur(src_gray, detected_edges, Size(3, 3));
    
         /// 运行Canny算子
         Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
         //第一个参数是原图像,第二个参数是输出图像,支持本地计算,第三个参数是低阈值,第四个参数是高阈值,第五个参数是内部sobel算子使用的内核大小。
         /// 使用 Canny算子输出边缘作为掩码显示原图像
         dst = Scalar::all(0);
         //把dst填充为黑色
         src.copyTo(dst, detected_edges);
         //第一个参数为输出图像,第二个参数为掩码;即把第二个图像中非0的部分在src中的像素复制给dst;
    
         imshow(window_name, dst);
     }
    
    /** @函数 main */
    int main(int argc, char** argv)
    {
        /// 装载图像
        src = imread("E:\\code\\test\\image\\lena.png",1);

        if (!src.data)
        {
            return -1;
        }

        /// 创建与src同类型和大小的矩阵(dst)
        dst.create(src.size(), src.type());

        /// 原图像转换为灰度图像
        cvtColor(src, src_gray, CV_BGR2GRAY);

        /// 创建显示窗口
        namedWindow(window_name, CV_WINDOW_AUTOSIZE);

        /// 创建trackbar
        createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold);

        /// 显示图像
        CannyThreshold(0, 0);

        /// 等待用户反应
        waitKey(0);

        return 0;
    }

710官方网站 1

    /// 使用 3x3内核降噪
    blur(src_gray, detected_edges, Size(3, 3));

    /// 运行Canny算子
    Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
    //第一个参数是原图像,第二个参数是输出图像,支持本地计算,第三个参数是低阈值,第四个参数是高阈值,第五个参数是内部sobel算子使用的内核大小。
    /// 使用 Canny算子输出边缘作为掩码显示原图像

相关文章