矩陣掩膜(Mask,也被稱為kernel):
用於選定圖像、圖形或物體,對處理圖像(全部或局部)進行遮擋,來控制圖像處理區域或處理過程。用於覆蓋的特定圖像或者物體稱為掩膜或模板。管血圖像處理中可以做膠片、濾光片等
數字圖像處理中,掩膜為二維矩陣數組,有時也用多值圖像。數字圖像處理中,圖像掩模主要用於:
- 提取感興趣,用預先制作的感興趣去掩膜與待處理圖像相乘,得到感興趣區圖像,感興趣區圖內圖像數值保持不變,而區外圖像值都為0.
- 屏蔽作用,用掩膜對圖像還是那個某些區域作屏障,使其不參與處理或不參加處理參數計算,或僅對屏蔽區域做處理或同級。
- 結構特征提取,用相似性變量或圖像匹配方法檢測或提取圖像中與掩膜相似的結構特征。
- 特殊圖像的制作。
- 提高對比度。
用途:掩膜是一種圖像濾鏡的模板,實用掩膜經常處理的是遙感圖像。當提取道路或者河流或者房屋時,通過一個n*n的矩陣來對圖像進行像素過濾,然后將我們需要的地物或者標志突出顯示出來。這個矩陣就是一種掩膜。
在OpenCV中,掩模操作是相對簡單的。大致的意思是,通過一個掩模矩陣,重新計算圖像中的每一個像素值。掩模矩陣控制了舊圖像當前位置以及周圍位置像素對新圖像當前位置像素值的影響力度。用數學術語講,即我們自定義一個權重表。
代碼:
1 int cols = (src.cols - 1) * src.channels(); 2 3 int offsetx = src.channels(); 4 5 int rows = src.rows; //圖像的行數 6 7 dst = Mat::zeros(src.size(), src.type()); //輸出容器 8 9 for(int row = 1; row < (rows - 1); row++) 10 11 { 12 13 const uchar* previous = src.ptr<uchar>(row - 1); 14 15 const uchar* current = src.ptr<uchar>(row); 16 17 const uchar* next = src.ptr<uchar>(row + 1); 18 19 uchar* output = dst.ptr<uchar>(row); 20 21 for (int col = offsetx; col < cols; col++) 22 23 { 24 25 output[col] = saturate_cast<uchar>( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); 26 27 } 28 29 }
獲取圖像的像素指針:
Mat數據類型指針(Mat::ptr):
格式:
1 C++: uchar* Mat::ptr(int i=0) 2 3 4 5 C++: const uchar* Mat::ptr(int i=0) const 6 7 8 9 C++: template<typename _Tp> _Tp* Mat::ptr(inti=0) 10 11 12 13 C++: template<typename _Tp> const _Tp*Mat::ptr(int i=0) const
作用:表示返回指定矩陣行的指針,其中i表示基於0的索引。
常見用法:
例一:
1 cv::Mat image = cv::Mat(400, 600, CV_8UC3); //寬400,長600,3通道彩色圖片 2 3 Vec3b* data00 = image.ptr<cv::Vec3b>(0); //data00是指向image第一行第一個元素指針 4 5 Vec3b* data10 = image.ptr<cv::Vec3b>(1); //data10是指向image第二行第一個元素指針 6 7 Vec3b* data01 = image.ptr<cv::Vec3b>(0, 1); //data01是指向image第一行第二個元素指針 8 9 data01->val[0] = 0; //修改data01即第一行第二個元素第一通道值為0 10 11 data01->val[1] = 0; //修改data01即第一行第二個元素第二通道值為0 12 13 data01->val[2] = 255; //修改data01即第一行第二個元素第三通道值為255
結果:
例二:
1 Mat.ptr<uchar>(i,j)//代表第i行,第j個點的值(j的大小包含通道數),這是一個地址 2 3 i = Mat.rols(); 4 5 j = Mat.cols()*Mat.channels(); 6 7 ucahr//代表這個容器存儲的類型,和C++的Vector<int> test;一樣的 8 9 10 11 Mat.ptr<uchar>(i) //獲取像素矩陣的指針,索引i表示第幾行,從0開始計行數。這是一個指針 12 13 const uchar* current= myImage.ptr<uchar>(row);//獲得當前行指針 14 15 p(row,col) = current[col]//獲取當前像素點P(row, col)的像素值 這是一個值
像素范圍處理:saturate_cast<uchar>(data);
功能:確保RGB值的范圍在0~255之間。
1 saturate_cast<uchar>(-100); //返回值為0 2 3 saturate_cast<uchar>(288); //返回值為255 4 5 saturate_cast<uchar>(100); //返回值為100
矩陣掩膜函數:filter2D()函數
格式:
1 void filter2D( InputArray src, 2 OutputArray dst, 3 int ddepth, 4 InputArray kernel, 5 Point anchor = Point(-1,-1), 6 double delta = 0, 7 int borderType = BORDER_DEFAULT );
參數:
參數 |
描述 |
||||||||||||||||
InputArray 類型的 src |
原圖像 |
||||||||||||||||
OutputArray 類型的 dst |
目標圖像與原圖尺寸和通道數相同 |
||||||||||||||||
Int 類型的 ddepth |
目標圖像的深度 |
||||||||||||||||
InputArray 類型的 kernel |
卷積核(或相關核),單通道浮點矩陣;如果將不同的內核應用於不同的通道,請使用拆分將圖像拆分為單獨的顏色平面,然后進行處理 |
||||||||||||||||
Point 類型的 ancho |
內核的錨點,指示內核中過濾點的相對位置;錨應位於內核中;默認值(-1,-1)表示錨位於內核中心 |
||||||||||||||||
double 類型的 delta |
在將它們存儲在dst中之前,將可選值添加到已過濾的像素中。類似於偏置 |
||||||||||||||||
int 類型的 borderType |
表示邊緣類型;像素外推法(一般不管它) 邊緣處理類型:
|
代碼
1 Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, 2 3 -1, 5, -1, 4 5 0, -1, 0);//定義掩膜(銳化算子) 6 7 filter2D(src, dst, src.depth(), kernel);
獲取當前CPU時間:getTickCount()函數
1 double t = getTickCount(); //獲取當前CPU時間,返回毫秒數 2 3 Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, 4 5 -1, 5, -1, 6 7 0, -1, 0);//定義掩膜(銳化算子) 8 9 filter2D(src, dst, src.depth(), kernel); 10 11 double timeconsume = (getTickCount() - t) / getTickFrequency(); //時間差轉換為s 12 13 printf("time consume %.2f\n", timeconsume);
完整代碼:

1 #include<opencv2/opencv.hpp> 2 3 #include<iostream> 4 5 #include<math.h> 6 7 8 9 using namespace cv; 10 11 using namespace std; 12 13 14 15 int main(int argc, char** argv) 16 17 { 18 19 Mat src, dst; 20 21 src = imread("./Picture/1.jpg"); 22 23 if (!src.data) 24 25 { 26 27 printf("cloud not load image"); 28 29 return -1; 30 31 } 32 33 namedWindow("input", WINDOW_AUTOSIZE); // WINDOW_AUTOSIZE 會根據圖像大小顯示窗口大小,無法修改窗口的小 34 35 imshow("input", src); 36 37 38 39 int cols = (src.cols - 1) * src.channels(); //圖像的列數 40 41 int offsetx = src.channels(); //返回圖像src的通道數目 42 43 int rows = src.rows; //圖像的行數 44 45 dst = Mat::zeros(src.size(), src.type()); //創建與src大小、類型相同的零數組作為輸出容器 46 47 for(int row = 1; row < (rows - 1); row++) 48 49 { 50 51 const uchar* previous = src.ptr<uchar>(row - 1);//previous指向src的前一行(row-1)第一個元素的指針 52 53 const uchar* current = src.ptr<uchar>(row); //當前行 54 55 const uchar* next = src.ptr<uchar>(row + 1);//后一行 56 57 uchar* output = dst.ptr<uchar>(row); 58 59 for (int col = offsetx; col < cols; col++) 60 61 { 62 63 /* 64 65 其中 saturate_cast<uchar>(data) 的功能是確保data的值在0-255之間 66 67 1 saturate_cast<uchar>(-100); //返回值為0 68 69 2 saturate_cast<uchar>(288); //返回值為255 70 71 3 saturate_cast<uchar>(100); //返回值為100 72 73 */ 74 75 output[col] = saturate_cast<uchar>( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); 76 77 } 78 79 } 80 81 82 83 84 85 //double t = getTickCount(); //獲取當前CPU時間 86 87 //Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, 88 89 // -1, 5, -1, 90 91 // 0, -1, 0);//定義掩膜(銳化算子) 92 93 //filter2D(src, dst, src.depth(), kernel); 94 95 //double timeconsume = (getTickCount() - t) / getTickFrequency(); //時間差 96 97 //printf("time consume %.2f\n", timeconsume); 98 99 100 101 102 103 namedWindow("contrast image demo", WINDOW_AUTOSIZE); //WINDOW_NORMAL 可以利用鼠標改變圖像大小顯示窗口大小 104 105 imshow("contrast image demo", dst); 106 107 108 109 waitKey(0); 110 111 return 0; 112 113 }
運行結果: