ImagingCompare.pas 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. {
  2. Vampyre Imaging Library
  3. by Marek Mauder
  4. https://github.com/galfar/imaginglib
  5. https://imaginglib.sourceforge.io
  6. - - - - -
  7. This Source Code Form is subject to the terms of the Mozilla Public
  8. License, v. 2.0. If a copy of the MPL was not distributed with this
  9. file, You can obtain one at https://mozilla.org/MPL/2.0.
  10. }
  11. {
  12. This unit contains various image comparing functions and image difference
  13. computations.
  14. }
  15. unit ImagingCompare;
  16. {$I ImagingOptions.inc}
  17. interface
  18. uses
  19. SysUtils, Classes, ImagingTypes, Imaging, ImagingFormats, ImagingUtility;
  20. { Computes various error metrics for two images. Images must have
  21. the same size and format. Only formats with 1, 2, and 4 byte samples are
  22. supported (no indexed, compressed, etc.).}
  23. procedure ComputeErrorMetrics(const Image1, Image2: TImageData;
  24. var PSNR, MSE, RMSE, PAE, MAE: Single);
  25. implementation
  26. procedure ComputeErrorMetrics(const Image1, Image2: TImageData;
  27. var PSNR, MSE, RMSE, PAE, MAE: Single);
  28. var
  29. I: Integer;
  30. Info: TImageFormatInfo;
  31. Samples, Bps: Integer;
  32. PixelPtr1, PixelPtr2: PByte;
  33. Diff, MaxSample: Single;
  34. begin
  35. GetImageFormatInfo(Image1.Format, Info);
  36. Bps := Info.ChannelCount div Info.BytesPerPixel;
  37. Assert((Image1.Width = Image2.Width) and (Image1.Height = Image2.Height) and
  38. (Image1.Format = Image2.Format));
  39. Assert(not Info.IsIndexed and not Info.IsSpecial and not Info.UsePixelFormat
  40. and (Bps in [1, 2, 4]));
  41. Diff := 0;
  42. PSNR := 0;
  43. MSE := 0;
  44. RMSE := 0;
  45. PAE := 0;
  46. MAE := 0;
  47. PixelPtr1 := Image1.Bits;
  48. PixelPtr2 := Image2.Bits;
  49. Samples := Image1.Width * Image1.Height * Info.ChannelCount;
  50. for I := 0 to Samples - 1 do
  51. begin
  52. // Compute difference between pixels
  53. case Bps of
  54. 1: Diff := Abs(PixelPtr2^ - PixelPtr1^);
  55. 2:
  56. begin
  57. if Info.IsFloatingPoint then
  58. Diff := Abs(HalfToFloat(PWord(PixelPtr2)^) - HalfToFloat(PWord(PixelPtr1)^))
  59. else
  60. Diff := Abs(PWord(PixelPtr2)^ - PWord(PixelPtr1)^);
  61. end;
  62. 4:
  63. begin
  64. if Info.IsFloatingPoint then
  65. Diff := Abs(PSingle(PixelPtr2)^ - PSingle(PixelPtr1)^)
  66. else
  67. Diff := Abs(PUInt32(PixelPtr2)^ - PUInt32(PixelPtr1)^);
  68. end;
  69. end;
  70. // Update metrics
  71. MAE := MAE + Diff;
  72. PAE := MaxFloat(PAE, Diff);
  73. MSE := MSE + Diff * Diff;
  74. Inc(PixelPtr1, Bps);
  75. Inc(PixelPtr2, Bps);
  76. end;
  77. if Info.IsFloatingPoint then
  78. MaxSample := 1.0
  79. else
  80. MaxSample := Pow2Int(Bps * 8) - 1;
  81. // Final metrics calculations
  82. MAE := MAE / Samples;
  83. MSE := MSE / Samples;
  84. RMSE := Sqrt(MSE);
  85. if RMSE < 0.0001 then
  86. PSNR := 1e06
  87. else
  88. PSNR := 20 * Log10(MaxSample / RMSE);
  89. end;
  90. {
  91. File Notes:
  92. -- TODOS ----------------------------------------------------
  93. - none
  94. -- 0.26.5 Changes/Bug Fixes -----------------------------------
  95. - Added ComputeErrorMetrics.
  96. - Unit created.
  97. }
  98. end.