1.掩膜(mask)概念
用選定的圖像,圖形或物體,對處理的圖像(全部或局部)進行遮擋,來控制圖像處理的區域或處理過程。用於覆蓋的特定圖像或物體稱為掩模或模板。光學圖像處理中,掩模可以足膠片,濾光片等。掩模是由0和1組成的一個二進制圖像。當在某一功能中應用掩模時,1值區域被處理,被屏蔽的0值區域不被包括在計算中。通過指定的數據值,數據范圍,有限或無限值,感興趣區和注釋文件來定義圖像掩模,也可以應用上述選項的任意組合作為輸入來建立掩模。
2.掩膜的作用
數字圖像處理中,掩模為二維矩陣數組,有時也用多值圖像數字圖像處理中,圖像掩模主要用於:
- 提取感興趣區,用預先制作的感興趣區掩模與待處理圖像相乘,得到感興趣區圖像,感興趣區內圖像值保持不變,而區外圖像值都為0。
- 屏蔽作用,用掩模對圖像上某些區域作屏蔽,使其不參加處理或不參加處理參數的計算,或僅對屏蔽區作處理或統計。
- 結構特征提取,用相似性變量或圖像匹配方法檢測和提取圖像中與掩模相似的結構特征。
- 特殊形狀圖像的制作
- 掩膜是一種圖像濾鏡的模板,實用掩膜經常處理的是遙感圖像。當提取道路或者河流,或者房屋時,通過一個N * N的矩陣來對圖像進行像素過濾,然后將我們需要的地物或者標志突出顯示出來。這個矩陣就是一種掩膜。
-
在OpenCV的中,掩模操作是相對簡單的。大致的意思是,通過一個掩模矩陣,重新計算圖像中的每一個像素值。掩模矩陣控制了舊圖像當前位置以及周圍位置像素對新圖像當前位置像素值的影響力度。用數學術語講,即我們自定義一個權重表
3.通過掩膜操作實現圖像對比圖的改變
矩陣的掩膜操作十分簡單,根據掩膜來重新計算每個像素的像素值,掩膜(mask)也被稱為內核。
通過掩膜操作實現圖像對比度提高,公式如下
Mat kern = (Mat_<char>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
紅色是中心像素,從上到下,從左到右對每個像素做同樣的處理操作,得到最終結果就是對比度提高之后的輸出圖像墊對象。
4.像素范圍處理saturate_cast <typename _Tp>()
- saturate_cast <UCHAR>( - 100),返回0
- saturate_cast <UCHAR>(288),返回255
- saturate_cast <UCHAR>(100),返回100
這個函數的功能是確保RGB值范圍在0〜255之間。
5.自定義使用掩膜操作實現圖像對比度的提高
(1)獲取對象像素指針
------CV_Assert(myImage.depth())
------Mat.ptr<uchar>(int i=0)獲取像素矩陣的指針,索引i表示第幾行,從0行開始計數
------獲得當前行指針const uchar * current= myImage.ptr<uchar>(row);
------獲取當前像素點P(row,col)的像素值p(row,col)=current[col]
上源代碼:
using namespace std; using namespace cv; int main(int argc, char **argv) { Mat src = imread("E:\\vsprom\\learn02\\nv1.jpg"); if (src.empty()) { cout << "can not load imagefile...." << endl; return -1; } namedWindow("in image win", CV_WINDOW_AUTOSIZE); imshow("in image win", src); Mat dst; dst = Mat::zeros(src.size(), src.type());//用原圖像的尺寸和類型初始化目標圖像並將所有像素值清零 int cols = src.cols * src.channels();//圖像矩陣的寬度(列數)=原圖像列數*圖像的通道數,因為掩膜矩陣要在圖像矩陣內,所以計算時要給列和行減1 int rows = src.rows;//圖像的高度(行數) int offsetx = src.channels();//掩膜計算偏移量等於圖像通道數 for (int row = 1; row < (rows - 1); row++)//從第二行開始到倒數第二行結束 { const uchar* previous = src.ptr<uchar>(row - 1);//上一行 const uchar* current = src.ptr<uchar>(row);//獲取row行的像素指針 const uchar* next = src.ptr<uchar>(row + 1);//下一行 uchar* outcurrent = dst.ptr<uchar>(row);//輸出圖像的當前行像素指針 for (int col = offsetx; col < (cols - offsetx); col++)//從第二列(按通道偏移計算)到倒數第二列 { outcurrent[col] = saturate_cast<uchar>( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));//分別對應中間,左右,右邊,上面,下面;使用掩膜修改輸出圖像每一點的像素值,然后saturate_cast限制像素范圍為0-255 } } //將修改完的輸出圖像在窗口展示出來 namedWindow("out win", CV_WINDOW_AUTOSIZE); imshow("out win", dst); waitKey(0); return 0; }
效果圖:第一張為原圖,第二張位對比度提高后的圖
6.使用opencv 的API實現圖像掩膜
1.定義一個3*3的掩膜如下
Mat kernal = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
2.使用opencv函數進行掩膜操作
filter2D(src, dst, src.depth(), kernal);
源代碼如下:
#include<opencv2\opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main(int argc, char **argv) { Mat src = imread("E:\\vsprom\\learn02\\nv1.jpg"); if (src.empty()) { cout << "can not load imagefile...." << endl; return -1; } namedWindow("in image win", CV_WINDOW_AUTOSIZE); imshow("in image win", src); Mat dst; //dst = Mat::zeros(src.size(), src.type());//用原圖像的尺寸和類型初始化目標圖像並將所有像素值清零 //int cols = src.cols * src.channels();//圖像矩陣的寬度(列數)=原圖像列數*圖像的通道數,因為掩膜矩陣要在圖像矩陣內,所以計算時要給列和行減1 //int rows = src.rows;//圖像的高度(行數) //int offsetx = src.channels();//掩膜計算偏移量等於圖像通道數 //for (int row = 1; row < (rows - 1); row++)//從第二行開始到倒數第二行結束 //{ // const uchar* previous = src.ptr<uchar>(row - 1);//上一行 // const uchar* current = src.ptr<uchar>(row);//獲取row行的像素指針 // const uchar* next = src.ptr<uchar>(row + 1);//下一行 // uchar* outcurrent = dst.ptr<uchar>(row);//輸出圖像的當前行像素指針 // for (int col = offsetx; col < (cols - offsetx); col++)//從第二列(按通道偏移計算)到倒數第二列 // { // outcurrent[col] = saturate_cast<uchar>( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));//分別對應中間,左右,右邊,上面,下面;使用掩膜修改輸出圖像每一點的像素值,然后saturate_cast限制像素范圍為0-255 // } //} //創建掩膜 3*3 Mat kernal = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); //掩膜操作 filter2D(src, dst, src.depth(), kernal); //將修改完的輸出圖像在窗口展示出來 namedWindow("dst win", CV_WINDOW_AUTOSIZE); imshow("dst win", dst); waitKey(0); return 0; }
處理結果如下圖: