c++ - 如何使用 C++ 以及 iostream 和 stdio header 缩放 .bmp 图像?

标签 c++ algorithm scale bmp

我目前正在用 C++ 完成我的第一个编程作业,我的目标是仅使用基本的 IO header 缩放位图图像。

我用过 http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29作为我查找标题信息的引用指南。

我的问题是创建一种算法,通过添加单个像素来放大图像。 我制作了一系列带有注释的 for 循环(它们使用标题信息来确定它们需要运行多少),但我不知道在操作实际像素方面下一步该做什么,这是哪里我需要帮助

当我运行该程序时,会创建一个新的 BMP 文件(称为 Image2),但它已损坏且大小为 1kb(很可能是因为该程序尚未完成)。

这是代码,如果有人也可以对此提出批评或让我知道避免我目前正在做的任何不良做法,我将不胜感激。

 int main()
    {
    
    FILE* pFile = NULL;
    FILE* pFile2 = NULL;
    
        
        //Open Image.bmp (In directory) as read binary
        pFile = fopen("Image.bmp", "rb");
        //Scan through the program and set to send.
        fseek (pFile, 0, SEEK_END);
        //Read file data
        int fileData = ftell (pFile);
        //set back to start of char pointer
        rewind (pFile);
    
    
        //Create a Char Filebuffer, this will be where data is viewed.
        char* FileBuffer = new char[fileData];
        //Read pFile into Filebuffer
        fread(FileBuffer, fileData, 1, pFile);
    
            //Read out BMP Header Data and Cast to Int
            int ImageSize = *(int*)&FileBuffer[2];
            int ImageOffset = *(int*)&FileBuffer[10]; //ImageOffset = Image Header Size
            int ImageHeight = *(int*)&FileBuffer[18];
            int ImageWidth = *(int*)&FileBuffer[20];
            int BitsPerPixel = *(int*)&FileBuffer[24];
    
        //Create a New Buffer that starts off at Pixel Data
        char* NewFileBuffer = FileBuffer + ImageOffset;
    
            
                std::cout << "Enter the amount of times you want to scale the image by." << std::endl;
                std::cin >> ScaleValue;
                std::cout << "\n";
    
                //Create New Image row/height/size variables
                int RowSizeOld = (BitsPerPixel * ImageWidth +31)/32 * 4;
                int RowSizeNew = (BitsPerPixel *(ImageWidth * ScaleValue) + 31) / 32 * 4;
                int NewImageSize = ImageOffset + (RowSizeNew * (ScaleValue * ImageHeight) );
                int NewImageHeight = ImageHeight * ScaleValue;
                int NewImageWidth = ImageWidth * ScaleValue;
    
    
    // These ints define the colour values for RGB and Padding
    int r = ImageOffset + 1; 
    int g = ImageOffset + 2; 
    int b= ImageOffset + 3; 
    int p = ImageOffset + 4; 
    
    
    
    //Rescale Image here, for (Newfile buffer [0])
        // This for loop figures out how many times the newHeight variable must iterate
        for (int newHeight = 0 ; newHeight < NewImageHeight ; newHeight++)
        {
            //This line scales up the amount of rows in terms of scale value
            for(int doubleLine = 0 ; doubleLine < ScaleValue ; doubleLine++)
            {
                //This for loop then figures out the width of the new image in pixels as an int value
                for (int newWidth = 0 ; newWidth < NewImageWidth ; newWidth++)
                { 
                    //This loop figures out how many times you need to increase the pixel density (for each pixel)
                    for (int pixelMultiplier = 0 ; pixelMultiplier < ScaleValue ; pixelMultiplier++)
                    {
                    
                  //Move pixel data around to scale image (This is where I'm having trouble)
        
                    }
                }
    
    
            }
    
    
        }
    
    
        //Create a new File pointer, add image name + bmp string
        FILE* pFile2;
        pFile2 = fopen("Image2.bmp", "wb");
        fwrite(NewFileBuffer, (NewImageSize + ImageOffset), sizeof(char) , pFile2);
    
    return 0;
    }

这是我关于 SE 的第一篇文章,如果代码格式有点笨拙或问题难以理解,我深表歉意(我已经通读了论坛并修改了我的代码以使其更具可读性)

最佳答案

进行简单的最近重采样可能是最简单的方法。为此,您只需计算新旧尺寸之间的比率,如下所示:

float xStep = (float)oldWidth / (float)newWidth;
float yStep = (float)oldHeight / (float)newHeight;

现在您知道,当您在新图像的 x 方向上步进 1 个像素时,您将在旧图像中步进“xStep”像素。然后,您将采样位置四舍五入到最接近的整数位置,并从旧图像中采样并将其写入新图像!您现在有一个简单的重新采样图像。

为了获得更好的结果,您可以 Bi-linear filter当你重新采样时。这是一个非常简单的二维线性插值。

为了给您一个过滤浮点值的一维示例,您可以编写如下代码:

for( float x = 0, int xOut = 0; x += xStep, xOut++; xOut < newWidth; )
{
    const float sample0  = old1D[std::floor( x )];
    const float sample1  = old1D[std::ceil( x )];

    const float t        = x - std::floor( x );

    const float sample   = sample0 + ((sample1 - sample0) * t);

    new1D[xOut] = sample;
}

当然,我不会处理边缘情况,但处理这些情况并扩展到 2D 应该留作作业中的练习。

同样值得注意的是,如果您将图像向下缩放超过 2 倍,这种过滤看起来会有点错误,因为您仍然完全跨越像素。这通常通过在每一步将图像预过滤成一组宽度和高度一半的图像来解决。这被称为 mip-mapping .

祝你好运!

关于c++ - 如何使用 C++ 以及 iostream 和 stdio header 缩放 .bmp 图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24672744/

相关文章:

c++ - 在 C++ 中获取硬编码内存地址的内容

algorithm - 在列表中查找升序三元组

algorithm - 生成强连接、均匀分布、随机的有向图

javascript - D3 变焦 v3 与 v5

python - 使用 PIL 缩放图像以保持透明度和颜色?

r - ggplot 整数中断方面

c++将NTP服务器返回的时间转换为字符串

c++ - 什么会导致类中的数据成员初始化为零?

c++ - 期望以确切的对象实例作为参数调用

algorithm - 有没有时间复杂度O(lg * n)(迭代对数函数)的算法?