Author Topic: Convertig ifGray8 to float and back changes intensity  (Read 249 times)

Offline heju

  • Imaging User
  • *
  • Posts: 4
    • View Profile
Convertig ifGray8 to float and back changes intensity
« 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

Code: [Select]
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:
Code: [Select]
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 ;) )
Code: [Select]
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...
« Last Edit: 9 February 2019, 10:38:24 by heju »

Offline Galfar

  • Administrator
  • Imaging User
  • *****
  • Posts: 372
    • View Profile
    • Galfar's Homepage
Re: Convertig ifGray8 to float and back changes intensity
« Reply #1 on: 11 February 2019, 00:35:17 »
Thanks for the report, I'll have a look at this.