C++如何使用指针数组缩小图像

C++ how to shrink an image using a pointer array?

本文关键字:缩小 图像 数组 指针 何使用 C++      更新时间:2023-10-16

我正在编写一个处理图像的 c++ 程序,这是缩小图像的函数。 有一个"像素"指针数组和一个定义了图像颜色的类。 除了Visual Studio中包含的库之外,我不能使用任何其他库进行此图像程序。 我对此功能有问题,我需要遍历图像中的像素并将其拆分为块;用户将输入块的宽度/高度。 创建块后,需要从每个块中获取平均RGB值(该平均值将成为单个新像素),并且所有块的排列都将"缩小"图像。 到目前为止,似乎创建块是因为图像变小,但我的图像完全变成灰色。RGB 像素的总数正确添加,但代码的其余部分必须关闭某些内容,我无法确定它。这是我的代码:

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

下面是图像类:

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

这是像素类:

class pixel
{
public:
    unsigned char red;      //the red component
    unsigned char green;    //the green component
    unsigned char blue;     //the blue component
};

好的,减去大量的内存泄漏和误导性名称,您在CreateBlock中找到平均值的正确想法。 我会尝试如下:

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

免责声明,我实际上还没有测试过任何这些,确保新的 rgb 值在可接受的范围内(我认为是 0-255? 您还需要一些边界检查/特殊情况,以应对图像大小不能完全被块大小整除的情况。

您没有在CreateBlock代码中使用currpix。您正在对代码中分配的随机数求平均值:

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

问题似乎是您在此处使用未初始化的值:

  totred = totred + block[i][j].red;
  totblue = totblue + block[i][j].blue;
  totgreen = totgreen + block[i][j].green;

您分配了block,但未能初始化任何值。 因此redgreenblue都有随机值。

您还有一个内存泄漏 - 您在此处分配了block,但未能解除分配它:

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

取而代之的是,最简单的解决方案是使用 std::vector<std::vector<pixel>>

#include <vector>
//...
std::vector<std::vector<pixel> > block(blockHeight, std::vector<pixel>(blockWidth));

一行代码可以完成循环完成的所有操作,还可以消除内存泄漏。 它真正没有做的是使用您需要的值初始化block。 这些值是什么 - 你需要确定它们。