【问题标题】:Programmatically swap colors from a loaded bitmap to Red, Green, Blue or Gray, pixel by pixel以编程方式将加载的位图中的颜色逐个像素地交换为红色、绿色、蓝色或灰色
【发布时间】:2011-01-09 23:23:35
【问题描述】:

在此处下载源代码:http://www.eyeClaxton.com/download/delphi/ColorSwap.zip

是的,我想将“大部分为蓝色”的内容转换为“大部分为绿色”的内容。

我想获取原始位图(浅蓝色)并将颜色(逐个像素)更改为红色、绿色、蓝色和灰色的等价关系。为了理解我的意思,我提供了源代码和屏幕截图。任何帮助将不胜感激。如果需要更多信息,请随时询问。

如果您可以查看下面的代码,我有三个函数正在寻求帮助。 “RGBToRed、RGBToGreen 和 RGBToRed”函数我似乎想不出正确的公式。

unit MainUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TMainFrm = class(TForm)
    Panel1: TPanel;
    Label1: TLabel;
    Panel2: TPanel;
    Label2: TLabel;
    Button1: TButton;
    BeforeImage1: TImage;
    AfterImage1: TImage;
    RadioGroup1: TRadioGroup;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrm: TMainFrm;

implementation

{$R *.DFM}
function RGBToGray(RGBColor: TColor): TColor;
var
  Gray: Byte;
begin
  Gray := Round(
    (0.90 * GetRValue(RGBColor)) +
    (0.88 * GetGValue(RGBColor)) +
    (0.33 * GetBValue(RGBColor)));

  Result := RGB(Gray, Gray, Gray);
end;

function RGBToRed(RGBColor: TColor): TColor;
var
  Red: Byte;
begin
  // Not sure of the algorithm for this color
  Result := RGB(Red, Red, Red);
end;

function RGBToGreen(RGBColor: TColor): TColor;
var
  Green: Byte;
begin
  // Not sure of the algorithm for this color
  Result := RGB(Green, Green, Green);
end;

function RGBToBlue(RGBColor: TColor): TColor;
var
  Blue: Byte;
begin
  // Not sure of the algorithm for this color
  Result := RGB(Blue, Blue, Blue);
end;

procedure TMainFrm.FormCreate(Sender: TObject);
begin
  BeforeImage1.Picture.LoadFromFile('Images\RightCenter.bmp');
end;

procedure TMainFrm.Button1Click(Sender: TObject);
var
  Bitmap: TBitmap;
  I, X: Integer;
  Color: Integer;
begin
  Bitmap := TBitmap.Create;
  try
    Bitmap.LoadFromFile('Images\RightCenter.bmp');

    for X := 0 to Bitmap.Height do
    begin
      for I := 0 to Bitmap.Width do
      begin
        Color := ColorToRGB(Bitmap.Canvas.Pixels[I, X]);

        case Color of
          $00000000: ;   // Skip any Color Here!
        else
          case RadioGroup1.ItemIndex of
            0: Bitmap.Canvas.Pixels[I, X] := RGBToBlue(Color);
            1: Bitmap.Canvas.Pixels[I, X] := RGBToRed(Color);
            2: Bitmap.Canvas.Pixels[I, X] := RGBToGreen(Color);
            3: Bitmap.Canvas.Pixels[I, X] := RGBToGray(Color);
          end;
        end;
      end;
    end;
    AfterImage1.Picture.Graphic := Bitmap;
  finally
    Bitmap.Free;
  end;
end;

end.

好的,我很抱歉没有说得更清楚。我正在尝试获取位图(蓝色)并将蓝色像素与另一种颜色交换。就像下面的照片。

【问题讨论】:

  • 我不明白。您提供的代码在哪些方面尚未满足您的需求?
  • 好的,我喜欢你提供的截图和代码,但我没有从我们这里得到你想要的。问题是什么,或者哪个部分没有按您想要的方式工作?
  • 如果您可以看看上面的代码,我有三个函数正在寻求帮助。 “RGBToRed、RGBToGreen 和 RGBToRed”函数我似乎想不出正确的公式。
  • 所以你想让所有的红色也变成绿色(看看窗口的 X)。有上千种方法可以将“大部分是蓝色”的东西变成“大部分是绿色”的东西,我希望你知道。
  • 好的,我会重新组合,稍后尝试用另一种方式提问。

标签: delphi colors bitmap


【解决方案1】:

我不知道你想要达到什么目的。一、问题和equivalence relations有什么关系?

二是代码

function RGBToRed(RGBColor: TColor): TColor;
var
  Red: Byte;
begin
  // Not sure of the algorithm for this color
  Result := RGB(Red, Red, Red);
end;

毫无意义。返回值未定义。 RGB 函数采用 0 到 255 范围内的红色、绿色和蓝色强度,并返回具有这些分量的 TColor。比如RGB(255, 0, 0)是纯红色,即255红,0绿,0蓝。然而,在上面的代码中,Red 没有初始化,所以Result 可以是任何灰色(取决于Red 恰好是什么)。 [而且,你可能知道,如果你混合等量的红色、绿色和蓝色,你会得到灰色。] 例如,Red 在你运行应用程序时可能恰好是 45,然后结果将是灰色RGB(45, 45, 45)。下次可能是 163。

也许您想要一个接受TColor 并返回它的红色部分的函数?然后GetRValue 就可以了,当然还有GetGValueGetBValue

或者,也许您想从给定的TColor 创建灰色,就像您使用 Photoshop 从彩色图像创建灰度图像时所做的那样。那么,如果ColorTColor,则相应的灰度值为

grey := (GetRValue(Color) + GetGValue(Color) + GetBValue(Color)) div 3;

还有其他方法可以做到这一点(产生细微不同的灰度图像,但这是最简单(也是最快)的)。 (例如,您可以将颜色从 RGB 转换为 HSV 或 HSL,然后将饱和度设置为零。)

更新

我想我知道你想做什么。也许您想提取红色、绿色和蓝色通道。也就是说,您要将红色情况下的每个像素RGB(R, G, B) 转换为RGB(R, 0, 0)。如果这是你想做的,那么你应该这样做

function RGBToRed(RGBColor: TColor): TColor;
begin
  Result := RGB(GetRValue(RGBColor), 0, 0);
end;

对于其他组件也是如此,即

function RGBToGreen(RGBColor: TColor): TColor;
begin
  Result := RGB(0, GetGValue(RGBColor), 0);
end;

function RGBToBlue(RGBColor: TColor): TColor;
begin
  Result := RGB(0, 0, GetBValue(RGBColor));
end;

或者,也许

或者您可能只想将图像设为灰度,然后将其“着色”为红色(或绿色或蓝色)。然后你需要重型机械。理论上,您希望在红色情况下将每个像素从HSV(h, s, v) 替换为HSV(0, s, v),在绿色情况下替换HSV(120, s, v),在蓝色情况下替换HSV(240, s, v)。或者,也许您还希望将饱和度 s 设置为 1。

我使用以下规则在 RGB 和 HSV 之间进行转换:

function RGBToHSV(const Color: TRGB): THSV;
var
  cmax, cmin, cdiff: real;
begin
  cmax := MaxComponent(Color);
  cmin := MinComponent(Color);
  cdiff := cmax - cmin;

  with Color, result do
  begin

    // Hue
    if cmax = cmin then
      hsvHue := 0
    else if cmax = rgbRed then
      hsvHue := (60 * (rgbGreen - rgbBlue) / cdiff)
    else if cmax = rgbGreen then
      hsvHue := (60 * (rgbBlue - rgbRed) / cdiff) + 120
    else
      hsvHue := (60 * (rgbRed - rgbGreen) / cdiff) + 240;

    hsvHue := Fix360(hsvHue);

    // Saturation
    if cmax = 0 then
      hsvSaturation := 0
    else
      hsvSaturation := 1 - cmin / cmax;

    // Value
    hsvValue := cmax;

  end;

end;

function HSVToRGB(const Color: THSV): TRGB;
var
  hi: integer;
  f, q, p, t: real;
begin

  with Color do
  begin

    hi := floor(hsvHue / 60) mod 6;
    f := hsvHue / 60 - floor(hsvHue / 60);
    p := hsvValue * (1 - hsvSaturation);
    q := hsvValue * (1 - f * hsvSaturation);
    t := hsvValue * (1 - (1 - f) * hsvSaturation);

    case hi of
      0: result := RGB(hsvValue, t, p);
      1: result := RGB(q, hsvValue, p);
      2: result := RGB(p, hsvValue, t);
      3: result := RGB(p, q, hsvValue);
      4: result := RGB(t, p, hsvValue);
      5: result := RGB(hsvValue, p, q);
    end;

  end;

end;

在哪里

type
  TRGB = record
    rgbRed,            // red intensity between 0 and 1
    rgbGreen,          // green intensity between 0 and 1
    rgbBlue: double;   // blue intensity between 0 and 1
  end;

  THSV = record
    hsvHue,            // hue angle between 0 and 360
    hsvSaturation,     // saturation between 0 (grey) and 1 (full colour)
    hsvValue: double;  // value between 0 (dark) and 1 ("normal")
  end;

最终的结果,在绿色的情况下,会是这样的

在第一种情况下(色调固定为 120)和

在后一种情况下(色调固定为 120,饱和度固定为 1)。

或者,可能

即使经过编辑,您的问题也很笼统。您想将“主要是蓝色”的东西转换为“主要是绿色”的东西。但是有一千种方法可以做到这一点!当然,一个非常简单的方法就是交换蓝色和绿色通道,即将RGB(r, g, b)替换为RGB(r, b, g),或者,明确地,

function SwapBlueGreen(Color: TColor): TColor;
begin
  result := RGB(GetRValue(Color), GetBValue(Color), GetGValue(Color));
end;

然后你会得到类似的东西

红色和绿色通道已交换的位置。请注意,红色的棍子现在是绿色的,而绿草现在是红色的。白色的东西仍然是白色的。

终于

欢迎来到像素图操作的世界!有很多简单而有趣的事情要做。我的更多示例:https://english.rejbrand.se/algosim/manual/pmproc/pmproc.html

【讨论】:

  • 是的,我想将“大部分为蓝色”的内容转换为“大部分为绿色”的内容。
  • +1 出色的综合答案!也许有一天我可以理解这些代码背后的逻辑:)
【解决方案2】:

通过“像素”属性访问颜色信息真的很慢。您应该考虑使用“扫描线”属性来获得大约 2 个数量级更快的代码。 http://blogs.embarcadero.com/pawelglowacki/2010/04/15/39051 包含如何操作的代码示例。

成功了!

【讨论】:

    猜你喜欢
    • 2011-10-28
    • 2017-08-19
    • 2022-12-19
    • 2012-08-03
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    相关资源
    最近更新 更多