從本篇部落格開始了解opencv中imgproc庫。imgproc顧名思義就是image process即圖像處理,像圖像濾波、圖像形态學(膨脹腐蝕、開運算、閉運算等)、圖像縮放等一些圖像處理相關知識。
圖像平滑(smoothing)也稱為圖像模糊(blurring),是一種在圖像進行中使用頻率很高的操作,進行圖像平滑的操作原因有很多,在這裡重點介紹使用平滑操作降低圖檔噪聲。因為在圖像中,噪聲的能量大都集中在幅度譜的低頻和中頻部分,而在較高的頻段,一些重要的細節資訊往往被噪聲淹沒。在一幅圖像中,所謂的高頻部分是指圖像中像素值落差很大的部分,而低頻則是指像素值與旁邊的像素值相差不大甚至相同,而圖像的一些細節的部分往往由高頻資訊來展現,圖像中摻雜的噪聲往往也處于高頻段,這就造成了一些細節資訊被噪聲淹沒,可以根據不同的噪聲類型用不同的濾波器進行處理。
濾波的目的有兩個即:1.抽出對象的特征作為圖像識别的特征模式;2.為适應圖像處理要求,消除數字圖像所混入的噪聲
對圖像濾波有兩個要求:1.不能損壞圖像的輪廓和邊緣等重要資訊;2.使圖像清晰視覺效果更好
為了進行圖像平滑操作,通常在圖像上加一個濾波器(filter),最常見的類型是線性的,輸出像素值(g(i, j))最終由原像素值和權重值決定。其公式如下:
其中h(k, l)被稱為核(kernel),是加到圖像上濾波器(filter)的系數,它有助于把濾波器進行可視化為一個視窗在圖像上滑動,這些設計到鄰域的卷積操作。
鄰域算子值利用給定像素周圍像素的值決定此像素的最終輸出。左邊圖像就是原像素的值,中間圖像是濾波器(filter),filter的目的就是将濾波器的權重值進行這樣的可視化視窗,最右邊的圖像是原圖像和濾波器一起卷積生成,圖像中的綠色部分是左圖中青色和中間濾波器卷積計算得到的結果。是以可以看出圖像像素最終的值不僅與原像素有關也可濾波器選取的kernel視窗大小有關。
方框濾波
在有了上述的理論基礎之後,首先介紹一下方框濾波。
這是所有濾波器中最簡單的一種濾波方式。每一個輸出像素的是核心鄰域像素值的平均值得到。
通用的濾波kernel如下:
這裡是一個長寬分别為Kwidth和Kheight的視窗函數,在此區域内鄰域中像素值疊加求平均即可求出位于kernel中心點像素的像素值。opencv中提供了方框濾波函數boxFilter()
C++: void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-,-), bool normalize=true, int borderType=BORDER_DEFAULT )
參數解釋:
. InputArray src: 輸入圖像,可以是Mat類型
. OutputArray dst: 經濾波後輸出圖像
. int ddepth: 目标圖像的深度,若設定為-1,則深度與原圖像深度相同
. Size ksize: Size類型,核心的大小,一般用Size(w, h)表示,如Size(3, 3)表示kernel視窗大小為3x3
. Point anchor = Point(-1,-1): 進行濾波操作的點,如果是預設值(-1, -1)說明對上述視窗中心點所對應的像素點進行操作
. bool normalize = true: 核心是否被歸一化處理,有預設值true
. int borderType = BORDER_DEFAULT: 用于腿短圖像外部像素的某種便捷模式,有預設值BORDER_DEFAULT.
方框濾波用的kernel如下:
其中
如果計算在kernel視窗中像素綜合可以使用integral().
方框濾波示例代碼如下:
#include <iostream>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
const int g_nTrackBarMaxValue = ; //軌迹條最大值
int g_nTrackBarValue; //軌迹條初始值
Mat g_srcImage, g_dstImage; //定義圖像全局變量
int g_nKernelTrackbarValue; //定義軌迹條的值
void on_kernelTrackbar(int, void*);
int main()
{
g_srcImage = imread("lena.jpg");
//判斷圖像是否加載成功
if(g_srcImage.empty())
{
cout << "圖像加載失敗!" << endl;
return -;
}
else
cout << "圖像加載成功!" << endl << endl;
namedWindow("原圖像",WINDOW_AUTOSIZE);
imshow("原圖像", g_srcImage); //顯示原圖像
g_nTrackBarValue = ; //初始化軌迹條初始值
namedWindow("方框濾波",WINDOW_AUTOSIZE); //軌迹條依附視窗
char kernelName[];
sprintf(kernelName, "濾波kernel %d",g_nTrackBarMaxValue);
//建立軌迹條
createTrackbar(kernelName, "方框濾波", &g_nTrackBarValue,g_nTrackBarMaxValue,on_kernelTrackbar);
on_kernelTrackbar(g_nTrackBarValue, );
waitKey();
return ;
}
void on_kernelTrackbar(int, void*)
{
//根據輸入值重新計算kernel尺寸,見程式詳解
g_nKernelTrackbarValue = g_nTrackBarValue * + ;
//方框濾波函數
boxFilter(g_srcImage, g_dstImage, -, Size(g_nKernelTrackbarValue, g_nKernelTrackbarValue));
imshow("方框濾波", g_dstImage);
}
程式分析:
1. 關于軌迹條的建立和使用請參考《opencv(九)之Trackbar滑動條建立和使用》
2. kernel尺寸為3、5、7……這樣的奇數,是以根據輸入軌迹條的不同的值需要重新計算kernel的尺寸即:
g_nKernelTrackbarValue = g_nTrackBarValue * 2 + 3;
對于語句中最後參數加3是因為軌迹條預設最小值為0,是以在軌迹條在最小值時也可以形成一個3x3大小的kernel濾波器,如果語句改為:
g_nKernelTrackbarValue = g_nTrackBarValue * 2 + 1;
則當軌迹條位于最小值時,圖像與原圖像一緻,無濾波效果
程式運作結果如下: