写入.BMP - 扭曲的图像

时间:2013-12-07 17:00:12

标签: c++ image bitmap

我想写一个.bmp文件的法线贴图,所以我先实现了一个简单的.bmp编写器:

void BITMAPLOADER::writeHeader(std::ofstream& out, int width, int height)
{
    BITMAPFILEHEADER tWBFH;
    tWBFH.bfType = 0x4d42;
    tWBFH.bfSize = 14 + 40 + (width*height*3);
    tWBFH.bfReserved1 = 0;
    tWBFH.bfReserved2 = 0;
    tWBFH.bfOffBits = 14 + 40;

    BITMAPINFOHEADER tW2BH;
    memset(&tW2BH,0,40);
    tW2BH.biSize = 40;
    tW2BH.biWidth = width;
    tW2BH.biHeight = height;
    tW2BH.biPlanes = 1;
    tW2BH.biBitCount = 24;
    tW2BH.biCompression = 0;

    out.write((char*)(&tWBFH),14);
    out.write((char*)(&tW2BH),40);
}

bool TERRAINLOADER::makeNormalmap(unsigned int width, unsigned int height)
{
    std::ofstream file;
    file.open("terrainnormal.bmp");

    if(!file)
    {
        file.close();
        return false;
    }

    bitmaploader.writeHeader(file,width,height);


    for(int y = 0; y < height; y++)
    {
        for(int x = 0; x < width; x++)
        {
            file << static_cast<unsigned char>(255*x/height);    //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
            file << static_cast<unsigned char>(0);               //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
            file << static_cast<unsigned char>(0);               //(unsigned char)((getHeight(float(x)/float(width),float(y)/float(height))));
        };
    };

    file.close();

    return true;
};

writeHeader(...)函数来自SO,来自已解决的工作帖子。 (我已经忘记了它的名字)

getHeight(...)使用双三次插值,因此我可以将其写入大分辨率图像,并保持平滑。它也将用于碰撞检测,现在用作剪贴图的LOD因子。

现在问题是这会输出扭曲的图像。这些图片将告诉我的一切:

预期/失真的结果:

  • 表示高度图:我有描述网格的函数:getHeight(x,z)。它返回了正确的结果,因为我已经使用着色器(通过将高度作为顶点属性)进行了测试。从互联网上下载的图片:

Correct image

  • 将y(x,z)函数值写入.BMP :(代码注释掉的部分):

Lines are distorted

  • 使用简单的功能:file << static_cast<unsigned char>(255*(float)x/height)

Lines are distorted

应该是从黑到白的简单混合。

我使用的图像大小为256 x 256,因为我读过它应该是4的倍数。我可以使用库,但是我想在没有库的情况下解决这个问题。是什么导致了这种失真?

修改 在最后一张图片上,有些线条也是彩色的,但它们不应该是。这篇文章很相似,但我的高度图并没有像这篇帖子那样线性扭曲:Image Distortion with Lock Bits

修改 另一个奇怪的问题是,当我不能使所有颜色相同时,颜色也会变形。例如,将RED设置为高度,并留下G和B 0,它不仅变成了RED,而且变成了嘈杂的彩色高度图。

编辑/评论/ 如果我理解正确,那么标题的大小就是我的像素数据。在像素数据之前,必须有 4 * n 字节。所以填充意味着在标题之后我添加了更多填充该位置的数据。

例如假设(我会看起来很热得到它)我的标题是55个字节,然后我应该再添加1个字节,因为55 + 1 = 56和4 | 56。

所以

file << static_cast<unsigned char>('a');

for(int y = 1; y <= width; y++)
{
    for(int x = 1; x <= height; x++)
    {
        file << static_cast<unsigned char>(x);
        file << static_cast<unsigned char>(x);
        file << static_cast<unsigned char>(x);
    };
};

应该是正确的。

但我意识到了真正的问题(正如Jigsore评论的那样)。当我从int投射到char时,似乎 1位数字变为1字节,2位数字变为2,3位数字变为3字节将高度限制为3位数效果很好,但图像有些白皙,因为“最暗”。颜色变为(100,100,100)而不是(0,0,0)。此外,这也是非常规失真的原因,因为它取决于多少山丘和#39;或者&#39; mountains&#39;有一排。我怎么能解决这个问题,我希望最后一个问题呢?我不想将图像压缩到100-256范围。;)

1 个答案:

答案 0 :(得分:1)

以二进制模式打开文件。

在Windows下,如果您以默认文本模式打开文件,它将在每次写出0x0d(换行)后写入额外的0x0a(返回)字符。第一次发生这种情况时,它将改变以下像素的颜色,因为RGB顺序不对齐。在它发生3次之后你会被一个完整的像素关闭。