在前面的博客中,我们介绍了在MFC中使用OpenGL绘图,现在我们需要将OpenGL窗口中所展示的图形绘制出来,或者保存为图像,坊间使用的很多代码都过于复杂,冗余的代码都浪费在了手写Bmp格式,内存数据格式转换等问题上。我们通常需要简洁强大且高校的代码,于是opencv库成为了我们的首选,并将这些功能封装在类中使得其易于使用。感谢这篇博客的内容,建立了glGraber类,使得我们可以摆脱繁重的代码,特此收录。
代码被封装在了glGraber类中,我们在这里给出了类的代码:
#ifndef GL_GRABER_H_ #define GL_GRABER_H_ #include <opencv2\opencv.hpp> #include <GL\GL.h> class glGraber { public: glGraber(); ~glGraber(); void glGrab(); void saveColorImg(std::string& _str); private: GLbyte* colorArr; GLint viewPort[4]; cv::Size win; }; #endif
#include "stdafx.h" #include "glGraber.h" glGraber::glGraber() { colorArr = NULL; } glGraber::~glGraber() { if (colorArr != NULL){ delete[] colorArr; colorArr = NULL; } } void glGraber::glGrab() { glGetIntegerv(GL_VIEWPORT, viewPort); if (colorArr != NULL){ delete[] colorArr; colorArr = NULL; } win.width = viewPort[2]; win.height = viewPort[3]; colorArr = new GLbyte[4 * win.area()]; glReadPixels(viewPort[0], viewPort[1], viewPort[2], viewPort[3], GL_RGBA, GL_UNSIGNED_BYTE, colorArr); } void glGraber::saveColorImg(std::string & str){ cv::Mat img; std::vector<cv::Mat> imgPlanes; img.create(win.height, win.width, CV_8UC3); cv::split(img, imgPlanes); for (int i = 0; i < win.height; i++) { UCHAR* plane0Ptr = imgPlanes[0].ptr<UCHAR>(i); UCHAR* plane1Ptr = imgPlanes[1].ptr<UCHAR>(i); UCHAR* plane2Ptr = imgPlanes[2].ptr<UCHAR>(i); for (int j = 0; j < win.width; j++) { int k = 4 * (i * win.width + j); // RGBA plane2Ptr[j] = colorArr[k]; plane1Ptr[j] = colorArr[k + 1]; plane0Ptr[j] = colorArr[k + 2]; } } cv::merge(imgPlanes, img); cv::flip(img, img, 0); if (str.length() == 0){ str = "untitled.jpg"; } cv::imwrite(str.c_str(), img); }
于是我们使用这个类进行截图就需要如下两个步骤:先是抓取绘图区像素到内存,然后是保存内存中数据到图片
void COpenGLControl::SnapShot(){ std::string name = "temp.png"; Graber m_snap; m_snap.glGrab(); m_snap.saveColorImg(name); }
当然,你可以进一步完善这个类,使它更加强大。
OK, See You Next Chapter!