以编程方式逐个像素地交换来自小位图(原始)的颜色

时间:2011-01-10 19:03:48

标签: delphi colors bitmap

在此下载带有已编译可执行文件的源代码(大小:161 KB(165,230字节)):http://www.eyeClaxton.com/download/delphi/ColorSwap.zip

原始位图大小仅为28x15像素,颜色为浅蓝色。我希望能够点击右边的任何彩色面板,并将原始位图颜色从浅蓝色更改为面板颜色。

如果你点击灰色面板,你可以看到这个在行动,我只是无法弄清楚如何正确使用其他颜色。任何帮助将不胜感激。如果需要更多信息,请随时询问。

我有asked this question before但是我无法弄清楚我想要做什么,所以我希望这个更清楚。

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;
    BeforeImage1: TImage;
    AfterImage1: TImage;
    Panel3: TPanel;
    Panel4: TPanel;
    Panel5: TPanel;
    Panel6: TPanel;
    Panel7: TPanel;
    Panel8: TPanel;
    Panel9: TPanel;
    Image1: TImage;
    Label3: TLabel;
    Panel10: TPanel;
    Memo1: TMemo;
    Label4: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Panel4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  MainFrm: TMainFrm;

implementation

uses
  Math;

{$R *.DFM}
function Min(const A, B, C: Integer): Integer;
begin
  Result := Math.Min(A, Math.Min(B, C));
end;

function Max(const A, B, C: Integer): Integer;
begin
  Result := Math.Max(A, Math.Max(B, C));
end;

function RGBToGray(theRed, theGreen, theBlue: Byte): Byte;
begin
  Result := (Max(theRed, theGreen, theBlue) + Min(theRed, theGreen, theBlue)) div 2;
end;

function BlueToGray(theColor: TColor): TColor;
var
  R, G, B, X: Byte;
begin
  R := (theColor and $FF);
  G := (theColor and $FF00) shr 8;
  B := (theColor and $FF0000) shr 16;

  X := RGBToGray(R, G, B);
  Result := TColor(RGB(X, X, X));
end;

procedure TMainFrm.FormCreate(Sender: TObject);
begin
  Image1.Picture.Graphic := BeforeImage1.Picture.Bitmap;
end;

procedure TMainFrm.Panel4Click(Sender: TObject);
var
  Bitmap: TBitmap;
  I, X: Integer;
  Color: Integer;
begin
  Bitmap := TBitmap.Create;
  try
    Bitmap.Assign(BeforeImage1.Picture.Bitmap);
    Panel4.Caption := '';
    Panel5.Caption := '';
    Panel6.Caption := '';
    Panel7.Caption := '';
    Panel8.Caption := '';
    Panel9.Caption := '';
    (Sender as TPanel).Caption := 'X';

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

        case (Sender as TPanel).Tag of
          1: ; // I need a function something like BlueToRed(Color);
          2: ; // I need a function something like BlueToGreen(Color);
          3: ; // I need a function something like BlueToYellow(Color);
          4: ; // I need a function something like BlueToFuchsia(Color);
          5: ; // I need a function something like BlueToCyan(Color);
          6: Bitmap.Canvas.Pixels[I, X] := BlueToGray(Color);
        end;
        Image1.Picture.Graphic := Bitmap;
      end;
      Application.ProcessMessages();
      Sleep(100);
    end;
    AfterImage1.Picture.Graphic := Bitmap;
  finally
    Bitmap.Free;
  end;
end;

end.

1 个答案:

答案 0 :(得分:7)

问题仍然没有明确定义,因为灰色不像任何其他颜色(在RGB模型中,也不在HSV模型中),因此没有单一,明显的方法来实现其他颜色按钮

然而,一种自然的方式(也许是最自然的方式)就像我在上一个问题的答案中所建议的那样,即在红色案例中将每个像素从HSV(h, s, v)转换为HSV(0, s, v)绿色案例中为HSV(120, s, v),蓝色案例中为HSV(240, s, v)。数字0,120和240是色调的角度。

要做到这一点,你只需要在RGB和HSV之间进行转换的功能(我确实在最后一个问题中给你了。)

我在你的代码中看到你已经命名了函数BlueToRed(Color)等,这是不合适的,因为任何颜色都会变成红色等,所以更好的名字将是{{1等等。

为了使其尽可能清晰,我在程序中添加了红色和绿色按钮的代码。请参阅

的更新版本

http://privat.rejbrand.se/ColorSwap.zip

(另外,请注意“ColorSwap”是不合适的名称。更好的名称是“FixHue”。)

<强>性能

另外,正如您可能已经注意到的那样,性能可怕!图像着色需要几秒钟!

这不是因为CPU很慢(实际上它非常快),但主要是由于两个设计错误:

  1. 永远不要在屏幕上更新像素图。相反,更新内存中的像素图,然后,完成后,将位图复制到屏幕。

  2. 请勿使用ColorToRed属性。这很慢。请改用Pixels

  3. 如果你做得对,你应该能够每秒进行几百次更新......