Opencv--矩陣掩膜
掩膜定義:
首先我們從物理的角度來看看mask到底是什麼過程。
在半導體制造中,許多晶片工藝步驟採用光刻技術,用於這些步驟的圖形“底片”稱為掩膜(也稱作“掩模”),其作用是:在矽片上選定的區域中對一個不透明的圖形模板遮蓋,繼而下面的腐蝕或擴散將隻影響選定的區域以外的區域。
用選定的影象、圖形或物體,對處理的影象(全部或區域性)進行遮擋,來控制影象處理的區域或處理過程。用於覆蓋的特定影象或物體稱為掩模或模板。光學影象處理中,掩模可以足膠片、濾光片等。
掩膜用處
數字影象處理中,掩模為二維矩陣陣列,有時也用多值影象。數字影象處理中,影象掩模主要用於:
- 提取感興趣區,用預先製作的感興趣區掩模與待處理影象相乘,得到感興趣區影象,感興趣區內影象值保持不變,而區外影象值都為0。
- 遮蔽作用,用掩模對影象上某些區域作遮蔽,使其不參加處理或不參加處理引數的計算,或僅對遮蔽區作處理或統計。
- 結構特徵提取,用相似性變數或影象匹配方法檢測和提取影象中與掩模相似的結構特徵。
- 特殊形狀影象的製作。
掩膜是一種影象濾鏡的模板,實用掩膜經常處理的是遙感影象。當提取道路或者河流,或者房屋時,通過一個n*n的矩陣來對影象進行畫素過濾,然後將我們需要的地物或者標誌突出顯示出來。這個矩陣就是一種掩膜。
在OpenCV中,掩模操作是相對簡單的。大致的意思是,通過一個掩模矩陣,重新計算影象中的每一個畫素值。掩模矩陣控制了舊影象當前位置以及周圍位置畫素對新影象當前位置畫素值的影響力度。用數學術語講,即我們自定義一個權重表。
掩膜運算的一個小例項
以圖和掩膜的與運算為例:
原圖中的每個畫素和掩膜中的每個對應畫素進行與運算。比如1 & 1 = 1;1 & 0 = 0;
比如一個3 * 3的影象與3 * 3的掩膜進行運算,得到的結果影象就是:
如果用一句話總結,掩膜就是兩幅影象之間進行的各種位運算操作。
掩膜操作實現影象對比度調整
通過掩膜操作實現影象對比度提高。
I(i,j) = 5*I(i,j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]
紅色是中心畫素,從上到下,從左到右對每個畫素做同樣的處理操作,得到最終結果就是對比度提高之後的輸出影象Mat物件。
filter2D功能
- filter2D 函式的定義如下:
void filter2D(
InputArray src, //處理的原圖,Mat型別變數
OutputArray dst, //處理後的輸出影象,Mat型別變數
int ddepth, //ddepth表示點陣圖深度,有32、24、8等
InputArray kernel,//掩膜模板
Point anchor=Point(-1,-1),
double delta=0,
int borderType=BORDER_DEFAULT
);
測量程式執行時間;
有的時候,想知道要我們的程式一共運行了多長時間,這個很常用,也很簡單,僅僅需要兩個函式即可。
opencv裡使用getTickCount()與getTickFrequency()函式記錄時間;
-
函式解釋:
-
GetTickCount:
它返回從作業系統啟動到當前所經過的毫秒數,常常用來判斷某個方法執行的時間,其函式原型是DWORD GetTickCount(void),返回值以32位的雙字型別DWORD儲存,因此可以儲存的最大值是(2^32-1) ms約為49.71天,因此若系統執行時間超過49.71天時,這個數就會歸0C++版 DWORD k=::GetTickCount(); //獲取毫秒級數目 int se = k/1000; // se為秒 cout<<se<<endl; 庫檔案:kernel32.dll C/C++標頭檔案:winbase.h windows程式設計中可以使用標頭檔案windows.h
-
getTickFrequency()函式:返回CPU的頻率,即每秒cpu的滴答數。
#include <opencv2\opencv.hpp> using namespace cv; using namespace std; int main() { //1 記錄程式開始執行點 timeStart double timeStart = (double)getTickCount(); //2 此部分為需要測試執行時間的程式 int a = 0; while (a < 50000000) { a++; } //3 記錄程式消耗的總時間timeConsume double timeEnd = (double)getTickCount(); double frequency = getTickFrequency(); double timeConsume = (timeEnd - timeStart) / frequency; cout << "執行上面程式共耗時:" << timeConsume << "秒\n" << endl; // 執行上面程式共耗時:0.086982秒 system("pause"); return 0; }
-
掩膜例項:
#include"opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main() {
//1).empty() 判斷檔案讀取是否正確
//2).rows 獲取影象行數(高度)
//3).cols 獲取影象列數(長度)
//4).channels() 獲取影象通道數
//5).depth() 獲取影象位深度
Mat img, dst,dst2;
img = imread("D:/111.jpg", 1);
if (!img.data) {
cerr << "open file error" << endl;
return -1;
}
namedWindow("previous_picture", WINDOW_AUTOSIZE);
imshow("previous_picture", img);
int rows = img.rows;
int offsetX = img.channels(); //影象的通道數
int cols = (img.cols - 1)*img.channels();//獲取影象的列數,一定不要忘記影象的通道數
//返回指定的大小和型別的陣列 建立一個跟img一樣大小 ,型別的影象矩陣
dst = Mat::zeros(img.size(), img.type());
for (int row = 1; row < rows - 1; row++) {
//Mat.ptr<uchar>(int i=0) 獲取畫素矩陣的指標,索引i表示第幾行,從0開始計行數。
//獲得當前行指標const uchar* current= img.ptr<uchar>(row );
//獲取當前畫素點P(row, col)的畫素值 p(row, col) =current[col]
//Mat.ptr<uchar>(row):獲取第row行的影象畫素指標。影象的行數從0開始計數
//獲取點P(row, col)的畫素值:P(row.col) = Mat.ptr<uchar>(row)[col]
//獲取上一行的指標
const uchar* X_previous = img.ptr<uchar>(row - 1);
//獲取當前行的指標
const uchar* X = img.ptr<uchar>(row);
//獲取下一行的指標
const uchar* X_next = img.ptr<uchar>(row + 1);
//獲取待處理圖片的當前行的指標
uchar* output = dst.ptr<uchar>(row);
//開始鎖定對應行的某一列,找到某個確定的元素
for (int col = offsetX; col < cols; col++) {
//對待處理圖片當前行的第col列進行畫素處理
//畫素範圍處理saturate_cast<uchar>
//X[col-offsetx]是當前的畫素點的左邊那個畫素點的位置,因為一個畫素點有三個通道
//X[col+offsetx]是當前的畫素點的右邊那個畫素點的位置,因為一個畫素點有三個通道
//X_previous[col]表示當前畫素點對應的上一行的那個畫素點
//X_next[col]表示當前畫素點對應的下一行的那個畫素點
output[col] = saturate_cast<uchar>(5 * X[col] - (X[col - offsetX] + X[col + offsetX] + X_previous[col] + X_next[col]));
}
}
namedWindow("new_picture1", WINDOW_AUTOSIZE);
imshow("new_picture1", dst);
//opencv提供的方法:
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(img, dst2, img.depth(), kernel);
namedWindow("new_picture2", WINDOW_AUTOSIZE);
imshow("new_picture2", dst2);
waitKey(0);
return 0;
}