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:
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:
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();
}
Adding the following two lines solved this problem.
glPixelStorei (GL_UNPACK_ALIGNMENT, Image->align);
glPixelStorei (GL_UNPACK_ROW_LENGTH, Image->widthStep / Image->nChannels);
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.
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D (GL_TEXTURE_2D, 0, 3, Image->width, Image->height, 0, GL_BGR, GL_UNSIGNED_BYTE, Image->imageData);
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.