Rotating image using classes - c++

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.

Related

Setting pixel color of 8-bit grayscale image using pointer

I have this code:
QImage grayImage = image.convertToFormat(QImage::Format_Grayscale8);
int size = grayImage.width() * grayImage.height();
QRgb *data = new QRgb[size];
memmove(data, grayImage.constBits(), size * sizeof(QRgb));
QRgb *ptr = data;
QRgb *end = ptr + size;
for (; ptr < end; ++ptr) {
int gray = qGray(*ptr);
}
delete[] data;
It is based on this: https://stackoverflow.com/a/40740985/8257882
How can I set the color of a pixel using that pointer?
In addition, using qGray() and loading a "bigger" image seem to crash this.
This works:
int width = image.width();
int height = image.height();
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
image.setPixel(x, y, qRgba(0, 0, 0, 255));
}
}
But it is slow when compared to explicitly manipulating the image data.
Edit
Ok, I have this code now:
for (int y = 0; y < height; ++y) {
uchar *line = grayImage.scanLine(y);
for (int x = 0; x < width; ++x) {
int gray = qGray(line[x]);
*(line + x) = uchar(gray);
qInfo() << gray;
}
}
And it seems to work. However, when I use an image that has only black and white colors and print the gray value, black color gives me 0 and white gives 39. How can I get the gray value in a range of 0-255?
First of all you are copying too much data in this line:
memmove(data, grayImage.constBits(), size * sizeof(QRgb));
The size ob Qrgb is 4 bytes, but according to the documentation, the size of a Format_Grayscale8 pixel is only 8 bits or 1 byte. If you remove sizeof(QRgb) you should be copying the correct amount of bytes, assuming all the lines in the bitmap are consecutive (which, according to the documentation, they are not -- they are aligned to at minimum 32-bits, so you would have to account for that in size). The array data should not be of type Qrgb[size] but ucahr[size]. You can then modify data as you like. Finally, you will probably have to create a new QImage with one of the constructors that accept image bits as uchar and assign the new image to the old image:
auto newImage = QImage( data, image.width(), image.height(), QImage::Format_Grayscale8, ...);
grayImage = std::move( newImage );
But instead of copying image data, you could probably just modify grayImage directly by accessing its data through bits(), or even better, through scanLine(), maybe something like this:
int line, column;
auto pLine = grayImage.scanLine(line);
*(pLine + column) = uchar(grayValue);
EDIT:
According to scanLine documentation, the image is at least 32-bit aligned. So if your 8-bit grayScale image is 3 pixels wide, a new scan line will start every 4 bytes. If you have a 3x3 image, the total size of the memory required to hold the image pixels will be 12. The following code shows the required memory size:
int main() {
auto image = QImage(3, 3, QImage::Format_Grayscale8);
std::cout << image.bytesPerLine() * image.height() << "\n";
return 0;
}
The fill method (setting all gray values to 0xC0) could be implemented like this:
auto image = QImage(3, 3, QImage::Format_Grayscale8);
uchar gray = 0xc0;
for ( int i = 0; i < image.height(); ++i ) {
auto pLine = image.scanLine( i );
for ( int j = 0; j < image.width(); ++j )
*pLine++ = gray;
}

shrink image c++ - 'System.AccessViolationException'

I have a project where we have to develop some image processing functions. One of the functions is shrinking an image.
this is the description of the function
void averageRegions(int blockWidth, int blockHeight)
INPUTS: Integers indicating the width and height of the blocks?to be averaged
OUTPUTS: NONE
When this function is called, you should create a new image that will consist of 1 pixel for every block of size
blockWidth by blockHeight pixels in the original image, with each pixel being the average color of the pixels in that
region in the original image.
Please note that it may be easier if you split this into 2 functions and call your helper function from within this one.
The second function could then just calculate the average value of a block of pixels given to it, and return that
to the original function to be used. However, this implementation is up to you! Complete it as you see fit.
I have completed the code of it however after closing the app I get this error
An unhandled exception of type 'System.AccessViolationException' occurred in MCS2514Pgm2.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
or this one
Heap Corruption Detected: after Normal block (#126) at 0x004cF6c0 CRT detected that the application wrote to memory after end of heap bugger.
This is the function code
void averageRegions(int blockWidth, int blockHeight)
{
//please add the code
int height = inImage.getHeight();
int width = inImage.getWidth();
pixel** myPixels = inImage.getPixels();
pixel* pixelptr;
int Rsum = 0, Gsum = 0, Bsum = 0;
int Ravg, Gavg, Bavg, pcount = 0, m, n;
outImage.createNewImage(width/blockWidth, height/blockHeight);
pixel** outPixels = outImage.getPixels();
//pixelptr = &myPixels[0][4];
for(int x = 0; x < height; x +=blockHeight)
{
for(int y = 0; y < width; y += blockWidth)
{
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
Rsum += myPixels[i][j].red;
Gsum += myPixels[i][j].green;
Bsum += myPixels[i][j].blue;
pcount++;
}
}
Ravg = Rsum/pcount;
Gavg = Gsum/pcount;
Bavg = Bsum/pcount;
for(int i = x; i < blockHeight+x; i++)
{
for(int j = y; j < blockWidth+y; j++)
{
myPixels[i][j].red = Ravg;
myPixels[i][j].green = Gavg;
myPixels[i][j].blue = Bavg;
m = x/blockHeight;
n = y/blockWidth;
outPixels[m][n].red = myPixels[i][j].red;
outPixels[m][n].green = myPixels[i][j].green;
outPixels[m][n].blue = myPixels[i][j].blue;
}
}
pcount=0;
Rsum = 0;
Gsum = 0;
Bsum = 0;
}
}
inImage = outImage;
}
this is the image.h
#ifndef IMAGE
#define IMAGE
#include <atlimage.h>
#include <string>
#include <cstdlib>
#include "globals.h"
#include "pixel.h"
using namespace std;
class image {
public:
image(); //the image constructor (initializes everything)
image(string filename); //a image constructor that directly loads an image from disk
~image(); //the image destructor (deletes the dynamically created pixel array)
void createNewImage(int width, int height); //this function deletes any current image data and creates a new blank image
//with the specified width/height and allocates the needed number of pixels
//dynamically.
bool loadImage(string filename); //load an image from the specified file path. Return true if it works, false if it is not a valid image.
//Note that we only accept images of the RGB 8bit colorspace!
void saveImage(string filename); //Save an image to the specified path
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 viewImage(CImage* myImage); //This function is called by the windows GUI. It returns the image in format the GUI understands.
private:
void pixelsToCImage(CImage* myImage); //this function is called internally by the image class.
//it converts our pixel struct array to a standard BGR uchar array with word spacing.
//(Don't worry about what this does)
pixel** pixels; // pixel data array for image
int width, height; // stores the image dimensions
};
#endif
And this is Pixel.h
#ifndef PIXEL_H
#define PIXEL_H
class pixel
{
public:
unsigned char red; //the red component
unsigned char green; //the green component
unsigned char blue; //the blue component
};
#endif
Can any one tell me why I am getting this error
In addition:
the error is taking me to this line in dbgdel.cpp
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
This error occurs because you are accessing outside of memory allocated for an array. There are several places in your code where this can happen.
If height is not a multiple of blockHeight, or width is not a multiple of blockWidth, your i/j loops will access elements outside of the memory allocated for myPixels.
Another possibility is when writing to outPixels if blockHeight and blockWidth are not equal. Your computation of m and n may have the blockHeight and blockWidth swapped (you're dividing x by blockHeight).
In
for (int x = 0; x < height; x += blockHeight)
say height is 100 and blockHeight is 33
x == 0. 0 < 100, so the body is entered and iterates 0 -> 32
x == 33. 33 < 100, so the body is entered and iterates 33 -> 65
x == 66. 66 < 100, so the body is entered and iterates 66 -> 98
x == 99. 99 < 100, so the body is entered and iterates 99 -> 131
Sadly there is no 100 -> 131.

Sometimes I get EXEC_BAD_ACCESS (Access violation) when reversing an array

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.

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

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.

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.