以编程方式将加载的位图中的颜色逐个像素地交换为红色,绿色,蓝色或灰色

时间:2011-01-09 23:23:36

标签: delphi colors bitmap

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

是的,我想将“大多数是蓝色”的东西转换成“大多数是绿色”的东西。

我想采用原始位图(浅蓝色)并将颜色(Pixel by Pixel)更改为红色,绿色,蓝色和灰色等效关系。为了了解我的意思,我已经包含了源代码和屏幕截图。任何帮助将不胜感激。如果需要更多信息,请随时询问。

如果您可以查看下面的代码,我有三个功能,我正在寻求帮助。功能“RGBToRed,RGBToGreen和RGBToRed”我似乎无法提出正确的公式。

alt text

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.

好的,我为没有让它更清楚而道歉。我正在尝试采用位图(蓝色)并将蓝色像素换成另一种颜色。就像下面的镜头一样。

alt text

alt text

2 个答案:

答案 0 :(得分:13)

我不知道你想要达到的目标。首先,问题与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。

我使用以下rutines在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;

在绿色案例中,最终结果将类似于

Hue fixed to 120 http://english.rejbrand.se/algosim/manual/pmproc/fixHue120.jpg

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

Hue fixed to 120 and saturation fixed to 1 http://english.rejbrand.se/algosim/manual/pmproc/monochromatic120.jpg

在后一种情况下(色调固定为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;

然后你会得到像

这样的东西

R and G channels swapped http://english.rejbrand.se/algosim/manual/pmproc/swapRG.jpg

红色和绿色通道已交换。请注意,红色的棍子现在是绿色的,绿色的草现在是红色的。什么是白色仍然是白色。

<强>最后

欢迎来到pixmap操作的世界!有很多简单而有趣的事情要做。我的一些例子:http://english.rejbrand.se/algosim/manual/pmproc/pmproc.html

答案 1 :(得分:2)

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

成功!