1. 程式人生 > > Opencv學習筆記(四)--影象處理平滑,銳化操作

Opencv學習筆記(四)--影象處理平滑,銳化操作

影象平滑演算法

影象平滑與影象模糊是同一概念,主要用於影象的去噪。平滑要使用濾波器,為不改變影象的相位資訊,一般使用線性濾波器。

幾種不同的平滑方法:

1. 歸一化濾波器
Blurs an image using the normalized box filter.
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT )
其中ksize為核視窗大小,
Point(-1, -1):
Indicates where the anchor point (the pixel evaluated) is located with respect to the neighborhood.If there is a negative value, then the center of the kernel is considered the anchor point.

2. 高斯濾波
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT )
sigmaX: The standard deviation in x. Writing 0 implies that x is calculated using kernel size.
sigmaxY: The standard deviation in y. Writing 0 implies that y is calculated using kernel size.

3. 中值濾波
void medianBlur(InputArray src, OutputArray dst, int ksize)
Size of the kernel (only one because we use a square window). Must be odd.因為其核視窗為正方形,所以他只有一個。
中值濾波對椒鹽噪聲的去噪效果最好。

Opencv加椒鹽噪聲

椒鹽噪聲是由影象感測器,傳輸通道,解碼處理等產生的黑白相間的亮暗點噪聲。椒鹽噪聲往往由影象切割引起。

我們用程式來模擬椒鹽噪聲,隨機選取一些畫素,把這些畫素設為白色。

void salt(Mat& image, int n) {
    for (int k = 0; k<n; k++) {
        int i = rand() % image.cols;
        int j = rand() % image.rows;

        if (image.channels() == 1) {   //判斷是一個通道
            image.at<uchar>(j, i) = 255;
        }
        else {
            image.at<cv::Vec3b>(j, i)[0] = 255;
            image.at<cv::Vec3b>(j, i)[1] = 255;
            image.at<cv::Vec3b>(j, i)[2] = 255;
        }
    }
}

//測試程式

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
void salt(Mat &image, int n ); //椒鹽噪聲產生函式
int main(void)
{
    Mat src; Mat dst;

    /// Load the source image
    src = imread("cute.jpg", IMREAD_COLOR);
    salt(src, 30000);
    dst = src.clone();
    medianBlur(src, dst, 3);
    string window_origin = "Origin";
    string window_median = "Median";
    imshow(window_origin, src);
    imshow(window_median, dst);
    waitKey(0);

    return 0;
}

可以看到中值濾波對椒鹽噪聲簡直是好的逆天了,這裡加入了30000個噪聲點。
這裡寫圖片描述
這裡放一個高斯濾波的效果圖,可以看到在對椒鹽噪聲的處理上,高斯是比不過中值濾波的。
這裡寫圖片描述

銳化操作

銳化濾波器是為了突出顯示影象的邊界和其他的細節,這些銳化是基於一階導數和二階導數的。
一階導數可以產生粗的影象邊緣,並廣泛的應用於邊緣提取,二階導數對於精細的細節相應更好,常被用於影象增強。
常用的運算元為SobelLaplacian

Sobel運算元

導數求出的是變化最大的一部分,即突變:
這裡寫圖片描述
可以看到在圓圈的區域的導數最大。

下面給出具體求解步驟:

步驟:
1.首先進行對影象高斯平滑消除噪聲
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
2.將彩色的影象轉換成灰度影象
cvtColor( src, src_gray, CV_RGB2GRAY );
3.分別計算x方向和y方向的導數,ddepth為影象的深度,應該避免溢位的情況,因此設定CV_16S
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
4.將其轉成CV_8U
convertScaleAbs( grad_x, abs_grad_x );
convertScaleAbs( grad_y, abs_grad_y );
5.用兩個方向的倒數去模擬梯度
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );

應用例項:

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

/**
* @function main
*/
int main(int, char** argv)
{
    //![variables]
    Mat src, src_gray;
    Mat grad;
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
    //![variables]

    //![load]
    src = imread("cute.jpg", IMREAD_COLOR); // Load an image

    if (src.empty())
    {
        return -1;
    }
    //![load]

    //![reduce_noise]
    GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
    //![reduce_noise]

    //![convert_to_gray]
    cvtColor(src, src_gray, COLOR_BGR2GRAY);
    //![convert_to_gray]

    //![sobel]
    /// Generate grad_x and grad_y
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;

    /// Gradient 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);

    /// Gradient 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);
    //![sobel]

    //![convert]
    convertScaleAbs(grad_x, abs_grad_x);
    convertScaleAbs(grad_y, abs_grad_y);
    //![convert]

    //![blend]
    /// Total Gradient (approximate)
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
    //![blend]

    //![display]
    const char* window_name = "Sobel Demo - Simple Edge Detector";
    const char* window="Origin";
    imshow(window,src);
    imshow(window_name, grad);
    waitKey(0);
    //![display]

    return 0;
}

結果如圖所示:
這裡寫圖片描述

Laplacian運算元

程式碼實現:

#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

/**
* @function main
*/
int main(int, char** argv)
{
    //![variables]
    Mat src, src_gray, dst;
    int kernel_size = 3;
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
    //![variables]

    //![load]
    src = imread("cute.jpg", IMREAD_COLOR); // Load an image

    if (src.empty())
    {
        return -1;
    }
    //![load]

    //![reduce_noise]
    /// Reduce noise by blurring with a Gaussian filter
    GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
    //![reduce_noise]

    //![convert_to_gray]
    cvtColor(src, src_gray, COLOR_BGR2GRAY); // Convert the image to grayscale
                                             //![convert_to_gray]

                                             /// Apply Laplace function
    Mat abs_dst;
    //![laplacian]
    Laplacian(src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT);
    //![laplacian]

    //![convert]
    convertScaleAbs(dst, abs_dst);
    //![convert]

    //![display]
    const char* window_name = "Laplace Demo";
    const char* window = "Origin";
    imshow(window, src);
    imshow(window_name, abs_dst);
    waitKey();
    //![display]

    return 0;
}

這裡寫圖片描述