简洁的OpenGL窗口截图——opengl+opencv实现

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

发表评论