I have been attempting to work with SDL and openGL for a project Im working on, and to enable easy testing, I would like to be able to draw in 2D to the screen and the only way I have found to allow me to do this is SDL surfaces to create and draw BMP images. This is fine as being able to save the image will be a nice feature later on but if there is another better way to do this with openGL or some other method, please say :).
This is the code I am currently using:
int w = 255;
int h = 255;
SDL_Surface* surface = SDL_CreateRGBSurface(0,w,h,32,0,0,0,0);
SDL_LockSurface(surface);
int bpp = surface->format->BitsPerPixel;
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
Uint32 *p = (Uint32 *)surface->pixels + (i * surface->pitch) + (j * bpp);
*p = SDL_MapRGB(surface->format,i,j,i);
}
}
SDL_UnlockSurface(surface);
SDL_SaveBMP(surface, "Test.bmp");
This is just a basic test thing to allow me to get to terms with how to do this, Im sure I have some issues with memory handling here but Im not sure when if at all to delete *p. The issue that I am having the biggest problem with though is where I use SDL_MapRGB. the program crashes when it hits this with a SIGSEGV segmentation fault and I cant figure out what I am doing wrong.
You do not free the memory pointed by p.
But after use, you have to free the surface as
SDL_FreeSurface(surface);
Also, bpp is in bits. You have to divide it by 8 to get it in bytes.
And, to do arithmetic in bytes, you have to use
Uint32 *p = (Uint32 *)((Uint8 *)surface->pixels + (i * surface->pitch) + (j * bpp));
Related
I am currently programming a game on C++ and am working with the SDL 2.0 library.
I am attempting to disect a 32x32 image from a texture to store as a tile and am attempting to recreate it from the pixels of a texture. When I run this code and attempt to edit the Uint32* by a for loop, I can edit it but once I try to creat the image, I get a heap corruption.
I currently have this code running:
Uint32* pixels = (Uint32*)m_pSprite->GetPixels();
int pixelCount = (m_pSprite->GetPitch() / 4) * m_pSprite->GetHeight();
int tileOffset = 0;
int spriteSheetOffset = 0;
int widthOffset = m_pSprite->GetWidth();
Uint32* tilePixels = new Uint32(32);
for (int y = 0; y < 32; y++)
{
tileOffset = (y * 32);
spriteSheetOffset = (y * widthOffset);
for (int x = 0; x < 32; x++)
{
tilePixels[tileOffset + x] = pixels[spriteSheetOffset + x];
}
}
int tilePitch = 32*4;
SDL_Texture* texture = SDL_CreateTexture(backBuffer.GetRenderer(), SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, TILE_WIDTH, TILE_HEIGHT);
I can see that there is something wrong with the Uint32* variable and that this is obviously not a best practice but I am still wrapping my head around what can and cannot be done, and what is the best way etc.
Does anyone have an explanation of what could be happening?
Uint32* tilePixels = new Uint32(32);
This is dynamically allocating a single Uint32, and initializing/constructing it to the value 32. It seems you want a 32*32 array of those. Try this:
Uint32* tilePixels = new Uint32[32*32]; // brackets allocate an array
Although, since the size of your array is static (known at compile-time), it would be best to just use a stack-allocated array instead of a dynamic one:
Uint32 tilePixels[32*32];
See if that fixes it.
I'm working on a section of someone else's code and hence have been limited to the amount of modification I can do. Anyway, I'm currently trying to create a texture array and have become stuck with a problem:
What I need to support is n textures being individually loaded and stored as GLubytes in a vector. I then need to take all of the data stored in that vector and store it in a single GLubyte object. Currently my code looks something like this:
vector<GLubyte*> vecPixelData;
GLubyte* puData;
for(int i = 0; i < NumberOfTextures; i++)
{
GLubyte* pixData;
LoadTexture(&pixData);
vecPixelData.push_back(pixData);
}
int puDataSize = nWidth * nHeight * 4 * NumberOfTextures;
puData = new GLubyte[puDataSize];
for(int i = 0; i < NumberOfTextures; i++)
*puData += *vecPixelData[i];
Now I'm sure I'm missing some fundamental points on how to copy memory from vecPixelData to puData, and if not, can anyone give me a 'pointer' as to somewhere to begin on how to check if puData is actually storing the data required. (I've tried using the memory window but the data in puData doesn't seem to get altered.)
EDIT:
The Solution in the end was:
int puDataSize = nWidth * nHeight * 4;
puData = new GLubyte[puDataSize * NumberOfTextures];
for(int i = 0; i < NumberOfTextures.size(); i++)
memcpy(puData + (puDataSize * i), vecPixelData[i], puDataSize);
If I understand your problem correctly you need to use std::copy. Something along the lines of std::copy(*vecPixelData[i], *vecPixelData[i] + imageSize, puData + offstet) (leaving the calculations of imageSize and offset to you) inside your last for loop.
I am loading an image using the OpenEXR library.
This works fine, except the image is loaded rotated 180 degrees. I use the loop shown below to reverse the array but sometimes the program will quit and xcode will give me an EXEC_BAD_ACCESS error (Which I assume is the same as an access violation in msvc). It does not happen everytime, just once every 5-10 times.
Ideally I'd want to reverse the array in place, although that led to errors everytime and using memcpy would fail but without causing an error, just a blank image. I'd like to know what's causing this problem first.
Here is the code I am using: (Rgba is a struct of 4 "Half"s r, g, b, and a, defined in OpenEXR)
Rgba* readRgba(const char filename[], int& width, int& height){
Rgba* pixelBuffer = new Rgba[width * height];
Rgba* temp = new Rgba[width * height];
// ....EXR Loading code....
// TODO: *Sometimes* the following code results in a bad memory access error. No idea why.
// Flip the image to conform with OpenGL coordinates.
for (int i = 0; i < height; i++){
for(int j = 0; j < width; j++){
temp[(i*width)+j] = pixelBuffer[(width*height)-(i*width)+j];
}
}
delete pixelBuffer;
return temp;
}
Thanks in advance!
Change:
temp[(i*width)+j] = pixelBuffer[(width*height)-(i*width)+j];
to:
temp[(i*width)+j] = pixelBuffer[(width*height)-(i*width)+j - 1];
(Hint: think about what happens when i = 0 and j = 0 !)
And here's how you can optimize this code, to save memory and for cycles:
Rgba* readRgba(const char filename[], int& width, int& height)
{
Rgba* pixelBuffer = new Rgba[width * height];
Rgba tempPixel;
// ....EXR Loading code....
// Flip the image to conform with OpenGL coordinates.
for (int i = 0; i <= height/2; i++)
for(int j = 0; j < width && (i*width + j) <= (height*width/2); j++)
{
tempPixel = pixelBuffer[i*width + j];
pixelBuffer[i*width + j] = pixelBuffer[height*width - (i*width + j) -1];
pixelBuffer[height*width - (i*width + j) -1] = tempPixel;
}
return pixelBuffer;
}
Note that optimal (from a memory usage best practices point of view) would be to pass pixelBuffer* as a parameter and already allocated. It's a good practice to allocate and release the memory in the same piece of code.
I am working with OpenCV and Qt, Opencv use BGR while Qt uses RGB , so I have to swap those 2 bytes for very big images.
There is a better way of doing the following?
I can not think of anything faster but looks so simple and lame...
int width = iplImage->width;
int height = iplImage->height;
uchar *iplImagePtr = (uchar *) iplImage->imageData;
uchar buf;
int limit = height * width;
for (int y = 0; y < limit; ++y) {
buf = iplImagePtr[2];
iplImagePtr[2] = iplImagePtr[0];
iplImagePtr[0] = buf;
iplImagePtr += 3;
}
QImage img((uchar *) iplImage->imageData, width, height,
QImage::Format_RGB888);
We are currently dealing with this issue in a Qt application. We've found that the Intel Performance Primitives to be be fastest way to do this. They have extremely optimized code. In the html help files at Intel ippiSwapChannels Documentation they have an example of exactly what you are looking for.
There are couple of downsides
Is the size of the library, but you can link static link just the library routines you need.
Running on AMD cpus. Intel libs run VERY slow by default on AMD. Check out www.agner.org/optimize/asmlib.zip for details on how do a work around.
I think this looks absolutely fine. That the code is simple is not something negative. If you want to make it shorter you could use std::swap:
std::swap(iplImagePtr[0], iplImagePtr[2]);
You could also do the following:
uchar* end = iplImagePtr + height * width * 3;
for ( ; iplImagePtr != end; iplImagePtr += 3) {
std::swap(iplImagePtr[0], iplImagePtr[2]);
}
There's cvConvertImage to do the whole thing in one line, but I doubt it's any faster either.
Couldn't you use one of the following methods ?
void QImage::invertPixels ( InvertMode mode = InvertRgb )
or
QImage QImage::rgbSwapped () const
Hope this helps a bit !
I would be inclined to do something like the following, working on the basis of that RGB data being in three byte blocks.
int i = 0;
int limit = (width * height); // / 3;
while(i != limit)
{
buf = iplImagePtr[i]; // should be blue colour byte
iplImagePtr[i] = iplImagaePtr[i + 2]; // save the red colour byte in the blue space
iplImagePtr[i + 2] = buf; // save the blue color byte into what was the red slot
// i++;
i += 3;
}
I doubt it is any 'faster' but at end of day, you just have to go through the entire image, pixel by pixel.
You could always do this:
int width = iplImage->width;
int height = iplImage->height;
uchar *start = (uchar *) iplImage->imageData;
uchar *end = start + width * height;
for (uchar *p = start ; p < end ; p += 3)
{
uchar buf = *p;
*p = *(p+2);
*(p+2) = buf;
}
but a decent compiler would do this anyway.
Your biggest overhead in these sorts of operations is going to be memory bandwidth.
If you're using Windows then you can probably do this conversion using the BitBlt and two appropriately set up DIBs. If you're really lucky then this could be done in the graphics hardware.
I hate to ruin anyone's day, but if you don't want to go the IPP route (see photo_tom) or pull in an optimized library, you might get better performance from the following (modifying Andreas answer):
uchar *iplImagePtr = (uchar *) iplImage->imageData;
uchar buf;
size_t limit = height * width;
for (size_t y = 0; y < limit; ++y) {
std::swap(iplImagePtr[y * 3], iplImagePtr[y * 3 + 2]);
}
Now hold on, folks, I hear you yelling "but all those extra multiplies and adds!" The thing is, this form of the loop is far easier for a compiler to optimize, especially if they get smart enough to multithread this sort of algorithm, because each pass through the loop is independent of those before or after. In the other form, the value of iplImagePtr was dependent on the value in previous pass. In this form, it is constant throughout the whole loop; only y changes, and that is in a very, very common "count from 0 to N-1" loop construct, so it's easier for an optimizer to digest.
Or maybe it doesn't make a difference these days because optimizers are insanely smart (are they?). I wonder what a benchmark would say...
P.S. If you actually benchmark this, I'd also like to see how well the following performs:
uchar *iplImagePtr = (uchar *) iplImage->imageData;
uchar buf;
size_t limit = height * width;
for (size_t y = 0; y < limit; ++y) {
uchar *pixel = iplImagePtr + y * 3;
std::swap(pix[0], pix[2]);
}
Again, pixel is defined in the loop to limit its scope and keep the optimizer from thinking there's a cycle-to-cycle dependency. If the compiler increments and decrements the stack pointer each time through the loop to "create" and "destroy" pixel, well, it's stupid and I'll apologize for wasting your time.
cvCvtColor(iplImage, iplImage, CV_BGR2RGB);
I am trying to take the imageData of image in this where w= width of image and h = height of image
for (int i = x; i < x+h; i++) //height of frame pixels
{
for (int j = y; j < y+w; j++)//width of frame pixels
{
int pos = i * w * Channels + j; //channels is 3 as rgb
// if any data exists
if (data->imageData[pos]>0) //Taking data (here is the problem how to take)
{
xPos += j;
yPos += i;
nPix++;
}
}
}
jeff7 gives you a link to a very old version of OpenCV. OpenCV 2.0 has a new C++ wrapper that is much better than the C++ wrapper mentioned in the link. I recommend that you read the C++ reference of OpenCV for information on how to access individual pixels.
Another thing to note is: you should have the outer loop being the loop in y-direction (vertical) and the inner loop be the loop in x-direction. OpenCV is in C/C++ and it stores the values in row major.
See good explanation here on multiple methods for accessing pixels in an IplImage in OpenCV.
From the code you've posted your problem lies in your position variable, you'd want something like int pos = i*w*Channels + j*Channels, then you can access the RGB pixels at
unsigned char r = data->imageData[pos];
unsigned char g = data->imageData[pos+1];
unsigned char b = data->imageData[pos+2];
(assuming RGB, but on some platforms I think it can be stored BGR).
uchar* colorImgPtr;
for(int i=0; i<colorImg->width; i++){
for(int j=0; j<colorImg->height; j++){
colorImgPtr = (uchar *)(colorImg->imageData) + (j*colorImg->widthStep + i-colorImg->nChannels)
for(int channel = 0; channel < colorImg->nChannels; channel++){
//colorImgPtr[channel] here you have each value for each pixel for each channel
}
}
}
There are quite a few methods to do this (the link provided by jeff7 is very useful).
My preferred method to access image data is the cvPtr2D method. You'll want something like:
for(int x = 0; x < width; ++x)
{
for(int y = 0; y < height; ++y)
{
uchar* ptr = cvPtr2D(img, y, x, NULL);
// blue channel can now be accessed with ptr[0]
// green channel can now be accessed with ptr[1]
// red channel can now be accessed with ptr[2]
}
}
(img is an IplImage* in the above code)
Not sure if this is the most efficient way of doing this etc. but I find it the easiest and simplest way of doing it.
You can find documentation for this method here.