OpenCV圖像處理之矩陣的掩膜操作
3.矩陣的掩膜操作
(接雲岫H:OpenCV3.1.0圖像處理教程(1))
OpenCV中的C++類和函數都是定義在命名空間cv之內的,有兩種方法可以訪問。第一種是,在代碼開頭的適當位置,加上using namespace cv;這句。
另外一種是在使用OpenCV類和函數時,都加入cv::命名空間。不過這種情況難免會不爽,每用一個OpenCV的類或者函數,都要多敲四下鍵盤寫出cv::,很麻煩。
所以,淺墨推崇大家在代碼開頭的適當位置,加上using namespace cv;這句。於是和opencv命名空間一了百了了。
改回來就好了,運行結果如下:
知識補充:掩膜操作提高圖像的對比度。
一個圖像的通道數是N,就表明每個像素點處有N個數,一個a×b的N通道圖像,其圖像矩陣實際上是b行N×a列的數字矩陣。所以要知道圖像矩陣的實際的行列,cols(列數)=圖像的cols*通道數,行數rows是一樣的圖像的rows。
OpenCV中圖像的通道可以是1、2、3和4。其中常見的是1通道和3通道,2通道和4通道不常見。
1通道的是灰度圖。
3通道的是彩色圖像,比如RGB圖像。
4通道的圖像是RGBA,是RGB加上一個A通道,也叫alpha通道,表示透明度。PNG圖像是一種典型的4通道圖像。alpha通道可以賦值0到1,或者0到255,表示透明到不透明。
2通道的圖像是RGB555和RGB565。2通道圖在程序處理中會用到,如傅里葉變換,可能會用到,一個通道為實數,一個通道為虛數,主要是編程方便。RGB555是16位的,2個位元組,5+6+5,第一位元組的前5位是R,後三位+第二位元組是G,第二位元組後5位是B,可見對原圖像進行壓縮了。
框和圖像左上角對齊,圖像矩陣從(0,0)開始記,最左上角是(0,0),所以中心點一開始坐標是(1,1)。所以row是從1開始,到rows-1結束的,同理col應該也是,肯定到不了最後一個,這裡對應的框都是對應圖像像素點的,不是圖像矩陣,所以是提前在cols中先將圖像的cols-1並不是直接在圖像矩陣cols上減一,那麼對應的圖像矩陣的col初始值並非對應圖像cols為1,圖像矩陣的cols是0,沒意義。而是當圖像的cols為2,此時圖像矩陣的cols是通道值。我們就可以把這個特殊值設出來為offsetx。
中間像素點和左邊像素點對應的圖像矩陣列數相差應該是通道數,例如3通道相當於左邊那個大座位可以坐三個人,行數圖像矩陣和圖像像素行數是一樣的。
一般我們是不會在原圖上做修改的,所以用const 來對current進行設定,const是一個C++語言的限定符,它限定一個變數不允許被改變。使用const在一定程度上可以提高程序的安全性和可靠性。在此處是用了它修飾指針的功能,
如果const位於*的左側,則const就是用來修飾指針所指向的變數,即指針指向為常量;
如果const位於*的右側,const就是修飾指針本身,即指針本身是常量。
因此,推薦使用int const* p,而不是使用const int* p(雖然兩者意義完全一樣),這樣更容易理解。(const其他的功能見https://www.cnblogs.com/chogen/p/4574118.html)
由於設定的current設定是const,因為不可以修改,故在原圖像不能輸出。
所以我們設一個和src一樣大的矩陣元素全是零dst且類型一致,利用指針將算出的像素放到dst中來輸出掩膜後的圖。
程序:
#include <opencv2/opencv.hpp>#include <iostream>#include <math.h>using namespace cv;int main(int argc, char** argv ) { Mat src, dst; src = imread("F:/VisualStudio2015/Opencvlearning/test2/test2/timg.jpg"); if (!src.data) { printf("could not load image...
"); return -1; } namedWindow("input image", CV_WINDOW_AUTOSIZE); imshow("input image", src); int cols = (src.cols-1) *src.channels(); int offsetx = src.channels(); int rows = src.rows; dst = Mat::zeros(src.size(), src.type()); for (int row = 1; row < (rows - 1); row++) { const uchar*previous = src.ptr<uchar>(row - 1); const uchar*current = src.ptr<uchar>(row); const uchar*next = src.ptr<uchar>(row + 1); uchar*output=dst.ptr<uchar>(row); for (int col =offsetx ; col < cols; col++) { output[col] = 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]); } } namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE); imshow("contrast image demo", dst); waitKey(0); return 0;}
會發現圖像邊緣很不好,似乎因為像素值放進去被截取了,我們利用函數使所有像素值在0-255之間。uchar表示無符號數取值範圍即0-255。
輸出就是對比度提高後的圖片,效果很好。
程序:
#include <opencv2/opencv.hpp>#include <iostream>#include <math.h>using namespace cv;int main(int argc, char** argv ) { Mat src, dst; src = imread("F:/VisualStudio2015/Opencvlearning/test2/test2/timg.jpg"); if (!src.data) { printf("could not load image...
"); return -1; } namedWindow("input image", CV_WINDOW_AUTOSIZE); imshow("input image", src); int cols = (src.cols-1) *src.channels(); int offsetx = src.channels(); int rows = src.rows; dst = Mat::zeros(src.size(), src.type()); for (int row = 1; row < (rows - 1); row++) { const uchar*previous = src.ptr<uchar>(row - 1); const uchar*current = src.ptr<uchar>(row); const uchar*next = src.ptr<uchar>(row + 1); uchar*output=dst.ptr<uchar>(row); for (int col =offsetx ; col < cols; col++) { output[col] =saturate_cast<uchar>( 5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col])); } } namedWindow("contrast image demo", CV_WINDOW_AUTOSIZE); imshow("contrast image demo", dst); waitKey(0); return 0;}
其實opencv帶有他的API函數可以實現上述功能
結果圖輸出是一樣的。
*其中filter2D中的第三個參數表示輸出的點陣圖深度,例子中填scr.depth()表示和原圖的點陣圖深度一樣,在你不知道是多少時,也可以選擇填-1,就是暗示輸出的點陣圖深度和原圖像相同,兩個都可以,效果一樣。當然你也可以選擇與原圖的點陣圖深度不一樣,只是很容易出錯。故一般就是-1或src.depth(),其中src是原圖代號不同例子不同。
小知識:
getTickcount函數:它返回從操作系統啟動到當前所經的計時周期數。 getTickFrequency函數:返回每秒的計時周期數。
getTickCount用來獲取我們程序的執行時間的,可以知道此處的API程序執行時間用多久。
第一步獲取一開始的執行時間,然後執行了API指令後,用新的執行時間減去一開始的執行時間t,再除以一個當量即getTickFrequency(),就可以表示時間用了多少。再列印出來輸出。程序如下:
可以知道那兩句API的執行用了0.02秒。
推薦閱讀:
※使用OpenCV與Face++實現人臉解鎖
※做增強現實AR,高通sdk與opencv有什麼區別。各有什麼利弊?
※用OpenCV人臉檢測,出現這個錯誤,大神賜教?