用C++和RGBA像素向量进行双线性调整大小

4
我正在使用双线性技术重新调整图像大小,参考了这里的方法,但我只看到一个黑色图像。首先,我使用LodePNG对我的图像进行解码,并将像素存储在vector<unsigned char>变量中。它说它们是以RGBARGBA格式存储的,但当我尝试将图像应用于X11窗口时,我意识到它们是以BGRABGRA格式存储的。我不知道是X11 API改变了顺序还是LodePNG解码器的问题。无论如何,在任何操作之前,我都会将BGR转换为RGB:
// Here is where I have the pixels stored
vector<unsigned char> Image;

// Converting BGRA to RGBA, or vice-versa, I don't know, but it's how it is shown
// correctly on the window
unsigned char red, blue;
unsigned int i;
for(i=0; i<Image.size(); i+=4)
{
    red  = Image[i + 2];
    blue = Image[i];
    Image[i] = red;
    Image[i + 2] = blue;
}

现在,我正在尝试在将图像应用于窗口之前更改其大小。大小应为窗口的大小(拉伸它)。 我首先尝试将RGBA转换为整数值,如下所示:

vector<int> IntImage;
for(unsigned i=0; i<Image.size(); i+=4)
{
    IData.push_back(256*256*this->Data[i+2] + 256*this->Data[i+1] + this->Data[i]);
}

现在我有一个来自上面指定链接的函数,它应该进行插值:
vector<int> resizeBilinear(vector<int> pixels, int w, int h, int w2, int h2) {
    vector<int> temp(w2 * h2);
    int a, b, c, d, x, y, index ;
    float x_ratio = ((float)(w-1))/w2 ;
    float y_ratio = ((float)(h-1))/h2 ;
    float x_diff, y_diff, blue, red, green ;

    for (int i=0;i<h2;i++) {
        for (int j=0;j<w2;j++) {
            x = (int)(x_ratio * j) ;
            y = (int)(y_ratio * i) ;
            x_diff = (x_ratio * j) - x ;
            y_diff = (y_ratio * i) - y ;
            index = (y*w+x) ;                
            a = pixels[index] ;
            b = pixels[index+1] ;
            c = pixels[index+w] ;
            d = pixels[index+w+1] ;

            // blue element
            // Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
            blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
                   (c&0xff)*(y_diff)*(1-x_diff)   + (d&0xff)*(x_diff*y_diff);

            // green element
            // Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
            green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
                    ((c>>8)&0xff)*(y_diff)*(1-x_diff)   + ((d>>8)&0xff)*(x_diff*y_diff);

            // red element
            // Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
            red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
                  ((c>>16)&0xff)*(y_diff)*(1-x_diff)   + ((d>>16)&0xff)*(x_diff*y_diff);

            temp.push_back( 
                    ((((int)red)<<16)&0xff0000) |
                    ((((int)green)<<8)&0xff00) |
                    ((int)blue) |
                    0xff); // hardcode alpha ;
        }
    }
    return temp;
}

我是这样使用它的:

vector<int> NewImage = resizeBilinear(IntData, image_width, image_height, window_width, window_height);

这段代码应该返回调整大小后图像的RGBA向量。现在,我要从整数格式转换回RGBA格式。

Image.clear();

for(unsigned i=0; i<NewImage.size(); i++)
{
    Image.push_back(NewImage[i] & 255);
    Image.push_back((NewImage[i] >> 8) & 255);
    Image.push_back((NewImage[i] >> 16) & 255);
    Image.push_back(0xff);
}

我得到的是一个黑色窗口(默认背景颜色),所以我不知道我缺少了什么。如果我注释掉获取新图像并只将IntImage转换回RGBA的行,我会得到正确的值,因此我不知道是否是混乱的RGBA/int <> int/RGBA引起的。现在我感到很困惑。我知道这可以被优化/简化,但现在我只想让它工作。


你尝试过输出Image向量的所有值以查看它们是什么吗? - OneOfOne
我得到了一个1.7 Mb的数据输出,其中前838680个字节是连续的00 00 00 FF。 - ali
1个回答

1
你的代码中数组访问不正确:

vector<int> temp(w2 * h2); // initializes the array to contain zeros
...
temp.push_back(...); // appends to the array, leaving the zeros unchanged

你应该进行覆盖而不是追加;为此,计算数组位置:
temp[i * w2 + j] = ...;

或者,将数组初始化为空状态,然后将您的内容附加到其中:

vector<int> temp;
temp.reserve(w2 * h2); // reserves some memory; array is still empty
...
temp.push_back(...); // appends to the array

目前为止,我不再看到黑色背景了,图像在水平方向上被正确地拉伸了,但在垂直方向上仍然保持原来的高度,并且是全蓝的。我不明白为什么它没有垂直地被调整大小。 - ali
蓝色图像可能与颜色顺序错误有关,但水平调整是由X服务器引起的。我的窗口是一个平面无边框对话框,看起来像是顶部栏应该出现的空间没有被绘制。 - ali

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接