C++实现Photoshop图像黑白调整

Photoshop CS的图像黑白调整功能,是通过对红、黄、绿、青、蓝和洋红等6种颜色的比例调节来完成的。能更精细地将彩色图片转换为高质量的黑白照片。

Photoshop CS图像黑白调整功能的计算公式为:

gray = (max - min) * ratio_max + (mid - min) * ratio_max_mid + min

公式中:gray为像素灰度值,max、mid和min分别为图像像素R、G、B分量颜色的最大值、中间值和最小值,ratio_max为max所代表的分量颜色(单色)比率,ratio_max_mid则为max与mid两种分量颜色所形成的复色比率。

用上面公式计算的灰度值,与我们通常所用的灰度计算方法有很大不同,通常所用的灰度公式为,是直接将颜色各分量乘以相应的比率相加而成,如:gray = 0.3R + 0.59G + 0.11B,而上面公式则是在最小值代表的颜色分量基础上,用最大值与最小值之差表示单色部分(红、绿、蓝),用中间值与最小值之差表示复色部分(黄、青、洋红),将单色和复色部分分别乘以与之对应的比率后相加,再加上最小值而得到灰度值。对于每个单独的像素来说,计算灰度值只需要用到上述6种颜色比率中的2种即可。在计算过程中可根据像素RGB相互关系选择对应的单色和复色比率,如像素RGB的大小关系为R>G>B,单色比率选最大值R红色,复色比率则为最大值R与中间值G所形成的复色黄色。

用程序代码实现上面的灰度计算公式并不复杂,难点还是前面所说的根据像素RGB相互关系选择对应的单色和复色比率。在前天我写的《C++实现Photoshop图层颜色混合模式》和《C++实现Photoshop图层颜色混合模式(续)》2篇文章中,已经实现了这项功能,同时,Photoshop图像黑白调整功能中附加的着色功能,也在上面2篇文章中实现。本文的目的也就是用上面文章中提供的2个函数,编写一个相对简单的图像黑白调整界面,来实现图像动态黑白调整。

下面是用BCB2007写的一个界面程序代码:

程序头文件部分:

//--------------------------------------------------------------------------- #ifndef bwMainH #define bwMainH //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <ComCtrls.hpp> #include <Dialogs.hpp> #include <ExtCtrls.hpp> #define USE_GDIPLUS #include "ColorMixer.h" //--------------------------------------------------------------------------- enum TLockType {ltEdit, ltTrack}; typedef Set<TLockType, ltEdit, ltTrack> TLockTypes; class TForm1 : public TForm { __published: // IDE-managed Components TPaintBox *PaintBox1; TLabel *Label1; TLabel *Label2; TLabel *Label3; TLabel *Label4; TLabel *Label5; TLabel *Label6; TLabel *Label7; TLabel *Label8; TLabel *Label9; TLabel *Label10; TLabel *Label11; TLabel *Label12; TLabel *Label13; TLabel *Label18; TComboBox *ComboBox1; TEdit *Edit1; TTrackBar *TrackBar1; TEdit *Edit2; TTrackBar *TrackBar2; TEdit *Edit3; TTrackBar *TrackBar3; TEdit *Edit4; TTrackBar *TrackBar4; TEdit *Edit5; TTrackBar *TrackBar5; TEdit *Edit6; TTrackBar *TrackBar6; TCheckBox *CheckBox1; TGroupBox *GroupBox1; TLabel *Label14; TLabel *Label15; TLabel *Label16; TLabel *Label17; TPaintBox *PaintBox2; TEdit *Edit7; TTrackBar *TrackBar7; TEdit *Edit8; TTrackBar *TrackBar8; TColorDialog *ColorDialog1; void __fastcall FormCreate(TObject *Sender); void __fastcall FormDestroy(TObject *Sender); void __fastcall ComboBox1Change(TObject *Sender); void __fastcall TrackBar1Change(TObject *Sender); void __fastcall Edit1Change(TObject *Sender); void __fastcall Edit1KeyPress(TObject *Sender, char &Key); void __fastcall Edit1Exit(TObject *Sender); void __fastcall CheckBox1Click(TObject *Sender); void __fastcall TrackBar7Change(TObject *Sender); void __fastcall Edit7Change(TObject *Sender); void __fastcall Edit7KeyPress(TObject *Sender, char &Key); void __fastcall PaintBox2Click(TObject *Sender); void __fastcall PaintBox1Paint(TObject *Sender); void __fastcall PaintBox2Paint(TObject *Sender); void __fastcall TrackBar8Change(TObject *Sender); private: // User declarations Bitmap *Source; // 源图像 Bitmap *Dest; // 调整后的图像 Gdiplus::Color MixColor; // 混合颜色 int GrayOptions[6]; // 灰度选项数组 int Bright; // 亮度 TTrackBar *TrackBars[6]; // 灰度选项条元件数组 TEdit *Edits[6]; // 灰度选项编辑框数组 TLockTypes Lock; Gdiplus::Rect rect; int __fastcall GetHue(void); int __fastcall GetSat(void); void __fastcall SetHue(int hue); void __fastcall SetSat(int sat); void __fastcall MixColorToHSV(void); void __fastcall HSVToMixColor(void); void __fastcall Execute(void); void __fastcall MixColorChange(void); public: // User declarations __fastcall TForm1(TComponent* Owner); __property int Hue = {read=GetHue, write=SetHue}; // 色相 __property int Sat = {read=GetSat, write=SetSat}; // 饱和度 }; //--------------------------------------------------------------------------- const CustomIndex = 11; // 自定义选项索引 const DefaultTint = 0xe1d3b3; // 缺省混合颜色 const int DefOptions[][6] = // 预定义灰度选项 { {40, 60, 40, 60, 20, 80}, {128, 128, 100, 100, 128, 100}, {100, 100, 100, 100, 100, 100}, {0, 0, 0, 0, 0, 0}, {-40, 235, 144, -68, -3, -107}, {120, 110, -10, -50, 0, 120}, {50, 120, 90, 50, 0, 0}, {0, 0, 0, 110, 110, 110}, {120, 120, -10, -50, -50, 120}, {-50, -50, -50, 150, 150, 150}, {120, 110, 40, -30, 0, 70} }; extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif

代码文件部分:

//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "bwMain.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- ULONG gdiplusToken; void __fastcall TForm1::FormCreate(TObject *Sender) { Gdiplus::GdiplusStartupInput gdiplusStartupInput; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); TrackBars[0] = TrackBar1; TrackBars[1] = TrackBar2; TrackBars[2] = TrackBar3; TrackBars[3] = TrackBar4; TrackBars[4] = TrackBar5; TrackBars[5] = TrackBar6; Edits[0] = Edit1; Edits[1] = Edit2; Edits[2] = Edit3; Edits[3] = Edit4; Edits[4] = Edit5; Edits[5] = Edit6; Source = new Bitmap(WideString("\\source1.jpg")); rect.Width = Source->GetWidth(); rect.Height = Source->GetHeight(); Dest = new Bitmap(rect.Width, rect.Height, Source->GetPixelFormat()); ComboBox1Change(NULL); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { delete Dest; delete Source; GdiplusShutdown(gdiplusToken); } //--------------------------------------------------------------------------- // 执行图像黑白调整 void __fastcall TForm1::Execute(void) { for (int i = 0; i < 6; i ++) // 获取灰度选项条数据 GrayOptions[i] = TrackBars[i]->Position; BitmapData dst, src; Dest->LockBits(&rect, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &dst); Source->LockBits(&rect, ImageLockModeRead, PixelFormat24bppRGB, &src); try { ImageGray(&dst, &src, GrayOptions); // 源图黑白调整到目标图 if (CheckBox1->Checked) // 如果色调选项被选,着色 ImageColorMixer(&dst, MixColor.GetValue(), TRUE); } __finally { Source->UnlockBits(&src); Dest->UnlockBits(&dst); } PaintBox1Paint(NULL); // 显示图像 } //--------------------------------------------------------------------------- // 预设黑白调整选项改变 void __fastcall TForm1::ComboBox1Change(TObject *Sender) { if (ComboBox1->ItemIndex == CustomIndex) return; MixColor.SetValue(DefaultTint); // 设置缺省混合颜色 MixColorToHSV(); // 计算并设置缺省色相、饱和度控件 Lock = TLockTypes() << ltEdit << ltTrack; try { for (int i = 0; i < 6; i ++) // 装入预设的选项数据到相应的控件 { TrackBars[i]->Position = DefOptions[ComboBox1->ItemIndex][i]; Edits[i]->Text = DefOptions[ComboBox1->ItemIndex][i]; } if (CheckBox1->Checked) CheckBox1->Checked = false; // 取消色调选项 else Execute(); } __finally { Lock.Clear(); } } //--------------------------------------------------------------------------- // 黑白调整数据选项条改变 void __fastcall TForm1::TrackBar1Change(TObject *Sender) { if (Lock.Contains(ltTrack)) return; Lock = TLockTypes() << ltEdit; try { TTrackBar *bar = (TTrackBar*)Sender; Edits[bar->Tag]->Text = bar->Position; ComboBox1->ItemIndex = CustomIndex; // 预设下拉框设置为自定义 Execute(); } __finally { Lock.Clear(); } } //--------------------------------------------------------------------------- // 黑白调整数据编辑框改变 void __fastcall TForm1::Edit1Change(TObject *Sender) { if (Lock.Contains(ltEdit)) return; TEdit *edit = (TEdit*)Sender; if (edit->Text != "" && edit->Text != "-") TrackBars[edit->Tag]->Position = StrToInt(edit->Text); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key) { if (Key >= ' ' && Key != '-' && (Key < '0' || Key > '9')) Key = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit1Exit(TObject *Sender) { TEdit *edit = (TEdit*)Sender; if (edit->Text == "") edit->Text = TrackBars[edit->Tag]->Position; } //--------------------------------------------------------------------------- // 混合颜色改变,画混合颜色,显示其RGB值 void __fastcall TForm1::MixColorChange(void) { PaintBox2Paint(NULL); Label18->Caption = "R: " + IntToStr(MixColor.GetRed()) + ", G: " + MixColor.GetGreen() + ", B: " + MixColor.GetBlue(); Execute(); } //--------------------------------------------------------------------------- inline void RgbSwap(int &a, int &b) { a += b; b = a - b; a -= b; } // 按混合颜色计算并改变HSV void __fastcall TForm1::MixColorToHSV(void) { int max, mid, min; max = MixColor.GetRed(); mid = MixColor.GetGreen(); min = MixColor.GetBlue(); if (max < mid) RgbSwap(max, mid); if (max < min) RgbSwap(max, min); if (min > mid) RgbSwap(min, mid); int max_min = max - min; if (max_min == 0) { Hue = 0; Sat = 0; } else { int H; if (max == MixColor.GetRed()) H = ((MixColor.GetGreen() - MixColor.GetBlue()) * 60 + 30) / max_min; else if (max == MixColor.GetGreen()) H = ((MixColor.GetBlue() - MixColor.GetRed()) * 60 + 30) / max_min + 120; else H = ((MixColor.GetRed() - MixColor.GetGreen()) * 60 + 30) / max_min + 240; Hue = H < 0? H + 360 : H; Sat = (max_min * 100) / max; } Bright = max; MixColorChange(); } //--------------------------------------------------------------------------- // 按HSV计算并改变混合颜色 void __fastcall TForm1::HSVToMixColor(void) { if (Sat == 0) { MixColor = Gdiplus::Color(Bright, Bright, Bright); } else { int index = Hue / 60; int f = Hue % 60; if ((index & 1) == 0) f = 60 - f; int a = Bright; int b = (Bright * (6000 - Sat * f)) / 6000; int c = (Bright * (100 - Sat)) / 100; switch (index) { case 0: MixColor = Gdiplus::Color(a, b, c); break; case 1: MixColor = Gdiplus::Color(b, a, c); break; case 2: MixColor = Gdiplus::Color(c, a, b); break; case 3: MixColor = Gdiplus::Color(c, b, a); break; case 4: MixColor = Gdiplus::Color(b, c, a); break; case 5: MixColor = Gdiplus::Color(a, c, b); } } MixColorChange(); } //--------------------------------------------------------------------------- int __fastcall TForm1::GetHue(void) { return TrackBar7->Position; } //--------------------------------------------------------------------------- int __fastcall TForm1::GetSat(void) { return TrackBar8->Position; } //--------------------------------------------------------------------------- void __fastcall TForm1::SetHue(int hue) { if (Hue == hue) return; Lock = TLockTypes() << ltEdit << ltTrack; try { TrackBar7->Position = hue; Edit7->Text = hue; } __finally { Lock.Clear(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::SetSat(int sat) { if (Sat == sat) return; Lock = TLockTypes() << ltEdit << ltTrack; try { TrackBar8->Position = sat; Edit8->Text = sat; } __finally { Lock.Clear(); } } //--------------------------------------------------------------------------- // 色调选盒改变 void __fastcall TForm1::CheckBox1Click(TObject *Sender) { Label14->Enabled = CheckBox1->Checked; Label15->Enabled = CheckBox1->Checked; Label16->Enabled = CheckBox1->Checked; Label17->Enabled = CheckBox1->Checked; Label18->Visible = CheckBox1->Checked; Edit7->Enabled = CheckBox1->Checked; Edit8->Enabled = CheckBox1->Checked; TrackBar7->SliderVisible = CheckBox1->Checked; TrackBar8->SliderVisible = CheckBox1->Checked; if (CheckBox1->Checked) ComboBox1->ItemIndex = CustomIndex; MixColorChange(); } //--------------------------------------------------------------------------- // 色相选项条改变 void __fastcall TForm1::TrackBar7Change(TObject *Sender) { if (!Lock.Contains(ltTrack)) Edit7->Text = TrackBar7->Position; } //--------------------------------------------------------------------------- // 饱和度选项条改变 void __fastcall TForm1::TrackBar8Change(TObject *Sender) { if (!Lock.Contains(ltTrack)) Edit8->Text = TrackBar8->Position; } //--------------------------------------------------------------------------- // 色相或者饱和度编辑框改变 void __fastcall TForm1::Edit7Change(TObject *Sender) { TEdit *edit = (TEdit*)Sender; if (Lock.Contains(ltEdit) || edit->Text == "") return; int val = StrToInt(edit->Text); TTrackBar *bar = edit->Tag == 0? TrackBar7 : TrackBar8; if (bar->Position != val) bar->Position = val; HSVToMixColor(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit7KeyPress(TObject *Sender, char &Key) { if (Key >= ' ' && (Key < '0' || Key > '9')) Key = 0; } //--------------------------------------------------------------------------- // 调用颜色对话框选择混合颜色 void __fastcall TForm1::PaintBox2Click(TObject *Sender) { if (CheckBox1->Checked && ColorDialog1->Execute(Handle)) { MixColor.SetFromCOLORREF(ColorDialog1->Color); MixColorToHSV(); } } //--------------------------------------------------------------------------- // 画黑白调整图像和源图像 void __fastcall TForm1::PaintBox1Paint(TObject *Sender) { Gdiplus::Graphics *g = new Gdiplus::Graphics(PaintBox1->Canvas->Handle); try { g->DrawImage(Dest, rect); if (Sender != NULL) { g->TranslateTransform(0, rect.Height); g->DrawImage(Source, rect); } } __finally { delete g; } } //--------------------------------------------------------------------------- // 画混合颜色 void __fastcall TForm1::PaintBox2Paint(TObject *Sender) { if (CheckBox1->Checked) PaintBox2->Canvas->Brush->Color = (TColor)MixColor.ToCOLORREF(); else PaintBox2->Canvas->Brush->Color = Color; PaintBox2->Canvas->Pen->Color = clMedGray; PaintBox2->Canvas->Rectangle(PaintBox2->ClientRect); } //---------------------------------------------------------------------------

界面程序中,实现图像黑白调整功能主要靠Execute函数完成:

// 执行图像黑白调整
void __fastcall TForm1::Execute(void)
{
for (int i = 0; i < 6; i ++)// 获取灰度选项条数据
GrayOptions[i] = TrackBars[i]->Position;
BitmapData dst, src;
Dest->LockBits(&rect, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &dst);
Source->LockBits(&rect, ImageLockModeRead, PixelFormat24bppRGB, &src);
try
{
ImageGray(&dst, &src, GrayOptions);// 源图黑白调整到目标图
if (CheckBox1->Checked)// 如果色调选项被选,着色
ImageColorMixer(&dst, MixColor.GetValue(), TRUE);
}
__finally
{
Source->UnlockBits(&src);
Dest->UnlockBits(&dst);
}
PaintBox1Paint(NULL);// 显示图像
}

其中的ImageGray函数用于将源图按用户所选参数,进行黑白调整并拷贝到目标图;ImageColorMixer用于目标图的着色。这2个函数请见《C++实现Photoshop图层颜色混合模式(续)代码较长,不便转贴)。

下面是几张程序运行界面图:

1、缺省黑白调整参数运行界面,其中右上边的下拉编辑框显示的是一些预设黑白效果选项:

2、选择红外线效果黑白调整参数运行界面:

3、使用缺省参数进行黑白调整后,再用所选颜色进行着色的界面:

4、在上面界面基础上,色调不变,加大黄色调参数,使图中人物衣服颜色明亮一些,同时减少蓝色调参数,使人物的围脖颜色变暗一些:

如有错误或者建议,请来信指导:maozefa@hotmail.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值