0

I'm writing a program that creates a mosaic using filler images. I'm having an issue with accessing the private data for the pixels for each filler image. I can get the pixels from the source image (image* displayed) but when I try to get the filler image to size down specific to the block size entered, I lose the data. The filler images need to be resized to the blockheight and blockwidth so that they can properly fit the source image height and width, that is the goal of the resizeFillerImage function. I am using linked links when loading the folder with all the filler images, and I do get the averages right when I load them into the program. The pixel** array is private data within a main Image class that contains the fillerImage class, and I cannot change this, so I need to be able to get the pixels for the filler images and set them to the temporary copy image I create.

Here is my code:

Globals:

image* displayed;
fillerNode* head = NULL;
fillerNode* head2 = NULL;
fillerNode* temp1;
fillerNode* shrinkedList;

//This function will resize each filler image based on the block size
void resizeFillerImage(int blockWidth, int blockHeight)
{
    int blockSize = blockWidth * blockHeight;
    int avgRed = 0, avgGreen = 0, avgBlue = 0;

    image* temp = new image;
    temp->createNewImage(displayed->getWidth() / blockWidth, displayed->getHeight() / blockHeight);
    pixel** shrinkPix = temp->getPixels(); //THIS IS WHERE I GET THE ERROR
    //The pixel numbers get reset instead of being assigned to temp

    for (int i = 0; i < displayed->getHeight() / blockHeight; i++)
    {
        for (int j = 0; j < displayed->getWidth() / blockWidth; j++)
        {
            for (int k = 0; k < blockHeight; k++)
            {
                for (int m = 0; m < blockWidth; m++)
                {
                    avgRed = avgRed + shrinkPix[i * blockHeight + k][j * blockWidth + m].red;
                    avgGreen = avgGreen + shrinkPix[i * blockHeight + k][j * blockWidth + m].green;
                    avgBlue = avgBlue + shrinkPix[i * blockHeight + k][j * blockWidth + m].blue;
                }
            }

            avgRed = avgRed / blockSize;
            avgGreen = avgGreen / blockSize;
            avgBlue = avgBlue / blockSize;

            shrinkPix[i][j].red = avgRed;
            shrinkPix[i][j].green = avgGreen;
            shrinkPix[i][j].blue = avgBlue;

            avgRed = 0;
            avgGreen = 0;
            avgBlue = 0;
        }
    }

    for (int i = 0; i < displayed->getHeight(); i++)
    {
        for (int j = 0; j < displayed->getWidth(); j++)
        {
            if ((i > displayed->getHeight() / blockHeight) || (j > displayed->getWidth() / blockWidth))
            {
                shrinkPix[i][j].red = 0;
                shrinkPix[i][j].green = 0;
                shrinkPix[i][j].blue = 0;
            }
        }
    }

    displayed = temp;
    return;
}

//This function should generate the photomosaic from the loaded image.  Each filler image should represent a section of the original image
//that is blockWidth by blockHeight big.
void generateMosaic(int blockWidth, int blockHeight)
{
    for (int i = FIRST_FILLER_NUMBER; i <= LAST_FILLER_NUMBER; i++)
    {
        shrinkedList = new fillerNode;

        fillerImage* tempImage = new fillerImage();
        resizeFillerImage(blockHeight, blockHeight);

    }

}

Here is the fillerImage class:

fillerImage::fillerImage() //constructor
{
    this->timesUsed = 0;
    this->averageColor.red = 0;
    this->averageColor.green = 0;
    this->averageColor.blue = 0;
}

fillerImage::fillerImage(string filename) : image(filename)
{
    timesUsed = 0;
}

fillerImage::~fillerImage() //destructor
{
    timesUsed = NULL;
    averageColor.red = NULL;
    averageColor.green = NULL;
    averageColor.blue = NULL;
}

void fillerImage::calculateAverageColor() //calcuate the average color assign that color to private  member averageColor
{
    pixel** pix = getPixels();
    int area = FILLER_IMAGE_HEIGHT * FILLER_IMAGE_WIDTH;
    int totRed = 0, totGreen = 0, totBlue = 0;

    for (int i = 0; i < FILLER_IMAGE_HEIGHT; i++)
    {
        for (int j = 0; j < FILLER_IMAGE_WIDTH; j++)
        {
            totRed += pix[i][j].red;
            totGreen += pix[i][j].green;
            totBlue += pix[i][j].blue;
        }
    }

    averageColor.red = totRed / area;
    averageColor.green = totGreen / area;
    averageColor.blue = totBlue / area;
}

pixel fillerImage::getAverageColor() //return the average color
{
    return this->averageColor;
}

int fillerImage::getTimesUsed() //return how many times this fillerimage has been used
{
    return this->timesUsed;
}

void fillerImage::setTimesUsed(int used) //assign "used" to timesUsed
{
    this->timesUsed = used;
}

FillerNode struct:

struct fillerNode{
    fillerImage *data;
    fillerNode *pre;
    fillerNode *next;
};

Image Class header:

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 object 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
};
T-Bird
  • 187
  • 1
  • 4
  • 20
  • ***temp->getPixels(); //THIS IS WHERE I GET THE ERROR*** How could anyone help? I mean what is image? – drescherjm Dec 12 '14 at 22:57
  • @wakjah I'm trying to modify pixels, but it's a private pixel** array in a class and I cannot write a setter function to get the pixels. I can only use getpixels() from that class. My line with the specific problem is pointed out in the first part of the code. I'm asking how can I access the pixel array to set the pixels to 'temp' – T-Bird Dec 12 '14 at 22:58
  • @drescherjm I'll add that class header file – T-Bird Dec 12 '14 at 22:58
  • Given that `image::getPixels` returns a modifiable (non-const) pointer to its data, you ***are*** modifying the contents of its data. The problem is presumably in what you do with `displayed` **after** the call to `resizeFillerImage` completes. – wakjah Dec 12 '14 at 23:02
  • @wakjah We have a pixel value beforehand for the shrinkPix pixel array, but it sets everything to 205 for RGB values right after that statement with the temp->getPixels(). After that, the code ends up breaking when I try to use shrinkPix[i][j].color to set the average colors. Displayed is just a copy of the source image to display on the form. – T-Bird Dec 12 '14 at 23:06
  • 205 (0xCD) looks like uninitialized heap memory -> 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory http://stackoverflow.com/a/127404/487892 – drescherjm Dec 12 '14 at 23:32
  • @drescherjm okay that makes sense, because it's giving it a default value because it can't find the pixels. I've used getPixels in other areas of this program and it successfully finds each one. So the question is, what is wrong with that one line of code that isn't allowing the compiler to get the pixels? – T-Bird Dec 13 '14 at 00:11
  • I suspect createNewImage is not actually filling the image. – drescherjm Dec 13 '14 at 00:36
  • Reading your comments I believe you should be loading or copying an image between `temp->createNewImage(displayed->getWidth() / blockWidth, displayed->getHeight() / blockHeight);` and `pixel** shrinkPix = temp->getPixels();` – drescherjm Dec 13 '14 at 00:53

1 Answers1

0

The error was that I created a copy of the source image and then tried to get pixels from an empty copy, so I created another 2D pixel array and got the pixels there, and used each array accordingly.

pixel** myPix = displayed->getPixels();
int height = displayed->getHeight();
int width = displayed->getWidth();

image* temp = new image;
temp->createNewImage(displayed->getWidth() / blockWidth, displayed->getHeight() / blockHeight);
pixel** shrinkPix = temp->getPixels();


for (int i = 0; i < displayed->getHeight() / blockHeight; i++)
{
    for (int j = 0; j < displayed->getWidth() / blockWidth; j++)
    {
        for (int k = 0; k < blockHeight; k++)
        {
            for (int m = 0; m < blockWidth; m++)
            {
                avgRed = avgRed + myPix[i * blockHeight + k][j * blockWidth + m].red;
                avgGreen = avgGreen + myPix[i * blockHeight + k][j * blockWidth + m].green;
                avgBlue = avgBlue + myPix[i * blockHeight + k][j * blockWidth + m].blue;
            }
        }

        avgRed = avgRed / blockSize;
        avgGreen = avgGreen / blockSize;
        avgBlue = avgBlue / blockSize;

        shrinkPix[i][j].red = avgRed;
        shrinkPix[i][j].green = avgGreen;
        shrinkPix[i][j].blue = avgBlue;

        avgRed = 0;
        avgGreen = 0;
        avgBlue = 0;
    }
}

for (int i = 0; i < displayed->getHeight(); i++)
{
    for (int j = 0; j < displayed->getWidth(); j++)
    {
        if ((i > displayed->getHeight() / blockHeight) || (j > displayed->getWidth() / blockWidth))
        {
            myPix[i][j].red = 0;
            myPix[i][j].green = 0;
            myPix[i][j].blue = 0;
        }
    }
}
T-Bird
  • 187
  • 1
  • 4
  • 20