Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm writing a c++ program that manipulates images, and this is the function to shrink it. There is a 'pixel' pointer array and a class that has the image colors defined. I cannot use any other library besides the ones included in Visual Studio for this image program. I'm having an issue with this function, I need to traverse the pixels in the image and split it into blocks; the user will enter the block width/height. After the blocks are created, the average RGB values need to be taken from each block (that average will become a single new pixel), and with all of them arranged it will 'shrink' the image. So far it seems the blocks are created because the image becomes smaller, but my image turns completely gray. The totals for the RGB pixels are adding correctly, but something must be off in the rest of the code and I haven't been able to pinpoint it. Here is my code:

//creates a block of average colors based on range of pixels given
pixel CreateBlock(int start, int stop, pixel** currpix, int blockHeight, int blockWidth)
{
    pixel** block;          //Problem? might have to be a single pointer pixel* block[];
    block = new pixel*[blockHeight];

    for (int i = 0; i < blockHeight; i++)
        block[i] = new pixel[blockWidth];

    pixel newPix;

    float totred = 0, totblue = 0, totgreen = 0;
    int redav = 0.0, blueav = 0.0, greenav = 0.0;

    for (int i = 0; i < blockHeight; i++)
    {
        for (int j = 0; j < blockWidth; j++)
        {
            totred = totred + block[i][j].red;
            totblue = totblue + block[i][j].blue;
            totgreen = totgreen + block[i][j].green;
        }
    }

    redav = totred / (blockHeight*blockWidth);
    blueav = totblue / (blockHeight* blockWidth);
    greenav = totgreen / (blockHeight*blockWidth);

    newPix.red = redav;
    newPix.blue = blueav;
    newPix.green = greenav;

    return newPix;
}

//make a new image that is a smaller resampling of the bigger image
void averageRegions(int blockWidth, int blockHeight)
{
    int height = displayed->getHeight(), width = displayed->getWidth();
    int i = 0, j = 0;
    pixel** currpix = displayed->getPixels();           //PROBLEM
    image* shrunk = displayed;
    //shrunk->getPixels();
    shrunk->createNewImage(width / blockWidth, height / blockHeight);
    while (i < height)
    {
        while (j < width)
        {
            int start = i, stop = i + 10;
            shrunk->getPixels()[i][j] = CreateBlock(start, stop, currpix, blockHeight, blockWidth);
            j = j + blockWidth;
        }
        i = i + blockHeight;
    }

    return;
}

Here is the image class:

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 
};

Here is the pixel class:

class pixel
{
public:
    unsigned char red;      //the red component
    unsigned char green;    //the green component
    unsigned char blue;     //the blue component
};
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
167 views
Welcome To Ask or Share your Answers For Others

1 Answer

Ok, well minus the massive memory leak and misleading name, you have the right idea in CreateBlock for finding the average. I would try something along the lines of this:

pixel averagePixels(pixel **oldImage, int startRow, int startCol, int blockHeight, int blockWidth){
    float rTot, gTot, bTot;
    pixel avg;

    for(int i = startRow ; i < blockHeight + startRow ; i++){
        for(int j = startCol ; j < blockWidth + startCol ; j++){
            rTot += oldImage[i][j].red;
            gTot += oldImage[i][j].green;
            bTot += oldImage[i][j].blue;
        }
    }
    avg.red   = rTot / (blockHeight * blockWidth);
    avg.green = gTot / (blockHeight * blockWidth);
    avg.blue  = bTot / (blockHeight * blockWidth);
    return avg;
}

pixel **shrinkImage(pixel **oldImage, int blockHeight, int blockWidth){
    int newHeight = oldImage->getHeight() / blockHeight;
    int newWidth  = oldImage->getWidth()  / blockWidth;
    pixel **newImage = new pixel* [newHeight];
    for(int i = 0 ; i < newHeight ; i++)
        newImage[i] = new pixel[newWidth];

    for(int i = 0 ; i < newHeight){
        for(int j = 0 ; j < newWidth){
            newImage[i][j] = averagePixels(oldImage, blockHeight * i, blockWidth * j, blockWidth, blockHeight);
        }
    }
    return newImage;
}

Disclaimer, I haven't actually tested any of this, and it would probably be wise (at least for testing purposes) to ensure that the new rgb values are within the acceptable range (0-255 I presume?). You'll also need some bounds checking/special cases for when the image size is not perfectly divisible by the block size.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...