基於標記的AR的OpenCV實現:動態視訊輸入
阿新 • • 發佈:2018-12-31
我的上篇部落格《基於標記的AR的OpenCV實現》實現的是單幅圖片的標記檢測和增強現實,稍微改動了程式實現了攝像頭視訊流影象的動態檢測和實時增強,經測試,
實時性不錯,在標記不被遮擋的情況下,繪製的虛擬模型和實時與檢測標記結合,但標記只要有被遮擋一少部分,標記就檢測失敗。
以下講下程式修改部分。
1:show函式並沒有修改,但還是講一下程式流程,首先在main()函式中呼叫show()函式後,在show()函式中,首先完成一些顯示引數的初始化,這部分只需執行一次即可,然後將影象資料讀入pixeldata中,之後通過glutDisplayFunc(&display)呼叫display()函式進行顯示,但請注意, display()函式只會執行一次。glutMainLoop進入GLUT事件處理迴圈。在一個GLUT程式中,這個例程被呼叫一次
。一旦被呼叫,這個程式將永遠不會返回 。它將呼叫必要的任何已註冊的回撥。
int show(const char* filename,int argc, char** argv,Mat_<float>& cameraMatrix, vector<Marker>& detectedMarkers) { //開啟檔案 FILE* pfile=fopen(filename,"rb"); if(pfile == 0) exit(0); //讀取影象大小 fseek(pfile,0x0012,SEEK_SET); fread(&imagewidth,sizeof(imagewidth),1,pfile); fread(&imageheight,sizeof(imageheight),1,pfile); //計算畫素資料長度 pixellength=imagewidth*3; while(pixellength%4 != 0)pixellength++; pixellength *= imageheight; //讀取畫素資料 pixeldata = (GLubyte*)malloc(pixellength); if(pixeldata == 0) exit(0); fseek(pfile,54,SEEK_SET); fread(pixeldata,pixellength,1,pfile); //以上是讀取一個bmp影象寬高和影象資料的操作 //關閉檔案 fclose(pfile); build_projection(cameraMatrix); //這是建立攝像機內參數矩陣,就是相機矩陣,display函式開始匯入的模型就是相機矩陣 setMarker(detectedMarkers); //匯入找到的標識 //初始化glut執行 glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(imagewidth,imageheight); glutCreateWindow(filename); glutDisplayFunc(&display); glutMainLoop(); //------------------------------------- free(pixeldata); return 0; }
2:為了實現display()函式的迴圈呼叫,執行glutPostRedisplay();語句會觸發一次display()的執行,有兩種思路:1:設定一個定時器,定時執行glutPostRedisplay();從而週期性
呼叫display()函式;2:在display()函式體最後執行glutPostRedisplay();從而完成自我不斷觸發呼叫。我採用了思路2的做法成功實現,思路1原理上也可實現。
主要修改display()函式。#if 1---#endif為新增部分,主要是更新影象資料,並執行markerDetector.processFrame(src,camMatrix, distCoeff,markers);從而得到更新後標記。
pixeldata的更新還是採用show()函式中讀影象檔案的方法,因此先將從攝像頭讀入影象儲存為一個臨時圖片檔案"aa.bmp",在用fread()讀入的方式,這種方法確實比較low,
但比較容易實現了想要達到的效果。
void display(void)
{
#if 1
Mat src;
camera >> src;
imwrite("aa.bmp",src);
//開啟檔案
FILE* pfile=fopen("aa.bmp","rb");
if(pfile == 0) exit(0);
fseek(pfile,54,SEEK_SET);
fread(pixeldata,pixellength,1,pfile);
//以上是讀取一個bmp影象寬高和影象資料的操作
//關閉檔案
fclose(pfile);
double t = (double)getTickCount();
markerDetector.processFrame(src,camMatrix, distCoeff,markers);
t = ((double)getTickCount() - t)/getTickFrequency();
cout<<"t"<<t<<endl;
setMarker(markers); //匯入找到的標識
#endif
cout<<"display"<<endl;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//繪製圖片,第一、二、三、四個引數表示圖象寬度、圖象高度、畫素資料內容、畫素資料在記憶體中的格式,最後一個引數表示用於繪製的畫素資料在記憶體中的位置
glDrawPixels(imagewidth,imageheight,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixeldata);
/*
glMatrixMode - 指定哪一個矩陣是當前矩陣
glMatrixMode設定當前矩陣模式:
GL_MODELVIEW,對模型視景矩陣堆疊應用隨後的矩陣操作.
GL_PROJECTION,對投影矩陣應用隨後的矩陣操作.
GL_TEXTURE,對紋理矩陣堆疊應用隨後的矩陣操作.
與glLoadIdentity()一同使用
glLoadIdentity():該函式的功能是重置當前指定的矩陣為單位矩陣。
在glLoadIdentity()之後我們為場景設定了透檢視。glMatrixMode(GL_MODELVIEW)設定當前矩陣為模型檢視矩陣,模型檢視矩陣儲存了有關物體的資訊。
*/
//繪製座標 ,匯入相機內參數矩陣模型
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projectionMatrix.data);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY); //啟用客戶端的某項功能
glEnableClientState(GL_NORMAL_ARRAY);
glPushMatrix();
glLineWidth(3.0f);
float lineX[] = {0,0,0,1,0,0};
float lineY[] = {0,0,0,0,1,0};
float lineZ[] = {0,0,0,0,0,1};
const GLfloat squareVertices[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
};
const GLubyte squareColors[] = {
255, 255, 0, 255,
0, 255, 255, 255,
0, 0, 0, 0,
255, 0, 255, 255,
};
for (size_t transformationIndex=0; transformationIndex<m_detectedMarkers.size(); transformationIndex++)
{
const Transformation& transformation = m_detectedMarkers[transformationIndex].transformation;
Matrix44 glMatrix = transformation.getMat44();
//匯入相機外引數矩陣模型
glLoadMatrixf(reinterpret_cast<const GLfloat*>(&glMatrix.data[0])); //reinterpret_cast:任何型別的指標之間都可以互相轉換,修改了運算元型別,僅僅是重新解釋了給出的物件的位元模型而沒有進行二進位制轉換
glVertexPointer(2, GL_FLOAT, 0, squareVertices); //指定頂點陣列的位置,2表示每個頂點由三個量構成(x, y),GL_FLOAT表示每個量都是一個GLfloat型別的值。第三個引數0。最後的squareVertices指明瞭陣列實際的位置。這個squareVertices是由第一個引數和要畫的圖形有幾個頂點決定大小,理解。
glEnableClientState(GL_VERTEX_ARRAY); //表示啟用頂點陣列
glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors); //RGBA顏色,四個頂點
glEnableClientState(GL_COLOR_ARRAY); //啟用顏色陣列
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
float scale = 0.5;
glScalef(scale, scale, scale);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, lineX);
glDrawArrays(GL_LINES, 0, 2);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, lineY);
glDrawArrays(GL_LINES, 0, 2);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, lineZ);
glDrawArrays(GL_LINES, 0, 2);
}
glFlush();
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glutSwapBuffers();
glutPostRedisplay();
}
本部落格所改程式碼為mastering opencv with practical computer vision projects 第二章書中程式碼。
我實現的程式碼已上傳到,需要的自行下載。