Results 1 to 9 of 9

Thread: How to desaturate image?

  1. #1

    How to desaturate image?

    Hello everyone,

    my first post here, I got directed to this forum from following StackOverflow thread.

    I am using AsphyreSphinx framework to draw 2D DirectX scene on form canvas. I am drawing image to form canvas like this:
    Code:
    DXCore.Canvas.UseImage(TableResources.TableImage, TexFull4);
    DXCore.Canvas.TexMap(FMetrics.RawTableBounds, clWhite4);
    TableResources.TableImage is of TAsphyreImage type. DXCore.Canvas is TAsphyreCanvas. This works fine and draws proper image. However, I have need to also draw black & white version of the same image (desaturate it).

    I have tried to use various combinations of parameters in TexMap(), but none gave nothing close to desaturated image. Some things I tried:
    Code:
    DXCore.Canvas.TexMap(FMetrics.RawTableBounds, cGray4(100));
    DXCore.Canvas.TexMap(FMetrics.RawTableBounds, cRGB4(100, 100, 100));
    There is 4th parameter to function that takes TBlendingEffect enum, I tried various combinations with that too, but without success.

    I also tried to manually desaturate image after loading it, with cLerp(), like this:
    Code:
    procedure TTableResources.ImageToGrayscale(const AImage: TAsphyreImage);
    var
      C1: Integer;
      x, y: Integer;
    begin
      for C1 := 0 to AImage.TextureCount - 1 do
        for x := 0 to AImage.Texture[C1].Width - 1 do
          for y := 0 to AImage.Texture[C1].Height - 1 do
            AImage.Texture[C1].Pixels[x, y] := cLerp(AImage.Texture[C1].Pixels[x, y], cColor(cGrayValue(AImage.Texture[C1].Pixels[x, y])), 0.8);
    end;
    ..but this works awfuly slow (~20-30 seconds to process one image), and doesnt return desired output.

    SilverWarrior answered me that this isnt really possible with Asphyre, and I would have to utilize other libraries for that. So my question is, how can I fast desaturate image that is 1200x800px? Is this really not possible with Asphyre (e.g. some combination of color + blending effect in TexMap()?)? Thanks!

  2. #2
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    Location
    Spokane,WA,Usa
    Posts
    206
    Code:
    Function Gray(vColor:TByte4):TByte4;
    Var
      vAverage:TFlt;
    begin
      vAverage:=vColor.R*0.3+vColor.G*0.59+vColor.B*0.11;
      result.R:=Round(vAverage);
      result.G:=Round(vAverage);
      result.B:=Round(vAverage);
      result.A:=vColor.A;
    end;

  3. #3
    That wont do it. It produces black image for me (i'm using ImageToGrayscale method i provided in first post, which does Gray() instead cLerp()), and also it's equally slow.

  4. #4
    Quote Originally Posted by Carver413 View Post
    Code:
    Function Gray(vColor:TByte4):TByte4;
    Var
      vAverage:TFlt;
    begin
      vAverage:=vColor.R*0.3+vColor.G*0.59+vColor.B*0.11;
      result.R:=Round(vAverage);
      result.G:=Round(vAverage);
      result.B:=Round(vAverage);
      result.A:=vColor.A;
    end;
    Round() would be bottlenecking that
    Code:
    Function Gray(vColor:TByte4):TByte4;
    Var
      vAverage: byte;
    begin
      vAverage:=round(vColor.R*0.3+vColor.G*0.59+vColor.B*0.11);
      result.R:=vAverage;
      result.G:=vAverage;
      result.B:=vAverage;
      result.A:=vColor.A;
    end;
    The function should work, if you are getting black you are not using it with right parameters and result value. It's not directly compatible with TColor if that is the type.
    Last edited by User137; 16-07-2014 at 05:25 PM.

  5. #5
    I'm not familiar with Asphyre but usualy delphi image classes expose 'scanline' property, it's faster than 'pixels'

  6. #6
    Figured it out guys. I had to use .Lock() on texture, which gave me back pointer to pixels, similar to what ScanLine does. Much faster, and with that gray multiplication trick I made it to work.

    Code:
    procedure TTableResources.DesaturateImage(const AImage: TAsphyreImage);
    type
      PPixelRec = ^TPixelRec;
      TPixelRec = packed record
        B: Byte;
        G: Byte;
        R: Byte;
        A: Byte;
      end;
    var
      C1, x, y: Integer;
      bitsp: pointer;
      pitch: Integer;
      bytes_per_pixel: Integer;
      pixel: PPixelRec;
      gray_value: Byte;
    begin
      for C1 := 0 to AImage.TextureCount - 1 do
      begin
        AImage.Texture[C1].Lock(Rect(0, 0, AImage.Texture[C1].Width, AImage.Texture[C1].Height), bitsp, pitch);
        try
          bytes_per_pixel := pitch div AImage.Texture[C1].Width;
          for y := 0 to AImage.Texture[C1].Height - 1 do
            for x := 0 to AImage.Texture[C1].Width - 1 do
            begin
              pixel := PPixelRec(Integer(bitsp) + y * pitch + x * bytes_per_pixel);
              gray_value := Round(0.30 * pixel^.r + 0.59 * pixel^.g + 0.11 * pixel^.b);
              pixel^.r := gray_value;
              pixel^.g := gray_value;
              pixel^.b := gray_value;
            end;
        finally
          AImage.Texture[C1].Unlock;
        end;
      end;
    end;
    Thanks!

  7. #7
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    Location
    Spokane,WA,Usa
    Posts
    206
    Quote Originally Posted by User137 View Post
    Round() would be bottlenecking that
    Code:
    Function Gray(vColor:TByte4):TByte4; Var   vAverage: byte; begin   vAverage:=round(vColor.R*0.3+vColor.G*0.59+vColor.B*0.11);   result.R:=vAverage;   result.G:=vAverage;   result.B:=vAverage;   result.A:=vColor.A; end;
    The function should work, if you are getting black you are not using it with right parameters and result value. It's not directly compatible with TColor if that is the type.
    Thanks, I guess I overlooked that.

  8. #8
    Quote Originally Posted by reiser View Post
    Figured it out guys. I had to use .Lock() on texture, which gave me back pointer to pixels, similar to what ScanLine does. Much faster, and with that gray multiplication trick I made it to work.
    I'm glad you found solution for this.
    You might wanna update the SO question with your answer so other pepole could make use of it.

  9. #9
    Did you try http://graphics32.org/wiki/Main/Graphics32? has a lot of filters and image manipulation methods.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •