Can someone explain how I am to access this array? (image processing program) - c++

I am working on the implementation of functions for an already written image processing program. I am given explanations of functions, but not sure how they are designating pixels of the image.
In this case, I need to flip the image horizontally, i.e., rotates 180 degrees around the vertical axis
Is this what makes the "image" i am to flip?
void Image::createImage(int width_x, int height_y)
{
width = width_x;
height = height_y;
if (pixelData!=NULL)
freePixelData();
if (width <= 0 || height <= 0) {
return;
}
pixelData = new Color* [width]; // array of Pixel*
for (int x = 0; x < width; x++) {
pixelData[x] = new Color [height]; // this is 2nd dimension of pixelData
}
}
I do not know if all the functions I have written are correct.
Also, the Image class calls on a Color class
So to re-ask: what am I "flipping" here?
Prototype for function is:
void flipLeftRight();
As there is no input into the function, and I am told it modifies pixelData, how do I flip left to right?

A quick in place flip. Untested, but the idea is there.
void flipHorizontal(u8 *image, u32 width, u32 height)
{
for(int i=0; i < height; i++)
{
for(int j=0; j < width/2; j++)
{
int sourceIndex = i * width + j;
int destIndex = (i+1) * width - j - 1;
image[sourceIndex] ^= image[destIndex];
image[destIndex] ^= image[sourceIndex];
image[sourceIndex] ^= image[destIndex];
}
}
}

well, the simplest approach would be to read it 1 row at a time into a temporary buffer the same size as 1 row.
Then you could use something like std::reverse on the temporary buffer and write it back.
You could also do it in place, but this is the simplest approach.
EDIT: what i;ve described is a mirror, not a flip, to mirror you also need to reverse the order of the rows. Nothing too bad, to do that I would create a buffer the same size as the image, copy the image and then write it back with the coordinates adjusted. Something like y = height - x and x = width - x.

Related

Rotating image using classes

I'm having trouble rotating an image 90 degrees, the images are 768 x 768 pixels. The code I have shown here is able to create a new image, but the function I've written isn't manipulating it at all. My image class and function that's in the driver to rotate it is below. I have to rotate all the pictures 90 degrees clockwise and counterclockwise; I think my issue is trying to get the pointers to correctly switch the pixels around.
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
image(image &other); //copy constructor
~image(); //the image destructor (deletes the dynamically created pixel array)
pixel** getPixels(); //return the 2-dimensional pixels array
int getWidth(); //return the width of the image
int getHeight(); //return the height of the image
void createNewImage(int width, int height);
private:
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
void pixelsToCImage(CImage* myImage);
};
void RotateClockWise(image *imageIn)
{
image rotateImg;
image *ptr = (image*) &rotateImg;
*ptr = *imageIn;
int height = rotateImg.getHeight();
int width = rotateImg.getWidth();
pixel** rotatePix = rotateImg.getPixels();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rotatePix[i][j] = rotatePix[j][i];
*(ptr + j * height + (height - i - 1)) = *(ptr + i * width + j);
}
}
}
First your code is very c style. This is cool, I love this kind of coding, but you can make your life easier with references.
Solution for your code:
You never set point to imageIn, just the copy the value from image in to rotateImg:
image rotateImg;
image *ptr = (image*) &rotateImg;
*ptr = *imageIn;
This means you just modify the local variable rotateImg and not the object which is given by the pointer.
And here just a plain NO:
ptr points on an image. Each +j means "go to the next image" or more precissly: ptr = ptr + sizeof(image); which should be around 12 bytes + vtable. Dont do this. You You can just do this when you loop over an 1 dimensional pixel array.
*(ptr + j * height + (height - i - 1)) = *(ptr + i * width + j); //BAD
Here is some C style code which solves the problem. I did not know you could give a 2 dimensional array via a double pointer **ptr (indirect pointers).
void RotateClockWise(image* imageIn)
{
image rotateImg;
rotateImg = *imageIn;
image *ptr = imageIn;
int height = rotateImg.getHeight();
int width = imageIn->getWidth();
pixel** normalPix = rotateImg.getPixels();
pixel** rotatePix = imageIn->getPixels();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
rotatePix[i][j] = normalPix[(height-1)-j][(width-1)-i];
}
}
}
I am to lazy to code it in C++ Style, but have a look at the Reference
void RotateClockWise(image& imageIn)
You have imageIn argument that probably points to image you want to rotate. However, you create rotateImg object, get pointer to this object (ptr) and duplicate imageIn to this ptr. So, now you manipulate image copy instead of image itself, that is why object pointed by imageIn never changes its value.

Tileset crop calculation C++

So I have this problem with my tileset rendering. It's a little tricky to explain but i'll do my best.
Basicly what i do is i load these "tile numbers" from TMX files and they only represent the tileset number in the tileset. So if i use a tile that is on a row below the first one i only get the number. But i want both X and Y position to calculate where i would crop the image when i display it in my game.
So my array would look something like this,
1,1,1,2,1,1,1,1,9,1,6,1,1
1,1,1,2,2,2,1,1,1,1,1,1,1
1,1,1,1,1,2,1,1,1,1,1,1,1
1,1,1,1,1,2,1,1,1,3,1,1,1
1,6,1,1,1,2,1,1,1,1,1,1,1
1,1,5,5,1,2,2,2,1,1,1,1,1
1,1,1,1,1,1,1,2,1,1,1,1,1
Tileset:
http://puu.sh/9Tv2X/7938b6abf4.png
so when i render all the tiles in the first row in this tileset, numbers 1-4 (since the tileset is 4 tiles long) it works fine but anything past that would get cropped outside the image.
So for that i need the Y position to increase and to reset the X position everytime it goes outside the tileset width which is (32 * (tileNumber - 1)) but my brain cant figure out how to do this.
tile width and height is 32.
my code for drawing the tilset:
void TileMap::Draw()
{
for (unsigned int i = 0; i < mapVector.size(); i++)
{
for (unsigned int j = 0; j < mapVector[i].size(); j++)
{
int tileY = 0;
int tileX = mapVector[i][j] - 1;
if (tileWidth * mapVector[i][j] > tilesetWidth)
{
//now what
}
if (mapVector[i][j] > 0)
{
tileSprite->SetPosition(j * tileWidth, i * tileHeight);
tileSprite->SetTextureRect(tileX * tileWidth, tileY * tileHeight, 32, 32);
tileSprite->Draw();
}
}
}
}

How to efficiently render a 24-bpp image on a 32-bpp display?

First of all, I'm programming in the kernel context so no existing libraries exist. In fact this code is going to go into a library of my own.
Two questions, one more important than the other:
As the title suggests, how can I efficiently render a 24-bpp image onto a 32-bpp device, assuming that I have the address of the frame buffer?
Currently I have this code:
void BitmapImage::Render24(uint16_t x, uint16_t y, void (*r)(uint16_t, uint16_t, uint32_t))
{
uint32_t imght = Math::AbsoluteValue(this->DIB->GetBitmapHeight());
uint64_t ptr = (uint64_t)this->ActualBMP + this->Header->BitmapArrayOffset;
uint64_t rowsize = ((this->DIB->GetBitsPerPixel() * this->DIB->GetBitmapWidth() + 31) / 32) * 4;
uint64_t oposx = x;
uint64_t posx = oposx;
uint64_t posy = y + (this->DIB->Type == InfoHeaderV1 && this->DIB->GetBitmapHeight() < 0 ? 0 : this->DIB->GetBitmapHeight());
for(uint32_t d = 0; d < imght; d++)
{
for(uint32_t w = 0; w < rowsize / (this->DIB->GetBitsPerPixel() / 8); w++)
{
r(posx, posy, (*((uint32_t*)ptr) & 0xFFFFFF));
ptr += this->DIB->GetBitsPerPixel() / 8;
posx++;
}
posx = oposx;
posy--;
}
}
r is a function pointer to a PutPixel-esque thing that accepts x, y, and colour parameters.
Obviously this code is terribly slow, since plotting pixels one at a time is never a good idea.
For my 32-bpp rendering code (which I also have a question about, more on that later) I can easily Memory::Copy() the bitmap array (I'm loading bmp files here) to the frame buffer.
However, how do I do this with 24bpp images? On a 24bpp display this would be fine but I'm working with a 32bpp one.
One solution I can think of right now is to create another bitmap array which essentially contains values of 0x00(colour) and the use that to draw to the screen -- I don't think this is very good though, so I'm looking for a better alternative.
Next question:
2. Given, for obvious reasons, one cannot simply Memory::Copy() the entire array at once onto the frame buffer, the next best thing would be to copy them row by row.
Is there a better way?
Basically something like this:
for (uint32_t l = 0; l < h; ++l) // l line index in pixels
{
// srcPitch is distance between lines in bytes
char* srcLine = (char*)srcBuffer + l * srcPitch;
unsigned* trgLine = ((unsigned*)trgBuffer) + l * trgPitch;
for (uint32_t c = 0; c < w; ++c) // c is column index in pixels
{
// build target pixel. arrange indexes to fit your render target (0, 1, 2)
++(*trgLine) = (srcLine[0] << 16) | (srcLine[1] << 8)
| srcLine[2] | (0xff << 24);
srcLine += 3;
}
}
A few notes:
- better to write to a different buffer than the render buffer so the image is displayed at once.
- using functions for pixel placement like you did is very (very very) slow.

Correct flip/mirror of pixels of an image?

http://tinypic.com/r/fwubzc/5
That shows what a flip should be and what a mirror should be.
Code for both types of mirrors:
void mirrorLeftRight()
{
for (int x = 0; x < width/2; x++) {
for (int y = 0; y < height; y++) {
int temp = pixelData[x][y];
pixelData[x][y]=pixelData[width-x][y]
pixelData[width-x][y]=temp;
}
}
}
void mirrorUpDown()
{
for (int x = 0; x < width; x++) {
for (int y = 0; y < height/2; y++) {
int temp = pixelData[x][y];
pixelData[x][y]=pixelData[x][height-y]
pixelData[x][height-y]=temp;
}
}
}
Does this seem right for mirrors?
And for flip, just a matter of using width and height w/o dividing by 2?
You need to use width-1-x instead of width-x, and height-1-y instead of height-y. Otherwise for x==0 you'll try to index [width], which is outside the array.
It shouldn't work since you are swapping pixels while you just have to override the right part of the image with the left part. Same thing applies to the mirrorUpDown.
If you swap them you obtain a flip, if you overwrite them you obtain a mirror.
mirrorLeftRight: take pixels from left half and use them to overwrite right part
mirrorUpDown: take pixels from upper part and use them to overwrite lower one
flip: in this case you don't overwrite but you swap pixels (source half it's not influent in this case)
The code above seems more like the correct way to Flip, not mirror.
Mirror I would guess that you not switch the pixels, but rather copy from one side to the other.
With mirror I would guess that you need to change
int temp = pixelData[x][y];
pixelData[x][y]=pixelData[width-x][y]
pixelData[width-x][y]=temp;
to something like this only
pixelData[x][y]=pixelData[width-x][y]

How to access image Data from a RGB image (3channel image) in opencv

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.