I am trying to save texture to a image using SOIL2 library.
int _width, _height;
unsigned char* _image = SOIL_load_image("C:\\Temp\\RED.png", &_width, &_height, 0, SOIL_LOAD_RGB);
int save_result = SOIL_save_image
(
"C:\\temp\\atlas.png",
SOIL_SAVE_TYPE_PNG,
_width, _height, GL_RGB,
_image
);
But image does not gets saved the return values from the saved function is 0.
In my case (GL_RGBA) I needed to set the channels parameter to 4 (not GL_RGBA) to get it working. In your case, you probably need to change it to 3 (not GL_RGB).
Related
With Qt, I am trying to convert a Format_Indexed8 image to Format_RGB30 by using a custom conversion rule defined by a color table. I thought this would be simple, since QImage::convertToFormat can take a color table as an argument, but I can't make it work.
Here is my code:
QImage image = QImage(data, width, height, QImage::Format_Indexed8);
QVector<QRgb> colorTable(256);
for (int i = 0; i < 255; i++)
colorTable[i] = qRgb(255 - i, i, i);
image = image.convertToFormat(QImage::Format_RGB30, colorTable);
This code just gives me an image that is in RGB format, but that looks identical to the eye to the grayscale image.
I think the color table argument in QImage::convertToFormat is required to convert from RGB to indexed, while you're converting the other way around.
I would try setting the color table directly in the indexed file (source), using QImage::setColorTable, then call convertToFormat passing the format argument only:
QImage image = QImage(data, width, height, QImage::Format_Indexed8);
image.setColorTable(colorTable);
image = image.convertToFormat(QImage::Format_RGB30);
This is not necessary since Qt 5.5 (released in July of 2015). You can now use QImage::Format_Grayscale8. Your code would be simply:
QImage image{data, width, height, QImage::Format_Grayscale8};
I am trying convert a RGB image into YUV.
I am loading image using openCV.
I am calling the function as follows:
//I know IplImage is outdated
IplImage* im = cvLoadImage("1.jpg", 1);
//....
bgr2yuv(im->imageData, dst, im->width, im->height);
the function to convert Color image to yuv image is given below.
I am using ffmpeg to do that.
void bgr2yuv(unsigned char *src, unsigned char *dest, int w, int h)
{
AVFrame *yuvIm = avcodec_alloc_frame();
AVFrame *rgbIm = avcodec_alloc_frame();
avpicture_fill(rgbIm, src, PIX_FMT_BGR24, w, h);
avpicture_fill(yuvIm, dest, PIX_FMT_YUV420P, w, h);
av_register_all();
struct SwsContext * imgCtx = sws_getCachedContext(imgCtx,
w, h,(::PixelFormat)PIX_FMT_BGR24,
w, h,(::PixelFormat)PIX_FMT_YUV420P,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale(imgCtx, rgbIm->data, rgbIm->linesize,0, h, yuvIm->data, yuvIm->linesize);
av_free(yuvIm);
av_free(rgbIm);
}
I am getting wrong output after conversion.
I am thinking this is due to padding happening in the IplImage.
(My input image width is not multiple of 4).
I updated linesize variable even after that I am not getting correct output.
Its working fine when I am using images whose width is multiple of 4.
Can anybody tell what is the problem in the code.
Check IplImage::align or IplImage::widthStep and use these to set AVFrame::linesize. For the RGB frame, for example, you would set:
frame->linesize[0] = img->widthStep;
The layout of the dst array can be whatever you want, it depends on how you're using it afterwards.
We need to do as follows:
rgbIm->linesize[0] = im->widthStep;
But I think output data from sws_scale() is not padded to make it multiple of 4.
So when you are copying this data (dest) again to IplImage this will
create problem in displaying, saving etc..
So we need to set widthStep=width as follows:
IplImage* yuvImage = cvCreateImageHeader(cvGetSize(im), 8, 1);
yuvImage->widthStep = yuvImage->width;
yuvImage->imageData = dest;
I want to transfer opengl framebuffer data to AVCodec as fast as possible.
I've already converted RGB to YUV with shader and read it with glReadPixels
I still need to fill AVFrame data manually. Is there any better way?
AVFrame *frame;
// Y
frame->data[0][y*frame->linesize[0]+x] = data[i*3];
// U
frame->data[1][y*frame->linesize[1]+x] = data[i*3+1];
// V
frame->data[2][y*frame->linesize[2]+x] = data[i*3+2];
You can use sws_scale.
In fact, you don't need shaders for converting RGB->YUV. Believe me, it's not gonna have a very different performance.
swsContext = sws_getContext(WIDTH, HEIGHT, AV_PIX_FMT_RGBA, WIDTH, HEIGHT, AV_PIX_FMT_YUV, SWS_BICUBIC, 0, 0, 0 );
sws_scale(swsContext, (const uint8_t * const *)sourcePictureRGB.data, sourcePictureRGB.linesize, 0, codecContext->height, destinyPictureYUV.data, destinyPictureYUV.linesize);
The data in destinyPictureYUV will be ready to go to the codec.
In this sample, destinyPictureYUV is the AVFrame you want to fill up. Try to setup like this:
AVFrame * frame;
AVPicture destinyPictureYUV;
avpicture_alloc(&destinyPictureYUV, codecContext->pix_fmt, newCodecContext->width, newCodecContext->height);
// THIS is what you want probably
*reinterpret_cast<AVPicture *>(frame) = destinyPictureYUV;
With this setup you CAN ALSO fill up with the data you already converted to YUV in the GPU if you desire... you can choose the way you want.
I want to take screenshot from OpenGL window and save it to image file of any type. DevIL method described here gives correct PNG. Replace ilSaveImage with ilSave and you can save image in different formats. SOIL method here gives flipped vertically image. Replacing code below
vector< unsigned char > buf( w * h * 3 );
glPixelStorei( GL_PACK_ALIGNMENT, 1 );
glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buf[0] );
int err = SOIL_save_image ("img.bmp", SOIL_SAVE_TYPE_BMP, w, h, 3, &buf[0]);
with only one line creates the correct image.
int err = SOIL_save_screenshot("img.bmp",SOIL_SAVE_TYPE_BMP, 0, 0, w, h);
Q1: Is any more convenient alternatives using other libraries?
Q2: Which one is the best way? Comparison is appreciated e.g. performance\compatibility.
I am trying to create a gl::Texture object using image data as a BYTE * with the parameters below.
FreeGLUT - I use this to create a 2d texture and bind it to a quad.:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0); etc etc
This works fine, however I cannot find a way to create a gl::Texture object in Cinder.
text = gl::Texture(loadImage(loadAsset("text.jpg"))); // works with images files
text = gl::Texture(data, GL_RGBA8, 640, 480); // BTYE * data This gives me a grey screen -
This seemed the most likely, however I have no idea what to do with Format format = format();
Texture (const unsigned char *data, int dataFormat, int aWidth, int aHeight, Format format=Format())
I really have no understanding of how this works and cant find any better tutorials online. Thanks.
apparently dataFormat is the format parameter to glTexImage2D and should be something like GL_RGBA or GL_RGB (or GL_BGRA_EXT as in the example you provided)
What you want is the "internal format" which is set via the Format struct. So you set it like:
gl::Texture::Format fmt;
fmt.setInternalFormat(GL_RGBA8);
text = gl::Texture(data, GL_RGBA, 640, 480, fmt);
The GL_UNSIGNED_BYTE format is pre-set in that constructor of the cinder wrapper
Sometimes it can be easier to just look at the code instead of trying to find the 100% applicable documentation