【问题标题】:how do I fill the gaps between pixel in bmp file after loading the pixel array into the array with padded rows将像素数组加载到带有填充行的数组后,如何填充 bmp 文件中像素之间的空白
【发布时间】:2021-05-31 21:33:51
【问题描述】:

我用 C++ 编写了一个程序,使用 SetPixel windows 函数将 bmp 图像的像素绘制到控制台中,但是在将像素数组加载到数组中之后,图像被打印在控制台上,像素之间存在间隙。提前感谢您的帮助!

这是打印出来的图像在控制台上的输出。

这是我提供给它的原始图片。

正如您在此处看到的,图像宽度在控制台打印后也会发生变化。

// bmp bitmap
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
using namespace std;

#pragma pack(1)
struct BitmapFileHeader {
    unsigned short type;
    unsigned int size;
    unsigned short reserved1;
    unsigned short reserved2;
    unsigned int offset;
};
#pragma pack(0)

unsigned char grayScale(unsigned char r, unsigned char g, unsigned char b) {
    return ((r + g + b) / 3);
}
int main() {
    char *data;
    FILE *filePointer;
    int **ImageArray;
    BitmapFileHeader *bmp = (struct BitmapFileHeader*)malloc(sizeof(struct BitmapFileHeader));
    BITMAPINFOHEADER *BitmapInfoHeader = (BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER));
    HWND console = GetConsoleWindow();
    HDC context = ::GetDC(console) ;
    
    filePointer = fopen("tom.bmp", "rb");
    if(!filePointer) {
        perror("");
    }
    fread(reinterpret_cast<BitmapFileHeader*>(bmp), sizeof(BitmapFileHeader), 1, filePointer);
    fread(reinterpret_cast<BITMAPINFOHEADER*>(BitmapInfoHeader), sizeof(BITMAPINFOHEADER), 1, filePointer);

    if(BitmapInfoHeader->biSize == 40 && BitmapInfoHeader->biCompression == BI_BITFIELDS) {
        printf("This types of image uses Extra bit masks\n");
    }
    // row pading 
    int RowSize = ((BitmapInfoHeader->biBitCount * BitmapInfoHeader->biWidth + 31) / 32) * 4;
    int PixelArraySize = RowSize * BitmapInfoHeader->biHeight;
    int height = BitmapInfoHeader->biHeight * 5;
    int width = BitmapInfoHeader->biWidth * 5;
    
    printf("RowSize: %d PixelArraySize: %d\n", RowSize, PixelArraySize);
    
    ImageArray = (int**)malloc(sizeof(int*)*height);
    
    // memory allocation
    for(int i = 0; i < height; i++)
        ImageArray[i] = (int*)malloc(sizeof(int)*width);
        
    data = (char*)malloc(PixelArraySize);
    fseek(filePointer, bmp->offset, SEEK_SET);
    
     
    // set image into array 
    for(int ii = 0; ii < height; ii+=3) {
        fread(data, RowSize, 3, filePointer);
        for(int jj = 0; jj < width; jj+=3) {
            ImageArray[ii][jj] = grayScale(data[jj+2], data[jj+1], data[jj]);
                SetPixel(context, -jj+1000, -ii+500, RGB(data[jj+2], data[jj+1], data[jj]));
            }
    }
    fclose(filePointer);
    return 0;
}

这是我写的代码。

【问题讨论】:

    标签: c++ arrays c bmp


    【解决方案1】:

    一个像素由三个字节描述,每个 RGB 通道一个。您在这里处理两个索引:行数据中像素的索引和像素在宽度方向上的位置。您放置像素并访问具有相同索引的行数据。

    所以:

        for (int jj = 0; jj < width; jj++) {      // jj: position
            int kk = 3 * jj;                      // kk: data index
    
            ImageArray[ii][jj] = grayScale(data[kk + 2], data[kk + 1], data[kk]);
            SetPixel(context, -jj + 1000, -ii + 500, RGB(data[kk + 2], data[kk + 1], data[kk]));
        }
    

    垂直间隙,即空白行,来自递增 3,您应该只递增 1。(这里没有“数据索引”,因为您读取当前行的数据行宽 @987654322 @.)

    如果你想放大你的图像,正如宽度和高度乘以 5 所暗示的那样,你必须添加第三个索引:你现在有两个位置,源位置和目标位置。如果您将循环分开,这将更容易:在第一个嵌套循环中创建源图像的ImageArray,然后在目标坐标上循环将缩放的目标图像绘制到控制台:

    int scale = 5;
    int ww = scale * w;
    int hh = scale * h;
    
    // read ImageArray
    
    for (int y = 0; y < h; y++) {
        fread(data, RowSize, 3, filePointer);
    
        for (int x = 0; x < w; x++) {
            ImageArray[y][x] = ...;
                SetPixel(context, -jj+1000, -ii+500, RGB(data[jj+2], data[jj+1], data[jj]));
            }
    }
    
    for (int yy = 0; yy < hh; yy++) {
        fread(data, RowSize, 3, filePointer);
    
        for (int xx = 0; xx < ww; xx++) {
            int x = xx / scale;
            int y = yy / scale;
    
            SetPixel(context, yy, xx, ImageArray[y][x]);
        }
    }
    

    (这里,单字母代表源值,双字母代表目标值。)

    【讨论】:

    • 感谢您的快速重播,我已将增量更改为 1,并且 rbg 变为灰色,但间隙仍然存在但已最小化,我将宽度和高度相乘的原因是为了放大数组,如果我不将它乘以 5,图像将显示为一半。
    • 啊,我错过了你必须使用data[3 * jj + 2]等等。或者,您可以保留增量 3 并说 SetPixel(context, -jj / 3 + 1000, ...)。我会更新我的答案。
    • 哇,谢谢兄弟,但是-jj / 3 是什么意思?
    • 先生,更新您的回答,让我接受它作为回答
    • 如果我想将其放大 5 倍或某些因素怎么办?
    猜你喜欢
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多