OpenCV中常見的與圖像操作有關的數據容器有Mat,cvMat和IplImage。這三種類型都可以代表和顯示圖像,區別是:Mat類型側重於計算,數學性較高,OpenCV對Mat類型的計算進行了優化;CvMat和IplImage類型更側重於“圖像”,opencv對其中的圖像操作(縮放、單通道提取、圖像閾值操作等)進行了優化。在opencv2.0之前,opencv是完全用C實現的,但是,IplImage類型與CvMat類型的關系類似於面向對象中的繼承關系。實際上,CvMat之上還有一個更抽象的基類----CvArr,這在源代碼中會常見。
1. opencv文檔中明確聲明,CvMat已經過時了(CvMat is now obsolete, consider using Mat instead)不建議用;
2. 派生關系:CvArr -> CvMat -> IplImage
3. Mat用的一套東西是imread,imshow等,有別於CvArr及其子類的cvLoadImage(),cvShowImage()...
Mat類型:矩陣類型,Matrix。
在openCV中,Mat是一個多維的密集數據數組。可以用來處理向量和矩陣、圖像、直方圖等等常見的多維數據。
Mat有3個重要的方法:
1、Mat mat = imread(const String* filename); 讀取圖像
2、imshow(const string frameName, InputArray mat); 顯示圖像
3、imwrite (const string& filename, InputArray img); 儲存圖像
Mat類型較CvMat與IplImage類型來說,有更強的矩陣運算能力,支持常見的矩陣運算。在計算密集型的應用當中,將CvMat與IplImage類型轉化為Mat類型將大大減少計算時間花費。
1.像素值的讀取可使用at()函數:
uchar value = grayim.at<uchar>(i,j); //讀出第i行第j列像素值 graym.at<uchar>(i,j) = 128; //將第i行第j列像素值設置為128
2.使用Mat的成員函數ptr<>()
uchar* data = image.ptr<uchar>(j);
3.使用迭代器遍歷圖像
cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>(); for (; it != itend; ++it) { (*it)[0] = (*it)[0] / div*div + div / 2; (*it)[1] = (*it)[1] / div*div + div / 2; (*it)[2] = (*it)[2] / div*div + div / 2; }
4.圖像的載入、顯示和輸出到文件。 imread、imshow、imwrite
5.滑動條的創建和使用。
int createTrackbar(const string& trackbarname,const string& winname,int* value,int count,TrackbarCallback onChange=0,void* userdata=0);
第一個參數::軌跡名稱
第二個參數:窗口名字
第三個參數:一個指向整型的指針,表示滑塊位置。
第四個參數:int類型的count表示滑塊可以達到的最大位置值。
第五個參數:指向回調函數的指針,每次滑塊位置改變時,這個函數都會進行回調,默認值是0。
第六個參數:用戶傳給回調函數的數據,用來處理軌跡條事件。如果第三個參數value實參是全局變量的話,完全可以不用去管userdata參數。
1、Mat類常用的構造方法 Mat();//無參數構造
Mat(int rows, int cols, int type);//創建行數為rows,列數為cols,類型為type的圖像
Mat(Size size, int type);//創建大小為size,類型為type的圖像
Mat(int rows, int cols, int type, const Scalar& s);//創建創建行數為rows,列數為cols,類型為type的圖像,且全部元素(像素)初始化為 s
Mat(Size size, int type, const Scalar& s);//創建大小為size,類型為type的圖像,且全部元素(像素)初始化為 s
Mat(const Mat& m);//將m賦值給新創建的對象,是淺拷貝
#include<iostream> #include<opencv2/core/core.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<opencv2/highgui/highgui.hpp> using namespace std; using namespace cv; int main() { //創建空矩陣 Mat img1; //創建6x6的8位單通道矩陣(圖像) Mat img2(6, 6, CV_8UC1); //創建7x7的8位三通道矩陣(圖像) Mat img3(cv::Size(7, 7), CV_8UC3); //創建8x8的32位三通道矩陣(圖像),並且用cv::Scalar(0,255)填充 Mat img4(8, 8, CV_8UC3,cv::Scalar(0,255)); //創建7x7的8位三通道矩陣(圖像),並且用填充cv::Scalar(1, 2, 3)填充 Mat img5(cv::Size(7, 7), CV_8UC3, cv::Scalar(1,2,3)); Mat img6(img2); cout << img1 << endl; cout << img2 << endl; cout << img3 << endl; cout << img4 << endl; cout << img5 << endl; cout << img6 << endl; return 0; }
6.常用數據結構和函數
1)Point類
Point point; point.x = 10; point.y = 8; Point_<int>、Point2i、Point互相等價;Point_<float>、Point2f互相等價。
2)顏色表示 Scalar類
Scalar(b,g,r);
3)尺寸:Size類
typedef Size_<int> Size2i; typedef Size2i Size; Size_<int>、Size2i、Size三個類等價
4)矩形:Rect類
Rect類的成員變量 x,y,width,height,成員函數Size()返回尺寸,area()返回面積,contains(Ponit)點是否在矩形中,inside(Rect)矩形是否在該矩形內,tl()返回左上角點坐標,br()返回右下角點坐標; Rect rect = rect1 & rect2;求交集 Rect rect = rect1 | rect2;求並集 Rect rectShift = rect + point; Rect rectScale = rect + size;
5)顏色空間轉換:cvtColor()函數
可以實現RGB顏色向HSV、HSI等顏色空間的轉換,也可以轉換成灰度顏色。
cvtColor(srcImage,dstImage,COLOR_GRAY2BGR);
問題: 如果Mat 中想存小數,那么聲明是就要用CV_32FC1等浮點數的類型,並且在訪問像素的時候,指向每一行(i行)的指針: 不再是: uchar *data = src.ptr<uchar>(i); 了 (uchar 是0~255的無符號整數) 而是用:float *data = src.ptr<float>(i)。(以前不懂也沒注意這個,程序一直出錯)。 PS:因為再寫顏色相關圖的程序,需要保存一個掩碼mark 矩陣,其中每個元素存一個【0~1】的權重,用以前的遍歷圖片像素的代碼改的,結果總不對,后來才發現是新創建的矩陣的元素用的 uchar ,是無符號整型,不能存小數的,才恍然大悟,也才有了這篇blog,內容比較簡單,僅供自己學習,也供有需求的人參考。 以下參考自:http://www.cnblogs.com/wangguchangqing/p/4016179.html TYPE表示了矩陣中元素的類型以及矩陣的通道個數,它是一系列的預定義的常量,其命名規則為CV_(位數)+(數據類型)+(通道數)。具體的有以下值 CV_8UC1 CV_8UC2 CV_8UC3 CV_8UC4 CV_8SC1 CV_8SC2 CV_8SC3 CV_8SC4 CV_16UC1 CV_16UC2 CV_16UC3 CV_16UC4 CV_16SC1 CV_16SC2 CV_16SC3 CV_16SC4 CV_32SC1 CV_32SC2 CV_32SC3 CV_32SC4 CV_32FC1 CV_32FC2 CV_32FC3 CV_32FC4 CV_64FC1 CV_64FC2 CV_64FC3 CV_64FC4 這里U(unsigned integer)表示的是無符號整數,S(signed integer)是有符號整數,F(float)是浮點數。 例如:CV_16UC2,表示的是元素類型是一個16位的無符號整數,通道為2. C1,C2,C3,C4則表示通道是1,2,3,4 type一般是在創建Mat對象時設定,如果要取得Mat的元素類型,則無需使用type,使用下面的depth depth 矩陣中元素的一個通道的數據類型,這個值和type是相關的。例如 type為 CV_16SC2,一個2通道的16位的有符號整數。那么,depth則是CV_16S。depth也是一系列的預定義值, 將type的預定義值去掉通道信息就是depth值: CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F elemSize 矩陣一個元素占用的字節數,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes elemSize1 矩陣元素一個通道占用的字節數,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels Mat的常見屬性 data uchar型的指針。Mat類分為了兩個部分:矩陣頭和指向矩陣數據部分的指針,data就是指向矩陣數據的指針。 dims 矩陣的維度,例如5*6矩陣是二維矩陣,則dims=2,三維矩陣dims=3. rows 矩陣的行數 cols 矩陣的列數 size 矩陣的大小,size(cols,rows),如果矩陣的維數大於2,則是size(-1,-1) channels 矩陣元素擁有的通道數,例如常見的彩色圖像,每一個像素由RGB三部分組成,則channels = 3
關於將mat數據存放到xml中
void CapVideoFace()
{
int indexNum = 0; //跳幀數.
VideoCapture capture;
cv::Mat frame;
capture.open("resource/999.mp4");//讀取視頻文件
//capture.open("rtsp://admin:admin123@10.129.74.198:554/cam/realmonitor?channel=1&subtype=1"); //讀取rtsp流
if (!capture.isOpened())
{
LoggerN("capture open failed.");
return;
}
while (capture.read(frame)) {
//cv::Mat frame = imread("resource/2.jpg",1);
if (frame.data != NULL && indexNum++%3 ==0) {
FileStorage fs("xuchao.xml", FileStorage::WRITE);
fs << "vocabulary" << frame; fs.release(); FileStorage fsRead("xuchao.xml", FileStorage::READ); Mat mat_vocabulary; fsRead["vocabulary"] >> mat_vocabulary; fsRead.release();
indexNum == 0;
std::string strPic = Mat2Base64(frame, "jpg");
char* pBuffer = new char[3*1024*1024];
memcpy(pBuffer,strPic.c_str(),strPic.length());
detector[detectorIndex++].Put(pBuffer);
if(detectorIndex == THREADNUM)
detectorIndex = 0;
}
}
}
