Vampyre Imaging Library Forum

Imaging Category => Bugs And Other Insects => Topic started by: heju on 9 February 2019, 10:36:34

Title: Convertig ifGray8 to float and back changes intensity
Post by: heju on 9 February 2019, 10:36:34
Hi,

while converting gray 8bit images to float 32bit and back to gray 8 bit I noted that the intensity values dramatically change:

"in128.bmp" is a grayscale bitmap with pixel values of 128

img.CreateFromFile('in128.bmp');
img.Format:=ifGray8;
img.Format:=ifR32F;
img.Format:=ifGray8;
img.SaveToFile('out.bmp');


Now in the "out.bmp" image the pixel values are only 38.

As this is a bit of a problem for my application, I investigated a bit: The root cause seems to be here:
procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  DstInfo: PImageFormatInfo);
var
  I: LongInt;
  PixF: TColorFPRec;
  Gray: TColor64Rec;
  Alpha: Word;
begin
  for I := 0 to NumPixels - 1 do
  begin
    FloatGetSrcPixel(Src, SrcInfo, PixF);
    ClampFloatPixel(PixF);

    // alpha is saved from source pixel to Alpha,
    // Gray value is computed and set to highest word of Pix64 so
    // Pix64.Color contains grayscale value scaled to 64 bits
    Alpha := ClampToWord(Round(PixF.A * 65535.0));
    Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G +
      GrayConv.B * PixF.B) * 65535.0));

    GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
    Inc(Src, SrcInfo.BytesPerPixel);
    Inc(Dst, DstInfo.BytesPerPixel);
  end;
end;


Even the float image is single channel, the RGB-> gray conversion is calculated, reducing the pixel values (there is only intensity in red channel and this gets multiplied with GrayConv.R factor.

I workarounded the behaviour using the following approach (don't know if there are side effects). However now the value after conversion is the same as before:
(sry, you have to scroll down a bit maybe ;) )

procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo,
  DstInfo: PImageFormatInfo);
var
  I: LongInt;
  PixF: TColorFPRec;
  Gray: TColor64Rec;
  Alpha: Word;
begin
  for I := 0 to NumPixels - 1 do
  begin
    FloatGetSrcPixel(Src, SrcInfo, PixF);
    ClampFloatPixel(PixF);

    // alpha is saved from source pixel to Alpha,
    // Gray value is computed and set to highest word of Pix64 so
    // Pix64.Color contains grayscale value scaled to 64 bits
    Alpha := ClampToWord(Round(PixF.A * 65535.0));
    if SrcInfo.ChannelCount =1 then
      Gray.A := ClampToWord(Round(PixF.R * 65535.0))
    else
      Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G +
        GrayConv.B * PixF.B) * 65535.0));

    GraySetDstPixel(Dst, DstInfo, Gray, Alpha);
    Inc(Src, SrcInfo.BytesPerPixel);
    Inc(Dst, DstInfo.BytesPerPixel);
  end;
end;


Bye...
Title: Re: Convertig ifGray8 to float and back changes intensity
Post by: Galfar on 11 February 2019, 00:35:17
Thanks for the report, I'll have a look at this.