在前面的博客中,我们介绍了在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!