CBuilder中实现图象处理功能
前段时间,在一个程序中要对图象进行简单的处理,查阅了一些资料,其中大部分都是针对的Delphi的,Cbuilder的很少,我是一个忠实的Cbuilder用户,现在把我的用Cbuilder进行图象处理的过程供大家参考。
这里的图象处理的控件主要是用Timage,通过Timage载入图象文件。Timage可以载入的文件有BMP和JPG格式,BMP和JPG文件格式相互转化的代码如下:
1.JPG格式转化为BMP格式文件
void TMainForm::JpgToBmp(char *source,char *dest) //JPG格式转化为BMP格式文件
{
TJPEGImage *MyJpeg=new TJPEGImage();
Graphics::TBitmap *bmp=new Graphics::TBitmap();
try
{
MyJpeg->LoadFromFile(source);
bmp->Assign(MyJpeg);
bmp->SaveToFile(dest);
}
catch(...)
{
bmp->FreeImage();
MyJpeg->Free();
}
delete MyJpeg;
delete bmp;
}
2.Bmp转换为JPEG文件格式函数
void TMainForm::BmpToJpg(char *source,char *dest) //Bmp转换为JPEG文件格式函数
{
TJPEGImage *MyJpeg=new TJPEGImage();
Graphics::TBitmap *bmp=new Graphics::TBitmap();
try
{
bmp->LoadFromFile(source);
MyJpeg->Assign(bmp);// Assign(MyJpeg);
MyJpeg->Compress();
MyJpeg->SaveToFile(dest);
}
catch(...)
{
bmp->FreeImage();
MyJpeg->Free();
}
delete MyJpeg;
delete bmp;
}
TJPEGImage 类主要进行JPG文件格式的载入,使用时需要在头文件中加入
#include "Jpeg.hpp",
下面的进行几种图象的处理方法,需要指出的是数据处理必须在Tbitmap的形式下进行,TJPEGImage其实是压缩格式,不能直接进行图象中象素的处理,处理JPG文件可以先载入,再转化成BMP的形式,进行处理,处理完以后输出的时候再转化为JPG的格式就可以了。
在图象处理之前,先定义象素点的数据结构:
struct rgb_str
{
short r_color;
short g_color;
short b_color;
};
分别表示一个象素点的R,G,B分量值。(其实数据类型用char就可以了,char的范围是0-255,在亮度和对比度调整时容易越界导致数据丢失,再进行还原操作时就不能真正还原了,所以这里用short 类型来保证数据能够真实还原)
rgb_str rgb[2000][2000];定义2000*2000的图象,用户可以根据实际情况进行定义。
Graphics::TBitmap *bitmap; 用于进行图象变换的指针
图象处理以前,先载入图象到BMP的形式,然后将数据值导入到象素点的结构中。
JpgToBmp("temp.jpg","temp.bmp");
Image1->Picture->LoadFromFile(bmpName);
TColor color;
pic_dis_width=Image1->Picture->Width;
pic_dis_height=Image1->Picture->Height;
for(int i=0;i< pic_dis_width-1;i++)
{
for(int j=0;j< pic_dis_height-1;j++)
{
color=Image1->Canvas->Pixels[i][j] ; //Pixels[i][j]->
rgb[i][j].r_color=GetRValue(color);
rgb[i][j].g_color=GetGValue(color);
rgb[i][j].b_color=GetBValue(color);
}
}
bitmap=new Graphics::TBitmap();
bitmap->Width=pic_dis_width;
bitmap->Height=pic_dis_height;
3.图象反显
for(int i=0;i< pic_dis_width-1;i++)
{
for(int j=0;j< pic_dis_height-1;j++)
{
//color=Image1->Canvas->Pixels[i][j] ; //Pixels[i][j]->
rgb[i][j].r_color=255-rgb[i][j].r_color;
rgb[i][j].g_color=255-rgb[i][j].g_color;
rgb[i][j].b_color=255-rgb[i][j].b_color;
bitmap->Canvas->Pixels[i][j]=RGB(rgb[i][j].r_color,rgb[i][j].g_color,rgb[i][j].b_color);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
这段代码的功能就是把图象以负片的形式显示出来,就象照相机的底片一样。
4.平滑处理
就是将被处理点的前后左右上下共9个点进行平均,进行平滑
void __fastcall TMainForm::ButtonSmoothClick(TObject *Sender) //平滑处理
{
int red,green,blue;
for(int i=1;i< pic_dis_width-2;i++)
{
for(int j=1;j< pic_dis_height-2;j++)
{
red=rgb[i-1][j-1].r_color+rgb[i][j-1].r_color+rgb[i+1][j-1].r_color
+rgb[i-1][j].r_color+rgb[i][j].r_color+rgb[i+1][j].r_color
+rgb[i-1][j+1].r_color+rgb[i][j+1].r_color+rgb[i+1][j+1].r_color;
green=rgb[i-1][j-1].g_color+rgb[i][j-1].g_color+rgb[i+1][j-1].g_color
+rgb[i-1][j].g_color+rgb[i][j].g_color+rgb[i+1][j].g_color
+rgb[i-1][j+1].g_color+rgb[i][j+1].g_color+rgb[i+1][j+1].g_color;
blue=rgb[i-1][j-1].b_color+rgb[i][j-1].b_color+rgb[i+1][j-1].b_color
+rgb[i-1][j].b_color+rgb[i][j].b_color+rgb[i+1][j].b_color
+rgb[i-1][j+1].b_color+rgb[i][j+1].b_color+rgb[i+1][j+1].b_color;
bitmap->Canvas->Pixels[i][j]=RGB(red/9,green/9,blue/9);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
ShowMessage("平滑操作结束");
}
5.锐化图象处理
锐化图象的基本原理就是把相邻的两个象素点的值的差距人为的加大,以便突出他们之间的差距。Degree表示锐化的程度。Min和Max函数的意义就是取最大值和最小值。(象素点的三个分量的值的范围都在0~255之间,图象处理以后要把值恢复到这个范围之内。)
void __fastcall TMainForm::ButtonSharpenClick(TObject *Sender) //锐化图象处理
{
TCursor oldCursor=Image1->Cursor;
Image1->Cursor=crHourGlass;
float degree=0.3;
int red,green,blue;
for(int i=1;i<pic_dis_width-1;i++)
{
for(int j=1;j<pic_dis_height-1;j++)
{
red=rgb[i][j].r_color+degree*(rgb[i][j].r_color-rgb[i-1][j-1].r_color);
green=rgb[i][j].g_color+degree*(rgb[i][j].g_color-rgb[i-1][j-1].g_color);
blue=rgb[i][j].b_color+degree*(rgb[i][j].b_color-rgb[i-1][j-1].b_color);
red=min(255,max(0,red));
green=min(255,max(0,green));
blue=min(255,max(0,blue));
bitmap->Canvas->Pixels[i][j]=RGB(red,green,blue);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
Image1->Cursor=oldCursor;
}
6. 浮雕效果处理
void __fastcall TMainForm::Button2Click(TObject *Sender) //浮雕效果处理
{
int red,green,blue;
const int const_value=128;
for(int i=0;i< pic_dis_width-2;i++)
{
for(int j=0;j< pic_dis_height-2;j++)
{
red=abs(rgb[i][j].r_color-rgb[i+1][j+1].r_color+const_value);
green=abs(rgb[i][j].g_color-rgb[i+1][j+1].g_color+const_value);
blue=abs(rgb[i][j].b_color-rgb[i+1][j+1].b_color+const_value);
bitmap->Canvas->Pixels[i][j]=RGB(red,green,blue);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
}
7.亮度和对比度的调整
函数的表达式入如下,RedOffset,GreenOffset,BlueOffset分别表示RGB的亮度分量(单位是象素点值,范围-127~127),RedContrast,GreenContrast,BlueContrast分别表示RGB的对比度分量(单位是相对于以前的对比度比例),大家注意到没有,在代码中,参加变换的rgb数组,但是直接显示的是tempred, tempgreen, tempblue的象素值bitmap->Canvas->Pixels[i][j]=RGB(tempred,tempgreen,tempblue);这是因为要保持亮度和对比度调整的可逆性,超出0~255范围的象素点的图象变换将不能还原了,所以在定义象素点数据结构的时候用的short类型,尽量可以保存原始的变换数据。
void TMainForm::BrightnessAndContrast(int RedOffset=0,int GreenOffset=0,int BlueOffset=0,
float RedContrast=1,float GreenContrast=1,float BlueContrast=1)
{
int MidR = RedOffset - 127 * (RedContrast - 1); //计算新的位移量B
int MidG = GreenOffset - 127 * (GreenContrast - 1); //计算新的位移量B
int MidB = BlueOffset - 127 * (BlueContrast - 1); //计算新的位移量B
int Max = 255;
int tempred,tempgreen,tempblue;
for(int i=0;i< pic_dis_width-1;i++)
{
for(int j=0;j< pic_dis_height-1;j++)
{
//color=Image1->Canvas->Pixels[i][j] ; //Pixels[i][j]->
rgb[i][j].r_color=rgb[i][j].r_color * RedContrast + MidR; //计算Y = X * A + B
rgb[i][j].g_color=rgb[i][j].g_color * GreenContrast + MidG;
rgb[i][j].b_color=rgb[i][j].b_color * BlueContrast + MidB;
tempred=rgb[i][j].r_color;
tempgreen=rgb[i][j].g_color;
tempblue=rgb[i][j].b_color;
if (tempred > Max) tempred = Max; //输出值判断是否在0到255之间
if (tempred < 0) tempred = 0;
if (tempgreen > Max) tempgreen = Max; //输出值判断是否在0到255之间
if (tempgreen < 0) tempgreen = 0;
if (tempblue > Max) tempblue = Max; //输出值判断是否在0到255之间
if (tempblue < 0) tempblue = 0;
bitmap->Canvas->Pixels[i][j]=RGB(tempred,tempgreen,tempblue);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
}
8.图象的放大和缩小
Timage控件有这样一个属性AutoSize,当设置为true时,当Timage将以原始大小载入图片,属性Stretch=true表示将根据Image的大小对所显示的图象进行拉伸。实现的过程可以是这样的:首先载入图片,把AutoSize属性设置为true,取得图象真实的长度和宽度,然后根据放大缩小的比例来改变Image控件的长度和宽度,再把Image的Stretch属性设置为true,这样就实现了根据显示比例缩放图象的功能了,下面列出的是显示比例改变图片的大小的代码。
以下两句:
Image1->Top= (ScrollBox1->Height- Image1->Height)/2;
Image1->Left= (ScrollBox1->Width- Image1->Width)/2;
将放大缩小以后的Image控件的位置重定位。
void TMainForm::ChangePicture_ByRatio(float ratio) //根据显示比例改变图片的大小
{
Image1->AutoSize=true;
int pic_width=Image1->Width; //计算图片的大小
int pic_height=Image1->Height;
Image1->AutoSize=false;
Image1->Width=ratio*pic_width;
Image1->Height=ratio*pic_height;
Image1->Top= (ScrollBox1->Height- Image1->Height)/2;
Image1->Left= (ScrollBox1->Width- Image1->Width)/2;
Image1->Stretch=true;
}
9.图象的左右镜像
使图象的变成象镜子里看到的一样,实现起来比较简单,只要使图象的左右相对应的象素点的值进行交换就可以了。
void __fastcall TMainForm::Button6Click(TObject *Sender) //图象的左右镜像
{
TCursor oldCursor=MainForm->Cursor;
MainForm->Cursor=crHourGlass;
rgb_str temp_rgb;
for(int i=0;i< (pic_dis_width-1)/2;i++)
{
for(int j=0;j< pic_dis_height-1;j++)
{
temp_rgb= rgb[i][j];
rgb[i][j]=rgb[pic_dis_width-2-i][j];
rgb[pic_dis_width-2-i][j]=temp_rgb;
bitmap->Canvas->Pixels[i][j]=RGB(rgb[i][j].r_color,rgb[i][j].g_color,rgb[i][j].b_color);
bitmap->Canvas->Pixels[pic_dis_width-2-i][j]=RGB(rgb[pic_dis_width-2-i][j].r_color,rgb[pic_dis_width-2-i][j].g_color,rgb[pic_dis_width-2-i][j].b_color);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
MainForm->Cursor=oldCursor;
}
10.图象的上下翻转
实现的方式和左右镜像差不多。
void __fastcall TMainForm::Button7Click(TObject *Sender) //图象的上下翻转
{
TCursor oldCursor=MainForm->Cursor;
MainForm->Cursor=crHourGlass;
rgb_str temp_rgb;
for(int i=0;i< pic_dis_width-1;i++)
{
for(int j=0;j< (pic_dis_height-1)/2;j++)
{
temp_rgb= rgb[i][j];
rgb[i][j]=rgb[i][pic_dis_height-2-j];
rgb[i][pic_dis_height-2-j]=temp_rgb;
bitmap->Canvas->Pixels[i][j]=RGB(rgb[i][j].r_color,rgb[i][j].g_color,rgb[i][j].b_color);
bitmap->Canvas->Pixels[i][pic_dis_height-2-j]=RGB(rgb[i][pic_dis_height-2-j].r_color,rgb[i][pic_dis_height-2-j].g_color,rgb[i][pic_dis_height-2-j].b_color);
}
}
Image1->Picture->Bitmap->Assign(bitmap);
MainForm->Cursor=oldCursor;
}