Programmatically swap colors from a loaded bitmap to Red, Green, Blue or Gray, pixel by pixel
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.
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(RGBCol开发者_JAVA技巧or: 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.
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
in the first case (hue fixed to 120) and
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
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
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!
精彩评论