我如何计算 Firemonkey 中 TBitmap 的主色?

How can I calculate the dominant color of a TBitmap in Firemonkey?

在 Firemonkey 中有没有快速计算位图中主色(最常见的颜色)的方法?

或者 FMX 中是否有一个选项可以减少使用调色板时的颜色数量,例如如 Vcl.Imaging.GIFImg?

我已经实现了我自己的解决方案,它没有针对计算快速结果进行优化。

function GetDominanteColor(Bmp: TBitmap): TAlphaColor;
var
  BMPData: TBitmapData;
  x, y: integer;
  Col: TAlphaColor;
  Count: cardinal;
  Histogram: TDictionary<TAlphaColor, cardinal>;
begin
  result := TAlphaColors.Null;
  if Bmp.Width * Bmp.Height > 0 then
    if Bmp.Map(TMapAccess.Read, BMPData) then
    begin
      Histogram := TDictionary<TAlphaColor, cardinal>.Create;
      try
        // build histogram
        for x := 0 to Bmp.Width - 1 do
          for y := 0 to Bmp.Height - 1 do
          begin
            Col := BMPData.GetPixel(x, y);
            if Histogram.TryGetValue(Col, Count) then
              Histogram.Items[Col] := Count + 1
            else
              Histogram.Add(Col, 1);
          end;
        // search color with highest score
        Count := 0;
        for Col in Histogram.Keys do
        begin
          if Histogram.Items[Col] > Count then
          begin
            Count := Histogram.Items[Col];
            result := Col;
          end;
        end;
        {$IFDEF DEBUG}
        FMX.Types.Log.d('Dominante color %s from %d colors',
          [IntToHex(result, 8), x]);
        {$ENDIF}
      finally
        Histogram.Free;
      end;
      BMP.Unmap(BMPData);
    end;
end;

在旧 CPU (i5-3360@2.8GHz) 上,此功能最多需要 200 毫秒才能获得全高清图像。加速可以是限制颜色 space 或不采用每个像素而是使用一组具有代表性的像素。