OpenCV學習筆記(六)——對XML和YAML檔案實現I/O操作
OpenCV學習筆記(六)(七)(八)(九)(十)
OpenCV學習筆記(六)——對XML和YAML檔案實現I/O操作
1. XML、YAML檔案的開啟和關閉
XML\YAML檔案在OpenCV中的資料結構為FileStorage,開啟操作例如:
- string filename = "I.xml";
- FileStorage fs(filename, FileStorage::WRITE);
- \\...
- fs.open(filename, FileStorage::READ);
檔案關閉操作會在FileStorage結構銷燬時自動進行,但也可呼叫如下函式實現
- fs.release();
2.文字和數字的輸入和輸出
寫入檔案使用 << 運算子,例如:
- fs << "iterationNr" << 100;
讀取檔案,使用 >> 運算子,例如
- int itNr;
- fs["iterationNr"] >> itNr;
- itNr = (int) fs["iterationNr"];
3. OpenCV資料結構的輸入和輸出,和基本的C++形式相同
- Mat R = Mat_<uchar >::eye (3, 3),
- T = Mat_<double>::zeros(3, 1);
- fs << "R" << R; // Write cv::Mat
- fs << "T" << T;
- fs["R"] >> R; // Read cv::Mat
- fs["T"] >> T;
4. vector(arrays) 和 maps的輸入和輸出
vector要注意在第一個元素前加上“[”,在最後一個元素前加上"]"。例如:
- fs << "strings" << "["; // text - string sequence
- fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
- fs << "]"; // close sequence
對於map結構的操作使用的符號是"{"和"}",例如:
- fs << "Mapping"; // text - mapping
- fs << "{" << "One" << 1;
- fs << "Two" << 2 << "}";
讀取這些結構的時候,會用到FileNode和FileNodeIterator資料結構。對FileStorage類的[]操作符會返回FileNode資料型別,對於一連串的node,可以使用FileNodeIterator結構,例如:
- FileNode n = fs["strings"]; // Read string sequence - Get node
- if (n.type() != FileNode::SEQ)
- {
- cerr << "strings is not a sequence! FAIL" << endl;
- return 1;
- }
- FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
- for (; it != it_end; ++it)
- cout << (string)*it << endl;
5. 讀寫自己的資料結構
這部分比較複雜,參考最後的例項中的MyData結構自己領悟吧
最後,我這裡上一個例項,供大家參考。
原始檔裡填入如下程式碼:
- #include <opencv2/core/core.hpp>
- #include <iostream>
- #include <string>
- using namespace cv;
- using namespace std;
- void help(char** av)
- {
- cout << endl
- << av[0] << " shows the usage of the OpenCV serialization functionality." << endl
- << "usage: " << endl
- << av[0] << " outputfile.yml.gz" << endl
- << "The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by "
- << "specifying this in its extension like xml.gz yaml.gz etc... " << endl
- << "With FileStorage you can serialize objects in OpenCV by using the << and >> operators" << endl
- << "For example: - create a class and have it serialized" << endl
- << " - use it to read and write matrices." << endl;
- }
- class MyData
- {
- public:
- MyData() : A(0), X(0), id()
- {}
- explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // explicit to avoid implicit conversion
- {}
- void write(FileStorage& fs) const //Write serialization for this class
- {
- fs << "{" << "A" << A << "X" << X << "id" << id << "}";
- }
- void read(const FileNode& node) //Read serialization for this class
- {
- A = (int)node["A"];
- X = (double)node["X"];
- id = (string)node["id"];
- }
- public: // Data Members
- int A;
- double X;
- string id;
- };
- //These write and read functions must be defined for the serialization in FileStorage to work
- void write(FileStorage& fs, const std::string&, const MyData& x)
- {
- x.write(fs);
- }
- void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){
- if(node.empty())
- x = default_value;
- else
- x.read(node);
- }
- // This function will print our custom class to the console
- ostream& operator<<(ostream& out, const MyData& m)
- {
- out << "{ id = " << m.id << ", ";
- out << "X = " << m.X << ", ";
- out << "A = " << m.A << "}";
- return out;
- }
- int main(int ac, char** av)
- {
- if (ac != 2)
- {
- help(av);
- return 1;
- }
- string filename = av[1];
- { //write
- Mat R = Mat_<uchar>::eye(3, 3),
- T = Mat_<double>::zeros(3, 1);
- MyData m(1);
- FileStorage fs(filename, FileStorage::WRITE);
- fs << "iterationNr" << 100;
- fs << "strings" << "["; // text - string sequence
- fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
- fs << "]"; // close sequence
- fs << "Mapping"; // text - mapping
- fs << "{" << "One" << 1;
- fs << "Two" << 2 << "}";
- fs << "R" << R; // cv::Mat
- fs << "T" << T;
- fs << "MyData" << m; // your own data structures
- fs.release(); // explicit close
- cout << "Write Done." << endl;
- }
- {//read
- cout << endl << "Reading: " << endl;
- FileStorage fs;
- fs.open(filename, FileStorage::READ);
- int itNr;
- //fs["iterationNr"] >> itNr;
- itNr = (int) fs["iterationNr"];
- cout << itNr;
- if (!fs.isOpened())
- {
- cerr << "Failed to open " << filename << endl;
- help(av);
- return 1;
- }
- FileNode n = fs["strings"]; // Read string sequence - Get node
- if (n.type() != FileNode::SEQ)
- {
- cerr << "strings is not a sequence! FAIL" << endl;
- return 1;
- }
- FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
- for (; it != it_end; ++it)
- cout << (string)*it << endl;
- n = fs["Mapping"]; // Read mappings from a sequence
- cout << "Two " << (int)(n["Two"]) << "; ";
- cout << "One " << (int)(n["One"]) << endl << endl;
- MyData m;
- Mat R, T;
- fs["R"] >> R; // Read cv::Mat
- fs["T"] >> T;
- fs["MyData"] >> m; // Read your own structure_
- cout << endl
- << "R = " << R << endl;
- cout << "T = " << T << endl << endl;
- cout << "MyData = " << endl << m << endl << endl;
- //Show default behavior for non existing nodes
- cout << "Attempt to read NonExisting (should initialize the data structure with its default).";
- fs["NonExisting"] >> m;
- cout << endl << "NonExisting = " << endl << m << endl;
- }
- cout << endl
- << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;
- return 0;
- }
編譯後,在命令列進入到檔案目錄,執行test test.xml,執行結果如下,生成一個test . xml檔案,內容如下:
- <?xml version="1.0" ?>
- - <opencv_storage>
- <iterationNr>100</iterationNr>
- <strings>image1.jpg Awesomeness baboon.jpg</strings>
- - <Mapping>
- <One>1</One>
- <Two>2</Two>
- </Mapping>
- - <R type_id="opencv-matrix">
- <rows>3</rows>
- <cols>3</cols>
- <dt>u</dt>
- <data>1 0 0 0 1 0 0 0 1</data>
- </R>
- - <T type_id="opencv-matrix">
- <rows>3</rows>
- <cols>1</cols>
- <dt>d</dt>
- <data>0. 0. 0.</data>
- </T>
- - <MyData>
- <A>97</A>
- <X>3.1415926535897931e+000</X>
- <id>mydata1234</id>
- </MyData>
- </opencv_storage>
OpenCV學習筆記(七)——影像處理之濾波器ImgProc
先介紹幾個最基本的核濾波器相關的類
2D影像濾波器基礎類BaseFilter:dst(x,y) = F(src(x,y), src(x+1,y)... src(x+wdith-1,y), src(y+1,x)... src(x+width-1, y+height-1) ); 相關的呼叫函式為getLinearFilter、getMorphologyFilter
單行核濾波器基礎類BaseRowFilter:dst(x,y) = F(src(x,y), src(x+1,y),...src(x+width-1,y));相關的呼叫函式為getLinearRowFilter、getMorphologyRowFilter
單列核濾波器基礎類BaseColumnFilter:dst(x,y) = F(src(x,y), src(x,y+1),...src(x,y+width-1));相關的呼叫函式為getColumnSumFilter、getLinearColumnFilter、getMorphologyColumnFilter
類FilterEngine:該類可以應用在對影像的任意濾波操作當中,在OpenCV濾波器函式中扮演著很重要的角色,相關的函式有createBoxFitler、createDerivFitlter、createGaussianFilter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter
基於這些類有一些基本的濾波器bilateralFilter、blur、boxFilter
還有一些形態學操作如:dilate、erode、morphologyEx
還有基於核和影像卷積的濾波器filter2D
還有一些典型的濾波器如GaussianBlur、medianBlur、Laplacian、pyrMeanShiftFiltering、sepFilter2D
還有Sobel、Scharr運算子
其他一些函式有borderInterpolate、buildPyramid、copyMakeBorder、createBoxFilter、createDirivFilter、createGaussianFliter、createLinearFilter、createMorphologyFilter、createSeparableLinearFilter、getDerivKernels、getGaussianKernel、getKernelType、getStructuringElement、pyrDown、pyrUp
還老版本的濾波器cvSmooth
這裡介紹一下我使用Laplacian濾波的心得,這個函式的第三個引數為輸出的影像的深度,注意經過拉普拉斯運算元處理後得到的值是有正有負的,所以輸出影像的深度最好為輸入影像深度的2倍,才能有效防止資料溢位,如必須要使用8位的資料,可以再使用函式convertScaleAbs處理。而且要注意使用的拉普拉斯運算元掩膜的中心繫數為負。
OpenCV學習筆記(八)——影像處理之直方圖ImgProc
直方圖histograms也是影像處理中經常用到的一種手段。新版本對直方圖不再使用之前的histogram的形式,而是用統一的Mat或者MatND的格式來儲存直方圖,可見新版本Mat資料結構的優勢。先介紹下其相關的函式
calcHist、calcBackProject、compareHist、EMD、equalizeHist。除了這幾個常用的函式以為,還有一些c函式寫的直方圖類CvHistogram的相關操作,如下:cvCalcBackProjectPatch、cvCalcProbDensity、cvClearHist、cvCopyHist、cvCreateHist、cvGetHistValue_XD、cvGetMinMaxHistValue、cvMakeHistHeaderForArray、cvNormalizeHist、QueryHistValue_XD、cvReleaseHist、cvSetHistBinRanges、cvThreshHist、cvCalcPGH
calcHist函式為計算影像的直方圖,使用方法如下:
- // C++:
- void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )
- // C++:
- void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )
arrays為輸入影像指標,narrays為輸入影像的個數,channels為用來計算直方圖的通道列表,mask為掩膜矩陣,不為空的時候,只計算arrays中的掩膜區域的直方圖,hist為輸出的直方圖矩陣,dims為直方圖矩陣的維度,histSize為每一維直方圖矩陣的大小,ranges為每一維直方圖元素的取值範圍,是一個2維陣列的地址,uniform為直方圖是否為統一模式,統一模式下會拉伸為range的大小,accumulate為累計標誌,方便直方圖的更新,不需要重新計算
舉幾個例項方便大家理解:
對於影像為灰度圖,呼叫方式如下:
- int histSize = 255;
- float ranges[] = {0, 255};
- const float* histRange = {ranges};
- calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, &histRange);
直方圖的歸一化已經不再適合cvNormalizeHist這個函式了,只需要用對矩陣的歸一化函式normalize就可以實現了。
直方圖均衡化函式為equalizeHist,這個函式比較簡單,這裡就不詳細介紹了
直方圖的比較函式為compareHist,函式返回值為兩矩陣的相似程度,相似度衡量的辦法目前支援4種
計算反向投影圖函式為calcBackProject。所謂反向投影圖就是一個概率密度圖。calcBackProject的輸入為影像及其直方圖,輸出與待跟蹤影像大小相同,每一個畫素點表示該點為目標區域的概率。這個點越亮,該點屬於物體的概率越大。關於反向直方圖,可以參考一下這篇文章http://blog.163.com/thomaskjh@126/blog/static/370829982010112810358501/,這個函式使我們利用特徵直方圖尋找圖片中的特徵區域變得更加方便容易。這裡舉一個比較常用的例子:如果已經有一個膚色的特徵直方圖,則可以在待檢測影像中利用直方圖方向投影圖找出圖片中的膚色區域。– CV_COMP_CORREL Correlation相關係數,相同為1,相似度範圍為[ 1, 0 )
– CV_COMP_CHISQR Chi-Square卡方,相同為0,相似度範圍為[ 0, +inf )
– CV_COMP_INTERSECT Intersection直方圖交,數越大越相似,,相似度範圍為[ 0, +inf )
– CV_COMP_BHATTACHARYYA Bhattacharyya distance做常態分別比對的Bhattacharyya 距離,相同為0,,相似度範圍為[ 0, +inf )
OpenCV學習筆記(九)——2維特徵Feature2D
基於特徵點的影像匹配是影像處理中經常會遇到的問題,手動選取特徵點太麻煩了。比較經典常用的特徵點自動提取的辦法有Harris特徵、SIFT特徵、SURF特徵。
先介紹利用SURF特徵的特徵描述辦法,其操作封裝在類SurfFeatureDetector中,利用類內的detect函式可以檢測出SURF特徵的關鍵點,儲存在vector容器中。第二部利用SurfDescriptorExtractor類進行特徵向量的相關計算。將之前的vector變數變成向量矩陣形式儲存在Mat中。最後強行匹配兩幅影像的特徵向量,利用了類BruteForceMatcher中的函式match。程式碼如下:
- /**
- * @file SURF_descriptor
- * @brief SURF detector + descritpor + BruteForce Matcher + drawing matches with OpenCV functions
- * @author A. Huaman
- */
- #include <stdio.h>
- #include <iostream>
- #include "opencv2/core/core.hpp"
- #include "opencv2/features2d/features2d.hpp"
- #include "opencv2/highgui/highgui.hpp"
- using namespace cv;
- void readme();
- /**
- * @function main
- * @brief Main function
- */
- int main( int argc, char** argv )
- {
- if( argc != 3 )
- { return -1; }
- Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
- Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
- if( !img_1.data || !img_2.data )
- { return -1; }
- //-- Step 1: Detect the keypoints using SURF Detector
- int minHessian = 400;
- SurfFeatureDetector detector( minHessian );
- std::vector<KeyPoint> keypoints_1, keypoints_2;
- detector.detect( img_1, keypoints_1 );
- detector.detect( img_2, keypoints_2 );
- //-- Step 2: Calculate descriptors (feature vectors)
- SurfDescriptorExtractor extractor;
- Mat descriptors_1, descriptors_2;
- extractor.compute( img_1, keypoints_1, descriptors_1 );
- extractor.compute( img_2, keypoints_2, descriptors_2 );
- //-- Step 3: Matching descriptor vectors with a brute force matcher
- BruteForceMatcher< L2<float> > matcher;
- std::vector< DMatch > matches;
- matcher.match( descriptors_1, descriptors_2, matches );
- //-- Draw matches
- Mat img_matches;
- drawMatches( img_1, keypoints_1, img_2, keypoints_2, matches, img_matches );
- //-- Show detected matches
- imshow("Matches", img_matches );
- waitKey(0);
- return 0;
- }
- /**
- * @function readme
- */
- void readme()
- { std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
當然,進行強匹配的效果不夠理想,這裡再介紹一種FLANN特徵匹配演算法。前兩步與上述程式碼相同,第三步利用FlannBasedMatcher類進行特徵匹配,並只保留好的特徵匹配點,程式碼如下:
- //-- Step 3: Matching descriptor vectors using FLANN matcher
- FlannBasedMatcher matcher;
- std::vector< DMatch > matches;
- matcher.match( descriptors_1, descriptors_2, matches );
- double max_dist = 0; double min_dist = 100;
- //-- Quick calculation of max and min distances between keypoints
- for( int i = 0; i < descriptors_1.rows; i++ )
- { double dist = matches[i].distance;
- if( dist < min_dist ) min_dist = dist;
- if( dist > max_dist ) max_dist = dist;
- }
- printf("-- Max dist : %f \n", max_dist );
- printf("-- Min dist : %f \n", min_dist );
- //-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )
- //-- PS.- radiusMatch can also be used here.
- std::vector< DMatch > good_matches;
- for( int i = 0; i < descriptors_1.rows; i++ )
- { if( matches[i].distance < 2*min_dist )
- { good_matches.push_back( matches[i]); }
- }
- //-- Draw only "good" matches
- Mat img_matches;
- drawMatches( img_1, keypoints_1, img_2, keypoints_2,
- good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
- vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
- //-- Show detected matches
- imshow( "Good Matches", img_matches );
在FLANN特徵匹配的基礎上,還可以進一步利用Homography對映找出已知物體。具體來說就是利用findHomography函式利用匹配的關鍵點找出相應的變換,再利用perspectiveTransform函式對映點群。具體程式碼如下:
- //-- Localize the object from img_1 in img_2
- std::vector<Point2f> obj;
- std::vector<Point2f> scene;
- for( int i = 0; i < good_matches.size(); i++ )
- {
- //-- Get the keypoints from the good matches
- obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );
- scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );
- }
- Mat H = findHomography( obj, scene, CV_RANSAC );
- //-- Get the corners from the image_1 ( the object to be "detected" )
- Point2f obj_corners[4] = { cvPoint(0,0), cvPoint( img_1.cols, 0 ), cvPoint( img_1.cols, img_1.rows ), cvPoint( 0, img_1.rows ) };
- Point scene_corners[4];
- //-- Map these corners in the scene ( image_2)
- for( int i = 0; i < 4; i++ )
- {
- double x = obj_corners[i].x;
- double y = obj_corners[i].y;
- double Z = 1./( H.at<double>(2,0)*x + H.at<double>(2,1)*y + H.at<double>(2,2) );
- double X = ( H.at<double>(0,0)*x + H.at<double>(0,1)*y + H.at<double>(0,2) )*Z;
- double Y = ( H.at<double>(1,0)*x + H.at<double>(1,1)*y + H.at<double>(1,2) )*Z;
- scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) );
- }
- //-- Draw lines between the corners (the mapped object in the scene - image_2 )
- line( img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2 );
- line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 2 );
- line( img_matches, scene_corners[2], scene_corners[3], Scalar( 0, 255, 0), 2 );
- line( img_matches, scene_corners[3], scene_corners[0], Scalar( 0, 255, 0), 2 );
- //-- Show detected matches
- imshow( "Good Matches & Object detection", img_matches );
然後再看一下Harris特徵檢測,在計算機視覺中,通常需要找出兩幀影像的匹配點,如果能找到兩幅影像如何相關,就能提取出兩幅影像的資訊。我們說的特徵的最大特點就是它具有唯一可識別這一特點,影像特徵的型別通常指邊界、角點(興趣點)、斑點(興趣區域)。角點就是影像的一個區域性特徵,應用廣泛。harris角點檢測是一種直接基於灰度影像的角點提取演算法,穩定性高,尤其對L型角點檢測精度高,但由於採用了高斯濾波,運算速度相對較慢,角點資訊有丟失和位置偏移的現象,而且角點提取有聚簇現象。具體實現就是使用函式cornerHarris實現。
除了利用Harris進行角點檢測,還可以利用Shi-Tomasi方法進行角點檢測。使用函式goodFeaturesToTrack對角點進行檢測,效果也不錯。也可以自己製作角點檢測的函式,需要用到cornerMinEigenVal函式和minMaxLoc函式,最後的特徵點選取,判斷條件要根據自己的情況編輯。如果對特徵點,角點的精度要求更高,可以用cornerSubPix函式將角點定位到子畫素。
OpenCV學習筆記(十)——圖形互動和媒體介面HighGUI
OpenCV提供一個功能強大的UI介面,可以在MFC、Qt、WinForms、Cocoa等平臺下使用,甚至不需要其他的平臺。新版本的HighGUI介面包括:
建立並控制視窗,該視窗可以顯示圖片並記錄其內容
為視窗新增了trackbars控制元件,可以方便利用滑鼠進行控制而不是之前版本的只能利用鍵盤
讀寫硬碟和記憶體的圖片
讀取攝像頭的視訊、讀寫視訊檔案
先來介紹UI,包括函式createTrackbar、getTrackbarPos、setTrackbarPos、imshow、namedWindow、destroyWindow、destroyAllWindows、MoveWindow、ResizeWindow、SetMouseCallback、waitKey。這些函式保證了影像的基本處理、tarckbar的控制和滑鼠鍵盤的響應
介紹一下讀寫影像視訊的函式:影像相關的函式有imdecode、imencode、imread、imwrite。讀取視訊相關為VideoCapture類,負責捕捉檔案和攝像頭的視訊,該類內有成員函式VideoCapture、open、isOpened、release、grab、retrieve、read、get、set,寫視訊的類為VideoWriter,類內有成員函式VideoWriter、open、isOpened、write
新版本還為Qt做了新函式,這裡就不介紹了,有興趣的朋友可以自己看一下參考手冊的第四章第三節。
這裡介紹幾個常用的新功能,首先介紹一下新增滑桿控制元件Trackbar。呼叫函式為:
- createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );
第一個引數為字串作為標籤,第二個引數為所在視窗的名字,第三個引數為儲存滑桿位置的值地址,其範圍為0~alpha_slider_max(第四個引數),最後一個引數為移動滑桿時呼叫的回撥函式名。
OpenCV2.0版本加強了對視訊處理的支援,不再需要對一組連續的圖片進行處理,可以進行實時的影像採集和記錄以及儲存。視訊的操作基本都被封裝在VideoCapture類中。開啟視訊可以可以通過如下程式碼實現:
- VideoCapture captRefrnc(sourceReference);
- // or
- VideoCapture captUndTst;
- captUndTst.open(sourceCompareWith);
其中sourceReference和sourceCompareWith為string型,為檔名。還可以通過isOpened函式檢測視訊是否成功開啟。也可以呼叫release函式提前關閉視訊。還可以講VideoCapture放到Mat結構中,因為視訊流是一連串的,可以通過read函式或>>操作符逐幀的讀取,例如:
- Mat frameReference, frameUnderTest;
- captRefrnc >> frameReference;
- captUndTst.open(frameUnderTest);
read函式只能逐幀的抓取,如果要抓取某一幀,可以成對的呼叫grab函式和retrieve函式。get函式可以獲取視訊相關資訊。set函式可以控制視訊的一些值,比如是指視訊的當前位置或幀數。
可以使用VideoWriter類建立新視訊,其open,isOpened函式呼叫方法類似,write函式或<<運算子向視訊寫入內容,可以使用split函式和merge函式單獨調整RGB通道的值
今日,被一個網友指出,說OpenCV以前提供的讀寫功能採用VFW,效率低下且有些格式支援不好。而 OpenCV 2.0 內建了videoInput Library,可以自動在VFW和DirectShow間切換。videoInput是老外寫的功能強大的開源視訊處理庫。是一個第三方庫,2.0~2.2的版本專門有一個3rdparty對該庫進行支援,而在最新的2.3版本中,已經講videoInput庫整合到highgui中了,想使用它的話,只需要在cmake中設定巨集WITH_VIDEOiNPUT=OFF/ON即可。
以後有新學到的東西都會陸續補充進來。
from: http://blog.csdn.net/yang_xian521/article/category/910716
相關文章
- 檔案管理I/O筆記筆記
- Java學習筆記之I/OJava筆記
- Mybatis 學習筆記(一)——配置檔案SqlMapConfig.xml和對映檔案Mapper.xmlMyBatis筆記SQLXMLAPP
- Java學習筆記之I/O流(讀取壓縮檔案以及壓縮檔案)Java筆記
- 006零基礎學Python:Python 檔案I/O和File方法--學習筆記Python筆記
- OS學習筆記六:檔案系統筆記
- Linux檔案型別(學習筆記六)Linux型別筆記
- I/O流以及檔案的基本操作
- 檔案I/O
- 【Go學習筆記15】解析yamlGo筆記YAML
- opencv學習筆記(一)OpenCV筆記
- 我的OpenCV學習筆記(六):使用支援向量機(SVM)OpenCV筆記
- Python學習筆記|Python之檔案操作Python筆記
- python學習筆記:第8天 檔案操作Python筆記
- I/O埠和I/O記憶體記憶體
- 一起學Scala 檔案 I/O
- spark學習筆記--RDD鍵對操作Spark筆記
- 4、Linux入門學習筆記 檔案操作命令Linux筆記
- Java-0024-用I/O實現拷貝檔案Java
- I/O程式設計技術(檔案IO)筆記綱要梳理程式設計筆記
- ORACLE UTL_FILE檔案包的應用,檔案I/O操作Oracle
- hibernate筆記–實體類對映檔案”*.hbm.xml”詳解筆記XML
- Java I/O流 複製檔案速度對比Java
- 【Go學習筆記13】介面和實現Go筆記
- VC++學習筆記---配置檔案(一) ini檔案和propritiesC++筆記
- Laravel 學習筆記一: 專案框架和配置檔案Laravel筆記框架
- Javascript 學習 筆記六JavaScript筆記
- Oracle效能優化視訊學習筆記-資料庫配置和I/O問題Oracle優化筆記資料庫
- Java學習筆記之檔案Java筆記
- Opencv學習筆記(3)---紙牌數字識別練習實踐專案OpenCV筆記
- Redis 學習筆記(六)Redis 如何實現訊息佇列Redis筆記佇列
- 使用Task實現非阻塞式的I/O操作
- O(n)-O(1) 線性 RMQ 學習筆記MQ筆記
- Android學習筆記之AndroidManifest.xml檔案解析(詳解)Android筆記XML
- python pyyaml操作yaml配置檔案PythonYAML
- Python中檔案I/O高效操作處理的技巧Python
- XML學習筆記–背誦版XML筆記
- 【Go學習筆記16】解析xmlGo筆記XML