search
LoginSignup
32

More than 5 years have passed since last update.

posted at

updated at

PythonでOpenCVの画像をOpenGLで表示する

はじめに

OpenCVは非常に便利な画像処理のライブラリであるが,画像の描画はあまり得意ではないようである。また,imshowで表示すると,waitKey(1)が引数に関係なく15ms程度は少なくともかかるようで,60fps程度が上限になってしまうといえる。
http://13mzawa2.hateblo.jp/entry/2015/12/28/180021
3Dモデルを表示する場合や,高速なフレームレートで表示したい場合はOpenGLを使うのが良いみたいである。
Pythonでのコードがあまり見つからなかったのでメモしておく。

OpenCVの画像をOpenGLで表示

OpenCVの画像をOpenGLで表示するためには,glDrawPixelsでnumpy配列をOpenGLに渡すのが最もてっ取り早い。
https://qiita.com/smygw72/items/90bfe55a9eae5989d4bf
cap.read()で読み込んだnumpy配列をOpenGLの座標に合わせて上下反転し,BGRをRGBに変換してからglDrawPixelsで渡してやる。


from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import cv2
import numpy as np

# USB camera setup
cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
    raise("IO Error")
cap.set(cv2.CAP_PROP_FPS, 30)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 720)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

widowWidth = 720
windowHeight = 480

def draw():
    ret, img = cap.read() #read camera image
    #img = cv2.imread('image.png') # if use the image file
    img = cv2.flip(img, 0)
    img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #BGR-->RGB

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)

    glDrawPixels(img.shape[1], img.shape[0], GL_RGB,GL_UNSIGNED_BYTE, img)

    glFlush();
    glutSwapBuffers()

def init():
    glClearColor(0.7, 0.7, 0.7, 0.7)

def idle():
    glutPostRedisplay()

def reshape(w, h):
    glViewport(0, 0, w, h)
    glLoadIdentity()
    #Make the display area proportional to the size of the view
    glOrtho(-w / widowWidth, w / widowWidth, -h / windowHeight, h / windowHeight, -1.0, 1.0)

def keyboard(key, x, y):
    # convert byte to str
    key = key.decode('utf-8')
    # press q to exit
    if key == 'q':
        print('exit')
        sys.exit()

if __name__ == "__main__":

    glutInitWindowPosition(0, 0);
    glutInitWindowSize(widowWidth, windowHeight);
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE )
    glutCreateWindow("Display")
    glutDisplayFunc(draw)
    glutReshapeFunc(reshape)
    glutKeyboardFunc(keyboard)
    init()
    glutIdleFunc(idle)
    glutMainLoop()

しかし,上記のコードで表示して処理時間を測ってみると(カメラ読み込みではカメラのフレームレートに依存するためpng画像の読み込みで)あまり早くない。

調べてみると,glDrawPixelsは遅いらしい。テクスチャを貼り付ける形で表示すると早いらしいので,下記のコードのようにするのがおすすめである。画像はglTexImage2Dでテクスチャに変換するが,この場合上下反転する必要がなかった。

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import cv2
import numpy as np
import time

start = time.time()

# USB camera setup
cap = cv2.VideoCapture(0)
if cap.isOpened() is False:
    raise("IO Error")
cap.set(cv2.CAP_PROP_FPS, 30)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 720)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

widowWidth = 720
windowHeight = 480

def draw():
    # Paste into texture to draw at high speed
    ret, img = cap.read() #read camera image
    #img = cv2.imread('image.png') # if use the image file
    img= cv2.cvtColor(img,cv2.COLOR_BGR2RGB) #BGR-->RGB
    h, w = img.shape[:2]
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, img)

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glColor3f(1.0, 1.0, 1.0)

    # Enable texture map
    glEnable(GL_TEXTURE_2D)
    # Set texture map method
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    # draw square
    glBegin(GL_QUADS) 
    glTexCoord2d(0.0, 1.0)
    glVertex3d(-1.0, -1.0,  0.0)
    glTexCoord2d(1.0, 1.0)
    glVertex3d( 1.0, -1.0,  0.0)
    glTexCoord2d(1.0, 0.0)
    glVertex3d( 1.0,  1.0,  0.0)
    glTexCoord2d(0.0, 0.0)
    glVertex3d(-1.0,  1.0,  0.0)
    glEnd()

    glFlush();
    glutSwapBuffers()

def init():
    glClearColor(0.7, 0.7, 0.7, 0.7)

def idle():
    glutPostRedisplay()

def reshape(w, h):
    glViewport(0, 0, w, h)
    glLoadIdentity()
    #Make the display area proportional to the size of the view
    glOrtho(-w / widowWidth, w / widowWidth, -h / windowHeight, h / windowHeight, -1.0, 1.0)

def keyboard(key, x, y):
    # convert byte to str
    key = key.decode('utf-8')
    # press q to exit
    if key == 'q':
        print('exit')
        sys.exit()

if __name__ == "__main__":

    glutInitWindowPosition(0, 0);
    glutInitWindowSize(widowWidth, windowHeight);
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE )
    glutCreateWindow("Display")
    glutDisplayFunc(draw)
    glutReshapeFunc(reshape)
    glutKeyboardFunc(keyboard)
    init()
    glutIdleFunc(idle)
    glutMainLoop()

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
32