熱線電話:0755-23712116
郵箱:contact@shuangyi-tech.com
地址:深圳市寶安區(qū)沙井街道后亭茅洲山工業(yè)園工業(yè)大廈全至科技創(chuàng)新園科創(chuàng)大廈2層2A
總結(jié)學(xué)習(xí)下圖像處理方面基礎(chǔ)知識。
這是第一篇,簡單的介紹下使用OpenCV的三個基本功能:
然后概述下圖像噪聲的類型,并為圖像添加兩種常見的噪聲:高斯噪聲和椒鹽噪聲。
最后,使用中值濾波和均值濾波來處理帶有噪聲的圖像。
在OpenCV中,完成圖像的輸入輸出以及顯示,只需要以下幾個函數(shù):
namedWindow
創(chuàng)建一個可以通過其名字引用的窗口。第一個參數(shù),設(shè)置窗口的name,可以通過name引用該窗口;第二個參數(shù),設(shè)置窗口的大小。有以下幾個選擇:
imshow
顯示圖像
imread
讀取圖像數(shù)據(jù)到Mat
中,第一個參數(shù)是圖像的文件名;第二個參數(shù)是標(biāo)志,標(biāo)識怎么處理圖像的色彩。常用的幾個選項:
Mat
是OpenCV中最重要的數(shù)據(jù)結(jié)構(gòu),在做圖像處理時基本都是對該結(jié)構(gòu)體的操作。Mat
由兩部分構(gòu)成:矩陣頭和矩陣數(shù)據(jù),矩陣頭較小,創(chuàng)建的每個Mat
實(shí)例都擁有一個矩陣頭,而矩陣數(shù)據(jù)通常占有較大的空間,OpenCV中通過引用計數(shù)來管理這部分內(nèi)存空間,當(dāng)調(diào)用賦值運(yùn)算符和拷貝構(gòu)造函數(shù)時,并不會只復(fù)制矩陣頭,并不會復(fù)制矩陣數(shù)據(jù),只是將其的引用計數(shù)加1.例如:
Mat m = imread("img.jpg");
Mat a = m; // 賦值運(yùn)算符
Mat b(m); // 拷貝構(gòu)造函數(shù)
上面代碼中的a
,b
和m
各自擁有自己的矩陣頭,其引用的數(shù)據(jù)卻指向同一份。也就是說,修改了其中任意一個,都會影響到其余的兩個。
要想復(fù)制矩陣數(shù)據(jù),可以調(diào)用clone
和copyTo
這兩個函數(shù)
Mat m = imread("img.jpg");
Mat f = m.clone();
Mat g ;
m.copyTo(g);
將圖像讀入到Mat
后,有三種方式訪問Mat
中的數(shù)據(jù):
圖像噪聲是圖像在獲取或傳輸?shù)倪^程中受到隨機(jī)信號的干擾,在圖像上出現(xiàn)的一些隨機(jī)的、離散的、孤立的像素點(diǎn),這些點(diǎn)會干擾人眼對圖像信息的分析。圖像的噪聲通常是比較復(fù)雜的,很多時候?qū)⑵淇闯墒嵌嗑S隨機(jī)過程,因而可以借助于隨即過程描述噪聲,即使用概率分布函數(shù)和概率密度函數(shù)。
圖像的噪聲很多,性質(zhì)也千差萬別, 可以通過不同的方法給噪聲分類。
按照產(chǎn)生的原因:
噪聲和圖像信號的關(guān)系,可以分為:
最重要的來了,按照概率密度函數(shù)(PDF)分類:
按照指定的噪聲類型,生成一個隨機(jī)數(shù),然后將這個隨機(jī)數(shù)加到源像素值上,并將得到的值所放到[0,255]區(qū)間即可。
新的隨機(jī)數(shù)生成器被抽象成了兩個部分:隨機(jī)數(shù)生成引擎和要生成的隨機(jī)數(shù)符合的分布。
隨機(jī)數(shù)引擎有三種:
第一種最常用,而且速度比較快;第二種號稱最好的偽隨機(jī)數(shù)生成器
#include
std::random_device rd; // 隨機(jī)數(shù)種子
std::mt19937 mt(rd()); // 隨機(jī)數(shù)引擎
std::normal_distribution<> d(5,20); // 高斯分布
std::map<int,int> hist;
for(int n = 0; n < 10000; n ++)
++hist[std::round(d(mt))]; // 生成符合高斯分布的隨機(jī)數(shù)
使用C++的隨機(jī)數(shù)發(fā)生器為圖像添加兩種噪聲:椒鹽噪聲和高斯噪聲。
椒鹽噪聲是圖像中離散分布的白點(diǎn)或者黑點(diǎn),其代碼如下:
// 添加椒鹽噪聲
void addSaltNoise(Mat &m, int num)
{
// 隨機(jī)數(shù)產(chǎn)生器
std::random_device rd; //種子
std::mt19937 gen(rd()); // 隨機(jī)數(shù)引擎
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(row);
p[col++] = 255;
p[col++] = 255;
p[col] = 255;
}
}
上述代碼中使用ptr
獲取圖像某一行的行首指針,得到行首指針后就可以任意的訪問改行的像素值。
高斯噪聲是一種加性噪聲,為圖像添加高斯噪聲的代碼如下:
// 添加Gussia噪聲
// 使用指針訪問
void addGaussianNoise(Mat &m, int mu, int sigma)
{
// 產(chǎn)生高斯分布隨機(jī)數(shù)發(fā)生器
std::random_device rd;
std::mt19937 gen(rd());
std::normal_distribution<> d(mu, sigma);
auto rows = m.rows; // 行數(shù)
auto cols = m.cols * m.channels(); // 列數(shù)
for (int i = 0; i < rows; i++)
{
auto p = m.ptr(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;
}
}
}
隨機(jī)產(chǎn)生符合高斯分布的隨機(jī)數(shù),然后將該值和圖像原有的像素值相加,并將得到的和壓縮到[0,255]區(qū)間內(nèi)。
左邊是原圖,中間的是添加高斯噪聲后的圖像,最右邊的是添加椒鹽噪聲后的圖像。
根據(jù)噪聲類型的不同,選擇不同的濾波器過濾掉噪聲。通常,對于椒鹽噪聲,選擇中值濾波器(Median Filter),在去掉噪聲的同時,不會模糊圖像;對于高斯噪聲,選擇均值濾波器(Mean Filter),能夠去掉噪聲,但會對圖像造成一定的模糊。
在OpenCV中,對應(yīng)于均值濾波器的函數(shù)是blur
,該函數(shù)需要5個參數(shù),通常只設(shè)置前3個后兩個使用默認(rèn)值即可。blur(m, m2, Size(5, 5));
第一個參數(shù)是輸入的圖像,第二個參數(shù)是輸出的圖像,第三個參數(shù)是濾波器的大小,這里使用的是的矩形。
對應(yīng)于中值濾波器的函數(shù)是medianBlur(m1, m3, 5);
前兩個參數(shù)是輸入輸出的圖像,第三個參數(shù)是濾波器的大小,由于是選取的是中值,濾波器的大小通常是一個奇數(shù)。
下圖是對有噪聲圖像使用濾波器后的結(jié)果,中間的是原始圖像,左邊的是使用均值濾波器過濾高斯噪聲后的結(jié)果;右邊的是使用中值濾波器過濾椒鹽噪聲后的結(jié)果??梢悦黠@的看出,這兩種濾波器都能夠很好的去掉圖像的噪聲,但會對圖像造成一定的模糊,尤其是均值濾波器造成的模糊比較明顯。
本文算是第一篇文章,簡單的介紹下OpenCV的基本使用;接著訪問圖像中的像素,并借助于C++11的隨機(jī)數(shù)庫,為圖像添加高斯噪聲和椒鹽噪聲;最后使用中值濾波器和均值濾波器除去圖像,并對結(jié)果進(jìn)行了對比。
以后堅持每日對圖像處理的一些知識進(jìn)行整理。