You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FireMonkey中组合图像滤镜并扩展TFilterHueAdjust实现HSL调整?

HSL全参数调整的扩展方案及多滤镜叠加问题解决思路

一、直接自定义HSL全量调整逻辑

既然现有TFilterHueAdjust仅支持色相调整,且多滤镜叠加易出现效果冲突或损耗,最稳妥的方式是直接实现完整的HSL转换与调整逻辑,无需依赖现有滤镜组件。这种方式能一次性完成H(色相)、S(饱和度)、L(亮度)三个参数的调整,避免多次滤镜转换带来的色彩偏差。

核心思路:遍历位图每个像素,将RGB颜色值转换为HSL空间,调整对应参数后再转回RGB空间写入目标位图。示例代码如下:

procedure AdjustHSL(Source, Dest: TBitmap; HDelta, SScale, LScale: Single);
var
  X, Y: Integer;
  SR, SG, SB: Byte;
  H, S, L: Double;
begin
  Dest.SetSize(Source.Width, Source.Height);
  Dest.PixelFormat := pf24bit; // 确保像素格式统一

  for Y := 0 to Source.Height - 1 do
  begin
    for X := 0 to Source.Width - 1 do
    begin
      // 获取源像素RGB分量
      SR := Source.Canvas.Pixels[X, Y];
      SG := Source.Canvas.Pixels[X, Y] shr 8;
      SB := Source.Canvas.Pixels[X, Y] shr 16;

      // RGB转HSL
      RGBToHSL(SR, SG, SB, H, S, L);

      // 调整色相(偏移量范围0-360)
      H := H + HDelta;
      if H > 360 then H := H - 360;
      if H < 0 then H := H + 360;

      // 调整饱和度(缩放系数:0=灰度,1=原饱和度,大于1增强)
      S := S * SScale;
      S := EnsureRange(S, 0, 1);

      // 调整亮度(缩放系数:0=全黑,1=原亮度,大于1增亮)
      L := L * LScale;
      L := EnsureRange(L, 0, 1);

      // HSL转回RGB并写入目标位图
      Dest.Canvas.Pixels[X, Y] := HSLToRGB(H, S, L);
    end;
  end;
end;

// RGB转HSL辅助函数
procedure RGBToHSL(R, G, B: Byte; out H, S, L: Double);
var
  Min, Max, Delta: Double;
begin
  Min := Min(Min(R, G), B) / 255;
  Max := Max(Max(R, G), B) / 255;
  L := (Max + Min) / 2;

  if Max = Min then
  begin
    H := 0;
    S := 0;
  end
  else
  begin
    Delta := Max - Min;
    S := IfThen(L < 0.5, Delta/(Max+Min), Delta/(2-Max-Min));

    if R = Max then H := (G - B)/Delta
    else if G = Max then H := 2 + (B - R)/Delta
    else H := 4 + (R - G)/Delta;

    H := H * 60;
    if H < 0 then H := H + 360;
  end;
end;

// HSL转RGB辅助函数
function HSLToRGB(H, S, L: Double): TColor;
var
  R, G, B, Temp1, Temp2: Double;
  function HueToRGB(T1, T2, Hue: Double): Double;
  begin
    if Hue < 0 then Hue := Hue + 1;
    if Hue > 1 then Hue := Hue - 1;
    if Hue < 1/6 then Result := T1 + (T2 - T1) * 6 * Hue
    else if Hue < 0.5 then Result := T2
    else if Hue < 2/3 then Result := T1 + (T2 - T1) * (2/3 - Hue) * 6
    else Result := T1;
  end;
begin
  if S = 0 then
  begin
    R := L; G := L; B := L;
  end
  else
  begin
    Temp2 := IfThen(L < 0.5, L*(1+S), L+S-L*S);
    Temp1 := 2*L - Temp2;
    H := H / 360;

    R := HueToRGB(Temp1, Temp2, H + 1/3);
    G := HueToRGB(Temp1, Temp2, H);
    B := HueToRGB(Temp1, Temp2, H - 1/3);
  end;

  Result := RGB(Round(R*255), Round(G*255), Round(B*255));
end;

二、扩展TFilterHueAdjust类实现全参数调整

如果希望沿用现有滤镜框架,可以通过继承TFilterHueAdjust类,添加饱和度和亮度参数,并修改核心处理方法,将HSL三个参数的调整合并到一次滤镜处理中。示例代码如下:

type
  TFilterHSLAdjust = class(TFilterHueAdjust)
  private
    FSaturation: Single;
    FLightness: Single;
    procedure SetSaturation(Value: Single);
    procedure SetLightness(Value: Single);
  protected
    procedure DoFilter; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Saturation: Single read FSaturation write SetSaturation default 1.0;
    property Lightness: Single read FLightness write SetLightness default 1.0;
  end;

constructor TFilterHSLAdjust.Create(AOwner: TComponent);
begin
  inherited;
  FSaturation := 1.0;
  FLightness := 1.0;
end;

procedure TFilterHSLAdjust.SetSaturation(Value: Single);
begin
  if FSaturation <> Value then
  begin
    FSaturation := Value;
    Changed;
  end;
end;

procedure TFilterHSLAdjust.SetLightness(Value: Single);
begin
  if FLightness <> Value then
  begin
    FLightness := Value;
    Changed;
  end;
end;

procedure TFilterHSLAdjust.DoFilter;
var
  X, Y: Integer;
  SR, SG, SB: Byte;
  H, S, L: Double;
begin
  // 完全重写处理逻辑,避免依赖父类的单一色相调整
  Output.SetSize(Input.Width, Input.Height);
  Output.PixelFormat := Input.PixelFormat;

  for Y := 0 to Input.Height - 1 do
  begin
    for X := 0 to Input.Width - 1 do
    begin
      SR := Input.Canvas.Pixels[X, Y];
      SG := Input.Canvas.Pixels[X, Y] shr 8;
      SB := Input.Canvas.Pixels[X, Y] shr 16;

      RGBToHSL(SR, SG, SB, H, S, L);

      // 应用色相偏移
      H := H + Hue;
      if H > 360 then H := H - 360;
      if H < 0 then H := H + 360;

      // 应用饱和度缩放
      S := S * FSaturation;
      S := EnsureRange(S, 0, 1);

      // 应用亮度缩放
      L := L * FLightness;
      L := EnsureRange(L, 0, 1);

      Output.Canvas.Pixels[X, Y] := HSLToRGB(H, S, L);
    end;
  end;
end;

使用时替换原TFilterHueAdjust即可:

procedure AdjustHSL(Source, Dest: TBitmap; H, S, L: Single);
var
  Filter: TFilterHSLAdjust;
begin
  Filter := TFilterHSLAdjust.Create(nil);
  try
    Filter.Input := Source;
    Filter.Hue := H;
    Filter.Saturation := S;
    Filter.Lightness := L;
    Dest.Assign(Filter.Output);
  finally
    Filter.Free;
  end;
end;

三、多滤镜叠加问题的解决

如果坚持使用现有多个滤镜组件,需确保前一个滤镜的输出作为后一个滤镜的输入,按顺序叠加调整,而非每次从原始位图重新处理。正确的叠加方式示例:

procedure AdjustHSLWithFilters(Source, Dest: TBitmap; H, S, L: Single);
var
  TempBmp: TBitmap;
  HueFilter: TFilterHueAdjust;
  SatFilter: TFilterSaturationAdjust; // 假设存在饱和度滤镜
  LightFilter: TFilterBrightnessAdjust; // 假设存在亮度滤镜
begin
  TempBmp := TBitmap.Create;
  HueFilter := TFilterHueAdjust.Create(nil);
  SatFilter := TFilterSaturationAdjust.Create(nil);
  LightFilter := TFilterBrightnessAdjust.Create(nil);
  try
    // 第一步:调整色相
    HueFilter.Input := Source;
    HueFilter.Hue := H;
    TempBmp.Assign(HueFilter.Output);

    // 第二步:基于色相调整后的结果调整饱和度
    SatFilter.Input := TempBmp;
    SatFilter.Saturation := S;
    TempBmp.Assign(SatFilter.Output);

    // 第三步:基于饱和度调整后的结果调整亮度
    LightFilter.Input := TempBmp;
    LightFilter.Brightness := L;
    Dest.Assign(LightFilter.Output);
  finally
    LightFilter.Free;
    SatFilter.Free;
    HueFilter.Free;
    TempBmp.Free;
  end;
end;

内容的提问来源于stack exchange,提问作者Craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 00:45:18