你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 图形图象处理与游戏编程
5.4 FreeImage的图像处理软件
 

一、引言

图像处理与分析软件都涉及到图像文件的读写与绘制,以及位图信息的获取与设置等基本操作,需要编写相应的函数来实现这些功能。然而,图像文件类型的多样性以及文件格式的复杂性,导致图像读写函数的实现费时费力,且易出错。事实上,没有必要去重复这些基础工作。相反,可以借助于现有的图像处理库,如FreeImageImageLoadCImageImageJIPL等来实现这些基本功能,简化图像处理与分析软件的开发工作,从而把更多的精力放在更高级、面向具体问题的图像处理与分析算法的设计上,以提高开发效率。本文将以单文档应用程序为例,简要介绍利用Visual C++ 6.0下开发基于FreeImage的图像处理软件的基本方法。

二、FreeImage简介

FreeImage是一款免费的、开源的、跨平台(WindowsLinuxMac OS X)的,支持20多种图像类型的(如BMPJPEGGIFPNGTIFF等)图像处理库。其最大优点就是采用插件驱动型架构,具有快速、灵活、简单易用的特点,得到了广泛使用。相关的源码、库文件及帮助文档可以从http://freeimage.sourceforge.net/免费下载使用。

FreeImage的主要功能有多格式位图的读写;方便的位图信息获取;位深度转换;位图页面访问;基本的几何变换和点处理;通道合并与混合等。FreeImage暂时不支持矢量图形和高级图像处理,位图绘制需要由用户来完成。

FreeImage中的所有函数都以FreeImage_开头,如图像文件的读写函数分别为FreeImage_LoadFreeImage_SaveFIBITMAP数据结构保存着位图信息和像素数据,是FreeImage的核心。

三、初始化FreeImage

FreeImage主要包含头文件FreeImage.h、静态链接库FreeImage.libFreeImaged.lib,动态链接库FreeImage.dllFreeImaged.dll。其中,以d结尾的库文件用于调试版,其余用于发行版。为了在VC中使用FreeImage,需要将上述文件复制到相应目录下。将FreeImage.h复制到VC98\Include\中,FreeImaged.libFreeImage.lib复制到VC98\Lib\中,FreeImaged.dllFreeImage.dll复制到system32目录下。

建立一个单文档应用程序DIP,在工程的stdafx.h文件中包含FreeImage.h,并在工程设置对话框的Link标签中分别为调试版和发行版添加FreeImaged.libFreeImage.lib。也可以在stdafx.h中自动链接FreeImage库,代码如下:

#ifdef _DEBUG

#pragma comment(lib, "FreeImaged.lib")

#else

#pragma comment(lib, "FreeImage.lib")

#endif

默认情况下,FreeImage被当作动态链接库。若需用作静态链接库,则在应用程序类的InitInstance中调用FreeImage_Initialise(0)加载FreeImage库,重载ExitInstance并在其中调用FreeImage_DeInitialise()释放FreeImage库。

四、读取图像

FreeImage是插件驱动的,每种位图的读写函数实际上就是一个插件模块。采用插件驱动型构架便于功能扩展,通过创建或引入新的插件,可以支持新的图像类型。

为便于维护打开的位图,在文档类添加FIBITMAP型指针m_pFI,用以指向打开的位图。在构造函数中将其置为空,在析构函数中调用FreeDIB将其释放。FreeDIB定义如下:

void CDIPDoc:: FreeDIB ()

{

if(m_pFI) {

    FreeImage_Unload(m_pFI);//释放位图

    m_pFI = NULL;

}

}

OnNewDocument()OnFileOpen()函数中也应调用FreeDIB,以确保建立或打开新图像时先释放以前的位图。

读取图像的基本步骤如下:

调用库函数FreeImage_GetFileType由文件头分析文件类型,若不能识别,则调用库函数FreeImage_GetFIFFromFilename从文件扩展名判断文件类型。

若是支持的图像文件类型,则调用库函数FreeImage_FIFSupportsReading判断是否支持该位图类型的读操作,若支持则调用库函数FreeImage_Load加载位图。

在文档类中添加成员函数LoadDIB,实现位图读入功能,代码如下:

FIBITMAP* CDIPDoc::LoadDIB(LPCTSTR lpszPathName, int flag){

FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;

fif = FreeImage_GetFileType(lpszPathName);

if(fif == FIF_UNKNOWN) fif =

FreeImage_GetFIFFromFilename(lpszPathName);

if((fif != FIF_UNKNOWN) &&

FreeImage_FIFSupportsReading(fif)) {

FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, flag);

return dib;

}

return NULL;

}

若想在打开文件对话框中显示FreeImage所支持的图像文件类型,则可以在文档类中添加GetFilterString函数,用以创建FreeImage支持的图像类型过滤字符串。其基本过程为:调用FreeImage_GetFIFCount函数获取FreeImage库所支持的图像文件类型数;针对每种图像类型,调用FreeImage_GetFIFExtensionList获取其扩展名列表,调用FreeImage_GetFIFDescription函数获取其类型描述字符串;将各种图像类型信息依次连接成“BMP Files (bmp)|*.bmp|JPEG Files (jpg,jif,jpeg,jpe)|*.jpg;*.jif;*.jpeg;*.jpe||”形式的字符串,就形成了图像文件类型过滤字符串。

int CDIPDoc::GetFilterString(char *szFilter)

{

int i, iCount;

char Filter[1024], *token;

Filter[0] = '\0'; szFilter[0] = '\0';//空字符

for(i=0; i<FreeImage_GetFIFCount();i++){

strcat(Filter,FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i));

strcat(Filter, ",");

}

Filter[strlen(Filter)-1] = '\0';

strcat(szFilter, "All image files|");

token = strtok(Filter, ",");

while(token != NULL) {

strcat(szFilter, "*."); strcat(szFilter, token);

strcat(szFilter, ";");token = strtok(NULL, ",");

}

szFilter[strlen(szFilter)-1] = '|';

Filter[0] = '\0'; iCount = 0;

for(i=0;i<FreeImage_GetFIFCount();i++){

sprintf(Filter, "%s (%s)|", FreeImage_GetFIFDescription((FREE_IMAGE_FORMAT)i),FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i));

strcat(szFilter, Filter);

strcpy(Filter,FreeImage_GetFIFExtensionList((FREE_IMAGE_FORMAT)i));

token = strtok(Filter, ",");

while(token != NULL) {

strcat(szFilter, "*.");strcat(szFilter, token);

strcat(szFilter, ";");token=strtok(NULL, ",");

}

szFilter[strlen(szFilter)-1] = '|';  iCount++;

}

strcat(szFilter, "All Files (*.*)|*.*|");

strcat(szFilter, "|");

return iCount;

}

    在文档类中重载OnFileOpen,调用GetFilterString创建文件类型过滤字符串,调用LoadDIB加载位图。

void CDIPDoc::OnFileOpen()

{

FIBITMAP* pFI = NULL;

char szFilter[2048];

GetFilterString(szFilter);

CFileDialog dlg(TRUE,NULL,NULL,

OFN_HIDEREADONLY, szFilter);

if(dlg.DoModal() == IDOK){

CString strPath = dlg.GetPathName();

pFI = LoadDIB(strPath, 0);

if(pFI){

    FreeDIB();//释放以前的位图

    m_pFI = pFI;//指向新位图

UpdateAllViews (NULL);

}

}

}

五、绘制图像

在视图类的OnDraw函数中绘制图像。当前源图像与客户区尺寸相同时,调用SetDIBitsToDevice绘制,这样可以加快绘制速度,否则调用StretchDIBits按比例缩放位图。

void CDIPView::OnDraw(CDC* pDC)

{

CDIPDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

FIBITMAP *pFI = pDoc->m_pFI;

if(pFI){

BYTE* pBits = FreeImage_GetBits(pFI);

BITMAPINFO* pIf=FreeImage_GetInfo(pFI);

int W = FreeImage_GetWidth(pFI);

int H = FreeImage_GetHeight(pFI);

CRect rectClient;GetClientRect(rectClient);

int dstW = rectClient.Width();

int dstH = rectClient.Height();

::SetStretchBltMode(pDC->GetSafeHdc(),COLORONCOLOR);

if(dstW == W && dstH == H){

::SetDIBitsToDevice(pDC->GetSafeHdc(),0,0, W, H,0,0,0, H,pBits,pIf,DIB_RGB_COLORS);

}

else {//按比例缩放

float fScale=(float)(W*dstH)/(float)(H*dstW);

if(fScale > 1.0f)   

dstH = (int) (dstH / fScale);

else

    dstW = (int) (dstW * fScale);

::StretchDIBits(pDC->GetSafeHdc(),0,0,dstW,dstH,0,0,W,H,pBits,pIf,DIB_RGB_COLORS,SRCCOPY);

}

}

}

六、保存图像

1)调用FreeImage_GetFIFFromFilename函数从文件名判断期望保存的图像类型,如果不支持则返回;否则转(2)。

2)调用FreeImage_GetImageType判断当前位图数据类型,若为标准位图,则测试是否支持该种图像类型的写操作以及位深度转换,否则调用FreeImage_FIFSupportsExportType检查是否能够输出当前位图。若测试成功,则调用FreeImage_Save保存位图。

在文档类中定义成员函数SaveDIB实现上述功能,代码如下:

BOOL CDIPDOC::SaveDIB(FIBITMAP *dib, LPCTSTR *lpszPath, int flag){

FREE_IMAGE_FORMAT fif=FIF_UNKNOWN;

BOOL bSuccess = FALSE;

fif=FreeImage_GetFIFFromFilename(lpszPath);

if(fif != FIF_UNKNOWN ) {

BOOL bCanSave;

FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);

if(image_type == FIT_BITMAP) {

WORD bpp = FreeImage_GetBPP(dib);

bCanSave=(FreeImage_FIFSupportsWriting(fif) &&FreeImage_FIFSupportsExportBPP(fif, bpp));

}

else {

bCanSave=FreeImage_FIFSupportsExportType(fif, image_type);

}

if(bCanSave) bSuccess=

FreeImage_Save(fif,dib,lpszPath,flag);

}

return bSuccess;

}

在文档类中重载OnFileSaveAs,调用GetFilterString创建文件类型过滤字符串,调用SaveDIB按指定格式保存位图,代码如下。

void CDIPDoc::OnFileSaveAs()

{

char szFilter[2048];

int nFileFormats = 0;

nFileFormats = GetFilterString(szFilter);

CFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,szFilter);

if(dlg.DoModal() == IDOK)  {

CString strPathName, strExtList;

int nPos = 0, nFilterIndex;

nFilterIndex = dlg.m_ofn.nFilterIndex;

strPathName = dlg.GetPathName();

if(nFilterIndex > 1 && nFilterIndex <= FreeImage_GetFIFCount()){

strExtList = FreeImage_GetFIFExtensionList(

(FREE_IMAGE_FORMAT)(nFilterIndex-2));

nPos = strExtList.Find(',');

if(nPos == -1)

strPathName += "."+strExtList;

else

strPathName += "."+strExtList.Left(nPos);

}

SaveDIB(m_pFI, strPathName);

} 

}

七、结语

FreeImage是一款简单易用,能够读写多种图像类型,以及图像类型之间的相互转换和位深度转换,其位图信息和位图数据由FIBITMAP数据结构维护,可以在此基础上实现高级的图像处理与分析算法,提高了软件开发效率。

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089