Search code examples
delphifiremonkeydelphi-10.3-rio

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


Is there a quick way to calculate the dominant color (the most common color) in a bitmap in Firemonkey?

Or is there an option in FMX to reduce the number of colors when using a color palette, e.g. as in Vcl.Imaging.GIFImg?


Solution

  • I have implemented my own solution yet, which is not optimized for calculating fast results.

    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;
    

    On an old CPU (i5-3360@2.8GHz) this function needs up to 200ms for a full HD image. Acceleration could be to limit the color space or to take not each pixel but to use a representative set of pixels.