總結學習下圖像處理方面基礎知識。算法
這是第一篇,簡單的介紹下使用OpenCV的三個基本功能:數據結構
而後概述下圖像噪聲的類型,併爲圖像添加兩種常見的噪聲:高斯噪聲和椒鹽噪聲。
最後,使用中值濾波和均值濾波來處理帶有噪聲的圖像。dom
在OpenCV中,完成圖像的輸入輸出以及顯示,只須要如下幾個函數:函數
namedWindow
建立一個能夠經過其名字引用的窗口。第一個參數,設置窗口的name,能夠經過name引用該窗口;第二個參數,設置窗口的大小。有如下幾個選擇:學習
imshow
顯示圖像spa
imread
讀取圖像數據到Mat
中,第一個參數是圖像的文件名;第二個參數是標誌,標識怎麼處理圖像的色彩。經常使用的幾個選項:設計
Mat
是OpenCV中最重要的數據結構,在作圖像處理時基本都是對該結構體的操做。Mat
由兩部分構成:矩陣頭和矩陣數據,矩陣頭較小,建立的每一個Mat
實例都擁有一個矩陣頭,而矩陣數據一般佔有較大的空間,OpenCV中經過引用計數來管理這部份內存空間,當調用賦值運算符和拷貝構造函數時,並不會只複製矩陣頭,並不會複製矩陣數據,只是將其的引用計數加1.例如:指針
Mat m = imread("img.jpg"); Mat a = m; // 賦值運算符 Mat b(m); // 拷貝構造函數
上面代碼中的a
,b
和m
各自擁有本身的矩陣頭,其引用的數據卻指向同一份。也就是說,修改了其中任意一個,都會影響到其他的兩個。code
要想複製矩陣數據,能夠調用clone
和copyTo
這兩個函數orm
Mat m = imread("img.jpg"); Mat f = m.clone(); Mat g ; m.copyTo(g);
將圖像讀入到Mat
後,有三種方式訪問Mat
中的數據:
圖像噪聲是圖像在獲取或傳輸的過程當中受到隨機信號的干擾,在圖像上出現的一些隨機的、離散的、孤立的像素點,這些點會干擾人眼對圖像信息的分析。圖像的噪聲一般是比較複雜的,不少時候將其當作是多維隨機過程,於是能夠藉助於隨即過程描述噪聲,即便用機率分佈函數和機率密度函數。
圖像的噪聲不少,性質也千差萬別, 能夠經過不一樣的方法給噪聲分類。
按照產生的緣由:
噪聲和圖像信號的關係,能夠分爲:
最重要的來了,按照機率密度函數(PDF)分類:
按照指定的噪聲類型,生成一個隨機數,而後將這個隨機數加到源像素值上,並將獲得的值所放到[0,255]區間便可。
新的隨機數生成器被抽象成了兩個部分:隨機數生成引擎和要生成的隨機數符合的分佈。
隨機數引擎有三種:
第一種最經常使用,並且速度比較快;第二種號稱最好的僞隨機數生成器
#include <random> std::random_device rd; // 隨機數種子 std::mt19937 mt(rd()); // 隨機數引擎 std::normal_distribution<> d(5,20); // 高斯分佈 std::map<int,int> hist; for(int n = 0; n < 10000; n ++) ++hist[std::round(d(mt))]; // 生成符合高斯分佈的隨機數
使用C++的隨機數發生器爲圖像添加兩種噪聲:椒鹽噪聲和高斯噪聲。
椒鹽噪聲是圖像中離散分佈的白點或者黑點,其代碼以下:
// 添加椒鹽噪聲 void addSaltNoise(Mat &m, int num) { // 隨機數產生器 std::random_device rd; //種子 std::mt19937 gen(rd()); // 隨機數引擎 auto cols = m.cols * m.channels(); for (int i = 0; i < num; i++) { auto row = static_cast<int>(gen() % m.rows); auto col = static_cast<int>(gen() % cols); auto p = m.ptr<uchar>(row); p[col++] = 255; p[col++] = 255; p[col] = 255; } }
上述代碼中使用ptr<uchar>()
獲取圖像某一行的行首指針,獲得行首指針後就能夠任意的訪問改行的像素值。
高斯噪聲是一種加性噪聲,爲圖像添加高斯噪聲的代碼以下:
// 添加Gussia噪聲 // 使用指針訪問 void addGaussianNoise(Mat &m, int mu, int sigma) { // 產生高斯分佈隨機數發生器 std::random_device rd; std::mt19937 gen(rd()); std::normal_distribution<> d(mu, sigma); auto rows = m.rows; // 行數 auto cols = m.cols * m.channels(); // 列數 for (int i = 0; i < rows; i++) { auto p = m.ptr<uchar>(i); // 取得行首指針 for (int j = 0; j < cols; j++) { auto tmp = p[j] + d(gen); tmp = tmp > 255 ? 255 : tmp; tmp = tmp < 0 ? 0 : tmp; p[j] = tmp; } } }
隨機產生符合高斯分佈的隨機數,而後將該值和圖像原有的像素值相加,並將獲得的和壓縮到[0,255]區間內。
左邊是原圖,中間的是添加高斯噪聲後的圖像,最右邊的是添加椒鹽噪聲後的圖像。
根據噪聲類型的不一樣,選擇不一樣的濾波器過濾掉噪聲。一般,對於椒鹽噪聲,選擇中值濾波器(Median Filter),在去掉噪聲的同時,不會模糊圖像;對於高斯噪聲,選擇均值濾波器(Mean Filter),可以去掉噪聲,但會對圖像形成必定的模糊。
在OpenCV中,對應於均值濾波器的函數是blur
,該函數須要5個參數,一般只設置前3個後兩個使用默認值便可。
blur(m, m2, Size(5, 5));
第一個參數是輸入的圖像,第二個參數是輸出的圖像,第三個參數是濾波器的大小,這裏使用的是\(5 \times 5\)的矩形。
對應於中值濾波器的函數是medianBlur(m1, m3, 5);
前兩個參數是輸入輸出的圖像,第三個參數是濾波器的大小,因爲是選取的是中值,濾波器的大小一般是一個奇數。
下圖是對有噪聲圖像使用濾波器後的結果,中間的是原始圖像,左邊的是使用均值濾波器過濾高斯噪聲後的結果;右邊的是使用中值濾波器過濾椒鹽噪聲後的結果。能夠明顯的看出,這兩種濾波器都可以很好的去掉圖像的噪聲,但會對圖像形成必定的模糊,尤爲是均值濾波器形成的模糊比較明顯。
本文算是第一篇文章,簡單的介紹下OpenCV的基本使用;接着訪問圖像中的像素,並藉助於C++11的隨機數庫,爲圖像添加高斯噪聲和椒鹽噪聲;最後使用中值濾波器和均值濾波器除去圖像,並對結果進行了對比。
之後堅持每日對圖像處理的一些知識進行整理。