【问题标题】:C++ how to shrink an image using a pointer array?C ++如何使用指针数组缩小图像?
【发布时间】:2015-02-05 17:44:27
【问题描述】:

我正在编写一个处理图像的 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
};

【问题讨论】:

  • 我们对displayed 知之甚少,尤其是被调用的方法及其作用。另外,使用的其他名称呢?
  • 除非我的眼睛在欺骗我,否则你的 CreateBlock 函数中存在巨大的内存泄漏。
  • 你用CreateBlock 中的block 做什么?你分配内存,然后什么也不做。无论哪种方式,CreateBlock 似乎都是一个误导性的名称,如果您只是从该块中创建一个像素,正如返回值所暗示的那样。至于其余部分,displayed 类究竟包含什么?
  • 你在哪里释放这个语句中分配的内存:block = new pixel*[blockHeight];
  • @Deduplicator 显示是从图像类创建的 -> image* currImage; (当前图像)图像*显示; (对于新图像,当我需要私有数据时抓取像素和高度/宽度)

标签: c++ image visual-c++ pixel


【解决方案1】:

好的,减去大量内存泄漏和误导性名称,您在 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?)可能是明智的(至少出于测试目的)。当图像大小不能完全被块大小整除时,您还需要一些边界检查/特殊情况。

【讨论】:

  • 当它不是完全可分的时候,我们老师说只要把那部分剪掉就好了。 RGB 值也在 (0-255) 范围内。不过我会试试看,谢谢。
【解决方案2】:

问题似乎是您在这里使用了未初始化的值:

  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&lt;std::vector&lt;pixel&gt;&gt;

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

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

【讨论】:

  • 实际上是对它们进行了正确的总计,只是没有将其应用到每个块中。我单步执行了代码,它在遍历它们时确实抓取了像素值。我只是无法让它链接到块。我不能使用基于什么像素的矢量,它必须是一个指针。
  • 它似乎工作正常,但它是错误的。您正在动态创建一个结构。然后,您将在循环中使用未初始化的数据。无论您观察到什么,代码都是错误的。您很可能正在运行将值设置为 0 的调试版本。开始使用发布版本,您将看到这些值很可能包含随机垃圾。
  • 因此为什么会出现灰色图像。如何在不使用矢量格式并将它们设置为图像中当前像素的情况下正确创建块?
  • 我已经编辑和处理了一段时间,移动了一些东西,我可能只是在尝试使用它时忘记删除它。
【解决方案3】:

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

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

【讨论】:

  • 代码从平均区域函数开始,然后一个调用另一个。我在那里创建块,但我想我没有使用当前像素正确设置它,我不知道如何循环它并将所有像素放入每个块中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多