精华内容
下载资源
问答
  • C++图像处理 -- 图像色阶调整

    万次阅读 2015-02-27 19:16:17
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...

    阅读提示

        《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

        《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

        尽可能保持二者内容一致,可相互对照。

        本文代码必须包括《C++图像处理 -- 数据类型及公用函数文章中的BmpData.h头文件。


        在Photoshop中,图像色阶调整应用很广泛,本文介绍的图像色阶调整过程与Photoshop处理效果基本一致。

        Photoshop的色阶调整分输入色阶调整和输出色阶调整,其中输入色阶调整有3个调整点,即通常所说的黑场、白场及灰场调整。

        输入色阶调整的基本算法并不复杂,首先计算出白场与黑场的离差Diff,然后计算出像素各份量值与黑场的离差rgbDiff,如果rgbDiff<=0,像素各份量值等于0,否则,计算以rgbDiff与Diff的比值为底的灰场倒数的幂。用公式表示:

        Diff = Highlight -Shadow

        rgbDiff = RGB - Shadow

        clRGB = Power(rgbDiff / Diff,  1 / Midtones)

        其中Shadow为输入色阶低端数据(黑场),Highlight为输入色阶高端数据(白场), Midtones为输入色阶中间数据(灰场),Diff为二者的离差(必须大于1),RGB为调整前的像素分量值,clRGB为调整输入色阶后的像素分量值。

        输出色阶调整更简单,首先计算输出色阶白场与黑场的离差与255的比值系数,然后用输入色阶调整后的像素分量值乘上这个系数,再加上输出黑场值即可。用公式表示:

        outClRGB = clRGB * (outHighlight - outShadow) / 255 + outShadow

        其中,outShadow为输出黑场,outHighlight为输出白场,outClRGB为全部色阶调整后的像素分量值。

        前面已经提到输入色阶黑白场的离差必须大于1,而输入色阶并没有这个限制,输出黑白场的离差可以为负数,当输出黑场与白场完全颠倒时,输出色阶调整后的图片为原图片的负片。

        色阶调整涉及四个通道,即R、G、B各分量通道及整体颜色通道,如果每个通道单独调整,将是比较麻烦和耗时的,本文采用色阶表替换法,可一次性完成所有四个通道的色阶调整。

        下面是图像色阶调整的代码:

    // 色阶项结构
    typedef struct
    {
    	UINT Shadow;
    	FLOAT Midtones;
    	UINT Highlight;
    	UINT OutShadow;
    	UINT OutHighlight;
    }ColorLevelItem, *PColorLevelItem;
    
    typedef struct
    {
    	ColorLevelItem Blue;
    	ColorLevelItem Green;
    	ColorLevelItem Red;
    	ColorLevelItem RGB;
    }ColorLevelData, *PColorLevelData;
    
    VOID InitColorLevelData(PColorLevelData clData)
    {
    	PColorLevelItem item = &clData->Blue;
    	for (INT i = 0; i < 4; i ++, item ++)
    	{
    		item->Shadow = item->OutShadow = 0;
    		item->Highlight = item->OutHighlight = 255;
    		item->Midtones = 1.0;
    	}
    }
    
    BOOL GetColorLevelTable(PColorLevelItem item, LPBYTE clTable)
    {
    	INT diff = (INT)(item->Highlight - item->Shadow);
    	INT outDiff = (INT)(item->OutHighlight - item->OutShadow);
    
    	if (!((item->Highlight <= 255 && diff < 255 && diff >= 2) ||
    		(item->OutShadow <= 255 && item->OutHighlight <= 255 && outDiff < 255) ||
    		(!(item->Midtones > 9.99 && item->Midtones > 0.1) && item->Midtones != 1.0)))
    		return FALSE;
    
    	DOUBLE coef = 255.0 / diff;
    	DOUBLE outCoef = outDiff / 255.0;
    	DOUBLE exponent = 1.0 / item->Midtones;
    
    	for (INT i = 0; i < 256; i ++)
    	{
    		INT v;
    		// 计算输入色阶黑白场
    		if (clTable[i] <= (BYTE)item->Shadow)
    			v = 0;
    		else
    		{
    			v = (INT)((clTable[i] - item->Shadow) * coef + 0.5);
    			if (v > 255)
    				v = 255;
    		}
    		// 计算输入色阶灰场
    		v = (INT)(pow(v / 255.0, exponent) * 255.0 + 0.5);
    		// 计算输出色阶
    		clTable[i] = (BYTE)(v * outCoef + item->OutShadow + 0.5);
    	}
    	return TRUE;
    }
    
    BOOL CheckColorLevelData(PColorLevelData clData, BYTE clTables[][256])
    {
    	BOOL result = FALSE;
    	INT i, j;
    	for (i = 0; i < 3; i ++)
    	{
    		for (j = 0; j < 256; j ++)
    			clTables[i][j] = (BYTE)j;
    	}
    	PColorLevelItem item = &clData->Blue;
    	for (i = 0; i < 3; i ++, item ++)
    	{
    		if (GetColorLevelTable(item, clTables[i]))
    			result = TRUE;
    	}
    	for (i = 0; i < 3; i ++)
    	{
    		if (!GetColorLevelTable(item, clTables[i]))
    			break;
    		result = TRUE;
    	}
    	return result;
    }
    
    // 图像数据色阶调整
    VOID ImageColorLevel(BitmapData *dest, BitmapData *source, PColorLevelData clData)
    {
    	PARGBQuad pd, ps;
    	UINT width, height;
    	INT dstOffset, srcOffset;
    	GetDataCopyParams(dest, source, width, height, pd, ps, dstOffset, srcOffset);
    
    	BYTE clTables[3][256];
    	if (CheckColorLevelData(clData, clTables))
    	{
    		for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
    		{
    			for (UINT x = 0; x < width; x ++, ps ++, pd ++)
    			{
    				pd->Blue = clTables[0][ps->Blue];
    				pd->Green = clTables[1][ps->Green];
    				pd->Red = clTables[2][ps->Red];
    				pd->Alpha = ps->Alpha;
    			}
    		}
    	}
    	else if (dest != source)
    	{
    		for (UINT y = 0; y < height; y ++, ps += srcOffset, pd += dstOffset)
    		{
    			for (UINT x = 0; x < width; x ++, ps ++, pd ++)
    			{
    				pd->Color = ps->Color;
    			}
    		}
        }
    }
    

        下面给一个简单的图像色阶调整函数调用例子:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    	BitmapData dest, source;
    
    	Bitmap *sBmp = new Bitmap(L"..\\..\\media\\source1.jpg");
    	LockBitmap(sBmp, &source);
    
    	Bitmap *dBmp = new Bitmap(source.Width, source.Height, PixelFormat32bppARGB);
    	LockBitmap(dBmp, &dest);
    
    	ColorLevelData clData;
    	InitColorLevelData(&clData);
    
    	clData.RGB.Shadow = 10;
    	clData.RGB.Midtones = 1.2;
    	clData.RGB.Highlight = 240;
    	clData.RGB.OutShadow = 50;
    	clData.RGB.OutHighlight = 200;
    
    /*
    	clData.RGB.OutShadow = 255;
    	clData.RGB.OutHighlight = 0;
    */
    	ImageColorLevel(&dest, &source, &clData);
    
    	UnlockBitmap(dBmp, &dest);
    	UnlockBitmap(sBmp, &source);
    
    	Gdiplus::Graphics g(Canvas->Handle);
    	g.DrawImage(sBmp, 0, 0);
    	g.DrawImage(dBmp, source.Width, 0);
    
    	delete dBmp;
    	delete sBmp;
    }

        下面是文章Delphi图像处理 -- 图像色阶调整例子运行界面效果图,第一张效果图绿色通道色阶调整,第二张效果图是RGB输出色阶调整到完全颠倒时的负片图,详细的图像色阶调整界面例子请参考Delphi图像处理 -- 图像色阶调整》。
         


        本文代码系用BCB XE7编辑和编译。


        因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

        这里可访问《C++图像处理 -- 文章索引


    
    展开全文
  • c/c++图像处理

    千次阅读 2018-09-20 18:22:00
    c/c++图像处理--学习中 https://blog.csdn.net/column/details/15631.html
    展开全文
  • C++图像处理 -- 文章索引

    万次阅读 多人点赞 2012-01-09 21:40:13
    本文对已发布《C++图像处理》系列文章进行索引链接,以方便阅读和查找。 《C++图像处理 -- 数据类型及公用函数》。提供GDI+位图Bitmap转换过程以及几个最基本的通用过程。所有其它文章代码,包括例子代码,必须包括...

        本文对已发布《C++图像处理》系列文章进行索引链接,以方便阅读和查找。

        C++图像处理 -- 数据类型及公用函数》。提供GDI+位图Bitmap转换过程以及几个最基本的通用过程。所有其它文章代码,包括例子代码,必须包括该文章所介绍的头文件BmpData.h。

        C++图像处理 -- 平面几何变换类》。介绍图像平面几何变换类TransformMatrix。

        C++图像处理 -- 图像合成》。介绍图像合成方法,这也是图像拼合、拼接和显示的基础。

        C++图像处理 -- 图像显示》。在《C++图像处理 -- 图像合成》代码基础上结合Windows API完成图像数据的显示。

        《C++图像处理 -- 平面几何变换》。采用临近插值法、双线性插值法和双立方插值法等三种插值方式和TransformMatrix类,实现了较完整、通用的图形图像平面几何变换。     

        C++图像处理 -- 图像翻转(镜像)》。对图像的翻转处理,是产生一个与原图像在水平方向或者垂直方向相对称的镜像图像。

        《C++图像处理 -- 颜色矩阵变换》。 实现GDI+的ColorMatrix功能。

        C++图像处理 -- 亮度/对比度调整》。实现Photoshop亮度/对比度调整功能。

        C++图像处理 -- 线性亮度/对比度调整》。在《C++图像处理 -- 亮度/对比度调整》基础上改进亮度算法。

        C++图像处理 -- 表面模糊》。 实现Photoshop表面模糊功能。

        C++图像处理 -- 图像颜色混合(上)》。实现Photoshop图层颜色混合模式、黑白调整和灰度图象染色功能。

        C++图像处理 -- 图像颜色混合(中)》。优化颜色混合和灰度图象染色函数。

        C++图像处理 -- 图像颜色混合(下)》。完善颜色混合和灰度图象染色函数功能,增加了图像的Alpha通道处理和图像的不透明度处理。

        C++图像处理 -- 图像黑白调整应用》。利用BCB和GDI+实现完整的Photoshop图像黑白调整功能。

        C++图像处理 -- PCX格式图像(上)》。PCX格式图像解析并转换为GDI+位图。

        C++图像处理 -- PCX格式图像(下)》。GDI+位图转换为PCX格式图像。

        《C++图像处理 -- 图像色阶调整》。完整实现PhotoShop图像色阶调整功能,包括输入色阶和输出色阶调整。

     

        正在整理更新。未完待续。。。。。。

    
    展开全文
  • C++图像处理 -- 图像黑白调整应用

    万次阅读 多人点赞 2011-07-10 15:05:59
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...

    阅读提示

        《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。

        《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。

        尽可能保持二者内容一致,可相互对照。

        本文代码必须包括《C++图像处理 -- 数据类型及公用函数文章中的BmpData.h头文件。

     

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

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

        gray = (max - mid) * 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图像黑白调整功能中附加的着色功能,也在文章中实现。本文的在上面文章代码基础上,编写一个相对简单的图像黑白调整界面,来实现图像动态黑白调整。

        下面是用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 "BmpData.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;					// 调整后的图像
    	BitmapData srcData;
    	BitmapData dstData;
    	float bwColors[6];				// 灰度选项数组
    	int Bright;						// 亮度
    	TTrackBar *TrackBars[6];		// 灰度选项条元件数组
    	TEdit *Edits[6];				// 灰度选项编辑框数组
    	TLockTypes Lock;
    	Gdiplus::Rect rect;
    	ARGBQuad MixColor;				// 混合颜色
    
    	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;
    
    typedef FLOAT		BWParams, *PBWParams;
    
    // 黑白调整缺省参数:红,黄,绿,洋红,蓝,青
    CONST INT _BWDefault[] = {410, 614, 410, 819, 205, 614};
    
    enum
    {
    	BWIndexBlue		= 0x40000,
    	BWIndexGreen	= 0x20000,
    	BWIndexRed		= 0x00000
    };
    
    enum
    {
    	IndexBlue	= 0x00000,
    	IndexGreen	= 0x10000,
    	IndexRed	= 0x20000
    };
    
    typedef union 				// 颜色分量交换结构
    {
    	INT tmp;				// 交换时用的临时变量
    	struct
    	{
    		SHORT value;		// 颜色分量值
    		SHORT index;		// 颜色分量索引
    	};
    }RGBIndex;
    //---------------------------------------------------------------------------
    
    // 交换像素分量
    FORCEINLINE
    VOID SwapRgb(RGBIndex &a, RGBIndex &b)
    {
    	a.tmp ^= b.tmp;
    	b.tmp ^= a.tmp;
    	a.tmp ^= b.tmp;
    }
    //---------------------------------------------------------------------------
    
    // 获取黑白灰度
    FORCEINLINE
    INT	GetBWGray(CONST PARGBQuad pixel, CONST PINT bwParams)
    {
    	RGBIndex max, mid, min;
    	min.tmp = pixel->Blue | BWIndexBlue;
    	mid.tmp = pixel->Green | BWIndexGreen;
    	max.tmp = pixel->Red | BWIndexRed;
    
    	if (max.value < mid.value)
    		SwapRgb(max, mid);
    	if (max.value < min.value)
    		SwapRgb(max, min);
    	if (min.value > mid.value)
    		SwapRgb(min, mid);
    
    	return (((max.value - mid.value) * bwParams[max.index] +
    		(mid.value - min.value) * bwParams[max.index + mid.index - 1] +
    		512) >> 10) + min.value;
    }
    //---------------------------------------------------------------------------
    
    VOID ColorMix(PARGBQuad pd, CONST PARGBQuad ps, INT gray)
    {
    	// 灰度计算常数:蓝,绿、红
    	CONST INT ys[3] = {113, 604, 307};
    
    	RGBIndex max, mid, min;
    	min.tmp = ps->Blue | IndexBlue;
    	mid.tmp = ps->Green | IndexGreen;
    	max.tmp = ps->Red | IndexRed;
    
    	if (max.value < mid.value)
    		SwapRgb(max, mid);
    	if (max.value < min.value)
    		SwapRgb(max, min);
    	if (min.value > mid.value)
    		SwapRgb(min, mid);
    
    	INT max_min = max.value - min.value;
    	// 饱和度为0,返回灰度
    	if (max_min == 0)
    	{
    		pd->Blue = pd->Green = pd->Red = gray;
    		return;
    	}
    	INT mid_min = mid.value - min.value;
    
    	INT newMax, newMid, newMin;
    	gray <<= 10;
    	newMax = (gray + (max_min - mid_min) * ys[mid.index] + max_min * ys[min.index] + 512) >> 10;
    	newMin = newMax - max_min;
    	if (newMax > 255)
    	{
    		INT hueCoef = (mid_min << 10) / max_min;
    		INT v0 = (ys[mid.index] * hueCoef) >> 10;
    		INT v1 = ys[min.index] + ys[mid.index] - v0;
    		newMin = (gray - (ys[max.index] + v0) * 255 + (v1 >> 1)) / v1;
    		newMid = newMin + (((255 ^ newMin) * hueCoef + 512) >> 10);
    		newMax = 255;
    
    	}
    	else if (newMin < 0)
    	{
    		INT hueCoef = (mid_min << 10) / max_min;
    		INT tmp = ys[max.index] + ((ys[mid.index] * hueCoef + 512) >> 10);
    		newMax = (gray + (tmp >> 1)) / tmp;
    		newMid = (newMax * hueCoef + 512) >> 10;
    		newMin = 1;
    	}
    	else
    		newMid = newMin + mid_min;
    
    	((LPBYTE)pd)[max.index] = newMax;
    	((LPBYTE)pd)[mid.index] = newMid;
    	((LPBYTE)pd)[min.index] = newMin;
    }
    //---------------------------------------------------------------------------
    
    // 图像黑白调整。
    // 调整参数bwParams为元素数等于6的数组指针,分别为红,黄,绿,青,蓝,洋红
    VOID ImageBWCopy(BitmapData *dest, CONST BitmapData *source, CONST PBWParams bwParams = NULL)
    {
    	// 拷贝像素灰度参数,并交换青色和洋红色
    	INT params[6], *pparams;
    	if (bwParams)
    	{
    		for (INT i = 0; i < 6; i ++)
    			params[i] = (INT)(bwParams[i] * 1024 + 0.5);
    		params[3] ^= params[5];
    		params[5] ^= params[3];
    		params[3] ^= params[5];
    		pparams = params;
    	}
    	else
    		pparams = (INT*)_BWDefault;
    
    	PARGBQuad pd, ps;
    	UINT width, height;
    	INT dstOffset, srcOffset;
    	GetDataCopyParams(dest, source, width, height, pd, ps, dstOffset, srcOffset);
    
    	for (UINT y = 0; y < height; y ++, pd += dstOffset, ps += srcOffset)
    	{
    		for (UINT x = 0; x < width; x ++, pd ++, ps ++)
    		{
    			INT gray = GetBWGray(ps, pparams);
    			pd->Blue = pd->Green = pd->Red =
    				(gray & ~0xff) == 0? gray : gray > 255? 255 : 0;
    		}
    	}
    }
    //---------------------------------------------------------------------------
    
    // 灰度图像染色。
    VOID ImageTint(BitmapData *grayData, ARGB color)
    {
    	ARGBQuad colorTable[256];
    	PARGBQuad p = colorTable;
    
    	for (INT i = 0; i < 256; i ++, p ++)
    	{
    		ColorMix(p, (PARGBQuad)&color, i);
    		p->Alpha = 255;
    	}
    
    	p = (PARGBQuad)grayData->Scan0;
    	INT dataOffset = (grayData->Stride >> 2) - (INT)grayData->Width;
    
    	for (UINT y = 0; y < grayData->Height; y ++, p += dataOffset)
    	{
    		for (UINT x = 0; x < grayData->Width; x ++, p ++)
    		{
    			p->Color = colorTable[p->Blue].Color;
    		}
    	}
    }
    //---------------------------------------------------------------------------
    
    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;
    
    	// 从文件装入图像到tmp
    	Bitmap *tmp = new Bitmap(L"source1.jpg");
    	rect.Width = tmp->GetWidth();
    	rect.Height = tmp->GetHeight();
    	// 分别建立新的源和目标图像数据到srcData和dstData
    	GetBitmapData(rect.Width, rect.Height, &srcData);
    	GetBitmapData(rect.Width, rect.Height, &dstData);
    	// 将tmp图像数据分别锁定拷贝到srcData和dstData
    	tmp->LockBits(&rect,
    		ImageLockModeRead | ImageLockModeWrite | ImageLockModeUserInputBuf,
    		PixelFormat32bppARGB, &srcData);
    	tmp->UnlockBits(&srcData);
    	tmp->LockBits(&rect,
    		ImageLockModeRead | ImageLockModeWrite | ImageLockModeUserInputBuf,
    		PixelFormat32bppARGB, &dstData);
    	tmp->UnlockBits(&dstData);
    	delete tmp;
    	// 分别用图像数据srcData和dstData建立位图Source和Dest
    	// 注:图像数据结构用于数据处理,位图用于显示,这样即可绑定数据结构和位图,
    	//     又能避免每次处理图像数据时的锁定和解锁操作
    	Source = new Bitmap(srcData.Width, srcData.Height, srcData.Stride,
    		PixelFormat32bppARGB, (BYTE*)srcData.Scan0);
    	Dest = new Bitmap(dstData.Width, dstData.Height, dstData.Stride,
    		PixelFormat32bppARGB, (BYTE*)dstData.Scan0);
    
    	ComboBox1Change(NULL);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    	delete Dest;
    	delete Source;
    	FreeBitmapData(&dstData);
    	FreeBitmapData(&srcData);
    	GdiplusShutdown(gdiplusToken);
    }
    //---------------------------------------------------------------------------
    
    // 执行图像黑白调整
    void __fastcall TForm1::Execute(void)
    {
    	for (int i = 0; i < 6; i ++)				// 获取灰度选项条数据
    		bwColors[i] = TrackBars[i]->Position / 100.0;
    	ImageBWCopy(&dstData, &srcData, bwColors);	// 源图黑白调整到目标图
    	if (CheckBox1->Checked && Sat)				// 如果色调选项被选,着色
    		ImageTint(&dstData, MixColor.Color);
    	PaintBox1Paint(NULL);						// 显示图像
    }
    //---------------------------------------------------------------------------
    
    // 预设黑白调整选项改变
    void __fastcall TForm1::ComboBox1Change(TObject *Sender)
    {
    	if (ComboBox1->ItemIndex == CustomIndex)
    		return;
    	MixColor.Color = 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.Red) +
    					", G: " + MixColor.Green +
    					", B: " + MixColor.Blue;
    	Execute();
    }
    //---------------------------------------------------------------------------
    
    inline void RgbSwap(int &a, int &b)
    {
    	a ^= b;
    	b ^= a;
    	a ^= b;
    }
    
    // 按混合颜色计算并改变HSV
    void __fastcall TForm1::MixColorToHSV(void)
    {
    	int max, mid, min;
    
    	max = MixColor.Red;
    	mid = MixColor.Green;
    	min = MixColor.Blue;
    	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.Red)
    			H = ((MixColor.Green - MixColor.Blue) * 60 + 30) / max_min;
    		else if (max == MixColor.Green)
    			H = ((MixColor.Blue - MixColor.Red) * 60 + 30) / max_min + 120;
    		else
    			H = ((MixColor.Red - MixColor.Green) * 60 + 30) / max_min + 240;
    		Hue = H < 0? H + 360 : H;
    		Sat = (max_min * 100) / max;
    
    	}
    	Bright = max;
    }
    //---------------------------------------------------------------------------
    
    inline ARGB RgbToColor(int r, int g, int b)
    {
    	return (r << 16) | (g << 8) | b;
    }
    
    // 按HSV计算并改变混合颜色
    void __fastcall TForm1::HSVToMixColor(void)
    {
    	if (Sat == 0)
    	{
    		MixColor.Blue = MixColor.Green = MixColor.Red = 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.Color = RgbToColor(a, b, c);
    				break;
    			case 1:
    				MixColor.Color = RgbToColor(b, a, c);
    				break;
    			case 2:
    				MixColor.Color = RgbToColor(c, a, b);
    				break;
    			case 3:
    				MixColor.Color = RgbToColor(c, b, a);
    				break;
    			case 4:
    				MixColor.Color = RgbToColor(b, c, a);
    				break;
    			case 5:
    				MixColor.Color = RgbToColor(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;
    	Lock = TLockTypes() << ltTrack;
    	try
    	{
    		int val = StrToInt(edit->Text);
    		TTrackBar *bar = edit->Tag == 0? TrackBar7 : TrackBar8;
    		if (bar->Position != val)
    			bar->Position = val;
    		HSVToMixColor();
    	}
    	__finally
    	{
    		Lock.Clear();
        }
    }
    //---------------------------------------------------------------------------
    
    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.Color = (ARGB)ColorDialog1->Color;
    		MixColor.Blue = MixColor.Red;
    		MixColor.Red = (BYTE)ColorDialog1->Color;
    		MixColorToHSV();
    		MixColorChange();
    	}
    }
    //---------------------------------------------------------------------------
    
    // 画黑白调整图像和源图像
    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 =
    			(MixColor.Blue << 16) | (MixColor.Green << 8) | MixColor.Red;
    	else
    		PaintBox2->Canvas->Brush->Color = Color;
    	PaintBox2->Canvas->Pen->Color = Color;
    	PaintBox2->Canvas->Rectangle(PaintBox2->ClientRect);
    }
    //---------------------------------------------------------------------------
    

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

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

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

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

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

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

     

        因水平有限,错误在所难免,欢迎指正和指导。邮箱地址:maozefa@hotmail.com

        这里可访问《C++图像处理 -- 文章索引

    展开全文
  • C++图像处理 -- 图像显示

    万次阅读 多人点赞 2012-01-06 13:08:44
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 图像合成

    万次阅读 2012-01-04 21:20:49
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 图像颜色混合(下)

    千次阅读 多人点赞 2011-08-02 09:24:24
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 平面几何变换

    千次阅读 多人点赞 2011-07-14 13:09:40
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 图像颜色混合(上)

    万次阅读 多人点赞 2011-07-05 12:29:38
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 图像颜色混合(中)

    千次阅读 多人点赞 2011-07-09 23:55:44
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C#调用C++图像处理算法(opencv)

    千次阅读 2018-03-21 23:54:26
    C#调用C++图像处理算法(OpenCV) 因为需要做一个图像处理的程序,后来决定采用C#写界面,C++写算法调用opencv的函数。关于opencv的使用之前已经学习过了,需要实现的是在C#中如何使用C++语言编写的DLL。 参考:...
  • C++图像处理 -- 图像翻转(镜像)

    万次阅读 多人点赞 2012-12-12 22:24:40
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 表面模糊

    万次阅读 多人点赞 2012-12-07 22:10:43
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- 数据类型及公用函数

    万次阅读 多人点赞 2012-01-09 21:34:25
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 不经意间,用...
  • c++图像处理入门教程

    千次阅读 多人点赞 2019-07-30 14:53:27
    最近有人问我图像处理怎么研究,怎么入门,怎么应用,我竟一时语塞。仔细想想,自己也搞了两年图像方面的研究,做个两个创新项目,发过两篇论文,也算是有点心得,于是总结总结和大家分享,希望能对大家有所帮助。在...
  • C++图像处理 -- 颜色矩阵变换

    万次阅读 2012-12-18 23:53:53
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理类库

    2018-04-03 12:04:45
    GIFLIB 是一个 C 语言的 Gif 图像处理库。支持 Gif 图像读写。 如果需要单独处理某类图片格式,以上类库是比较好的选择,如果处理的格式种类比较多,下面的类库是比较好的选择。    2. freeimage C语言的...
  • C++图像处理 -- 亮度/对比度调整

    万次阅读 多人点赞 2011-12-14 08:17:52
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++图像处理 -- PCX格式图像(下)

    千次阅读 多人点赞 2013-01-28 22:58:09
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 《C++图像...
  • C++图像处理 -- 平面几何变换类

    千次阅读 热门讨论 2010-10-10 14:52:00
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • Java服务器部署基于OpenCV的C++图像处理项目(一) 由于最近项目需要在后台处理图片并返回结果给移动端,所以折腾了一周如何将c++代码和opencv打包并部署到java服务器中供后台调用,这里记录下详细过程。 基础环境...
  • visual c++图像处理

    千次阅读 2010-05-05 15:00:00
    VC++图象处理编程(一) 基本概念前言数字图像处理技术与理论是计算机应用的一个重要领域,许多工程应用都涉及到图像处理,一直有一个强烈的愿望,想系统的写一个关于数字图像处理的讲座,由于工作学习很忙,时至...
  • C++图像处理 -- PCX格式图像(上)

    千次阅读 多人点赞 2013-01-27 23:45:41
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 PCX是一个...
  • C++图像处理 -- 线性亮度/对比度调整

    万次阅读 多人点赞 2009-08-28 14:36:00
    阅读提示: 《C++图像处理》系列以代码清晰,可读性为主,全部使用C++代码。 《Delphi图像处理》系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM。 尽可能保持二者内容一致,可相互对照。 本文代码必须...
  • C++ 图像处理常用库

    2020-03-04 21:00:19
    OpenGL 渲染管线流程为:顶点数据 -> 顶点着色器 -> 图元装配 -> 几何着色器 -> 光栅化 -> 片段着色器 -> 逐片段处理 -> 帧缓冲 GPU上与渲染处理对应的GPU硬件包括: 顶点处理: Vertex Shader(顶点着色器) 纹理帖...
  • C/C++ 图像处理(19)------细化算法

    万次阅读 多人点赞 2018-05-10 00:49:08
    “C/C++ 图像处理”系列文章是随着本人做东西的先后写成的,文章的前后关系可能不太明显,在这里先跟关注专栏的各位老哥说声抱歉,在“深度学习”系列文章中会尽量改掉这个较为随意的风格,让文章更具可读性。...
  •  C++ 图像处理 之 亮度、色彩平衡调整(逼近PS法) 关键词:图像处理亮度调整 色彩平衡Photoshop   参考博客 http://blog.csdn.net/maozefa/article/details/4493395 ...
  • 对比度拉伸变换对图像进行对比度拉伸变换,压缩动态范围,将我们所关注的边界特征信息详细化,从而使得输出图像亮区域更亮,暗区域更暗,提高了图像的对比度。 opencv中的 LUT函数(look up table)为查表函数, ...
  • c++ 图像处理(十八) 双线性插值

    千次阅读 2019-09-09 12:16:50
    //如果差值点在图像的最右下角 if(fabs(y - height+1)) { f1 = qGray(image.pixel(x1,y1)); return f1; }else { f1 = qGray(image.pixel(x1,y1)); f3 = qGray(image.pixel(x1,y2)); //图像右方的插值 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 103,372
精华内容 41,348
关键字:

c++图像处理

c++ 订阅