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

发布于 2024-10-10 20:00:27 字数 2889 浏览 4 评论 0原文

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

是的,我想将“主要是蓝色”的内容转换为“主要是绿色”的内容。

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

如果您可以看一下下面的代码,我有三个函数正在寻求帮助。函数“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.

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

替代文本

Download source code here: http://www.eyeClaxton.com/download/delphi/ColorSwap.zip

Yes, I want to convert something "mostly blue" to something "mostly green".

I would like to take a original bitmap (light blue) and change the colors (Pixel by Pixel) to the red, green, blue and gray equivalence relation. To get an idea of what I mean, I have include the source code and a screen shot. Any help would be greatly appreciated. If more information is needed, please feel free to ask.

If you could take a look at the code below, I have three functions that I'm looking for help on. The functions "RGBToRed, RGBToGreen and RGBToRed" I can't seem to come up with the right formulas.

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.

Okay, I apologize for not making it clearer. I'm trying to take a bitmap (blue in color) and swap the blue pixels with another color. Like the shots below.

alt text

alt text

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

策马西风 2024-10-17 20:00:27

我不知道你想实现什么目标。首先,这个问题与等价关系有什么关系?

其次,代码

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;

最终结果将类似于

Hue 固定为 120

第一种情况下

(色调固定为 120)和色调固定为 120,饱和度固定为 1

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

或者,可能

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

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

然后你会得到类似

R 和 G 通道交换

的内容,其中红色和绿色通道已交换。请注意,红棍现在是绿色的,绿草现在是红色的。白色的东西仍然是白色的。

最后

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

I have no idea what you are trying to achieve. First, what does the question have to do with equivalence relations?

Secondly, the code

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

is meaningless. The return value is undefined. The RGB functions takes red, green, and blue intensities in the range 0 to 255 and returns the TColor having these components. For instance, RGB(255, 0, 0) is pure red, that is, 255 red, 0 green, and 0 blue. In the code above, however, Red is not initialized, so Result can be any grey colour (depending on what Red happens to be). [And, as you probably know, if you mix equal amounts of red, green, and blue, as you do, you get grey.] For instance, Red might happen to be 45 one time you run the application, and then the result will be the grey colour RGB(45, 45, 45). Next time it might be 163.

Maybe you want a function that accepts a TColor and returns the red component of it? Then GetRValue will do, and - of course - there is also GetGValue and GetBValue.

Or, maybe you want to create a grey colour from a given TColor, as you do when you use Photoshop to create a greyscale image from a colour image. Then, if Color is the TColor, the appropriate grey value is

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

There are other ways of doing this (resulting in subtly different greyscale images, but this is the easiest (and fastest)). (For instance, you can convert the colour from RGB to HSV or HSL and then set the saturation equal to zero.)

Update

I think I see what you want to do. Maybe you want to extract the red, green, and blue channels. That is, you want to transform each pixel RGB(R, G, B) to RGB(R, 0, 0) in the red case. If this is what you want to do, then you should do

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

and similarly for the other components, that is

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

and

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

Or, maybe

Or maybe you just want to make the image greyscale, and then "colour" it red (or green, or blue). Then you need the heavy machinery. Theoretically, you wish to replace each pixel from HSV(h, s, v) to HSV(0, s, v) in the red case, HSV(120, s, v) in the green case, and HSV(240, s, v) in the blue case. Or, maybe you also wish to set the saturation s to 1.

I use the following rutines to convert between RGB and 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;

and

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;

where

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;

The end result, in the green case, will be like

Hue fixed to 120

in the first case (hue fixed to 120) and

Hue fixed to 120 and saturation fixed to 1

in the latter case (hue fixed to 120, saturation fixed to 1).

Or, possibly

Your question is very vauge, even with the edit. You want to convert something "mostly blue" to something "mostly green". But there are a thousand ways of doing that! A very simple way, of course, is just to swap the blue and green channels, that is, replace RGB(r, g, b) with RGB(r, b, g), or, explicitly,

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

Then you get something like

R and G channels swapped

where the red and green channels have been swapped. Notice that the red stick is now green, and the green grass is now red. What's white remains white.

Finally

Welcome to the world of pixmap manipulation! There is a lot of easy and fun things to do. Some more of my examples: https://english.rejbrand.se/algosim/manual/pmproc/pmproc.html

慢慢从新开始 2024-10-17 20:00:27

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

成功!

Accessing color information via "Pixels" property is really slow. You should consider using "Scanline" property to get about 2 levels of magnitude faster code.
http://blogs.embarcadero.com/pawelglowacki/2010/04/15/39051 contains code samples how to do it.

Success!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文