• Welcome to Vampyre Imaging Library Forum. Please login or sign up.
 

Quality of resizing

Started by davem, 19 April 2010, 21:37:22

Previous topic - Next topic

davem

  Hi,
  first of all thanks for the great library!!

  However I got a problem resizing images because I always get rectangles in areas with the same or very similar color (such as the sky, wall etc). The rest of image (for example faces) are perfect. I used bicubic filter, I also tried to change the hardcoded value in the following code (in Imaging.pas, line 2334) to use other filters (sfGaussian, sfLanczos, sfMitchell) but the only difference was that the size of the rectangles has changed a little.

        rfBicubic: StretchResample(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight,
          DstImage, DstX, DstY, DstWidth, DstHeight, sfCatmullRom);

Am I doing something wrong or is this a bug? I used to use the attached unit in the previous versions of my program and that one produces much better results (you can compare, all attached).

Source: JPEG (from a camera)
Resolution: 13 MPix

The original picture is too large so you can get it from here: http://www.ildam.cz/foto/IMG_3692.JPG

  Please help!

   Thanks, David

davem

20 April 2010, 11:33:47 #1 Last Edit: 20 April 2010, 11:37:54 by davem
I ask, I answer. I like this forum.  :-)

Anyway, I found a problem in function StretchResample (ImagingFormats.pas). This function rounds the Weights which speeds up the process a bit but produces the ugly rectangles in the result. I tried to modify the function and it seems the result is much better now. Please consider implementing this into the next version of the library. Changed lines are marked with "DMA".


var  IWeightR, IAccumAR, IAccumRR, IAccumGR, IAccumBR : single;
...
      for J := 0 to DstHeight - 1 do
      begin
        ClusterY := MapY[J];
        for X := XMinimum to XMaximum do
        begin
          IAccumAR := 0.0;    // DMA
          IAccumRR := 0.0;    // DMA
          IAccumGR := 0.0;    // DMA
          IAccumBR := 0.0;    // DMA
          for Y := 0 to Length(ClusterY) - 1 do
          begin
            // IWeight := Round(256 * ClusterY[Y].Weight);  // DMA - do not use
            IWeightR:= 256*ClusterY[Y].Weight;      // DMA, remove rounding
            CopyPixel(
              @PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel],
              @SrcColor, Info.BytesPerPixel);

            IAccumBR := IAccumBR + SrcColor.B * IWeightR;   // DMA, use single instead of integer
            IAccumGR := IAccumGR + SrcColor.G * IWeightR;   // DMA, use single instead of integer
            IAccumRR := IAccumRR + SrcColor.R * IWeightR;   // DMA, use single instead of integer
            IAccumAR := IAccumAR + SrcColor.A * IWeightR;   // DMA, use single instead of integer
          end;
          with LineBufferInt[X - XMinimum] do
          begin
            A := round(IAccumAR); // DMA, round single
            R := round (IAccumRR);// DMA, round single
            G := round (IAccumGR);// DMA, round single
            B := round (IAccumBR);// DMA, round single
          end;
        end;

        DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX)* Info.BytesPerPixel];

        for I := 0 to DstWidth - 1 do
        begin
          ClusterX := MapX[I];
          IAccumAR := 0.0;    // DMA, use single
          IAccumRR := 0.0;    // DMA, use single
          IAccumGR := 0.0;    // DMA, use single
          IAccumBR := 0.0;    // DMA, use single
          for X := 0 to Length(ClusterX) - 1 do
          begin
            // IWeight := Round(256 * ClusterX[X].Weight);  // DMA - do not use anymore
            IWeightR:= 256*ClusterX[X].Weight;      // DMA, use single, do not round
            with LineBufferInt[ClusterX[X].Pos - XMinimum] do
            begin
              IAccumBR := IAccumBR + B * IWeightR;    // DMA
              IAccumGR := IAccumGR + G * IWeightR;    // DMA
              IAccumRR := IAccumRR + R * IWeightR;    // DMA
              IAccumAR := IAccumAR + A * IWeightR;    // DMA
            end;
          end;

          SrcColor.B := ClampInt(round(IAccumBR), 0, $00FF0000) shr 16; // DMA, added round on single
          SrcColor.G := ClampInt(round(IAccumGR), 0, $00FF0000) shr 16; // DMA, added round on single
          SrcColor.R := ClampInt(round(IAccumRR), 0, $00FF0000) shr 16; // DMA, added round on single
          SrcColor.A := ClampInt(round(IAccumAR), 0, $00FF0000) shr 16; // DMA, added round on single

          CopyPixel(@SrcColor, DstLine, Info.BytesPerPixel);
          Inc(DstLine, Info.BytesPerPixel);
        end;
      end;


By the way, it seems that the whole problem is in the "optimized" version, the "not optimized one" seems to work well.

Galfar

Thanks for locating the problem. I probably remove the "optimized" code path altogether, that's not the first problem with it and it's only marginally faster anyway.

davem

Quote from: Galfar on 20 April 2010, 16:06:48
Thanks for locating the problem. I probably remove the "optimized" code path altogether, that's not the first problem with it and it's only marginally faster anyway.


I agree, the difference is very small. That's actually the same what I did in the end.

Quick Reply

With Quick-Reply you can write a post when viewing a topic without loading a new page. You can still use bulletin board code and smileys as you would in a normal post.

Name:
Email:

Shortcuts: ALT+S save/post or ALT+P preview

SMF spam blocked by CleanTalk