开发环境:centos 7 | CLion | OpenCV 2.4.13 | gcc 4.8.5
之前在QT环境中实现过增强现实技术,主要是借用QT环境中的OpenGL模块实现增强现实效果,而OpenCV可以重新编译进而支持OpenGL,因此采用新的方法将之前的demo重新实现一遍《之前基于opencv与QT实现的增强现实博客》。另一方面,之前的工程采用的VS开发环境移植性很差,因此这里在linux开发环境下重新实现并将代码上传至github供各位参考。
在linux环境下对opencv源码进行编译,并开启opengl,具体见博客《OPENCV 支持OpenGL》。
配置好环境后可以用一个opengl的demo进行测试:
#include
#include
using namespace cv;
void onDraw(void* param)
{
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glRectf(-0.5f, -0.5f, 0.5f, 0.5f);
glFlush();
}
int main(void)
{
string openGLWindowName = "OpenGLDemo";
namedWindow(openGLWindowName, WINDOW_OPENGL);
resizeWindow(openGLWindowName, 640, 480);
setOpenGlContext(openGLWindowName);
setOpenGlDrawCallback(openGLWindowName, onDraw, NULL);
waitKey(0);
updateWindow(openGLWindowName);
waitKey(0);
return 0;
}
之后基于回调函数即可实现对OpenGL窗口的渲染,在C++中由于类间函数在调用时有默认隐藏的this指针参数,因此需要将回调函数设置为友元函数或者使用静态函数来实现。
friend void render(void *prama);
通过配置projection matrix 和 modelview matrix (对应相机的内参外参)实现对相机位置的计算。另一点困惑我比较久的是在渲染3D物体的时候,窗口中的图像背景就不显示了,在这里更新背景纹理的时候要更新projection matrix,与渲染3D物体的时候projection matrix为摄像头外参是不同的,具体可以参考代码中实现。
void OpenGLModule::XOpenGLModule::RenderBackgroundTexture() {
cv::Mat img = image_texture;
//OpenGL纹理用整型数表示
GLuint texture_ID;
float w = img.cols;
float h = img.rows;
// GLubyte* pixels;
//
// //获取图像指针
// int pixellength = width*height * 3;
// pixels = new GLubyte[pixellength];
// memcpy(pixels, img, pixellength * sizeof(char));
// imshow("OpenCV", img);
//将texture_ID设置为2D纹理信息
glGenTextures(1, &texture_ID);
glBindTexture(GL_TEXTURE_2D, texture_ID);
//纹理放大缩小使用线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//纹理水平竖直方向外扩使用重复贴图
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 纹理水平竖直方向外扩使用边缘像素贴图(与重复贴图二选一)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, texture_ID);
//将图像内存用作纹理信息
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, img.data);
const GLfloat bgTextureVertices[] = { 0, 0, w, 0, 0, h, w, h };
const GLfloat bgTextureCoords[] = { 1, 0, 1, 1, 0, 0, 0, 1 };
const GLfloat proj[] = { 0, -2.f / w, 0, 0, -2.f / h, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1 };
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(proj);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_ID);
// Update attribute values.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, bgTextureVertices);
glTexCoordPointer(2, GL_FLOAT, 0, bgTextureCoords);
glColor4f(1, 1, 1, 1);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glDeleteTextures(1,&texture_ID);
}
标记与之前博客中的方法一样,主要检测7*7方块中第二圈中不为黑色或者不为白色的方块。标记与效果图如下:
最后附代码地址:点击下载。