日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV常见的优化方法和技巧总结

發布時間:2024/4/15 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV常见的优化方法和技巧总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

OpenCV常見的優化方法和技巧總結

? ? 【尊重原創,轉載請注明出處】http://blog.csdn.net/guyuealian/article/details/78540206


目錄

OpenCV常見的優化方法和技巧總結

?一、OpenCV常見的優化方法總結

1.1 cv::imread()設置reduce模式:

1.2 查表法:LUT,

1.3 像素遍歷

1.4 openCL加速:使用UMat結構代替Mat

1.5 release內存釋放

1.6 多線程加速處理OpenMP

1.7 使用積分圖:integral

二、OpenCV常用技巧總結

釋放Mat圖像內存空間:

Mat多通道合并和分割

釋放圖像通道分割的圖像空間

計算運行時間

關于vector內存釋放的問題:

OpenCV LUT:

opencv多通道的使用?

opencv中Mat與數組之間值傳遞的快速方法

圖像的遍歷的快速方法

圖像遍歷優化和加速的常用方法:

防止圖像Rect區域越界的好方法

獲取OpenCV版本

讀寫XML或者yml文件數據的

Mat矩陣的運算,易錯的問題

Mat和IplImage相互轉換

Mat::data指針講解

OpenCV Mat數據類型及位數總結

Mat矩陣插入新的矩陣

顏色空間縮減的方法

YUV444,YUV422,YUV420解釋


?一、OpenCV常見的優化方法總結

1.1 cv::imread()設置reduce模式:

? cv::imread()設置reduce模式,?讀取縮放的低分辨率小圖,或者直接讀取灰度圖,可以做到自適應,先用EXIF信息讀取圖像的分辨率,當分辨率大于一定閾值,則設置讀取模式為:IMREAD_REDUCED_COLOR_2或者IMREAD_REDUCED_COLOR_4 ,避免內存過大以及編程resieze耗時

1.2 查表法:LUT,

? ? 使用lut的方法法,遠快于每個像素都計算的方法

1.3 像素遍歷

? ? openCV像素遍歷常用的是三種方法:ptr指針,迭代器(iterator)以及動態地址at

? ? 實現方式:?https://blog.csdn.net/keith_bb/article/details/53071133

? ? 使用Mat的ptr指針進行圖像遍歷更加高效,

特別的:一般圖像行與行之間往往存儲是不連續的,但是有些圖像可以是連續的,Mat提供了一個檢測圖像是否連續的函數isContinuous()。當圖像連通時,我們就可以把圖像完全展開,看成是一行進行處理。

動態地址at不適合用于像素遍歷,速度太慢了,比較適合隨機訪問的方式

1.4 openCL加速:使用UMat結構代替Mat

? ? 高性能:OpenCL的相關用法:UMat

? ? 在OpenCV3中,OCL module已經被舍棄。而是使用更易上手的Transparent API來替代 OCL module。因此只需要使用 UMat來替換Mat,而其余的代碼保持不變,即可實現加速.

? ? Mat轉換成UMat可以使用Mat::copyTo(OutputArray dst),也可以使用Mat::getUMat(int access_flags)

#include <chrono> #include <opencv2/opencv.hpp> #define millisecond 1000000 #define DEBUG_PRINT(...) printf( __VA_ARGS__); printf("\n") #define DEBUG_TIME(time_) auto time_ =std::chrono::high_resolution_clock::now() #define RUN_TIME(time_) (double)(time_).count()/millisecond using namespace std;void main() {string image_path = "1.jpg";cv::Mat image1 = cv::imread(image_path);cv::Mat dest1;DEBUG_PRINT("image size:[%d,%d]", image1.cols, image1.rows);//Mat convert to UMat//cv::UMat image2= image1.getUMat(cv::ACCESS_FAST);//ACCESS_READ, ACCESS_WRITE, ACCESS_RW和ACCESS_FASTcv::UMat image2;image1.copyTo(image2);cv::UMat dest2;DEBUG_TIME(T0);cv::blur(image1, dest1, cv::Size(15, 15));DEBUG_TIME(T1);cv::blur(image2, dest2, cv::Size(15, 15));DEBUG_TIME(T2);//UMat convert to Matcv::Mat dest3;dest2.copyTo(dest3);DEBUG_PRINT("CPU:%3.3fms", RUN_TIME(T1 - T0));DEBUG_PRINT("GPU:%3.3fms", RUN_TIME(T2 - T1)); }

image size:[2000,3008]
CPU:18.039ms
GPU:9.623ms?

? ? 說明:圖像越大,計算越復雜時,使用OpenCL加速的效果更明顯,如果使用分辨率小圖,其GPU的計算速度未必比CPU的快!!?

? ?參考資料:?https://blog.csdn.net/amusi1994/article/details/79529870

《OpenCV3.x中UMat對象介紹與使用》https://blog.csdn.net/jia20003/article/details/69802932

1.5 release內存釋放

?

1.6 多線程加速處理OpenMP

舉個例子:并行化for語句

? #pragma omp parallel for [clause[clause…]]for(index = first; qualification; index_expr){…}

????第一句中[]的部分是可選的,由自己的程序并行特點而定。大家先不要把精力放到這里面。后面的文章中會繼續講解的。

編寫規則
????1、index的值必須是整數,一個簡單的for形式:for(int i = start; i < end; i++){…} 。

????2、start和end可以是任意的數值表達式,但是它在并行化的執行過程中值不能改變,也就是說在for并行化執行之前,編譯器必須事先知道你的程序執行多少次,因為編譯器要把這些計算分配到不同的線程中執行。

????3、循環語句只能是單入口但出口的。這里只要你避免使用跳轉語句就行了。具體說就是不能使用goto、break、return。但是可以使用continue,因為它并不會減少循環次數。另外exit語句也是可以用的,因為它的能力太大,他一來,程序就結束了。

openMP參考資料:

https://www.cnblogs.com/ospider/p/5265975.html?

《openMP編程探索1——編程基礎》https://blog.csdn.net/bendanban/article/details/6302857?

《openMP編程探索2——循環并行化》:https://blog.csdn.net/bendanban/article/details/6303100

1.7 使用積分圖:integral

? 積分圖定義為:積分圖中坐P(x,y)的值為其左上角的所有像素之和

如上圖所示,為了求該矩形區域的灰度之和。我們可以用以下公式表示:?

需要注意的是,這里的總和并不包含點A,B,C的像素值。如上圖所示的小像素點,A,B,C所在的像素點不在矩形區域以內。

另外,有的時候不一定只是像素灰度值和,只要符合積分圖這一種計算思想的,均可以用積分圖來簡化計算。?
如果是求矩形區域的像素點平方和,也可以用

二、OpenCV常用技巧總結

釋放Mat圖像內存空間:

Mat image = imread("D:\\OpencvTest\\1.jpg");image.release();

Mat多通道合并和分割

#include <opencv2/opencv.hpp> using namespace std; using namespace cv;/*將多個mat合并為多通道mat */ cv::Mat mergeMultiChannels(cv::Mat A,cv::Mat B) {cv::Mat AB;vector<cv::Mat> ABchannels;ABchannels.push_back(A);ABchannels.push_back(B);cv::merge(ABchannels, AB);return AB; }/*將6通道的mat分割成2個三通道的mat */ void splitMultiChannels(cv::Mat mat,cv::Mat &A,cv::Mat &B) {vector<cv::Mat> channels;cv::split(mat, channels);//分割image1的通vector<cv::Mat> Avec, Bvec;Avec.push_back(channels[0]);Avec.push_back(channels[1]);Avec.push_back(channels[2]);Bvec.push_back(channels[3]);Bvec.push_back(channels[4]);Bvec.push_back(channels[5]);cv::merge(Avec, A);cv::merge(Bvec, B); } void main(){int width = 100;int height = 100;//cv::Mat AB = cv::Mat::zeros(cv::Size(width,height),CV_32FC(6));cv::Mat A1 = cv::Mat::zeros(cv::Size(width, height), CV_32FC3) + cv::Scalar(0.1, 0.2, 0.3);cv::Mat B1 = cv::Mat::zeros(cv::Size(width, height), CV_32FC3) + cv::Scalar(0.4, 0.5, 0.6);cv::Mat AB=mergeMultiChannels(A1, B1);//合并為6通道cv::Mat A2,B2;splitMultiChannels(AB, A2, B2);//分割為三通道return; }

釋放圖像通道分割的圖像空間

std::vector<cv::Mat> layers;split(image, layers);// free memoryfor (auto ii = 0; ii < layers.size(); ii++)layers[ii].release();layers.clear();

計算運行時間

using namespace cv;//設置宏定義 #define TB__(A) int64 A; A = cv::getTickCount() #define TE__(A) cout << #A << " : " << 1.E3 * double(cv::getTickCount() - A)/double(cv::getTickFrequency()) << "ms" << endl// 使用方法: TB__(cpu_cvt); #pragma omp parallel for num_threads(4)for (int k = 0; k < REPEATES; k++)cv::cvtColor(cpu_src, cpu_dst, CV_BGR2Lab); TE__(cpu_cvt);

?

#include <chrono>//run times test... #ifdef __DEBUG__TIME__ON #define LOG_TIME LOGE #define RUN_TIME(time_) (double)(time_).count()/millisecond//設置計算運行時間的宏定義 #define DEBUG_TIME(time_) auto time_ =std::chrono::high_resolution_clock::now() #define DEBUG_TIME_PRINT(time_) printf("run time: %s=%3.3f ms\n", #time_,(double)(time_).count()/millisecond) #else #define DEBUG_TIME(time_) #endif

?

關于vector內存釋放的問題:

? ? 由于vector的內存占用空間只增不減,比如你首先分配了10,000個字節,然后erase掉后面9,999個,留下一個有效元素,但是內存占用仍為10,000個。所有內存空間是在vector析構時候才能被系統回收。empty()用來檢測容器是否為空的,clear()可以清空所有元素。但是即使clear(),vector所占用的內存空間依然如故,無法保證內存的回收。

? ? 如果需要空間動態縮小,可以考慮使用deque。如果是vector類型,可以考慮用swap()來幫助你釋放內存。具體方法如下:
標準模板:

//放在頭文件 template < class T > void ClearVector(vector< T >& vt) {vector<T> vtTemp;vtTemp.swap(vt);//或者直接:vector<T>().swap(vt); };

?????swap()是交換函數,使vector離開其自身的作用域,從而強制釋放vector所占的內存空間,總而言之,釋放vector內存最簡單的方法是vector<Point>().swap(pointVec)。當時如果pointVec是一個類的成員,不能把vector<Point>().swap(pointVec)寫進類的析構函數中,否則會導致double free or corruption (fasttop)的錯誤,原因可能是重復釋放內存。(前面的pointVec.swap(vector<Point> ())用G++編譯沒有通過)
?????如果vector中存放的是指針,那么當vector銷毀時,這些指針指向的對象不會被銷毀,那么內存就不會被釋放。如下面這種情況,vector中的元素時由new操作動態申請出來的對象指針:

#include <vector> using namespace std; vector<void *> v;

? ? 每次new之后調用v.push_back()該指針,在程序退出或者根據需要,用以下代碼進行內存的釋放:

for (vector<void *>::iterator it = v.begin(); it != v.end(); it ++) if (NULL != *it) {delete *it; *it = NULL;} v.clear();

OpenCV LUT:

? ?多用LUT可以大大降低處理時間:比如下面是實現圖像Gamma矯正的函數,其中使用了LUT,這比使用for循環遍歷每個像素值,快很多,特別是圖片很大的時候:

void gammaCorrection(cv::Mat& dst, float fGamma){cv::Mat lut(1, 256, CV_8U);uchar *p = lut.data;for (int i = 0; i < 256; i++){p[i] = cv::saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f);}cv::LUT(dst, lut, dst);}

opencv多通道的使用?

typedef cv::Vec<float, 8> Vec8f;E2 = cv::Mat::zeros(srcImage.rows, srcImage.cols, CV_32FC(8));//背景 E(0)值//Mat bigMat = cv::Mat::zeros(cv::Size(256, 256), CV_8UC(8));//CV_32FC3std::cout << "channel = " << E2.channels() << " \n ";for (int i = 0; i < E2.rows; i++){for (int j = 0; j < E2.cols; j++){for (int c = 0; c < E2.channels(); c++){std::cout << "channel = " << c << " ";std::cout << E2.at<Vec8f>(i, j)[c] << " ;i = " << i << " j= " << j << " c= " << c << "\n";}}}

opencv中Mat與數組之間值傳遞的快速方法

? ? ? ?利用Mat來存儲數據,避免使用數組等操作

cv::Mat mean = (cv::Mat_<float>(2, 1) << 0.4404, 0.3111);cout << "mean=" << mean << endl;float a=mean.at<float>(0, 0);float b = mean.at<float>(0, 0);

? ? ? ?將數組內容傳遞給Mat,示例代碼:

unsigned char cbuf[height][width]; cv::Mat img(height, width, CV_8UC1, (unsigned char*)cbuf);

? ? ? ?將Mat中的內容傳遞給數組,如果Mat中的數據是連續的,那么對于傳遞到一維vector我們可以這樣:

std::vector<uchar> array(mat.rows*mat.cols); if (mat.isContinuous())array = mat.data;

? ? ? ?同樣的,傳遞到一維數組我們可以這樣

unsigned char *array=new unsigned char[mat.rows*mat.cols]; if (mat.isContinuous())array = mat.data;

? ? ? ? 對于二維vector的傳值,我們可以這樣處理

uchar **array = new uchar*[mat.rows]; for (int i=0; i<mat.rows; ++i)array[i] = new uchar[mat.cols];for (int i=0; i<mat.rows; ++i)array[i] = mat.ptr<uchar>(i);

圖像的遍歷的快速方法

? ? ? OpenCV圖像遍歷最高效的方法是指針遍歷方法。因為圖像在OpenCV里的存儲機制問題,行與行之間可能有空白單元(一般是補夠4的倍數或8的倍數,有些地方也稱作“位對齊”,目前我用到的FreeImage和c#中的bitmap中的存儲機制也是這樣的)。這些空白單元對圖像來說是沒有意思的,只是為了在某些架構上能夠更有效率,比如intel MMX可以更有效的處理那種個數是4或8倍數的行。Mat提供了一個檢測圖像是否連續的函數isContinuous()。當圖像連通時,我們就可以把圖像完全展開,看成是一行。因此最高效的遍歷方法如下:

void imageCopy(const Mat& image,Mat& outImage) { int nr=image.rows; int nc=image.cols; outImage.create(image.size(),image.type()); if(image.isContinuous()&&outImage.isContinuous()) { nr=1; nc=nc*image.rows*image.channels(); } for(int i=0;i<nr;i++) { const uchar* inData=image.ptr<uchar>(i); uchar* outData=outImage.ptr<uchar>(i); for(int j=0;j<nc;j++) { *outData++=*inData++; } } }

? ? ?PS:一般經過裁剪的Mat圖像,都不再連續了,如cv::Mat crop_img = src(rect);crop_img 是不連續的Mat圖像,如果想轉為連續的,最簡單的方法,就是將不連續的crop_img?重新clone()一份給新的Mat就是連續的了。關于Mat連續存儲的問題,可見:http://blog.csdn.net/guyuealian/article/details/78614662


圖像遍歷優化和加速的常用方法:

1、加減法比乘除法快,因此應避免使用乘除法

2、不能避免乘除法時,考慮使用“移位運算”

3、像素查表法LUT,遠快于每個像素都計算的方法

4、使用常量,會比使用變量快:如:

//使用變量相乘 int a=100; int b=200; int c=a*b;//使用常量相乘 int c=100*200;

? ?PS:特別是在for循環中,能用常量表示的,就不要用變量表示,所以“多使用宏定義define,準沒錯

?實例代碼:第四種的fast_ergodic4遍歷方法是最快的

#include <opencv2/opencv.hpp> #include <iostream>using namespace std; #define chans 3cv::Mat fast_ergodic4(cv::Mat image) {if (!image.isContinuous()){return image;}int rows = image.rows;int cols = image.cols;/*使用常量會比變量快,因此當圖像通道確定時,請將chans改為數字常量,如1,3,4等*///int chans = image.channels();cv::Mat outImage = cv::Mat::zeros(image.size(), image.type());cols = cols*rows*chans;uchar* inData = image.data;uchar* outData = outImage.data;for (int j = 0; j < cols; j += chans){outData[j] = 10 + inData[j];//BoutData[j + 1] = 10 + inData[j + 1];//GoutData[j + 2] = 10 + inData[j + 2];//R//outData[j + 3] = 10 + inData[j + 3];//A}return outImage; }cv::Mat fast_ergodic3(cv::Mat image) {int rows = image.rows;int cols = image.cols;/*使用常量會比變量快,因此當圖像通道確定時,請將chans改為數字常量,如1,3,4等*///int chans = image.channels();cv::Mat outImage = cv::Mat::zeros(image.size(), image.type());//outImage.create(image.size(), image.type());if (image.isContinuous()){cols = cols*rows;rows = 1;}//else//{// image = image.clone();// rows = 1;// cols = cols*image.rows*chans;//}cols *= chans;for (int i = 0; i < rows; i++){uchar* inData = image.ptr<uchar>(i);uchar* outData = outImage.ptr<uchar>(i);for (int j = 0; j < cols; j += chans){outData[j] = 10 + inData[j];//BoutData[j + 1] = 10 + inData[j + 1];//GoutData[j + 2] = 10 + inData[j + 2];//R//outData[j + 3] = 10 + inData[j + 3];//A}}return outImage; }/*避免乘法*/ cv::Mat fast_ergodic2(cv::Mat image) {int rows = image.rows;int cols = image.cols;/*使用常量會比變量快,因此當圖像通道確定時,請將chans改為數字常量,如1,3,4等*///int chans = image.channels();cv::Mat outImage = cv::Mat::zeros(image.size(), image.type());cols *= chans;for (int i = 0; i < rows; i++){uchar* inData = image.ptr<uchar>(i);uchar* outData = outImage.ptr<uchar>(i);for (int j = 0; j < cols; j += chans){outData[j] = 10 + inData[j];//BoutData[j + 1] = 10 + inData[j + 1];//GoutData[j + 2] = 10 + inData[j + 2];//R//outData[j + 3] = 10 + inData[j + 3];//A}}return outImage; }/*一般的指針遍歷方法*/ cv::Mat fast_ergodic1(cv::Mat image) {int rows = image.rows;int cols = image.cols;/*使用常量會比變量快,因此當圖像通道確定時,請將chans改為數字常量,如1,3,4等*///const int chans = image.channels();cv::Mat outImage = cv::Mat::zeros(image.size(), image.type());for (int i = 0; i < rows; i++){uchar* inData = image.ptr<uchar>(i);uchar* outData = outImage.ptr<uchar>(i);for (int j = 0; j < cols; j++){outData[j * chans] = 10 + inData[j * chans];//BoutData[j * chans + 1] = 10 + inData[j * chans + 1];//GoutData[j * chans + 2] = 10 + inData[j * chans + 2];//R//outData[j * chans + 3] = 10 + inData[j * chans + 3];//A}}return outImage; }int main() {string path = "D:\\imageEnhance\\images\\1.jpg";cv::Mat src = cv::imread(path);printf("image size = w=%d, h=%d\n", src.cols, src.rows);cv::Mat image1 = src.clone();cv::Mat image2 = src.clone();cv::Mat image3 = src.clone();cv::Mat image4 = src.clone();double T0 = static_cast<double>(cv::getTickCount());cv::Mat outImage1 = fast_ergodic1(image1);double T1 = static_cast<double>(cv::getTickCount());cv::Mat outImage2 = fast_ergodic2(image2);double T2 = static_cast<double>(cv::getTickCount());cv::Mat outImage3 = fast_ergodic3(image3);double T3 = static_cast<double>(cv::getTickCount());cv::Mat outImage4 = fast_ergodic4(image4);double T4= static_cast<double>(cv::getTickCount());printf("fast_ergodic1=%3.3fms\n", (T1 - T0) * 1000 / cv::getTickFrequency());printf("fast_ergodic2=%3.3fms\n", (T2 - T1) * 1000 / cv::getTickFrequency());printf("fast_ergodic3=%3.3fms\n", (T3 - T2) * 1000 / cv::getTickFrequency());printf("fast_ergodic4=%3.3fms\n", (T4 - T3) * 1000 / cv::getTickFrequency());//cv::imshow("src", src); cv::waitKey(30);//cv::imshow("outImage1", outImage1);//cv::imshow("outImage2", outImage2);//cv::imshow("outImage3", outImage3);//cv::imshow("outImage4", outImage4);cv::waitKey(0); }

?


防止圖像Rect區域越界的好方法

? ? ?OpenCV的cv::Rect提供了很多實用的方法,可參考:http://blog.csdn.net/da_yuan8421/article/details/60959419:

? ? ?在對圖像進行處理時,經常需要截取圖像中的某一區域進行處理,如果截取的區域越界時,就容易導致圖像崩潰。

//求兩個矩形的交集和并集 rect = rect1 & rect2; rect = rect1 | rect2; //對矩形進行對比,返回布爾變量 rect1 == rect2; rect1 != rect2;

? ?利用兩個Rect的交集,我們可以很輕松的避免圖像裁剪區域越界的情況,如下:

Rect rect; rect.x = -10; rect.y = -10; rect.height = 100000; rect.width = 20000; rect &= Rect(0, 0, src.cols, src.rows);//求交集 cv::Mat crop_img = src(rect);

? ? 上例子,原圖src的大小=200*200,需要裁剪為rect=[-10,-10,10000,20000],為了避免裁剪Rect越界,需要特殊的保護,最簡單的方法就是,加入這句話:rect &= Rect(0, 0, src.cols, src.rows),這個交集的Rect肯定是不會越界。


獲取OpenCV版本

#define CV_VERSION_ID CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)//若你OpenCV的版本是3.2.0,那麼輸出為: cout << CV_VERSION_ID << endl;//320 cout << CVAUX_STR(CV_MAJOR_VERSION) << endl;//3 cout << CVAUX_STR(CV_MINOR_VERSION) << endl;//2 cout << CVAUX_STR(CV_SUBMINOR_VERSION) << endl;//0

讀寫XML或者yml文件數據的

? ?read.xml文本內容:

<?xml version="1.0"?> <opencv_storage> <TrainingData type_id="opencv-matrix"><rows>10</rows><cols>8</cols><dt>f</dt><data>10. 10. 10. 10. 10. 10. 10. 10.11. 11. 11. 11. 11. 11. 11. 11.12. 12. 12. 12. 12. 12. 12. 12.13. 13. 13. 13. 13. 13. 13. 13.14. 14. 14. 14. 14. 14. 14. 14.15. 15. 15. 15. 15. 15. 15. 15.16. 16. 16. 16. 16. 16. 16. 16.17. 17. 17. 17. 17. 17. 17. 17.18. 18. 18. 18. 18. 18. 18. 18.19. 19. 19. 19. 19. 19. 19. 19. </data></TrainingData> <classes type_id="opencv-matrix"><rows>10</rows><cols>1</cols><dt>f</dt><data>0. 1. 2. 3. 4. 5. 6. 7. 8. 9. </data></classes> </opencv_storage>

OpenCV讀寫方法:

//讀xml_test.xml文本的數據 FileStorage fs_read;Mat TrainningData;Mat Classes;string readPath = "D:\\SmartAlbum\\image1\\read.xml";bool bR = fs_read.open(readPath, FileStorage::READ);if (bR){fs_read["TrainingData"] >> TrainningData;fs_read["classes"] >> Classes;cout << TrainningData << endl;cout << Classes << endl;}fs_read.release();//將數據寫到xml_write.xml文本中 (若不存在會自動創建一個空的xml文件)string writePath = "D:\\SmartAlbum\\image1\\write.xml";cv::FileStorage fs_write;bool bW=fs_write.open(writePath, FileStorage::WRITE);if (bW){fs_write << "TrainingData" << TrainningData;fs_write << "classes" << Classes;}fs_write.release();

? ? ?保存Vector數據的方法

#include <vector> #include<algorithm> #include <iostream> #include <string> #include "opencv2/opencv.hpp"using namespace std; using namespace cv;template<typename _Tp> void saveVector(FileStorage &fs, vector<_Tp> v,string nodeName) {fs << nodeName << "["; // 開始時,先輸入"["for (size_t i = 0; i < v.size(); i++){fs << v.at(i);}fs << "]"; }template<typename _Tp> bool readVector(FileStorage &fs, vector<_Tp> &v, string nodeName) {FileNode n = fs[nodeName];if (n.type() != FileNode::SEQ){cout << "err" << endl; return false;}FileNodeIterator it = n.begin(), it_end = n.end();for (; it != it_end; ++it) {v.push_back((_Tp)*it);}return true; }int main() {string savePath = "D:\\SmartAlbum\\image1\\data.xml";vector<string> imageName;imageName.push_back("image1.jpg");imageName.push_back("image2.jpg");imageName.push_back("image3.jpg");vector<int> level;level.push_back(1);level.push_back(2);level.push_back(3);FileStorage fw;string nodeName1 = "imageName";string nodeName2 = "level";//將數據寫到xml_write.xml文本中 (若已存在該文件,則會清空當前文件內容再寫入) if (fw.open(savePath, FileStorage::WRITE)) {saveVector<string>(fw, imageName, nodeName1);saveVector<int>(fw, level, nodeName2);}fw.release();//讀取文件內容vector<string> imageName2;vector<int> level2;string readPath = savePath;FileStorage fr;if (fr.open(readPath, FileStorage::READ)) {readVector<string>(fr, imageName2, nodeName1);readVector<int>(fr, level2, nodeName2);}fr.release();system("pause");return 0; }

若不未知結點名稱,可以直接遍歷文件的結點,訪問元素,如:

cv::FileStorage pfs(fileToRead, cv::FileStorage::READ); cv::FileNode fn = pfs.root(); for (cv::FileNodeIterator fit = fn.begin(); fit != fn.end(); ++fit) {cv::FileNode item = *fit;std::string somekey = item.name();//可以獲得node的名稱std::cout << somekey << std::endl; }

Mat矩陣的運算,易錯的問題

? ? ? ?注意Mat矩陣可以進行加減乘除的基本運算,但一個int型的常數和一個Scalar類型的常數進行運算是有區別的,以“+”為例子(也可以用cv::add()代替)

cv::Mat test = cv::Mat::zeros(cv::Size(100,100), CV_8UC3);cv::Mat test1 = test + 128;//僅第1通道被賦值為128cv::Mat test2 = test + cv::Scalar(128, 128, 128);//三個通道都被賦值為128

Mat和IplImage相互轉換

? ? ?Mat 是OpenCV和C++的接口矩陣類,ImlImage是OpenCV和C語言的接口的結構體,但是C++程序有時候時候還是要用到ImlImage,例如在MFC中的Picture Control顯示圖片。Mat和IplImage相互轉換方法:

//IplImage—>Mat //EXAMPLE: //淺拷貝: IplImage* pBinary=cvLoadImage("c://temp.jpg",0); Mat Img; Img=cvarrToMat(pBinary); //深拷貝只需要再在Mat里創建一個新的Mat對象,然后進行數據的復制,再用上述的函數進行數據頭的復制(淺拷貝): IplImage* pBinary=cvLoadImage("c://temp.jpg", 0); Mat ImgTemp; Img=cvarrToMat(pBinary); Mat Img = ImgTemp.clone(); //Mat—>IplImage //EXAMPLE: //淺拷貝: Mat Img=imread("1.jpg"); IplImage* pBinary = &IplImage(Img); //深拷貝只要再加一次復制數據: IplImage *input = cvCloneImage(pBinary);

? ? ? ?https://blog.csdn.net/lijiayu2015/article/details/52438160


Mat::data指針講解

? ? ? ?http://lib.csdn.net/article/opencv/24030


OpenCV Mat數據類型及位數總結

char ->CV_8SC unsigned char,uchar ->CV_8UC unsigned short int,ushort->CV_16UC short int->CV_16SC int ->CV_32SC float ->CV_32FC double->CV_64FC

float:??4字節,6-7位有效數字 -3.4E-38 到 3.4E38????
double: 8字節,15~16位有效數字 -1.7E-308 到 1.7E308

????在OpenCV里面,許多數據結構為了達到內存使用的最優化,通常都會用它最小上限的空間來分配變量,有的數據結構也會因為圖像文件格式的關系而給予適當的變量,因此需要知道它們聲明的空間大小來配置適當的變量。一 般標準的圖片,為RGB格式它們的大小為8bits格式,范圍為0~255,對一個int空間的類型來說實在是太小,整整浪費了24bits的空間,假設有個640*480的BMP文件空間存儲內存,那整整浪費了640*480*3*(32-8)bits的內存空間,總共浪費了2.6MB!,也就是那 2.6MB內什么東西都沒存儲,如果今天以8bits的格式來存儲則只使用到0.6MB的內存而已(640*480*3*(8)+54 bits),因此,對于文件格式的對應是一件很重要的事。
????在這邊除了要考慮bits的空間大小外,還要考慮使用類型的正負號的問題,一般的圖像文件是不存在負號的,如果今天即使選則正確的空間大小,可是出現的結果卻是負的,那就功虧一簣了。這里除了Float及double類型,char,int,short int都是用二的補數表示法,它們不具正負號bit,而Float,double則是用IEEE 754,在第32bit,64bit上有一個正負號bit.

cvCreateImage()及cvCreateMat()對應

1.Unsigned 8bits(一般的圖像文件格式使用的大小)
IplImage數據結構參數:IPL_DEPTH_8U
CvMat數據結構參數:CV_8UC1,CV_8UC2,CV_8UC3,CV_8UC4

變量類型空間大小范圍其他
uchar8bits0~255(OpenCV缺省變量,同等unsigned char)
unsigned char8bits0~255?

?

2.Signed 8bits
IplImage數據結構參數:IPL_DEPTH_8S
CvMat數據結構參數:CV_8SC1,CV_8SC2,CV_8SC3,CV_8SC4

?

變量類型空間大小范圍其他
char8bits-128~127?

?

3.Unsigned 16bits
IplImage數據結構參數:IPL_DEPTH_16U
CvMat數據結構參數:CV_16UC1,CV_16UC2,CV_16UC3,CV_16UC4
?

變量類型空間大小范圍其他
ushort16bits0~65535(OpenCV缺省變量,同等unsigned short int)
unsigned short int16bits0~65535(unsigned short)

?

4.Signed 16bits
IplImage數據結構參數:IPL_DEPTH_16S
CvMat數據結構參數:CV_16SC1,CV_16SC2,CV_16SC3,CV_16SC4
?

變量類型空間大小范圍其他
short int16bits-32768~32767(short)

?

5.Signed 32bits
IplImage數據結構參數:IPL_DEPTH_32S
CvMat數據結構參數:CV_32SC1,CV_32SC2,CV_32SC3,CV_32SC4
?

變量類型空間大小范圍其他
int32bits-2147483648~2147483647(long)

?

6.Float 32bits

IplImage數據結構參數:IPL_DEPTH_32F
CvMat數據結構參數:CV_32FC1,CV_32FC2,CV_32FC3,CV_32FC4
?

變量類型空間大小范圍其他
float32bits1.18*10-38~3.40*1038?

?

7.Double 64bits

CvMat數據結構參數:CV_64FC1,CV_64FC2,CV_64FC3,CV_64FC4
?

變量類型空間大小范圍其他
double64bits2.23*10-308~1.79*10308?

?

8.Unsigned 1bit

IplImage數據結構參數:IPL_DEPTH_1U

變量類型空間大小范圍其他
bool1bit0~1?

?

其他變量對應

1.Signed 64bits

int64

long long

2.Unsigned 64 bits

uint64

unsigned long long


Mat矩陣插入新的矩陣

enum insertType {Top = 0,Bottom = 1,Left = 2,Right = 3 };/* * cv::Mat src:原始數據矩陣* cv::Mat inMat:被插入的數據矩陣* insertType fea_type:插入類型:Top = 0 //在src矩陣頂部插入矩陣inMatBottom = 1 //在src矩陣低部插入矩陣inMatLeft = 2 //在src矩陣左部插入矩陣inMatRight = 3 //在src矩陣右部插入矩陣inMat*/ cv::Mat insertMat(cv::Mat src, cv::Mat inMat,insertType type) {cv::Mat dest= src.clone();int inNum = 0;if (type== Top){inNum = inMat.rows;cv::copyMakeBorder(dest, dest, inNum, 0, 0, 0, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0, 0));cv::Rect r(0, 0, dest.cols, inNum);inMat.copyTo(dest(r));}else if(type == Bottom){inNum = inMat.rows;cv::copyMakeBorder(dest, dest, 0, inNum,0, 0, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0, 0));cv::Rect r(0, dest.rows - inNum, dest.cols, inNum);inMat.copyTo(dest(r));}else if (type == Left){inNum = inMat.cols;cv::copyMakeBorder(dest, dest, 0, 0, inNum, 0, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0, 0));cv::Rect r(0, 0, inNum, dest.rows);inMat.copyTo(dest(r));}else if (type == Right){inNum = inMat.cols;cv::copyMakeBorder(dest, dest, 0, 0, 0, inNum, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0, 0));cv::Rect r(dest.cols- inNum, 0, inNum, dest.rows);inMat.copyTo(dest(r));}return dest; }

顏色空間縮減的方法

cv::Mat CreatTable(int level) {Mat lookUpTable(1, 256, CV_8UC1);uchar *p = lookUpTable.data;int div = 256 / level;for (size_t i = 0; i < 256; i++){p[i] = (i / div)*div;}return lookUpTable; } static cv::Mat lookUpTable = CreatTable(64);void main() {string p1= "D:\\SmartAlbum\\image1\\B\\B15.jpg";cv::Mat image1 = cv::imread(p1);cv::Mat dest;cv::LUT(image1, lookUpTable2, dest);cv::waitKey(0); }

YUV444,YUV422,YUV420解釋

https://blog.csdn.net/mandagod/article/details/78605586

? ? ?通常我們用RGB表示一種彩色。計算機系統里的LCD顯示的數據就是RGB來表示每個像素的顏色。
而在我們生活里,有黑白電視機與彩色電視機兩種,拍攝節目源時不可以用兩種不同的攝像機來存放兩種圖像數據。
所以為了兼容兩種電視機,專家就引入YUV格式代替RGB,其中Y表示亮度, U和V表示色差。 黑白電視機只用Y信號, 而彩色電視機可由YUV轉換成RGB再顯示顏色。

? ? ?通常我們所用的YUV格式是 ITU-R 的標準 , 也叫YCbCr。YUV是由RGB格式的數據轉換得來。

Y Y = 0.299 x R + 0.587 x G + 0.114 x B + 0 U Cb = -0.169 x R - 0.331 x G + 0.499 x B + 128 V Cr = 0.499 x R - 0.418 x G - 0.0813 x B + 128 Y Y = 0.299 x R + 0.587 x G + 0.114 x B + 0 U Cb = -0.169 x R - 0.331 x G + 0.499 x B + 128 V Cr = 0.499 x R - 0.418 x G - 0.0813 x B + 128

YUV4:4:4?
? ? ?其實就是YUV的數據各占用8位, 每個像素都由YUV組成

  • 同一行的相鄰4個像素數據: Y0U0V0 Y1U1V1 Y2U2V2 Y3U3V3

  • 存儲時: Y0 U0 V0 Y1 U1 V1 Y2 U2 V2 Y3 U3 V3 //即每個像素YUV的數據都會存放起來

  • 為什么叫4:4:4 , 意思就是4個像素里的數據有4個Y, 4個U, 4個V

  • YUV4:2:2
    ? ? ?其實絕大部分相鄰的兩個像素,數據差異應不大。所以為了節點空間便于存儲,丟失每個像素的部分數據。
    ? ? ?專家研究表明我們人對亮度比較敏感,而對色彩不怎么敏感。所以每個像素的亮度Y數據是絕對不動的,而色差數據可以進行丟棄。

  • 同一行的相鄰4個像素數據: Y0U0V0 Y1U1V1 Y2U2V2 Y3U3V3

  • 存儲時: Y0 U0 Y1 V1 Y2 U2 Y3 V3 // 每兩個相鄰的像素, 一個丟棄V數據,一個丟棄U數據

  • 為什么叫4:2:2, 意思就是相鄰的4個像素里有4個Y, 2個U, 2個V。 按上面存儲的順序也叫YUYV.

  • 但還原成RGB數據必須需要YUV, 像第一個像素只有Y0U0是沒法還原的,這時只能用下一像素的V1數據。

  • 還原時的YUV: [Y0U0V1] [Y1U0V1] [Y2U2V3] [Y3U2V3] //這樣還原理論上會對圖像的質量有影響的,但我們看不出來的.

  • YUV4:2:0
    ? ? ?專家們進一步研究表示,每一行的相鄰兩個像素與下一行同位置的兩個像素數據差異不大,可以進一步的丟數據。

  • 如兩行的像素數據:

  • Y00U00V00 Y01U01V01 Y02U02V02 Y03U03V03 ....

  • Y88U88V88 Y89U89V89 Y90U90V90 Y91U91V91 ....

  • ?
  • 存儲時: Y00U00 Y01 Y02U02 Y03 //每個像素的Y數據保留, 兩個像素數據只保留一個U數據。這一行不保留V數據(YUV: 420)

  • Y88V88 Y89 Y90V90 Y91 // .... 兩個像素數據只保留一個V數據, 這行不保留U數據(YUV: 402)

  • ?
  • 還原時只能相同位置的上下兩行4個像素結合還原:

  • Y00U00V88 Y01U00V88 Y02U02V90 Y03U02V90

  • Y88U00V88 Y89U00V88 Y90U02V90 Y91U02V90

  • ? ? ?yuv數據還分成打包的,平面的。
    ? ? ?打包的意思是: yuv數據是順序存放Y,接著U,再接著V數據存放。
    ? ? ?平面的意思是: yuv數據是分成三個地方存放, 一個地方只存Y數據, 一個只存U數據, 一個只存V數據

    總結

    以上是生活随笔為你收集整理的OpenCV常见的优化方法和技巧总结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。