Question

I am trying to display video on two screen at the same time using OpenGL/GLFW and OpenCV. When I test my code on my laptop (mid 2010 13" Macbook Pro) and an external screen the program works just fine (minus the fact the video plays at a very fast FPS - anyone who can also solve this problem would be very helpful. Also its upside down, but OpenCV can flips things just fine.) But when I move my code to a early 2008 Mac Pro and run the code the image does not seem to texture correctly. Image below:

The three color channels take up different columns

For some reason the three color records are split in different columns and the framing isn't right. This is what it should look like:

Better image

The placement of the images doesn't matter that is just because of the difference in the size of the screens. I was wondering if anyone has seen this problem before and if it could simply be a problem with how I am calling glTexImage2D? Posted below is the code I am using.

#include <stdio.h>
#include <string.h>

#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/imgproc/imgproc.hpp>

#include <GLFW/glfw3.h>
#include <GLUT/glut.h>

#define VIEWPORT_WIDTH              1280
#define VIEWPORT_HEIGHT             800
#define KEY_ESCAPE                  27

CvCapture* capture;
GLFWwindow* window1;
GLFWwindow* window2;
IplImage *image;
static GLuint texName;

void initTexture(IplImage* Image);
void applyTexture(int img_width, int img_height);
void loadImage(IplImage*, GLFWwindow* window);

int main(int argc, char* argv[])
{

    if (!glfwInit())
        exit(EXIT_FAILURE);

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);

    int count;
    GLFWmonitor** monitors = glfwGetMonitors(&count);
    window1 = glfwCreateWindow(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, "Simple example1", monitors[0], NULL);
    window2 = glfwCreateWindow(VIEWPORT_WIDTH, VIEWPORT_HEIGHT, "Simple example2", monitors[1], NULL);

    capture = cvCaptureFromAVI("../VideoTexture/movie.mov");
    assert(capture);
    // Initialize OpenGL
    glfwMakeContextCurrent(window1);


    while (!glfwWindowShouldClose(window1))
    {
            image = cvQueryFrame(capture);
    if(!cvGrabFrame(capture)){              // capture a frame 
        printf("Could not grab a frame\n\7");
        exit(0);
    }


        glfwMakeContextCurrent(window1);
        loadImage(image, window1);
        glfwMakeContextCurrent(window2);
        loadImage(image, window2);

    }


    return 0;


}

void initTexture(IplImage *Image)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);

    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, 3, Image->width, Image->height, 0, GL_BGR, GL_UNSIGNED_BYTE, Image->imageData);
}

void applyTexture(int img_width, int img_height)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glBindTexture(GL_TEXTURE_2D, texName);
    glBegin(GL_QUADS);
    glTexCoord2f(0, 0); glVertex3f(VIEWPORT_WIDTH /2, VIEWPORT_HEIGHT/2, 0);
    glTexCoord2f(0, 1); glVertex3f(VIEWPORT_WIDTH /2, VIEWPORT_HEIGHT/2+img_height, 0);
    glTexCoord2f(1, 1); glVertex3f(VIEWPORT_WIDTH /2+img_width, VIEWPORT_HEIGHT/2+img_height, 0);
    glTexCoord2f(1, 0); glVertex3f(VIEWPORT_WIDTH /2+img_width, VIEWPORT_HEIGHT/2, 0);
    glEnd();
    glFlush();
    glDisable(GL_TEXTURE_2D);
}

void loadImage(IplImage *Image, GLFWwindow* window)
{
    initTexture(Image);
    glViewport(0, 0, VIEWPORT_WIDTH , VIEWPORT_HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, VIEWPORT_WIDTH , 0, VIEWPORT_HEIGHT, -1, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    applyTexture(Image->width,Image->height);
    glfwSwapBuffers(window);
    glfwPollEvents();
}

Solved:

Adding the following two lines solved this problem.

glPixelStorei (GL_UNPACK_ALIGNMENT,  Image->align);
glPixelStorei (GL_UNPACK_ROW_LENGTH, Image->widthStep / Image->nChannels);
Was it helpful?

Solution

You need to set the pixel unpack/pack alignment to 1 when you send/read RGB image to/from GL. By default GL is going to read your image data as if each row were aligned to a 4-byte boundary, and clearly with tightly packed (8-bit) RGB that is not the case.

This should fix at least part of your problem:

glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D  (GL_TEXTURE_2D, 0, 3, Image->width, Image->height, 0, GL_BGR, GL_UNSIGNED_BYTE, Image->imageData);


Update:

The IplImage data structure provides all of the fields that you need in order to do this portably:

glPixelStorei (GL_UNPACK_ALIGNMENT,  Image->align);
glPixelStorei (GL_UNPACK_ROW_LENGTH, Image->widthStep / Image->nChannels);
glTexImage2D  (GL_TEXTURE_2D, 0, 3,  Image->width, Image->height, 0, GL_BGR, GL_UNSIGNED_BYTE, Image->imageData);

The fundamental issue is the same, however. It comes down to differences in image data alignment between the two machines.

As for your image being upside down, have a look at the origin field of the IplImage struct. You need to compensate for that yourself. GL does not have the ability to flip images during pixel transfer, unfortunately.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top