空草子·如何利用QT和opengl進入幻想鄉

  一個優秀的程序員可以賦予人無盡的幻想與深思,也讓人們難以抑制從內心深處迸發的感動。
        他們製造着幻想與華鳥風月之美,製造着只有那裏纔有的誤會、和解與真實。
        虛幻的東西反而帶給人們真實的五感,恐怕這便是二次元存在的意義吧。
        如果硬要說的話,手機、電腦和程序倒也成了二次元的產物呢。
        每天對着二維屏幕上的十幾行代碼傻傻發笑的不正是我們自己嗎?
        因此,那些批判什麼二次元三次元,還總說別人活在自己的世界裏的人,倒是應該照照鏡子纔對。
        更何況,你所看不到的是,在那些碎月與華麗的背後的造幻想之人的痛苦努力。

        我們正視這些幻想,這也是對他人努力成果的一種認可與尊重,難道不是嗎?

 好,今天利用QT和opengl和opencv帶大家進入幻想鄉,確切的說是把幻想鄉帶到現實中來。我們先上效果

其實是利用opengl與opencv完成增強現實。
        虛擬現實是帶人走入虛擬世界,例如3D頭盔、立體眼鏡等;而增強現實則是把虛幻的東西帶到現實中來,就像初音未來的全息演唱會。
        廢話說完了,教你怎麼做。原文的連接放到這裏了。上面只給出了部分代碼,經過完善之後被我實現了,還是很有趣的。
        http://blog.csdn.net/WAmani/article/details/52717844
我們先看一下這個類,需要注意的是繼承。這裏繼承的是QGLWidget而不是public QOpenGLWidget,和protected QOpenGLFunctions
在QGLWidget中,initializeOpenGLFunctions()方法是沒有的,也不需要。而在QOpenGLWideget中必須要用initializeOpenGLFunctions方法來初始化,paintGL()後面也必須調用update函數來防止卡幀。相比較下,QGLWidget卻可以用updateGL();來進行界面刷新。
        這個類中沒有使用外部的opengl庫函數,全部由opengl內部封裝。
#ifndef QSCARLETGLAUGMENTEDREALITY_H
#define QSCARLETGLAUGMENTEDREALITY_H
#include<QOpenGLWidget>
#include<QOpenGLFunctions>
#include<QOpenGLShaderProgram>
#include<QOpenGLBuffer>
#include<QGLWidget>
#include<QPoint>
#include<Eigen/Core>
#include<Eigen/Dense>
#include<QTimer>
#include<vector>
#include<QtOpenGL/QtOpenGL>
#include<opencv.hpp>
using namespace cv;
using namespace std;
//=================繪製增強現實類===============
#define MIN_LENGTH 35
#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480
class QScarletGLAugmentedReality :public QGLWidget//,protected QOpenGLFunctions
{
    //================需要注意的是,繼承方式的不同會導致代碼有很大差別
    Q_OBJECT
public:
    explicit QScarletGLAugmentedReality(QWidget* parent =0);
    ~QScarletGLAugmentedReality();//析構函數
protected:
    //三個重載函數
    void initializeGL();
    void initWidget();
    void paintGL();
    void resizeGL(int ,int );
    void loadGLTextures();//加載紋理
    void mousePressEvent(QMouseEvent *);//鼠標單機事件三態
private:
    //void start();//開始
    //繪製增強現實
    void imageProcess(Mat);
    void initialize_AugmentReality();
    void paint_AugmentReality();
    void resize_AugmentReality(int ,int );

    Mat frame;
    VideoCapture cam,video;
    vector<Point3f> Xworld;
    vector<Point2f> Ximage;
    GLfloat projection_matrix[16];
    vector<GLdouble> rotMatrix;//某一個標記的變換矩陣
    GLdouble rotMat[16];//爲了對應opengl函數格式定義的數組
    //GLdouble *rotMatrix = new GLdouble(16);
    vector<vector<GLdouble> >  RotationMatrix;//將所有的變換矩陣保存同一渲染
    Mat cameraMatrix = Mat(3,3,CV_64FC1,1);
    Mat distCoeffs   = Mat(1,4,CV_64FC1,1);
    //opengl
    QTimer clk;
    //GLfloat m_x, m_y, m_z;
    //GLfloat xx;
    float WINDOW_SIZE;
    //float Z_JUST;
    //int WINDOW_SIZE;
    GLuint m_texture[3];
    GLuint texturImage;
    GLuint texturFrame;

    //鼠標響應
    Mat warpMat;
    Point2f dstRect[4];
    Point2f srcRect[4];
    char number;
    Mat dobotPos = Mat(3, 1, CV_64FC1, Scalar(0, 0, 0));
    Mat dobotTargetPos;
    Point2f dobotFinalTargetPos;//歸一化後位置

private slots:
    void updateWindow();
    //void updateParams(int);
};

然後我們看一下類的實現。我就只粘貼核心代碼了,源碼之後會分享給各位。
 void QScarletGLAugmentedReality::updateWindow()
{
    //qDebug()<<"updateWindow";
    //獲取攝像頭圖像並進行格式轉換
    cam >> frame;
    //cv::imshow("frame",frame);
    //cv::waitKey();
    cvtColor(frame, frame, CV_BGR2RGB);
    for (char i = 0; i < 4; i++)
    {
        circle(frame, srcRect[i], 8, Scalar(255, 0, 0), -1, 8, 0);
    }
    circle(frame, Point(dobotPos.at<double>(0, 0), dobotPos.at<double>(1, 0)), 5, Scalar(0, 255, 255), -1, 8);
    imageProcess(frame);//這個函數主要是對圖像處理,對二維碼進行識別。
    QImage buf, tex;
    //將Mat類型轉換成QImage
    buf = QImage((const unsigned char*)frame.data, frame.cols, frame.rows, frame.cols * frame.channels(), QImage::Format_RGB888);
    tex = QGLWidget::convertToGLFormat(buf);
    glGenTextures(1, &texturFrame);//對應圖片的紋理定義
    glBindTexture(GL_TEXTURE_2D, texturFrame);//進行紋理綁定
    //紋理創建
    glTexImage2D(GL_TEXTURE_2D, 0, 3, tex.width(), tex.height(), 0,
        GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    updateGL();
}
當然,這只是很少一部分代碼,但是它可以幫我們理清思路。
        首先利用opencv攝像頭讀取影像,轉化爲opengl所用的色彩格式,然後進行圖像中的二維碼識別,進行座標轉換,最後用opengl進行繪製。愛我次奧不得不說原文的博主真是忒tm強悍了。順帶說一句,二維碼長成這個樣子。事實上,opencv3.2的contrib模塊中有對這種二維碼進行識別的模塊。也不是很複雜,主要是結合sovePnp函數進行位姿估計。

附上h文件和cpp文件的源碼連接:
http://download.csdn.net/download/qq_30547073/9967390

最後再給大家展示一下本人最新畫作。
沒錯,我想說的是,對某件事物的執着一定可以帶給你力量,它可以讓你獲得忍受一切痛苦與屈辱的能力。
總有一天,你所堅持的事物會像金子一樣閃閃發光。
那時你會被稱爲神明,因爲你做到了其他人永遠做不到的事情。

發佈了41 篇原創文章 · 獲贊 62 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章