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個噪聲點。
這裡放一個高斯濾波的效果圖,可以看到在對椒鹽噪聲的處理上,高斯是比不過中值濾波的。
銳化操作
銳化濾波器是為了突出顯示影象的邊界和其他的細節,這些銳化是基於一階導數和二階導數的。
一階導數可以產生粗的影象邊緣,並廣泛的應用於邊緣提取,二階導數對於精細的細節相應更好,常被用於影象增強。
常用的運算元為Sobel和Laplacian
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;
}
