PS. 由于csdn博客文章長度有限制,本文有部分內容被截掉了。
在OpenCV中文網站的wiki上有可讀性更好、并且是完整的版本,歡迎瀏覽。
OpenCV Wiki :《OpenCV 編程簡介(矩陣/圖像/視頻的基本讀寫操作)》
?
Introduction to programming with OpenCV
OpenCV編程簡介
Gady Agam
Department of Computer Science
January 27, 2006
Illinois Institute of Technology
-- URL: http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html#SECTION00040000000000000000
譯: chenyusiyuan
--?? January 26, 2010
--??? http://blog.csdn.net/chenyusiyuan
摘要:
本文旨在幫助讀者快速入門OpenCV,而無需閱讀冗長的參考手冊。掌握了OpenCV的以下基礎知識后,有需要的話再查閱相關的參考手冊。
目錄
一??? 簡介
o??? OpenCV的特點
o??? 有用的學習資源
o??? 命名規則
o??? 編譯建議
o??? 一個例程
二??? GUI命令
o??? 窗口管理
o??? 輸入處理
三?? OpenCV基本的數據結構
o??? 圖像數據結構
o??? 矩陣與向量
o??? 其它數據結構
四??? 圖像處理
o??? 內存分配與釋放
o??? 讀取和寫入圖像
o??? 訪問圖像像素
o??? 圖像轉換
o??? 繪圖指令
五??? 矩陣處理
o??? 內存分配與釋放
o??? 訪問矩陣元素
o??? 矩陣/向量運算
六??? 視頻處理
o??? 視頻的幀捕捉
o??? 幀信息的讀取與設置
o??? 保存視頻文件
=================================================
一、簡介
1、OpenCV的特點?
(1)??? 總體描述
o??? OpenCV是一個基于C/C++語言的開源圖像處理函數庫
o??? 其代碼都經過優化,可用于實時處理圖像
o??? 具有良好的可移植性
o??? 可以進行圖像/視頻載入、保存和采集的常規操作
o??? 具有低級和高級的應用程序接口(API)
o??? 提供了面向Intel IPP高效多媒體函數庫的接口,可針對你使用的Intel CPU優化代碼,提高程序性能(譯注:OpenCV 2.0版的代碼已顯著優化,無需IPP來提升性能,故2.0版不再提供IPP接口)
(2)??? 功能
o??? 圖像數據操作(內存分配與釋放,圖像復制、設定和轉換)
Image data manipulation (allocation, release, copying, setting, conversion).
o??? 圖像/視頻的輸入輸出(支持文件或攝像頭的輸入,圖像/視頻文件的輸出)
Image and video I/O (file and camera based input, image/video file output).
o??? 矩陣/向量數據操作及線性代數運算(矩陣乘積、矩陣方程求解、特征值、奇異值分解)
Matrix and vector manipulation and linear algebra routines (products, solvers, eigenvalues, SVD).
o??? 支持多種動態數據結構(鏈表、隊列、數據集、樹、圖)
Various dynamic data structures (lists, queues, sets, trees, graphs).
o??? 基本圖像處理(去噪、邊緣檢測、角點檢測、采樣與插值、色彩變換、形態學處理、直方圖、圖像金字塔結構)
Basic image processing (filtering, edge detection, corner detection, sampling and interpolation, color conversion, morphological operations, histograms, image pyramids).
o??? 結構分析(連通域/分支、輪廓處理、距離轉換、圖像矩、模板匹配、霍夫變換、多項式逼近、曲線擬合、橢圓擬合、狄勞尼三角化)
Structural analysis (connected components, contour processing, distance transform, various moments, template matching, Hough transform, polygonal approximation, line fitting, ellipse fitting, Delaunay triangulation).
o??? 攝像頭定標(尋找和跟蹤定標模式、參數定標、基本矩陣估計、單應矩陣估計、立體視覺匹配)
Camera calibration (finding and tracking calibration patterns, calibration, fundamental matrix estimation, homography estimation, stereo correspondence).
o??? 運動分析(光流、動作分割、目標跟蹤)
Motion analysis (optical flow, motion segmentation, tracking).
o??? 目標識別(特征方法、HMM模型)Object recognition (eigen-methods, HMM).
o??? 基本的GUI(顯示圖像/視頻、鍵盤/鼠標操作、滑動條)
Basic GUI (display image/video, keyboard and mouse handling, scroll-bars).
o??? 圖像標注(直線、曲線、多邊形、文本標注)
Image labeling (line, conic, polygon, text drawing)
(3)??? OpenCV模塊
o??? cv – 核心函數庫
o??? cvaux – 輔助函數庫
o??? cxcore – 數據結構與線性代數庫
o??? highgui – GUI函數庫
o??? ml – 機器學習函數庫
2、有用的學習資源
(1)??? 參考手冊:
o??? /docs/index.htm (譯注:在你的OpenCV安裝目錄內)
???? 網絡資源:
o??? 官方網站: http://www.intel.com/technology/computing/opencv/
o??? 軟件下載: http://sourceforge.net/projects/opencvlibrary/
(2)??? 書籍:
o??? Open Source Computer Vision Library
by Gary R. Bradski, Vadim Pisarevsky, and Jean-Yves Bouguet, Springer, 1st ed. (June, 2006).
chenyusiyuan: 補充以下書籍
o??? Learning OpenCV - Computer Vision with the OpenCV Library
by Gary Bradski & Adrian Kaehler, O'Reilly Media, 1 st ed. (September, 2008).
o??? OpenCV教程——基礎篇
作者:劉瑞禎 于仕琪,北京航空航天大學出版社,出版日期:200706
(3)?? 視頻處理例程(在 /samples/c/):
o??? 顏色跟蹤: camshiftdemo
o??? 點跟蹤: lkdemo
o??? 動作分割: motempl
o??? 邊緣檢測: laplace
(4)??? 圖像處理例程 (在 /samples/c/):
o??? 邊緣檢測: edge
o??? 圖像分割: pyramid_segmentation
o??? 形態學: morphology
o??? 直方圖: demhist
o??? 距離變換: distrans
o??? 橢圓擬合: fitellipse
3、OpenCV 命名規則
(1)?? 函數名:
??? cvActionTargetMod(...)
??? Action = 核心功能(core functionality) (e.g. set, create)
??? Target = 目標圖像區域(target image area) (e.g. contour, polygon)
??? Mod??? = (可選的)調整語(optional modifiers) (e.g. argument type)
(2)?? 矩陣數據類型:
??? CV_<bit_depth>(S|U|F)C<number_of_channels>
??? S = 符號整型
??? U = 無符號整型
??? F = 浮點型
??? E.g.: CV_8UC1 是指一個8位無符號整型單通道矩陣,
????????? CV_32FC2是指一個32位浮點型雙通道矩陣.
(3)??? 圖像數據類型:
??? IPL_DEPTH_<bit_depth>(S|U|F)
??? E.g.: IPL_DEPTH_8U 圖像像素數據是8位無符號整型.
????????? IPL_DEPTH_32F圖像像素數據是32位浮點型.
(4)??? 頭文件:
??? #include <cv.h>
??? #include <cvaux.h>
??? #include <highgui.h>?
??? #include <ml.h>
??? #include <cxcore.h>?? // 一般不需要,cv.h 內已包含該頭文件 4、編譯建議
(1)?? Linux:
g++ hello-world.cpp -o hello-world /
??? -I /usr/local/include/opencv -L /usr/local/lib? /
??? -lm -lcv -lhighgui -lcvaux
(2)??? Windows:
在Visual Studio的‘選項’和‘項目’中設置好OpenCV相關文件的路徑。
5、C例程
//
// hello-world.cpp
//
// 該程序從文件中讀入一幅圖像,將之反色,然后顯示出來.
//
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>
int main(int argc, char *argv[])
{
? IplImage* img = 0;
? int height,width,step,channels;
? uchar *data;
? int i,j,k;
? if(argc<2){
??? printf("Usage: main /n/7");
??? exit(0);
? }
? // load an image?
? img=cvLoadImage(argv[1]);
? if(!img){
??? printf("Could not load image file: %s/n",argv[1]);
??? exit(0);
? }
? // get the image data
? height??? = img->height;
? width???? = img->width;
? step????? = img->widthStep;
? channels? = img->nChannels;
? data????? = (uchar *)img->imageData;
? printf("Processing a %dx%d image with %d channels/n",height,width,channels);
? // create a window
? cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
? cvMoveWindow("mainWin", 100, 100);
? // invert the image
? // 相當于 cvNot(img);
? for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
??? data[i*step+j*channels+k]=255-data[i*step+j*channels+k];
? // show the image
? cvShowImage("mainWin", img );
? // wait for a key
? cvWaitKey(0);
? // release the image
? cvReleaseImage(&img );
? return 0;
}
=================================================
二、GUI 指令
1、窗口管理?
(1)??? 創建和定位一個新窗口:
? cvNamedWindow("win1", CV_WINDOW_AUTOSIZE);
? cvMoveWindow("win1", 100, 100); // offset from the UL corner of the screen
(2)??? 載入圖像:
? IplImage* img=0;
? img=cvLoadImage(fileName);
? if(!img) printf("Could not load image file: %s/n",fileName);
(3)?? 顯示圖像:?
?
?cvShowImage("win1",img);
該函數可以顯示彩色或灰度的字節型/浮點型圖像。字節型圖像像素值范圍為[0-255];浮點型圖像像素值范圍為[0-1]。彩色圖像的三色元素按BGR(藍-紅-綠)順序存儲。
(4)?? 關閉窗口:?
?
?cvDestroyWindow("win1");
(5)?? 改變窗口大小:
cvResizeWindow("win1",100,100); // new width/heigh in pixels2、輸入處理
(1)??? 處理鼠標事件:
o??? 定義一個鼠標處理程序:
void mouseHandler(int event, int x, int y, int flags, void* param)
? {
??? switch(event){
????? case CV_EVENT_LBUTTONDOWN:
??????? if(flags & CV_EVENT_FLAG_CTRLKEY)
????????? printf("Left button down with CTRL pressed/n");
??????? break;
????? case CV_EVENT_LBUTTONUP:
??????? printf("Left button up/n");
??????? break;
??? }
? }??
? x,y:?? 相對于左上角的像素坐標
? event: CV_EVENT_LBUTTONDOWN,?? CV_EVENT_RBUTTONDOWN,?? CV_EVENT_MBUTTONDOWN,
???????? CV_EVENT_LBUTTONUP,???? CV_EVENT_RBUTTONUP,???? CV_EVENT_MBUTTONUP,
???????? CV_EVENT_LBUTTONDBLCLK, CV_EVENT_RBUTTONDBLCLK, CV_EVENT_MBUTTONDBLCLK,
???????? CV_EVENT_MOUSEMOVE:
? flags: CV_EVENT_FLAG_CTRLKEY, CV_EVENT_FLAG_SHIFTKEY, CV_EVENT_FLAG_ALTKEY,
???????? CV_EVENT_FLAG_LBUTTON, CV_EVENT_FLAG_RBUTTON,? CV_EVENT_FLAG_MBUTTON
o??? 注冊該事件處理程序:?
?
mouseParam=5;
? cvSetMouseCallback("win1",mouseHandler,&mouseParam);
(2)??? 處理鍵盤事件:
o??? 實際上對于鍵盤輸入并沒有專門的事件處理程序.
o??? 按一定間隔檢測鍵盤輸入(適用于循環體中):?
?
?int key;
? key=cvWaitKey(10); // wait 10ms for input
o??? 中止程序等待鍵盤輸入:?
?
?int key;
? key=cvWaitKey(0); // wait indefinitely for input
o??? 鍵盤輸入的循環處理程序:
while(1){
??? key=cvWaitKey(10);
??? if(key==27) break;
??? switch(key){
????? case 'h':
??????? ...
??????? break;
????? case 'i':
??????? ...
??????? break;
??? }
? }?
(3)??? 處理滑動條事件:
o??? 定義一個滑動條處理程序:?
?
void trackbarHandler(int pos)
? {
??? printf("Trackbar position: %d/n",pos);
? }
o??? 注冊該事件處理程序:?
?
?int trackbarVal=25;
? int maxVal=100;
? cvCreateTrackbar("bar1", "win1", &trackbarVal ,maxVal , trackbarHandler);
o??? 獲取當前的滑動條位置:?
?
int pos = cvGetTrackbarPos("bar1","win1");
o??? 設置滑動條位置:?
??
cvSetTrackbarPos("bar1", "win1", 25);=================================================
三、OpenCV的基本數據結構
(譯注:OpenCV 1.1、1.2或2.0版本中各數據結構的結構體元素有所調整,以下僅作參考)
1、圖像數據結構
(1)??? IPL 圖像:
IplImage
? |-- int? nChannels;???? // 顏色通道數目 (1,2,3,4)
? |-- int? depth;???????? // 像素的位深:
? |?????????????????????? //?? IPL_DEPTH_8U, IPL_DEPTH_8S,
? |?????????????????????? //?? IPL_DEPTH_16U,IPL_DEPTH_16S,
? |?????????????????????? //?? IPL_DEPTH_32S,IPL_DEPTH_32F,
? |?????????????????????? //?? IPL_DEPTH_64F
? |-- int? width;???????? // 圖像寬度(像素為單位)
? |-- int? height;??????? // 圖像高度
? |-- char* imageData;??? // 圖像數據指針
? |?????????????????????? // 注意彩色圖像按BGR順序存儲數據
? |-- int? dataOrder;???? // 0 - 將像素點不同通道的值交錯排在一起,形成單一像素平面
? |?????????????????????? // 1 - 把所有像素同通道值排在一起,形成若干個通道平面,再把平面排列起來
? |?????????????????????? // cvCreateImage 只能創建像素交錯排列式的圖像
? |-- int? origin;??????? // 0 – 像素原點為左上角,
? |?????????????????????? // 1 – 像素原點為左下角 (Windows bitmaps style)
? |-- int? widthStep;???? // 相鄰行的同列點之間的字節數
? |-- int? imageSize;???? // 圖像的大小(字節為單位) = height*widthStep
? |-- struct _IplROI *roi;// 圖像的感興趣區域(ROI). ROI非空時對圖像的
? |?????????????????????? // 處理僅限于ROI區域.
? |-- char *imageDataOrigin; // 圖像數據未對齊時的數據原點指針
? |????????????????????????? // (需要正確地重新分配圖像內存 )
? |????????????????????????? // (needed for correct image deallocation)
? |-- int? align;???????? // 圖像數據的行對齊: 4 or 8 byte alignment
? |?????????????????????? // OpenCV 中無此項,采用widthStep代替
? |-- char colorModel[4]; // 顏色模型 – OpenCV中忽略此項
2、矩陣與向量
(1)??? 矩陣:
CvMat????????????????????? // 2D 矩陣
? |-- int?? type;????????? // 元素類型 (uchar,short,int,float,double) 與標志
? |-- int?? step;????????? // 整行長度字節數
? |-- int?? rows, cols;??? // 行、列數
? |-- int?? height, width; // 矩陣高度、寬度,與rows、cols對應
? |-- union data;
????? |-- uchar*? ptr;???? // data pointer for an unsigned char matrix
????? |-- short*? s;?????? // data pointer for a short matrix
????? |-- int*??? i;?????? // data pointer for an integer matrix
????? |-- float*? fl;????? // data pointer for a float matrix
????? |-- double* db;????? // data pointer for a double matrixCvMatND??????????????????? // N-維矩陣
? |-- int?? type;????????? // 元素類型 (uchar,short,int,float,double) 與標志
? |-- int?? dims;????????? // 矩陣維數
? |-- union data;
? |?? |-- uchar*? ptr;???? // data pointer for an unsigned char matrix
? |?? |-- short*? s;?????? // data pointer for a short matrix
? |?? |-- int*??? i;?????? // data pointer for an integer matrix
? |?? |-- float*? fl;????? // data pointer for a float matrix
? |?? |-- double* db;????? // data pointer for a double matrix
? |
? |-- struct dim[];??????? // 各維信息
????? |-- size;??????????? // 元素數目
????? |-- step;??????????? // 元素間距(字節為單位)CvSparseMat // N-維稀疏矩陣
(2)??? 一般矩陣:
CvArr*???? // 僅作為函數定義的參數使用,
?????????? // 表明函數可以接受不同類型的矩陣作為參數,
?????????? // 例如:IplImage*, CvMat* 甚至是 CvSeq*.
?????????? // 矩陣的類型通過矩陣頭的前4個字節信息來確定
(3)??? 標量:
CvScalar
? |-- double val[4]; //4D 向量
初始化函數:
CvScalar s = cvScalar(double val0, double val1=0, double val2=0, double val3=0);
// Example:
CvScalar s = cvScalar(20.0);
s.val[0]=10.0;
注意該初始化函數的函數名與對應的結構體名稱幾乎同名,差別僅在于函數名第一個字母是小寫的,而結構體名第一個字母是大寫的。它并不是一個 C++ 構造函數。(譯注:類似的還有 cvMat 與 CvMat、cvPoint 與 CvPoint 等等)
3、其它結構類型
(1)??? 點:
CvPoint????? p = cvPoint(int x, int y);
CvPoint2D32f p = cvPoint2D32f(float x, float y);
CvPoint3D32f p = cvPoint3D32f(float x, float y, float z);E.g.:
p.x=5.0;
p.y=5.0;
(2)??? 矩形框大小(以像素為精度):
CvSize?????? r = cvSize(int width, int height);
CvSize2D32f? r = cvSize2D32f(float width, float height);
(3)??? 矩形框的偏置和大小:
CvRect?????? r = cvRect(int x, int y, int width, int height);=================================================
四、圖像處理
1、圖像的內存分配與釋放
(1)??? 分配內存給一幅新圖像:
IplImage* cvCreateImage(CvSize size, int depth, int channels);?? size:? cvSize(width,height);
? depth: 像素深度: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
??? IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F
? channels: 像素通道數. Can be 1, 2, 3 or 4.
??? 各通道是交錯排列的. 一幅彩色圖像的數據排列格式如下:
??? b0 g0 r0 b1 g1 r1 ...
示例:
// Allocate a 1-channel byte image
IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
// Allocate a 3-channel float image
IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
(2)??? 釋放圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
cvReleaseImage(&img);
(3)??? 復制圖像:
IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
IplImage* img2;
img2=cvCloneImage(img1);? // 注意通過cvCloneImage得到的圖像
????????????????????? // 也要用 cvReleaseImage 釋放,否則容易產生內存泄漏
(4)??? 設置/獲取感興趣區域ROI:
void? cvSetImageROI(IplImage* image, CvRect rect);
void? cvResetImageROI(IplImage* image);
vRect cvGetImageROI(const IplImage* image);大多數OpenCV函數都支持 ROI.
(5)??? 設置/獲取感興趣通道COI:
void cvSetImageCOI(IplImage* image, int coi); // 0=all
int cvGetImageCOI(const IplImage* image);大多數OpenCV函數不支持 COI.
2、圖像讀寫
(1)??? 從文件中讀入圖像:?
?
?IplImage* img=0;
? img=cvLoadImage(fileName);
? if(!img) printf("Could not load image file: %s/n",fileName);? 支持的圖像格式: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,
?????????????????????????? SR, RAS, TIFF, TIF
OpenCV默認將讀入的圖像強制轉換為一幅三通道彩色圖像. 不過可以按以下方法修改讀入方式:?
??
img=cvLoadImage(fileName,flag);? flag: >0 將讀入的圖像強制轉換為一幅三通道彩色圖像
??????? =0 將讀入的圖像強制轉換為一幅單通道灰度圖像
??????? <0 讀入的圖像通道數與所讀入的文件相同.
(2)??? 保存圖像:?
?
?if(!cvSaveImage(outFileName,img)) printf("Could not save: %s/n", outFileName);保存的圖像格式由 outFileName 中的擴展名確定.
3、訪問圖像像素
(1)??? 假設你要訪問第k通道、第i行、第j列的像素。
(2)??? 間接訪問: (通用,但效率低,可訪問任意格式的圖像)
o??? 對于單通道字節型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
printf("intensity=%f/n",s.val[0]);
s.val[0]=111;
cvSet2D(img,i,j,s); // set the (i,j) pixel value
o??? 對于多通道字節型/浮點型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
CvScalar s;
s=cvGet2D(img,i,j); // get the (i,j) pixel value
printf("B=%f, G=%f, R=%f/n",s.val[0],s.val[1],s.val[2]);
s.val[0]=111;
s.val[1]=111;
s.val[2]=111;
cvSet2D(img,i,j,s); // set the (i,j) pixel value
(3)??? 直接訪問: (效率高,但容易出錯)
o??? 對于單通道字節型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
((uchar *)(img->imageData + i*img->widthStep))[j]=111;
o??? 對于多通道字節型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
o??? 對于多通道浮點型圖像:
IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
(4)??? 基于指針的直接訪問: (簡單高效)
o??? 對于單通道字節型圖像:
IplImage* img? = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
int height???? = img->height;
int width????? = img->width;
int step?????? = img->widthStep/sizeof(uchar);
uchar* data??? = (uchar *)img->imageData;
data[i*step+j] = 111;
o??? 對于多通道字節型圖像:
IplImage* img? = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
int height???? = img->height;
int width????? = img->width;
int step?????? = img->widthStep/sizeof(uchar);
int channels?? = img->nChannels;
uchar* data??? = (uchar *)img->imageData;
data[i*step+j*channels+k] = 111;
o??? 對于多通道浮點型圖像(假設圖像數據采用4字節(32位)行對齊方式):
IplImage* img? = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
int height???? = img->height;
int width????? = img->width;
int step?????? = img->widthStep/sizeof(float);
int channels?? = img->nChannels;
float * data??? = (float *)img->imageData;
data[i*step+j*channels+k] = 111;
(5)??? 基于 c++ wrapper 的直接訪問: (更簡單高效)
o??? 首先定義一個 c++ wrapper ‘Image’,然后基于Image定義不同類型的圖像:
template<class T> class Image
{
? private:
? IplImage* imgp;
? public:
? Image(IplImage* img=0) {imgp=img;}
? ~Image(){imgp=0;}
? void operator=(IplImage* img) {imgp=img;}
? inline T* operator[](const int rowIndx) {
??? return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
};
typedef struct{
? unsigned char b,g,r;
} RgbPixel;
typedef struct{
? float b,g,r;
} RgbPixelFloat;
typedef Image<RgbPixel>?????? RgbImage;
typedef Image
obj格式簡介
我們經常見到的*.obj文件有兩種:第一種是基于COFF(Common Object File Format)格式的OBJ文件(也稱目標文件),這種格式用于編譯應用程序;第二種是Alias|Wavefront公司推出的OBJ模型文件。我要講的OBJ文件格式是指第二種-OBJ模型文件。 說起3D文件格式,大家一定不會感到陌生,"*.3ds","*.max","*.lw","*.mb","*.dxf","*.obj",相信人人都能列舉出幾種來。但是說起OBJ文件的具體特征,卻很少有人能給出較為圓滿的描述。 很多人認識OBJ文件是從使用Poser開始的,Poser是一款人體建模軟件,要把Poser生成的人體導出到其它3D軟件中進行再加工,就用到了OBJ文件。OBJ文件是一種標準的3D模型文件格式,很適合用于3D軟件模型之間的互導。比如你在3dsMax或LightWave中建了一個模型,想把它調到Maya里面渲染或動畫,導出OBJ文件就是一種很好的選擇。目前幾乎所有知名的3D軟件都支持OBJ文件的讀寫,不過很多軟件需要通過插件才能做到這一點。
另外,作為一種優秀的文件格式,很多游戲引擎也都支持OBJ文件的讀取。 了解OBJ文件格式有什么用呢?如果你不學編程的話,用處確實不大。不過,3D軟件模型之間的互導是一件很常見的事情,不幸的是,目前的3D軟件模型導出功能都不那么完美,經常會出現缺面少線的情況,有時還會遇到導出的模型根本打不開的情況。如果情況非常緊急的話,你一定會不惜一切代價仔細研究,期望找到原因,解決問題。在這種情況下,我的教程也許會對你有很大幫助
OBJ文件是一種文本文件格式,這就意味著你可以直接用寫字板打開進行查看修改,如果你能看懂每一行的內容是什么意思,相信距離你成功的解決問題已經不遠了。
OBJ文件是Wavefront公司為它的一套基于工作站的3D建模和動畫軟件"Advanced Visualizer"開發的一種文件格式。
OBJ新版本是v3.0,代替以前的v2.11版本。
OBJ3.0格式支持多邊形(Polygon),直線(Lines),表面(Surfaces),和自由形態曲線(Free-form Curves)。
直線和多角形通過它們的點來描述,曲線和表面則根據于它們的控制點和依附于曲線類型的額外信息來定義。這些信息支持規則和不規則的曲線,包括那些基于貝塞爾(Bezier)曲線,B樣條(B-spline),基數(Cardinal/Catmull-Rom樣條),和泰勒方程(Taylor equations)的曲線。
OBJ文件 — 特點
(1)OBJ是一種3D模型文件,因此不包含動畫、材質特性、貼圖路徑、動力學、粒子等信息。
(2)OBJ文件主要支持多邊形(Polygons)模型。
(3)OBJ文件支持三個點以上的面。
(4)OBJ文件支持法線和貼圖坐標。
OBJ文件不支持有孔的多邊形面
OBJ文件不包含面的顏色定義信息,不過可以引用材質庫,材質庫信息儲存在一個后綴是".mtl"的獨立文件中。關鍵字"mtllib"即材質庫的意思。材質庫中包含材質的漫射(diffuse),環境(ambient),光澤(specular)的定義值, "usemtl"指定了材質之后,以后的面都是使用這一材質,直到遇到下一個"usemtl"來指定新的材質。
OBJ文件 — 基本結構
OBJ文件由一行行文本組成,注釋行以一個“井”號(#)為開頭,空格和空行可以隨意加到文件中以增加文件的可讀性。有字的行都由一兩個標記字母也就是關鍵字(Keyword)開頭,關鍵字可以說明這一行是什么樣的數據。多行可以邏輯地連接在一起表示一行,方法是在每一行最后添加一個連接符(/)。
注意連接符(/)后面不能出現空格或tab格,否則將導致文件出錯。
下列關鍵字可以在OBJ文件使用。
在這個列表中, 關鍵字根據數據類型排列,每個關鍵字有一段簡短描述。
頂點數據(Vertex data):
v 幾何體頂點 (Geometric vertices)
vt 貼圖坐標點 (Texture vertices)
vn 頂點法線 (Vertex normals)
vp 參數空格頂點 (Parameter space vertices)
自由形態曲線(Free-form curve)/表面屬性(surface attributes):
deg 度 (Degree)
bmat 基礎矩陣 (Basis matrix)
step 步尺寸 (Step size)
cstype 曲線或表面類型 (Curve or surface type)
元素(Elements):
p 點 (Point)
l 線 (Line)
f 面 (Face)
curv 曲線 (Curve)
curv2 2D曲線 (2D curve)
surf 表面 (Surface)
自由形態曲線(Free-form curve)/表面主體陳述(surface body statements):
parm 參數值 (Parameter values )
trim 外部修剪循環 (Outer trimming loop)
hole 內部整修循環 (Inner trimming loop)
scrv 特殊曲線 (Special curve)
sp 特殊的點 (Special point)
end 結束陳述 (End statement)
自由形態表面之間的連接(Connectivity between free-form surfaces):
con 連接 (Connect)
- 成組(Grouping):
g 組名稱 (Group name)
s 光滑組 (Smoothing group)
mg 合并組 (Merging group)
o 對象名稱 (Object name)
- 顯示(Display)/渲染屬性(render attributes):
bevel 導角插值 (Bevel interpolation)
c_interp 顏色插值 (Color interpolation)
d_interp 溶解插值 (Dissolve interpolation)
lod 細節層次 (Level of detail)
usemtl 材質名稱 (Material name)
mtllib 材質庫 (Material library)
shadow_obj 投射陰影 (Shadow casting)
trace_obj 光線跟蹤 (Ray tracing)
ctech 曲線近似技術 (Curve approximation technique)
stech 表面近似技術 (Surface approximation technique)
vs2008 + OpenCV-2.1.0-win32-vs2008安裝
vs2008 + OpenCV-2.1.0-win32-vs2008安裝
1. 安裝vs2008+sp1
2. 安裝opencv-2.1.0-win32-vs2008,假設安裝目錄為c:/opencv2.1。安裝過程中注意選擇添加環境變量,把 “add it to your Current User PATH “前的復選框勾上 .
3. 為vs2008配置openvc,過程如下:
?? 工具->選項->項目和解決方案->vc++目錄,
?????? “顯示一下內容的目錄”下拉列表中選擇“包含文件”,添加條目“C:/OpenCV2.1/include/opencv”;
?????? “顯示一下內容的目錄”下拉列表中選擇“庫文件” ,添加條目“C:/OpenCV2.1/lib”;
?"顯示一下內容的目錄"下拉列表選擇“源文件”,添加條目”C:/OpenCV2.1/src/cv” ,”C:/OpenCV2.1/src/cvaux” ,”C:
/OpenCV2.1/src/cxcore” ,”C:/OpenCV2.1/src/highgui”。
??????? 點擊“確定”。
4. 為單個工程配置運行環境,如:
?? (1) 新建一個win32命令控制臺項目opencvhello
?? (2) 在解決方案資源管理器中右鍵點擊項目名稱opencvhello,選擇“屬性”,
?????? 在“配置(C)”下拉列表中選擇Debug, 然后“配置屬性”->“鏈接器”->“輸入”->附加依賴項,添加??? cxcore210d.lib
cv210d.lib highgui210d.lib
?????? 在“配置(C)”下拉列表中選擇Release, 然后“配置屬性”->“鏈接器”->“輸入”->附加依賴項,添加?? cxcore210.lib
cv210.lib highgui210.lib
?????? 中間如果提示要保存的話,就保存。最后點擊確定。
?? (3) 測試。用下列代碼代替源代碼,注意imagename中保存的是圖片的硬盤地址,程序的運行結果是顯示imagename指向的圖片。
??
/***********************************************************************
?* OpenCV 2.0 測試例程
?* 于仕琪 提供
?***********************************************************************/
?
#include "stdafx.h"
#include "highgui.h"
?
//所有的以新風格命名的函數都在 cv 命名空間中
//如果希望不要每次都輸入 cv:: ,則可使用下面語句
//using namespace cv;
?
int _tmain(int argc, _TCHAR* argv[])
{
?
??? const char* imagename = "E://OpenCV2.1//samples//c//lena.jpg";
?
?cv::Mat img = cv::imread(imagename); // Matlab風格的 cvLoadImage 函數的另一種調用
??? if(img.empty())
??? {
??????? fprintf(stderr, "Can not load image %s/n", imagename);
??????? return -1;
??? }
?
??? if( !img.data ) // 檢查是否正確載入圖像
??????? return -1;
?
?cv::namedWindow("image", CV_WINDOW_AUTOSIZE); //創建窗口
?cv::imshow("image", img); //顯示圖像
?
?cv::waitKey();
?
?return 0;
}