Lazarus

Programming => Graphics => Graphics and Multimedia => BGRABitmap and LazPaint => Topic started by: del on April 14, 2021, 02:38:17 pm

Title: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 14, 2021, 02:38:17 pm
According to the comments in BGRABitmapTypes, rfBestQuality is the best quality among rfMitchell and rfSpline. Is it the best overall for upsizing interpolation? Better than rfLanczos4? I'm assuming that rfMitchell has some built-in anti-aliasing which makes it best for downsizing interpolation.

Code: Pascal  [Select][+][-]
  1. // rfMitchell: Mitchell filter, good for downsizing interpolation
  2. // rfSpline: Spline filter, good for upsizing interpolation, however slightly blurry
  3. // rfLanczos2: Lanczos with radius 2, blur is corrected
  4. // rfLanczos3: Lanczos with radius 3, high contrast
  5. // rfLanczos4: Lanczos with radius 4, high contrast
  6. // rfBestQuality: Best quality using rfMitchell or rfSpline
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: winni on April 16, 2021, 08:18:39 pm
Hi!

For downsizing Mitchell is the best filter.

For upsizing it depends on your needs.
For photographs Spline is the best.
But for technical drawings Lanzcos3 or 4 give better contrast.

Simple tests for upsizing:

Load a little icon into a BGRAbitmap and resize it to 512 x 512

Code: Pascal  [Select][+][-]
  1. var MyIcon : TBGRABitmap:
  2. ....
  3. MyIcon := TBGRAbitmap.create (FileName);
  4. MyIcon.resampleFilter := rfSpline; // or rfLanzos3 or ...
  5. BGRAReplace (MyIcon, MyIcon.resample (512,512));
  6. MyIcon.Draw (Image1.Canvas,0,0);
  7. MyIcon.free;
  8. ....
  9.  
  10.  
Winni


Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 17, 2021, 04:52:56 pm
OK thanks. I've already implemented the function with TRadioGroup to pick all the different methods. I'm guessing the issue is sharpness vs artifacts. I'll do some experiments.
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: winni on April 17, 2021, 06:56:22 pm
Hi!

And here is the base for a hardrock test:

Just create a 2 x 2 Bitmap and fill it with 4 different colors.
And then resample it with the different filters.
And follow the differents gradients.

Code: Pascal  [Select][+][-]
  1. var tmp: TBGRA.Bitmap;
  2. ...
  3. tmp := TBGRAbitmap.create (2,2);
  4. tmp.setpixel(0,0,cssBlue);
  5. tmp.setpixel(0,1,cssRed);
  6. tmp.setpixel(1,0,cssYellow);
  7. tmp.setpixel(1,1,cssLime);
  8. tmp.resampleFilter := rfspline; // rfLancos2, ....
  9. BGRAreplace (tmp, tmp.resample(512,512));
  10. tmp.Draw(Image1.Canvas, 0,0);
  11. tmp.free;
  12.  

Winni

PS.:
Demo with Spline Filter added
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 18, 2021, 06:46:54 am
That's a cool idea. However, I wonder about the utility of a test image that's smaller than most interpolating kernels. The image will probably get mirror-padded, so that's not a problem. But the higher-order (bigger footprint) kernels give a better truncated approximation of the sinc function, the ideal interpolator. Maybe I'm overthinking this. I'll run the experiment. The higher-order interpolators do give better approximations of the original analog signal. That's pretty much a given.
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: Thaddy on April 18, 2021, 09:26:07 am
Yes, in the case of images that is true, OTOH with audio it depends.
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 20, 2021, 01:58:28 am
Yeah I guess the real answer is it depends on the image. I don't like blurring and I don't like ringing. But it's a tradeoff. The rfSpline seems to be identical this implementation I have of the Catmull Rom. The input image was a 88x31 "geocities" button. Magnification 1.5 (1 1/2). Then I zoomed in 8x (800%) and took screenshots.

Edit: FWIW here is the procedure that generates the weights for the Catmull Rom kernel:

Code: Pascal  [Select][+][-]
  1. procedure GetCatrom(var catrom: array2flt; i_f: single; j_f: single);
  2. var
  3.   x1, x2, x3, y1, y2, y3, wx, wy, dx, dy: single;
  4.   i, j: integer;
  5.  
  6. begin
  7.   dx := j_f - Trunc(j_f);
  8.   dy := i_f - Trunc(i_f);
  9.  
  10.   for i := 0 to 3 do
  11.   begin
  12.     y1 := Abs(i - (1.0 + dy));
  13.     y2 := y1 * y1;
  14.     y3 := y1 * y2;
  15.  
  16.     if (y1 < 1.0) then
  17.     begin
  18.       wy := 1.5 * y3 - 2.5 * y2 + 1.0
  19.     end
  20.     else if ((y1 >= 1.0) and (y1 <= 2.0)) then
  21.     begin
  22.       wy := -0.5 * y3 + 2.5 * y2 - 4.0 * y1 + 2.0
  23.     end
  24.     else
  25.     begin
  26.       wy := 0.0
  27.     end;
  28.  
  29.     for j := 0 to 3 do
  30.     begin
  31.       x1 := Abs(j - (1.0 + dx));
  32.       x2 := x1 * x1;
  33.       x3 := x1 * x2;
  34.  
  35.       if (x1 < 1.0) then
  36.       begin
  37.         wx := 1.5 * x3 - 2.5 * x2 + 1.0
  38.       end
  39.       else if ((x1 >= 1.0) and (x1 <= 2.0)) then
  40.       begin
  41.         wx := -0.5 * x3 + 2.5 * x2 - 4.0 * x1 + 2.0
  42.       end
  43.       else
  44.       begin
  45.         wx := 0.0
  46.       end;
  47.  
  48.       catrom[i][j] := wx * wy;
  49.     end;
  50.   end;
  51. end;
  52.  
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: circular on April 20, 2021, 08:01:02 pm
If you're interested you can look in BGRAResample unit how the kernels are computed.

The function WideKernelResample will compute with any kernel you provide.

The rfSpline filter kernel is defined as follows:
Code: Pascal  [Select][+][-]
  1. function TSplineKernel.Interpolation(t: single): single;
  2. var
  3.   tt, ttt: single;
  4. begin
  5.   t := Abs(t);
  6.   tt := Sqr(t);
  7.   ttt := tt * t;
  8.   if t < 1 then
  9.     Result := (2 - Coeff) * ttt - (3 - Coeff) * tt + 1
  10.   else if t < 2 then
  11.     Result := -Coeff * (ttt - 5 * tt + 8 * t - 4)
  12.   else
  13.     Result := 0;
  14. end;
  15.  
  16. function TSplineKernel.KernelWidth: single;
  17. begin
  18.   Result := 2;
  19. end;
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 21, 2021, 02:48:25 am
Cool. I'm seeing a pattern here. I pulled some old code off of a backup CD and I had this thing called "PCC". It looks like the Catmull Rom and rfSpline are specific forms of the generic "PCC". I don't remember what "PCC" stood for. "Parametric" Cubic Convolution? "Piece-wise" Cubic Convolution? To make this a Catmull Rom, set "a" (or "Coeff") to -0.5. I notice with "a" set to -0.1 it runs a little "cooler" (less ringing) than the Catmull Rom ("a" = -0.5). Pardon the C++. It was originally the nasty C I used to code in.
Code: C  [Select][+][-]
  1. void GetPCC(Dbl2D& pcc, double x, double y)
  2. {
  3.   double dx {x - floor(x)};
  4.   double dy {y - floor(y)};
  5.   double a {-0.1};
  6.  
  7.   for (int i {0}; i < 4; i++)
  8.   {
  9.     double y1 {fabs(i - (1.0 + dy))};
  10.     double y2 {y1 * y1};
  11.     double y3 {y1 * y2};
  12.     double wy;
  13.  
  14.     if (y1 < 1.0)
  15.     {
  16.       wy = (a + 2.0) * y3 - (a + 3.0) * y2 + 1.0;
  17.     }
  18.     else if ((y1 >= 1.0) && (y1 <= 2.0))
  19.     {
  20.       wy = a * y3 - 5.0 * a * y2 + 8.0 * a * y1 - 4.0 * a;
  21.     }
  22.     else
  23.     {
  24.       wy = 0.0;
  25.     }
  26.  
  27.     for (int j {0}; j < 4; j++)
  28.     {
  29.       double x1 {fabs(j - (1.0 + dx))};
  30.       double x2 {x1 * x1};
  31.       double x3 {x1 * x2};
  32.       double wx;
  33.  
  34.       if (x1 < 1.0)
  35.       {
  36.         wx = (a + 2.0) * x3 - (a + 3.0) * x2 + 1.0;
  37.       }
  38.       else if ((x1 >= 1.0) && (x1 <= 2.0))
  39.       {
  40.         wx = a * x3 - 5.0 * a * x2 + 8.0 * a * x1 - 4.0 * a;
  41.       }
  42.       else
  43.       {
  44.         wx = 0.0;
  45.       }
  46.  
  47.       pcc.m_D2D[i][j] = wx * wy;
  48.     }
  49.   }
  50. }
  51.  
Title: Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: circular on April 21, 2021, 08:41:09 pm
Yes, your previous formula corresponds to a = -0.5

rfSpline uses Coeff = 0.5. That's just the opposite but the formula is the same (a = -Coeff)
Title: [SOLVED] Re: TResampleFilter rfBestQuality (BGRABitmapTypes)
Post by: del on April 21, 2021, 09:48:26 pm
Very cool. I read somewhere that the "Catmull Rom" coefficient (0.5) makes the interpolator continuous in the first derivative. Which is supposed to make it smoother or something. So I really didn't need to code it up, it was already there in rfSpline. I'm gonna mark this thread as "solved". Thanks for all the input.
TinyPortal © 2005-2018