如何使用C ++以及仅iostream和stdio标头缩放.bmp图像? [英] How to Scale a .bmp Image using C++ and just the iostream and stdio headers?

查看:100
本文介绍了如何使用C ++以及仅iostream和stdio标头缩放.bmp图像?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在用C ++进行第一次编程工作,我的目标是仅使用基本的IO标头缩放位图图像。

I am currently doing my first programming assignment in C++, and my objective is to Scale a Bitmap image using just the basic IO headers.

我曾经使用过< a href = http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29 rel = nofollow> http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29 作为查找标题信息的参考指南。

I've used http://en.wikipedia.org/wiki/BMP_file_format#DIB_header_.28bitmap_information_header.29 as my reference guide to finding the Header information.

我的问题是要创建一种算法,以添加单个像素的方式放大图像。
我做了一系列注释的for循环(它们使用标头信息来确定它们需要运行多少),但是我不知道下一步该如何操作实际像素,这是我需要帮助的地方

My problem is creating an algorithm to scale the image up in terms of adding in individual pixels. I have made a series of for loops which are commented (They use the header information to determine how much they need to run), but I have no idea what to do next in terms of manipulating the actual pixels, this is where I need help

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

When I run the program, a new BMP file (called Image2) is created, however it is corrupt and 1kb in size (Most likely because the program isn't finished).

这里是代码,如果有人也可以批评我或让我知道任何不良做法可避免

Here is the code, if anyone can also critique me on this or let me know any bad practices to avoid that I'm currently doing I would appreciate it.

 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上的第一篇文章,所以我很抱歉代码有点笨拙或难以理解(我已经阅读了论坛的内容,并整理了代码以使其更具可读性)

This is my first post on SE, so my apologies if the format of the code is a bit chunky or the question is hard to understand (I've read through the forum and have trimmed my code to make it more readable)

推荐答案

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

Doing a simple nearest re-sample is probably the easiest way to do it. To do this you simply calculate a ratio between the new and old sizes as follows:

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

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

Now you know that as you step 1 pixel in the x direction for the new image you would step "xStep" pixels in the old image. You then round the sampling position to the nearest integer location and sample that from the old image and write it to the new! You now have a simple re-sampled image.

要获得更好的结果,您可以双线性滤波器。这是一个非常简单的2D线性插值。

For even better results you can Bi-linear filter as you re-sample. This is a very simple 2D linear interpolation.

要给您一个过滤浮点值的一维示例,您可以编写一些类似以下的代码:

To give you a 1D example of filtering float values you would write some code something like as follows:

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。

Of course I'm not taking care of edge cases, but taking care of those and extending to 2D ought to be left as an exercise in the case of an assignment.

还值得注意的是,如果将图像向下缩放2倍以上,则由于您仍然完全跨过像素,因此这种过滤看起来会有点错误。通常可以通过在每个步骤将图像预过滤为宽度和高度的一半的图像集来解决。这就是 mip映射

Its also worth noting that this sort of filtering will look a bit wrong if you scale the image more than 2x downwards due to the fact that you still step over pixels completely. This is usually solved by pre-filtering the image into a set of images of half the width and height at each step. This is known as mip-mapping.

祝你好运!

这篇关于如何使用C ++以及仅iostream和stdio标头缩放.bmp图像?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆