简体   繁体   English

如何将 bitmap 从 VCL.Graphics.TBitmap 更改为 FMX.Graphics.TBitmap

[英]How to change bitmap from VCL.Graphics.TBitmap to FMX.Graphics.TBitmap

I'm trying to show an image taken with a camera on a multi-device form with paintbox after processing it with opencv. However, cvImage2Bitmap returns VCL.Graphics.TBitmap.在使用 opencv 处理后,我试图在带有 paintbox 的多设备形式上显示用相机拍摄的图像。但是,cvImage2Bitmap 返回 VCL.Graphics.TBitmap。 So I need to convert this to FMX.Graphics.TBitmap.所以我需要将其转换为 FMX.Graphics.TBitmap。

unit xml_cam2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, VCL.Graphics, FMX.Dialogs, FMX.ScrollBox,
  FMX.Memo, FMX.Objects, FMX.Controls.Presentation, FMX.StdCtrls,
  ocv.highgui_c,
  ocv.core_c,
  ocv.core.types_c,
  ocv.imgproc_c,
  ocv.imgproc.types_c,
  ocv.utils;

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    PaintBox1: TPaintBox;
    Memo1: TMemo;
    procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
    procedure FormCreate(Sender: TObject);
  private
    capture: pCvCapture;
    frame: pIplImage;
    procedure OnIdle(Sender: TObject; var Done: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation


var
  Bitmap, PaintBoxBitmap: FMX.Graphics.TBitmap;

{$R *.fmx}

procedure TForm1.FormCreate(Sender: TObject);
begin
  capture := cvCreateCameraCapture(CV_CAP_ANY);
  if Assigned(capture) then
    Application.OnIdle := OnIdle;
end;

procedure TForm1.OnIdle(Sender: TObject; var Done: Boolean);
begin
  if Assigned(capture) then
  begin
    frame := cvQueryFrame(capture);
    if Assigned(frame) then
    begin
      Bitmap := cvImage2Bitmap(frame);
      //cvImage2Bitmap returns VCL.Graphics.TBitmap
    end;
  end;

  Memo1.Lines.Add(IntToStr(Bitmap.Width));
  Memo1.Lines.Add(IntToStr(Bitmap.Height));

  if (PaintBoxBitmap = nil) then
    PaintBoxBitmap := FMX.Graphics.TBitmap.Create;
  PaintBoxBitmap.Assign(Bitmap);
  Invalidate;
  Bitmap.Free;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  if Assigned(PaintBoxBitmap) then
    PaintBox1.Canvas.DrawBitmap(PaintBoxBitmap, PaintBox1.ClipRect, PaintBox1.ClipRect, 1);
    Memo1.Lines.Add('b');
end;

end.

If you know any other efficient way to show iplimage to paintbox, please let us know.如果您知道向 paintbox 显示 iplimage 的任何其他有效方法,请告诉我们。

There are a couple of ways to do this.有几种方法可以做到这一点。 One way is to write the VCL bitmap to a TStream and then read it into the FMX bitmap. However, you can't convert the other way like that and it may be quite slow.一种方法是将 VCL bitmap 写入 TStream,然后将其读入 FMX bitmap。但是,您不能像那样转换另一种方式,它可能会很慢。 I prefer to use Scanlines to convert between one and the other.我更喜欢使用扫描线在一个和另一个之间进行转换。 In my code below I'm using 24 bit VCL bitmaps because I've found that the Windows API prefers these (AVIFile32 for example).在我下面的代码中,我使用 24 位 VCL 位图,因为我发现 Windows API 更喜欢这些(例如 AVIFile32)。 Both bitmaps need to be created before calling the procedures.两个位图都需要在调用过程之前创建。 Of course you need to be creating an FMX application for Windows and include VCL.Graphics in your uses.当然,您需要为 Windows 创建一个 FMX 应用程序,并在您的使用中包含 VCL.Graphics。 Any transparency in the FMX bitmap will be lost when converting to a 24 bit VCL bitmap.转换为 24 位 VCL bitmap 时,FMX bitmap 中的任何透明度都将丢失。

Convert 24 bit VCL bitmap to FMX bitmap将 24 位 VCL bitmap 转换为 FMX bitmap

procedure VCLtoFMX_Bitmap(const VCLBmp : VCL.Graphics.TBitmap ; out FMXBmp : FMX.Graphics.TBitmap);
var
  bData : TBitmapData;
  x, y : Integer;
  pfmxbyte, pvclbyte : PByte;
begin
  VCLBmp.PixelFormat := pf24bit;
  FMXBmp.SetSize(VCLBmp.Width, VCLBmp.Height);
  FMXBmp.Map(TMapAccess.ReadWrite, bdata);

  try
    for y := 0 to FMXBmp.Height - 1 do begin
      pfmxbyte := bdata.GetScanline(y);
      pvclbyte := VCLBmp.Scanline[y];
      for x := 0 to FMXBmp.Width - 1 do begin
        pfmxbyte^ := pvclbyte^; Inc(pvclbyte); Inc(pfmxbyte);
        pfmxbyte^ := pvclbyte^; Inc(pvclbyte); Inc(pfmxbyte);
        pfmxbyte^ := pvclbyte^; Inc(pvclbyte); Inc(pfmxbyte);
        pfmxbyte^ := $FF; Inc(pfmxbyte); // Full opacity
      end;
    end;
  finally
    FMXBmp.Unmap(bdata);
  end;
end;

Convert FMX bitmap to 24 bit VCL bitmap将 FMX bitmap 转换为 24 位 VCL bitmap

procedure FMXtoVCL_Bitmap(const FMXBmp : FMX.Graphics.TBitmap ; out VCLBmp : VCL.Graphics.TBitmap);
var
  bData : TBitmapData;
  x, y : Integer;
  pfmxbyte, pvclbyte : PByte;
begin
  VCLBmp.PixelFormat := pf24bit;
  VCLBmp.SetSize(FMXBmp.Width, FMXBmp.Height);
  FMXBmp.Map(TMapAccess.Read, bdata);

  try
    for y := 0 to FMXBmp.Height - 1 do begin
      pfmxbyte := bdata.GetScanline(y);
      pvclbyte := VCLBmp.Scanline[y];
      for x := 0 to FMXBmp.Width - 1 do begin
        pvclbyte^ := pfmxbyte^; Inc(pvclbyte); Inc(pfmxbyte);
        pvclbyte^ := pfmxbyte^; Inc(pvclbyte); Inc(pfmxbyte);
        pvclbyte^ := pfmxbyte^; Inc(pvclbyte); Inc(pfmxbyte, 2);
      end;
    end;
  finally
    FMXBmp.Unmap(bdata);
  end;
end;

It would be nice to move image data directly from one bitmap to the other, but doesn't seems to be an easy task.将图像数据直接从一个 bitmap 移动到另一个会很好,但似乎不是一件容易的事。

Instead, the simplest way ( as it was answered here VCL.Bitmap To FMX.Bitmap ) seems to be to save image to a memory stream and load again in FMX bitmap object.相反,最简单的方法(正如此处VCL.Bitmap To FMX.Bitmap所回答的那样)似乎是将图像保存到 memory stream 并在 FMX bitmap object 中再次加载。

This simple code just works.这个简单的代码就可以工作。 You pay the penalty for moving image data to memory to load again in the new bitmap, but seems fair in exchange for simplicity.您支付移动图像数据到 memory 的罚款以在新的 bitmap 中再次加载,但为了简单起见似乎是公平的。

procedure TForm1.FormCreate(Sender: TObject);
var
  ms : TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    VCL_bmp := VCL.Graphics.TBitmap.Create;
    try
      VCL_bmp.LoadFromFile('file.bmp');
      VCL_bmp.SaveToStream(ms);
      ms.Seek(0, soFromBeginning);
    finally
      FreeAndNil(VCL_bmp);
    end;

    FMX_bmp := FMX.Graphics.TBitmap.Create();
    try
      FMX_bmp.LoadFromStream(ms);

      ... do something with the image ...
    finally
      FreeAndNil(FMX_bmp);
    end;
  finally
    FreeAndNil(ms);
  end;
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM