RT...
解析GIF,得到每一帧后画到一个IMAGEE 上,再将它贴到摄像头上,可是背景无法透明...请问要怎么处理?这一是段GDI+的RGBA 转 ARGB的代码,在这里面可以进行透明,但其它色会丢失..
var a,r,g,b: Byte;
    bd: TBitmapData;
    hd : PChar;
    rc : TRect;
    img : PBYTE;
    png : TGpBitmap;
Func_GifImage_Draw(Pointer(OverlayGifs.Layers[i].dwHGifImage), OverlayGifs.Layers[i].nIDX,Image1.Canvas.Handle);        // 利用TImage.Picture.Bitmap的图像句柄Handle和调色板属性Palette建立一个GDI+位图
         bmp.Assign(image1.Picture.Bitmap);
        DrawTrans(Image1.Canvas,320,240,bmp,clred);
        with Image1.Picture.Bitmap do
        Png := TGpBitmap.Create(Handle,Palette);
        if (png <> nil) and (png.Width > 0) then
        begin
          rc.X := 0; rc.Y := 0;
          rc.Width := png.Width;
          rc.Height := png.Height;
          bd := png.LockBits(rc,[imRead], pf32bppARGB);
         img := PBYTE(bd.Scan0);
         for j := 0 to bd.Height -1  do
          begin
            hd := pchar(img) + j * bd.Stride;
           for k := 0 to bd.Width -1  do
            begin
       r := byte(hd[k*4+0]);
       g := byte(hd[k*4+1]);
       b := byte(hd[k*4+2]);
       a := byte(hd[k*4+3]);              {hd[k*4+0] := char(a);
      hd[k*4+1] := char(r);
      hd[k*4+2] := char(g);
              hd[k*4+3] := char(b); } //动画正常显示,背景不透明,(黑色,白,蓝)              hd[k*4+3] := char(a);
      hd[k*4+1] := char(r);
      hd[k*4+2] := char(g);
              hd[k*4+0] := char(b);
              hd[k*4+3] := char(b); //背景可以透明,但是B色丢失(显示很淡)
    end;
          end;
          m_pConfig.AddOverlay((TArrByte(bd.Scan0))[0], png.Width, png.Height, 0, 0, i);
          png.UnlockBits(bd);
    end;请问可不可以在循环中进行处理?将它透明化然后再贴到摄像头上?万分感谢

解决方案 »

  1.   

    hd[k*4+3] := char(b); //背景可以透明,但是B色丢失(显示很淡) 这是毫无道理的赋值。hd[k*4+3] 是Alpha字节,不明白把Blue字节值b赋给它意义何在?正确的做法应该是首先确定背景色的颜色值,然后逐像素判断替换背景色为0(或者背景色的Alpha=0)。不过GIF图片的背景色看上去是一样的,其实可能不只是一种颜色(抖动后又多个颜色成分),所以,重点在于确定背景色的颜色值有几种。 
      

  2.   

    RGB色的转换.不然颜色会刚好相反
             r := byte(hd[k*4+0]);
             g := byte(hd[k*4+1]);
             b := byte(hd[k*4+2]);
             a := byte(hd[k*4+3]);
                  if (r = g) and (g = b) then continue;
                  hd[k*4+0] := char(a);
            hd[k*4+1] := char(r);
             hd[k*4+2] := char(g);
                  hd[k*4+3] := char(b);
    改用这种方式,就正常了
    但是如果贴的是单张背景色为黑色的GIF就不行,显示为白色,如果再贴另一张上去,就正常了...
    不知为什么..解析 后的图片是会白色的...
      

  3.   

    RGB色的转换.不然颜色会刚好相反
    =========================================
    我不知道摄像头需要的像素RGB各分量是怎么排列的,但据我所知,GDI+的TGpBitmap与Delphi的TBitmap的像素RGB各分量的排列是一样的,0:Blue; 1:Green; 2:Red,如果是32位ARGB,则:3:Alpha。(不要把TColor中RGB的排列方式与图像像素RGB的排列方式混为一谈)另外请注意,因为LZ的GDI+ Bitmap是从Image1.Picture.Bitmap转换得来的32位ARGB格式图像,其Alpha值都是$FF
      

  4.   

    谢谢楼上热心人...我都快晕了...只是根据将原图贴到摄像头上的效果跟原图相比较,才发现要进行转换,但不知为啥有的图片的背景色就去不掉..会覆盖摄像头,有的图片很正常.
    另问你一下,已经取得图片的 scan0 和 RGB 色(24位),能否直接将它转为32位的?
      

  5.   

    24转换32其Alpha也是$FF,不是你想的已经把背景色的Alpha置零。你用LockBits已经转换成了32位,但是背景的透明度还是的逐点判断和修改。所以,我前面说了,最终你还是得“首先确定背景色的颜色值,然后逐像素判断替换背景色为0(或者背景色的Alpha=0)。”你可以参考一下我的文章:《http://blog.csdn.net/maozefa/archive/2007/01/30/1498217.aspx》四、利用GDI+位图扫描线,实现其它特色透明显示
      

  6.   

    谢谢,
    一.逐像素判断的速度太慢了..这是一个,还有就是我的背景图是摄像头,不知道怎么去限它的颜色值
    二.已经取得图片的 scan0 和 RGB 色(24位),能否直接将它转为32位的? 
      

  7.   

    就是将GIF贴到摄像头上,将GIF解析为BMP后,一张一张往上贴.实现动画效果,那关键就是背景色了..取摄像头的吗?
    有的BMP是单色背景色,有的已经是半透明的....
      

  8.   

    没做过。但是有一点提醒你,不要钻牛角尖:无论“有的BMP是单色背景色,有的已经是半透明的....”,转换为位图后不存在透明或半透明背景!
    另外,既然你有多祯GIF图像,为什么不试试直接传递该图像?方法是:
    每次只是选择当前祯(可参考我的多祯图像分解文章,但不要分解,只是选择当前页就行了),然后用LockBits方法锁定它(图像格式参数不能改变,只能取TGpBitmap打开GIF图像的原始格式,否则出错。),再将scan0传过去试试。
      

  9.   

    我想了一下,上面那个方法也不行的。
    只是我一直没明白LZ“将GIF贴到摄像头上”是什么意思?
    是否不断从摄像头采集图像数据,转换成TBitmap或者TGpBitmap,然后把多桢GIF图像逐祯合成到TBitmap或者TGpBitmap,最后将图像再转换为摄像头所需数据?
    如果是这样一个过程就好办了,逐祯选择GIF激活祯,将GIF图片直接合成到TBitmap或者TGpBitmap,这时背景的透明色就起作用了,然后转换为摄像头所需数据
      

  10.   

    不是的,不关摄像头的事...
    我这边做的操作是,在定时器中解开GIF,然后将BMP贴到摄像头上,没有从摄像头采集图像..
      

  11.   

    我不明白的就是这句“然后将BMP贴到摄像头上”,怎么贴?
      

  12.   

    调用 一个 directshow 中的 overlay 接口来贴的..
      

  13.   

    这破CSDN,怎么图片显示不了
    http://tg1a161.mail.163.com/netfolder/servlet/nfapp/GetFile?sid=jDjqdkPPEaMKjiuEWgPPqldYmAQqtOYP&mid=1tbinxMtMEL+9dj6OQAAsD往IMAGE 或BMP ...上放这张图片时,怎么让它透明化?
      

  14.   

    对不起,让你失望了。
    “黑色”背景很容易搞定(之所以把“黑色”用引号引上,我早就说过,看上去是黑色,其实不只一种颜色,而是由一个范围的颜色值组成的),多测试几下范围就可行了。
    关键是你原图的光照效果已经与原“黑色”背景融为一体,形成了混合半影调颜色,我想多牛的人也没有很好的办法,即使用Photoshop魔棒也没法弄干净。
    下面是我试验的代码, 你可以修改BkMaxColor,但无论修改多大,半影调也没法重现!我试验形成的图片01.rar也通过附件发给你看,0-x.png是没有背景的,01-x.png是加了背景的。const
      BkMaxColor = $FF3A3A3A;      // 最大背景颜色值
    var
      I, Count: Integer;
      Clsid: TClsid;
      Image: TGpImage;
      bkImage: TGpImage;
      Attr: TGpImageAttributes;
      bmp: TGpBitmap;
      tmp: TGpBitmap;
      tg, bg: TGpGraphics;
      GUID: TGUID;
    begin
      // 打开图像文件
      Image := TGpImage.Create('e:\0.gif');
      BkImage := TGpImage.Create('e:\1.gif');
      tmp := TGpBitmap.Create(Image.Width, Image.Height, pf32bppARGB);
      tg := TGpGraphics.Create(tmp);
      bmp := TGpBitmap.Create(Image.Width, Image.Height, pf32bppARGB);
      bg := TGpGraphics.Create(bmp);
      Attr := TGpImageAttributes.Create;
      try
        // 设置透明色范围
        Attr.SetColorKey($FF000000, BkMaxColor);
        Image.GetFrameDimensionsList(@GUID, 1);
        // 获取图像祯数
        Count := Image.GetFrameCount(GUID);
        GetEncoderClsid('image/png', Clsid);    for I := 0 to Count - 1 do
        begin
          // 选择激活祯
          Image.SelectActiveFrame(GUID, I);
          // 画当前祯到临时图
          tg.DrawImage(Image, 0, 0, Image.Width, Image.Height);
          // 合成图初始化为透明色
          bg.Clear(0);
          // 画背景图,如不需要背景图,可将下面注释掉
          bg.DrawImage(BkImage, 0, 0, bmp.Width, bmp.Height);
          // 画临时图
          bg.DrawImage(tmp, GpRect(0, 0, bmp.Width, bmp.Height),
              0, 0, tmp.Width, tmp.Height, utPixel, Attr);
          // 保存
          bmp.Save('e:\01-' + IntToStr(I) + '.png', Clsid);
        end;
      finally
        Attr.Free;
        bg.Free;
        bmp.Free;
        tg.Free;
        tmp.Free;
        BkImage.Free;
        Image.Free;
      end;
    end;
      

  15.   

    可以考虑借助PNG格式,此格式可以保证透明。
      

  16.   

    终于想办法把背景替换成带透明度的了,下面是用你给的图片制作的动画演示程序。也许你觉得颜色还是有些“淡”,客观上,是光晕部分有些损失,主观上,由于去掉黑色背景后,对比不强烈引起的视觉效果,供参考吧。
    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Gdiplus, ActiveX, ExtCtrls;type
      TForm1 = class(TForm)
        Timer1: TTimer;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure FormPaint(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        { Private declarations }
        Index: Integer;
        Count: Integer;
        Images: array of TGpImage;
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementationuses Math;{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
    type
      TARGBRect = packed record
        Blue, Green, Red, Alpha: Byte;
      end;
    var
      I, x, y: Integer;
      W, H: Integer;
      Image: TGpImage;
      bkImage: TGpImage;
      bmp: TGpBitmap;
      bg: TGpGraphics;
      GUID: TGUID;
      ig: TGpGraphics;
      Data: TBitmapData;
      P: PInteger;
    begin
      DoubleBuffered := True;
      // 打开图像文件
      Image := TGpImage.Create('e:\0.gif');
      W := Image.Width;
      H := Image.Height;
      BkImage := TGpImage.Create('e:\1.gif');
      bmp := TGpBitmap.Create(W, H, pf32bppARGB);
      bg := TGpGraphics.Create(bmp);
      try
        Image.GetFrameDimensionsList(@GUID, 1);
        // 获取图像祯数
        Count := Image.GetFrameCount(GUID);
        SetLength(Images, Count);
        for I := 0 to Count - 1 do
        begin
          Image.SelectActiveFrame(GUID, I);
          bg.DrawImage(Image, 0, 0, W, H);
          Data := bmp.LockBits(GpRect(0, 0, W, H), [imRead, imWrite], pf32bppARGB);
          P := Data.Scan0;
          for y := 1 to Data.Height do
            for x := 1 to Data.Width do
            begin
              // 计算不透明度,三种方法都试了
              with TARGBRect(P^) do
              Alpha := Max(Red, Max(Green, Blue));
              //Alpha := (Red + Green + Blue) div 3;
              //Alpha := (306 * Red + 601 * Green + 117 * Blue) div 1024;
              Inc(P);
            end;
          // 如果演示效果行,可以把Data.Scan0传递给你的那个函数m_pConfig.AddOverlay
          bmp.UnlockBits(Data);
          Images[I] := TGpBitmap.Create(W, H, pf32bppARGB);
          ig := TGpGraphics.Create(Images[I]);
          ig.DrawImage(BkImage, 0, 0, W, H);
          ig.DrawImage(bmp, 0, 0, W, H);
          ig.Free;
        end;
      finally
        bg.Free;
        bmp.Free;
        BkImage.Free;
        Image.Free;
      end;
    end;procedure TForm1.FormDestroy(Sender: TObject);
    var
      I: Integer;
    begin
      for I := 0 to Count - 1 do
        Images[I].Free;
    end;procedure TForm1.FormPaint(Sender: TObject);
    var
      g: TGpGraphics;
    begin
      g := TGpGraphics.Create(Canvas.Handle);
      try
        g.DrawImage(Images[Index], 0, 0);
      finally
        g.Free;
      end;
    end;procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Inc(Index);
      if Index = Count then
        Index := 0;
      Invalidate;
    end;end.
      

  17.   

    上面例子中Timer1.Interval 设置为100 - 200,自己调整
      

  18.   

    嗯 ..再次谢谢你..
    我原本也是在循环中对RGB色进行变换了,就是太淡了.效果不怎么好
    暂时只能先这样了