圖像濾波分爲空域濾波和頻域濾波兩個,這篇隨筆主要針對空域濾波。c++
固然空域與頻域之間是有必定關係的,好比均值濾波器,就是一種低通濾波,而像邊緣檢測,空域中通常使用的是拉普拉斯算子,其也是一種高通濾波。函數
你們都知道空域中的拉普拉斯算子是這樣子的:spa
0 | -1 | 0 |
-1 | 4 | -1 |
0 | -1 | 0 |
這個表示的是縱橫兩個方向的二階導,將這個算子應在圖像上能夠獲得圖像的邊緣痕跡,若是把邊緣再疊加到圖像上,則能夠是邊緣更加明顯,這個操做叫作銳化處理,銳化處理的算子能夠表示爲:指針
0 | -1 | 0 |
-1 | 5 | -1 |
0 | -1 | 0 |
以前咱們知道使用指針來操做像素,格式爲:code
數據類型* 指針名稱 = 矩陣名稱.ptr<數據類型>(行數);blog
使用算子時通常咱們要同時處理3行以上,咱們只須要同時創建這些指針便可。圖片
在這個操做中,咱們保存原來的圖像,所以咱們創建的指針類型爲const,同時咱們新加載一幅圖像,創建普通指針來操做:it
void sharpen(cv::Mat image,cv::Mat sharpen_image) { int num_channels = image.channels(); for (int r = 1; r < image.rows - 1; r++) { const uchar* last_r = image.ptr<const uchar>(r - 1); const uchar* curr_r = image.ptr<const uchar>(r); const uchar* next_r = image.ptr<const uchar>(r + 1); uchar* output = sharpen_image.ptr<uchar>(r); for (int c = num_channels; c < (image.cols - 1)*num_channels; c++) { output[c] =cv::saturate_cast<uchar> (5 * curr_r[c]-last_r[c] - curr_r[c - 1] - curr_r[c + 1] - next_r[c]) ; } } sharpen_image.row(0).setTo(cv::Scalar(0, 0, 0)); sharpen_image.row(sharpen_image.rows-1).setTo(cv::Scalar(0, 0, 0)); sharpen_image.col(0).setTo(cv::Scalar(0, 0, 0)); sharpen_image.col(sharpen_image.cols - 1).setTo(cv::Scalar(0, 0, 0)); }
這裏我使用了uchar型,好處是能夠處理各類類型的圖像,如果灰度圖像,下面4行的cv::Scalar(0,0,0)須要變成cv::Scalar(0);若只處理RGB圖像,也可使用cv::Vec3b型:圖像處理
void sharpenRGB(cv::Mat image, cv::Mat sharpen_image) { int num_channels = image.channels(); for (int r = 1; r < image.rows - 1; r++) { const cv::Vec3b* last_r = image.ptr<cv::Vec3b>(r - 1); const cv::Vec3b* curr_r = image.ptr<cv::Vec3b>(r); const cv::Vec3b* next_r = image.ptr<cv::Vec3b>(r + 1); cv::Vec3b* output = sharpen_image.ptr<cv::Vec3b>(r); for (int c = 1; c < image.cols - 1; c++) { for (int i = 0; i < 3;i++) output[c] = cv::saturate_cast<uchar> (5 * curr_r[c][i] - last_r[c][i] - curr_r[c - 1][i] - curr_r[c + 1][i] - next_r[c][i]); } } sharpen_image.row(0).setTo(cv::Scalar(0, 0, 0)); sharpen_image.row(sharpen_image.rows - 1).setTo(cv::Scalar(0, 0, 0)); sharpen_image.col(0).setTo(cv::Scalar(0, 0, 0)); sharpen_image.col(sharpen_image.cols - 1).setTo(cv::Scalar(0, 0, 0)); }
圖像處理結果以下:table
顏色對比度鮮明er。
固然這個程序是純手動擋的,OpenCV提供給了咱們一些縣城的函數,讓咱們直接能夠基於算子進行運算:
cv::filter2D(輸入圖像名稱,輸出圖像名稱,輸入圖像名稱.depth(),kernel);
kernel指代內核,即算子模型,其定義方法爲:
cv::Mat kernel(3(尺寸),3(尺寸),CV_32F(浮點數),cv::Scalar(0)(全部元素初始化爲0);
kernel.at<float>(1,1)=5.0;
kernel.at<float>(0,1)=-1.0;
kernel.at<float>(1,0)=-1.0;
kernel.at<float>(2,1)=-1.0;
kernel.at<float>(1,2)=-1.0;
這樣能夠提升效率,並易於改變算子進行新的運算。
均值濾波器在OpenCV中用blur(模糊)定義,函數爲:
cv::blur(輸入圖片名稱,輸出圖片名稱,cv::Size(5(尺寸),5(尺寸)));
int _tmain(int argc, _TCHAR* argv[]) { cv::Mat image; cv::Mat result; image = cv::imread("D://OpenCV//yedanshu.jpg"); cv::namedWindow("Original"); cv::blur(image, result, cv::Size(5, 5)); cv::namedWindow("Filtered"); cv::imshow("Original", image); cv::imshow("Filtered", result); cv::waitKey(0); return 0; }
這是爲了讓臨近的像素具備更高的權值,因此在清晰度上相比於通常均值濾波有很大突破,實現代碼爲:
cv::GaussianBlur(image, result, cv::Size(5, 5),1.5); //1.5表明方差
對於椒鹽噪聲來講,最好的處理辦法便是中值濾波,中值濾波在OpenCV中也有直接的辦法:
cv::medianBlur(輸入圖片名稱,輸出圖片名稱,int 濾波器尺寸);