OpenCV image loading for OpenGL Texture
From only looking at your texture loading code you are ignoring many considerations about how OpenCV lays out images in memory. I've already explained that for the opposite direction (glGetTexImage
into OpenCV image) in this answer, but will recapitulate it here for the CV-GL direction:
First of all OpenCV doesn't neccessarily store image rows tightly packed but might align them to certain byte boundaries (don't know how much, at least 4, but maybe 8 or more?). If you're lucky it will use 4-byte alignment and the GL is set to the default pixel storage mode of 4-byte alignment, too. But it's best to manually fiddle with the pixel storage modes in order to be on the safe side:
//use fast 4-byte alignment (default anyway) if possible
glPixelStorei(GL_UNPACK_ALIGNMENT, (image.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn't need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH, image.step/image.elemSize());
Then you have to account for the fact that OpenCV stores images from top to bottom, while the GL uses bottom to top. This could be taken care of by just mirroring the t-texture coordinate appropriately (maybe directly in the shader), but you could also just flip the image before uploading:
cv::flip(image, flipped, 0);
image = flipped; //maybe just cv::flip(image, image, 0)?
Last but not least OpenCV stores color images in BGR format so uploading it as RGB would distort the colors. So use GL_BGR
(requires OpenGL 1.2, but who doesn't have that?) in glTexImage2D
.
These might not be the complete solution to your problem (since I think those errors should rather result in a distorted rather than a black image), but they are definitely problems to take care of.
EDIT: Does your fragment shader actually compile successfully (in the complete version using the texture)? I'm asking because in the GLSL 3.30 you're using the word texture
is also the name of a builtin function (which should actually be used instead of the deprecated texture2D
function), so maybe the compiler has some name resolution problems (and maybe this error is ignored in your simplified shaders, given that the whole uniform will be optimized away and many GLSL compilers are known to be anything else than strictly standard compliant). So just try to give that sampler uniform a different name.
Loading texture for OpenGL with OpenCV
Your error appears there, right?
if( texture_cv = imread("stones.jpg")) {
because in if(expr)
expr must be bool
or can be casted to bool
. But there is no way to convert cv::Mat
into boolean implicitly. But you can check the result of imread
like that:
texture_cv = imread("stones.jpg");
if (texture_cv.empty()) {
// handle was an error
} else {
// do right job
}
See: cv::Mat::empty(), cv::imread
Hope that helped you.
Passing grayscale OpenCV image to an OpenGL texture
input format
I'd use GL_RED, since the GL_LUMINANCE format has been deprecated
internalFormat
depends on what you want to do in your shader, although you should always specify a sized internal format, e.g. GL_RGBA8 which gives you 8 bits per channel. Although, with GL_RGBA8, the green, blue and alpha channels will be zero anyway since your input data only has a single channel, so you should probably use the GL_R8 format instead. Also, you can use texture swizzling:
GLint swizzleMask[] = {GL_RED, GL_RED, GL_RED, GL_RED};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
which will cause all channels to 'mirror' the red channel when you access the texture in the shader.
OpenCV IplImage *Image to OpenGL GLuint texture
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.
OpenGL render to a OpenCV mat as texture and reuse it in OpenCV
So I solved my problem, which I should have posted more code to make an answer easier, by adding a VertexBufferObject which I totally ignored from the tutorial. Also and this is very important, I use SFML lib at the same time to display my frames. SFML also uses OpenGL internally. So I need to save and restore the OpenGL states which interfere with eachother.
I drop this link in case somebody has similar problems:
using-opengl-together-with-the-graphics-module
This added state save/restore before I use SFML together with the missing VAO code and a reset of OpenGL bindings after my Draw() method made it work. This might not be the most performant solution but for now it is a way to achieve what I needed.
Texture isn't loading properly OpenGL
The association of the texture coordinates to the vertices is wrong. Change to:
float vertices[] =
{
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _min.y, 1.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _min.y, 0.0f, 1.0f,
_max.x, _max.y, 1.0f, 0.0f,
_min.x, _max.y, 0.0f, 0.0f,
};
By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes.
This is because the GL_UNPACK_ALIGNMENT
parameter by default is 4. When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4 this may cause a misalignment.
Change the alignment by setting the GL_UNPACK_ALIGNMENT
to 1, before specifying the texture image with glTexImage2D
:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
When you remove glGenerateMipmap(GL_TEXTURE_2D);
, then you have to change the minifying function (GL_TEXTURE_MIN_FILTER
) as well. Since the filter is GL_LINEAR_MIPMAP_LINEAR
, the texture would be "Mipmap Incomplete" if you do not change the minimize function to GL_NEAREST
or GL_LINEAR
.
OpenCV webcam frames to OpenGL texture
Drawing a rectangle bounding the GLControl
solved it:
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0, 0); GL.Vertex2(0, 0);
GL.TexCoord2(0, 1); GL.Vertex2(0, 1);
GL.TexCoord2(1, 1); GL.Vertex2(1, 1);
GL.TexCoord2(1, 0); GL.Vertex2(1, 0);
GL.End();
m.Dispose();
Be sure to dispose the object after drawing the frame so you will not run out of memory.
Related Topics
What Strategies Have You Used to Improve Build Times on Large Projects
How to Get a List of Files in a Folder in Which the Files Are Sorted with Modified Date Time
Template Tricks with Const Char* as a Non-Type Parameter
Reshaping a 1-D Array to a Multidimensional Array
Converting Cv::Mat for Tesseract
Ensuring C++ Doubles Are 64 Bits
Why Does Enumwindows Return More Windows Than I Expected
Why Can't I Put a Variable Declaration in the Test Portion of a While Loop
Is There a Reason to Use Enum to Define a Single Constant in C++ Code
Sign Changes When Going from Int to Float and Back
This Declaration Has No Storage Class or Type Specifier in C++
Alternative to C++ Static Virtual Methods
What's the Difference Between New Char[10] and New Char(10)
C++ Unified Assignment Operator Move-Semantics
How to Pan Images in Qgraphicsview
Qt 4.X: How to Implement Drag-And-Drop Onto the Desktop or into a Folder