如题
我现在用的是bitmap.GetPixel和bitmap.SetPixel,请问有没有办法用ColorMatrix来做或其他的一些高效的方法?另画透明位图:我现在有2幅图,一副是要显示的图片A,另一副是遮照(mask)B,只有黑白2色,2幅图片大小一样,要实现的方法就是让A只显示B的白色部分的区域,小弟愚钝,现在也是用GetPixel和SetPixel来做的。
请教各位大虾,高效的处理方法,Gdi+里能不能有gid中那样的光栅操作来运算图片阿?

解决方案 »

  1.   

    用BitmapData对象来做吧,效率也很高        /// <summary>
            /// 图像明暗调整
            /// </summary>
            /// <param name="b">原始位图</param>
            /// <param name="degree">亮度[-255, 255]</param>
            /// <returns></returns>
            public static Bitmap Ki1381Lighten(Bitmap b, int degree)
            {
                if (b == null)
                {
                    return null;
                }            if (degree < -255) degree = -255;
                if (degree > 255) degree = 255;            try
                {                int width = b.Width;
                    int height = b.Height;                int pix = 0;                BitmapData data = b.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);                unsafe
                    {
                        byte* p = (byte*)data.Scan0;
                        int offset = data.Stride - width * 3;
                        for (int y = 0; y < height; y++)
                        {
                            for (int x = 0; x < width; x++)
                            {
                                // 处理指定位置像素的亮度
                                for (int i = 0; i < 3; i++)
                                {
                                    pix = p[i] + degree;                                if (degree < 0) p[i] = (byte)Math.Max(0, pix);
                                    if (degree > 0) p[i] = (byte)Math.Min(255, pix);                            } // i
                                p += 3;
                            } // x
                            p += offset;
                        } // y
                    }                b.UnlockBits(data);                return b;
                }
                catch
                {
                    return null;
                }        } // end of Lighten编译时要启用“允许不安全代码”
      

  2.   

    第二个问题我的想法是:扫描A,B每一个点,如果B点是黑的,那么A的对应点就用某种颜色做背景色代替(所谓的不显示?),否则A的这个点的颜色不动。SetPixel和GetPixel好像是太慢了。
      

  3.   

    Sorry,看错了,还以为在C#板块混呢...送上Delphi版,还好也做过,呵呵
    // ****************************************************************************
    // 亮度校正
    // 参数:
    //      bmp     输入Bitmap
    //      bmpOut  输出Bitmap
    //      s       校正值
    // ****************************************************************************
    function KiBright(bmp:TBitmap;var bmpOut:TBitmap;s:integer):boolean;
    var
        p: PByteArray;
        x, y: Integer;
    begin
    try
        //24位真彩色
      Bmp.PixelFormat := pf24Bit;
      bmpOut.PixelFormat := pf24Bit;  bmpOut.Width := bmp.Width;
      bmpOut.Height := bmp.Height;  for y := 0 to Bmp.Height - 1 do
      begin
        p := Bmp.scanline[y];
        for x := 0 to Bmp.Width - 1 do
        begin
          //每个象素点的R、G、B分量进行调节
          begin
            if s>0 then
            begin
              p[x * 3] := Min(255, p[x * 3] + s); //不能越界,限制在0~255
              p[x * 3 + 1] := Min(255, p[x * 3 + 1] + s);
              p[x * 3 + 2] := Min(255, p[x * 3 + 2] + s);
            end
            else begin
              p[x * 3] := max(0, p[x * 3] + s); //不能越界,限制在 -255~0
              p[x * 3 + 1] := max(0, p[x * 3 + 1] + s);
              p[x * 3 + 2] := max(0, p[x * 3 + 2] + s);
            end;
          end;
        end;
      end;  bmpOut.Assign(bmp);
      Result := true;
    except
      Result := false;
    end;end;
      

  4.   

    谢谢 ki1381() 
    第一个问题你的方法和我类似,就是逐一的判断和设置每一点,我现在用的是Gdi+,我想都是gdi+了,应该有办法效率更高吧,你C#的那个例子也许比我现在的要快,怎么说也是移动指针,但是delphi里我用的是gdiplus的库,不知道怎么找到那个bitmapData,就是图像的数据第2个问题,我现在就是同时读取2幅图,根据遮照图的R值来设置图像的Alpha值,也是逐点扫描,然后设置,效率可想而知,如果用以前的Gdi倒是有快速的光栅操作可以实现。
      

  5.   

    呵呵,在delphi里找到那个指针了,也是LockBits
      

  6.   

    在问一个问题
    gdi+中,如果TGPbitmap已经Create了,应该怎么改变width和height的值啊
    我现在总是先Free,然后在Create一边,有没有更好de办法啊
      

  7.   

    呵呵,我纯粹是看错了板块才误入此帖,抱歉。我现在已经不做Delphi了,所以你的问题还是请其他懂得的朋友来回答吧!另外我有一个Gamma校正的例子,不过也是C#的,看看有没有参考价值        /// <summary>
            /// Gamma校正
            /// </summary>
            /// <param name="bmp">输入Bitmap</param>
            /// <param name="val">[0 <-明- 1 -暗-> 2]</param>
            /// <returns>输出Bitmap</returns>
            public static Bitmap KiGamma(Bitmap bmp, float val)
            {
                if (bmp == null)
                {
                    return null;
                }            // 1表示无变化,就不做
                if (val == 1.0000f) return bmp;            try
                {
                    Bitmap b = new Bitmap(bmp.Width, bmp.Height);
                    Graphics g = Graphics.FromImage(b);
                    ImageAttributes attr = new ImageAttributes();                attr.SetGamma(val, ColorAdjustType.Bitmap);
                    g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attr);
                    g.Dispose();
                    return b;
                }
                catch
                {
                    return null;
                }
            }另外,Bmp.scanline速度也不慢啊,比一个个点傻取快得多
      

  8.   

    第一个问题参见我的Blog文章:http://blog.csdn.net/maozefa/archive/2007/01/28/1496383.aspx第二个问题使用如下代码(如代码与你的GDI+单元有出路,请适当修改;建立和释放图形和TgpGraphics代码省略):
    var
      attr: TGpImageAttributes;
      g: TGpGraphics;
      Image: TGpImage;
    begin
      .....
      attr := TGpImageAttributes.Create;
      attr.SetColorKey(aclWhite, aclWhite);  // 设置白色为透明显示
      g.DrawImage(Image, MakeRect(0, 0, Image.GetWidth, Image.GetHeight), 0, 0, Image.GetWidth, Image.GetHeight, UnitPixel, attr); 
      attr.Free;
      ...
    end;
      

  9.   

    再请看我的BLOG,关于图像透明显示的技巧:http://blog.csdn.net/maozefa/archive/2007/01/30/1498217.aspx