gpt4 book ai didi

c++ - 如何从 TBitmap 获取像素数组?

转载 作者:行者123 更新时间:2023-12-02 09:50:38 27 4
gpt4 key购买 nike

在相机应用程序中,位图像素阵列是从流式相机中检索的。
通过将像素数组写入命名管道来捕获像素数组,在管道的另一端,ffmpeg 检索它们并创建一个 AVI 文件。

我将需要创建一个自定义帧(启用自定义文本),并将其像素作为生成影片中的第一帧进行管道传输。

问题是我如何使用 TBitmap (为方便起见)

  • 从头开始创建 X x Y 单色(8 位)位图,使用
    自定义文本。我希望背景为白色,文本为
    变黑。 (主要是想出这一步,见下文。)
  • 检索我可以发送/写入管道的像素数组

  • 第 1 步:以下代码创建一个 TBitmap 并在其上写入文本:
    int w = 658;
    int h = 492;
    TBitmap* bm = new TBitmap();
    bm->Width = w;
    bm->Height = h;
    bm->HandleType = bmDIB;
    bm->PixelFormat = pf8bit;

    bm->Canvas->Font->Name = "Tahoma";
    bm->Canvas->Font->Size = 8;

    int textY = 10;
    string info("some Text");

    bm->Canvas->TextOut(10, textY, info.c_str());

    以上基本结束步骤1。

    写入/管道代码需要一个带有位图像素的字节数组;例如
    unsigned long numWritten;
    WriteFile(mPipeHandle, pImage, size, &numWritten, NULL);

    其中 pImage 是指向无符号字符缓冲区(位图像素)的指针,大小是此缓冲区的长度。

    更新:
    使用生成的 TBitmap 和 TMemoryStream 将数据传输到 ffmpeg 管道不会生成正确的结果。我得到一个扭曲的图像,上面有 3 条对角线。

    我收到的相机帧缓冲区的缓冲区大小正好是 323736 ,等于图像中的像素数,即 658x492。
    注意 我的结论是这个“位图”没有被填充。 658 不能被四整除。

    但是,将生成的位图转储到内存流后得到的缓冲区大小为 。 325798 ,即 2062 字节大于它应该是。正如@Spektre 在下面指出的那样,这种差异可能是填充?

    使用以下代码获取像素数组;
    ByteBuffer CustomBitmap::getPixArray()
    {
    // --- Local variables --- //
    unsigned int iInfoHeaderSize=0;
    unsigned int iImageSize=0;
    BITMAPINFO *pBitmapInfoHeader;

    unsigned char *pBitmapImageBits;

    // First we call GetDIBSizes() to determine the amount of
    // memory that must be allocated before calling GetDIB()
    // NB: GetDIBSizes() is a part of the VCL.
    GetDIBSizes(mTheBitmap->Handle,
    iInfoHeaderSize,
    iImageSize);

    // Next we allocate memory according to the information
    // returned by GetDIBSizes()
    pBitmapInfoHeader = new BITMAPINFO[iInfoHeaderSize];
    pBitmapImageBits = new unsigned char[iImageSize];

    // Call GetDIB() to convert a device dependent bitmap into a
    // Device Independent Bitmap (a DIB).
    // NB: GetDIB() is a part of the VCL.
    GetDIB(mTheBitmap->Handle,
    mTheBitmap->Palette,
    pBitmapInfoHeader,
    pBitmapImageBits);

    delete []pBitmapInfoHeader;

    ByteBuffer buf;
    buf.buffer = pBitmapImageBits;
    buf.size = iImageSize;
    return buf;
    }

    所以最后的挑战似乎是获得一个与来自相机的字节数组大小相同的字节数组。如何从 TBitmap 代码中查找和删除填充字节?

    最佳答案

    TBitmap有一个 PixelFormat 属性来设置位深度。
    TBitmap有一个 HandleType 属性来控制是创建 DDB 还是 DIB。 DIB 是默认值。

    由于您在不同系统之间传递 BMP,因此您确实应该使用 DIB 而不是 DDB,以避免像素数据的任何损坏/误解。

    另外,这行代码:

    Image1->Picture->Bitmap->Handle = bm->Handle;

    应该改为:

    Image1->Picture->Bitmap->Assign(bm);
    // or:
    // Image1->Picture->Bitmap = bm;

    或这个:

    Image1->Picture->Assign(bm);

    无论哪种方式,不要忘记 delete bm;之后,由于 TPicture复制输入 TBitmap ,它不具有所有权。

    要将 BMP 数据作为字节缓冲区获取,可以使用 TBitmap::SaveToStream() 方法,保存到 TMemoryStream .或者,如果您只想要像素数据,而不是完整的 BMP 数据(即,没有 BMP header - 请参阅 Bitmap Storage ),您可以使用 Win32 GetDiBits() 函数,它以 DIB 格式输出像素。您无法获得 DDB 像素的字节缓冲区,因为它们取决于它们被渲染到的设备。 DDB 只能在内存中与 HDC 一起使用。 s,你不能传递它们。但是,一旦有了最终设备可以将其渲染到,您就可以将 DIB 转换为 DDB。

    换句话说,从相机获取像素,将它们保存到 DIB,根据需要传递(即通过管道),然后用它做任何你需要的事情 - 保存到文件,转换为 DDB 以在屏幕上呈现, ETC。

    关于c++ - 如何从 TBitmap 获取像素数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59761501/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com