CxImage图像处理类库
转自:http://blog.csdn.net/byxdaz/archive/2009/04/10/4061324.aspx
CxImage是一个可以用于MFC 的C++图像处理类库类,它可以打开,保存,显示,转换各种常见格式的图像文件,比如BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K 等格式的文件。可以实现BMP<->JPG,PNG <>TIFF格式等等的互相转换。
CxImage不仅可以实现图像文件的类型转换,还可以实现在内存图像数据的类型转换,并且使用很方便。除了文件格式的相互转换,它还提供了很多很多图像后处理的功能,比如图像模糊,锐化等等,功能非常强大和实用。
CxImage中的x,大约代表了丰富的图像格式支持和丰富的图像处理功能,可以说CxImage是图像处理的十全大补汤。
用CxImage实现的图像处理程序
开发环境:
VC6, C++, Windows, MFC, Visual Studio, VS6, Dev
简介和许可
CxImaage是一个可以简便而快速地打开,保存,显示和转换图像文件的C++类库。CxImage类库是免费的。对于TIFF,JPEG,PNG和ZLIB,"如果你在你的产品中使用了这些源代码,虽然致谢不是必须的,但是却会得到众人的欣赏。"
CxImage是开源的并在zlib许可下发布。简单地说,你可以随意地使用这些代码,只要你不说它是你自己的就行了。
文件格式和链接的库
CxImage支持如下这些库的最新版本:
Zlib (1.2.3), Jasper ( 1.900.1), LibMNG (1.0.10), LibPNG (1.2.24). LibTIFF 3.8.2
j2k库(现在被称为openjpeg)和相关的类CxImageJ2K已经从项目中删除。JPEG2000格式的文件由Jasper和CximageJAS来支持。
Cximage 6.00提供了一个新的类CximageRAW和新的库LibDCR,用于读取来自数码相机的RAW图像。常见的文件扩展名有:RAW, CRW, NEF, CR2, DNG, ORF, ARW, ERF, 3FR, DCR, X3F, MEF, RAF, MRW, PEF, SR2。
CximageRAW提供了对图像的基本解码功能,它唯一的可选参数可以由SetCodecOption进行设置,以对插值质量进行可控制。可选的选项有(DECODE_QUALITY_LIN=0, DECODE_QUALITY_VNG=1, DECODE_QUALITY_PPG=2, DECODE_QUALITY_AHD=3).
CximagePNG:现在可以读取所有PNG_COLOR_TYPE_类型。但是,每个通道含有超过8位像素深度的PNG文件,会被转换到8位,这是CxImage的一个主要限制。
CxImageGIF:现在能够更好地支持对动态GIF图像的读取,通过SetRetreiveAllFrames设置属性,可以同时对图像中的所有帧进行解码。在CxImage的示例项目中,展示了如何实现这一选项,并展示了如何播放一副GIF动画。
CxImageBMP: 支持对32位图像的读写(支持Alpha通道)
CxImageICO: 支持对Vista PNG图标的读写;添加对多页图标的支持。
CxImageMNG: 支持对MNG Alpha图层的读取。
CxImageSKA: 新的用于支持SKA图像格式的类,这种图像通常用在视频租赁软件中。
CxImageJPG: 为JPEG图像格式的二次采样提供了 新的选项。ENCODE_SUBSAMPLE_422,ENCODE_SUBSAMPLE_444),默认情况下是 高采样率的4:1:1 。当然,也可以被设置成中等的4:2:2或者低等的4:4:4。
下图展示了不同采样率下,在压缩图像中所产生的不同数量的伪影。在压缩有着明显轮廓的图像的时候,采用4:4:4的采样率有助于减少轮廓的伪影。
可移植性
所有的类和项目都通过了不同编译器的测试,包括从VC++6 到VC++2008的微软系列编译器,Borland C++ Builder 3和6,同时部分地支持wxDev-C++和MinGW。
所有的库都支持UNICODE 和非UNICODE两个版本。(感谢Eric Jesover)
对于第一次使用的用户,你可以使用一个轻量级的版本(cximage600_lite)。这个版本去除了C库,但是添加了一个简单的示例项目。
所有控制台示例(/demo2)和CxImageCrtDll项目可以在VC++Express2005和 Microsoft Platform SDK环境下编译通过。如果你在编译链接的时候,遇到像"unresolved external..."(无法找到外部符号…)这样的错误,请检查是否所有C库都被编译了。或者手动地添加gdi32.lib 和user32.lib为项目的依赖库。
同时,CxImage也可以在Pocket PC 2003上工作。在CxImage中,为VC++ 2005编译器提供了一个可以工作的版本和相应的实例(cximage600_ce)。对于旧式的嵌入式VC编译器,最主要的限制是无法支持对异常的处理。为了解决这个问题,相应的异常处理语句try,throw和catch已经被定义在ximadef.h中的三个宏取代,同时还定义了CXIMAGE_SUPPORT_EXCEPTION_HANDLING。通过这样的方法,取消对异常处理的支持,可以成功编译链接整个库。虽然这个解决办法不是那么优雅,但是当异常处理被取消的时候,对代码的影响是最小的。同时,当异常处理被启用的时候,同样不会造成源代码的修改与变动。
对于平台之间little-endian和big-endian的兼容性,对于内建支持的图像文件格式(bmp, ico, tga, pcx, gif, ska),由ntohs和ntohl控制。
示例
大多数新的特性可以在CxImage的主要示例程序中尝试和体验。这个示例程序只是一个测试平台,虽然它提供很多有用的特性,但是它实在不是一个严谨的应用程序。
·CQuantizer : 这个类被DecreaseBpp菜单项所使用。在以前的版本中,这里有一个取整的错误,在某些情况下,白色(255,255,255)会被转换成(254,254,254)。在新的版本中,这个问题已经被修复了。
·Copy/Paste : 现在,新的粘贴功能支持元文件图像(例如,从Office应用程序中复制而来的图像)。这个示例内部使用了自定义的剪切板格式以测试Dump/Undump方法。Copy只工作在当前选区,但是你可以通过CxImage/Remove Selection 复制整幅图像。
·FloodFill : (/View/Tools/Flood Fill) 通过一个浮动的对话框,你可以测试色彩填充的颜色,偏差,透明度和是否选择。当透明度为0并且选择区域功能启用的时候,这个功能就变现为"魔法棒",用于根据颜色选区某个区域。
·Graph data extraction : (/Filters/graph data extraction) 这个示例演示了如何从图像(从扫描仪获取或者从互联网下载所得)中提取数字信息。转换后的数据被粘贴到剪切板,同时可以被保存成文本文件或者Excel表格文件。
数据提取对话框
数据提取结果
·RedEyeRemove : (/Filters/Non Linear/Remove Red Eye) 去除红眼的功能在照片处理中经常用到。你 必须在红眼周围选择一个区域,然后去除红眼的功能就会对红色通道进行过滤,从而去掉照片中的红眼。红眼的选区是一个矩形区域,同时可以包括部分的虹膜(眼黑),
过滤器会在以选区中点为中心的圆心区域工作,不会影响到选中的眼黑部分。
·SelectiveBlur / UnsharpMask : 这些非线性的滤镜可以增加图像的质量。SelectiveBlur可以去除二次噪声(比如JPEG图像中的伪影或者是数码相机的噪声),从而展示图像中的更多细节。而UnsharpMask可以增强图像的细节,但是却不会添加噪声。
·Custom linear filters : (/Filters/Linear/Custom) 一个用于测试新的滤镜功能核心的图像用户界面。
·Histogram : (/Colors/Histogram/...) 为了测试HistogramStretch(直方图),这个示例中提供了很多菜单项,通过不同的方法(0 = luminance, 1 = linked channels , 2 = independent channels)来测试直方图功能。对于有噪声的图像,阈值(threshold)这个参数增强了算法的健壮性。半饱和度(Half Saturation)和全饱和度(Full Saturation)可以测试转换颜色空间(ConvertColorSpace),直方图(Histogram)和饱和度(Saturate)在YUV颜色空间对直方图的拉伸效果。
·Thresholding : ( /Colors/Threshold... and /Colors/Adaptive Threshold). 透明度阈值(OptimalThreshold)是一个新的用于查找二进制图像透明度阈值的新方法。可选的算法有:
1 = 最大类间方差 (Otsu);
2 = 基特勒和伊尔林格沃斯(Kittler & Illingworth);
3 = 最大熵(maximum entropy);
4 = 位差(potential difference);
0 = 平均所有方法 (默认情况下,这也是示例程序中所使用的方法);
"保留低于阈值的颜色"(preserve colors less than the threshold)的选项,将测试Threshold2方法。这对于过滤带有噪声背景的彩色图像很有用。经过处理,我们将得到一幅带有一致背景的彩色图像(噪声被去除)。AdaptiveThreshold是对方法OptimalThreshold的一个应用,它将创建很多阈值模板。AdaptiveThreshold对于有着不一致的灯光照射效果的图像,非常有用。对于这类图像,我们不能简单地在整幅图像中使用某个单一的阈值。但是,如果我们的参数设置得不对,我们将得到一个非常差劲的处理结果。
·Add shadow : (/Filters/Add Shadow...) 这个菜单项的功能演示了如何将CxImage的多个小功能(选择(selections),高斯模糊( GaussianBlur),混合( Mix))组合使用,以达到常见的图像处理效果。
·Text smoothing : DrawStringEx 实现了一个新的选项CXTEXTINFO::smooth。我们可以通过文本工具(位于/View/Tools/Text),,选中抗锯齿("antialias")选项对这个功能进行测试。
类似的效果也同样可以利用TextBlur (/Filters/Non Linear/Text Blur)进行后处理获得。这是一个非线性的过滤器,它只对角或圆形的边缘起作用,从而不会影响到纵向或横向的线。下图展示了不同平滑方法的实际效果:
CxImage库的结构
在整个库的继承树中,CxImage位于所有其他模块的顶部。这不是一个完全的符合OOP的方式,但是至少从最初的版本一直到现在,它都工作得很好。现在想要改变整个结构,已经太晚了。但是,你总是可以使用这些继承类来操作相应格式的图像,例如你可以使用CxImageTIF来保存多页的TIFF文件。这样显得非常直观。
连接所有模块和C库的是CxFile。这是一个虚类,它提供了标准的方法,用于访问硬盘或者内存的文件数据。
CxImage的继承树
一个CxImage对象基本上对应于一副位图,同时添加了一些额外的成员变量用于存储一些有用的信息。
class CxImage
{
...
protected:
void* pDib; //包含文件头,调色板和像素数据
BITMAPINFOHEADER head; //标准文件头
CXIMAGEINFO info; //扩展信息
BYTE* pSelection; //选区
BYTE* pAlpha; //alpha通道
CxImage** ppLayers; //普通层
CxImage** ppFrames; //动画的帧
}
CxImage::head 是位图文件的文件头,而CxImage::pDib就是一个普通的位图(就像你在CxImageBMP::Encode中看到的一样)。
CxImage::info 是一个方便的信息容器。这些信息被不同的文件格式所共享,同时供所有成员函数访问。
typedef struct tagCxImageInfo {
DWORD dwEffWidth; //双字节对齐宽度
BYTE* pImage; //图像数据
void* pGhost; //如果这是一个备份(ghost),
//则pGhost指向它的原始对象
DWORD dwType; //原始图像格式
char szLastError[256]; //调试信息,最后的错误信息
long nProgress; //进度
long nEscape; //取消
long nBkgndIndex; //GIF, PNG, MNG使用
RGBQUAD nBkgndColor; //RGB透明使用
BYTE nQuality; //JPEG使用
long nFrame; //TIF, GIF, MNG使用,表示当前活动帧
long nNumFrames; //TIF, GIF, MNG使用,表示总帧数
DWORD dwFrameDelay; //GIF, MNG使用,表示帧的延迟
long xDPI; //水平分辨率
long yDPI; //垂直分辨率
RECT rSelectionBox; //对象的外包围框
BYTE nAlphaMax; //最大透明度
bool bAlphaPaletteEnabled; //如果调色板中的alpha值是启用的,
//则这个变量为true
bool bEnabled; //启用绘制函数
long xOffset;
long yOffset;
DWORD dwEncodeOption; //GIF, TIF使用:
// 0=def.1=unc,2=fax3,3=fax4,
// 4=pack,5=jpg
RGBQUAD last_c; //用于优化GetNearestIndex
BYTE last_c_index;
bool last_c_isvalid;
long nNumLayers;
DWORD dwFlags;
} CXIMAGEINFO; CxImage的不同层
CxImage对象同样是图层的集合,每个图层的缓冲区只在需要的时候申请。
CxImage::pDib是背景图像。 CxImage::pAlpha是透明层。CxImage::pSelection是选区层,用于创建要对图像的感兴趣区域进行处理的选择区域。在这三个特殊层之上,你可以添加通用的其他层,这些层都保存在CxImage::ppLayers中。通用层也是完整的CxImage对象,所以你可以创建复杂的嵌套层。CxImage::ppFrames 为动态图像(GIF)所预留。
CxImage类成员和操作
CxImage使用Doxygen 产生文档,但是由于一些历史的原因,很多不太通用的功能还没有文档。类成员的参考资料,发布历史以及许可信息都可以在这里(here )找到。
支持的格式和选项
整个CxImage库非常大,在主要的头文件ximcfg.h中,你可以找到很多编译选项开关,用于启用或者禁用某些特定的图像格式或者功能。每个JPG, PNG和 TIFF库将使得应用程序增加大约100KB的大小,同时,CxImage将使得应用程序增加大约50KB的大小。所以,为了减小你的应用程序的体积,你应该支持和链接你的应用程序确实需要的格式。
格式 | 定义#define | 需要的库 | 尺寸[kB] |
BMP GIF ICO TGA PCX WBMP WMF SKA | CXIMAGE_SUPPORT_BMP CXIMAGE_SUPPORT_GIF CXIMAGE_SUPPORT_ICO CXIMAGE_SUPPORT_TGA CXIMAGE_SUPPORT_PCX CXIMAGE_SUPPORT_WBMP CXIMAGE_SUPPORT_WMF CXIMAGE_SUPPORT_SKA | 内建 | 24 |
JPEG | CXIMAGE_SUPPORT_JPG | jpeg | 88 |
PNG | CXIMAGE_SUPPORT_PNG | png,zlib | 104 |
MNG | CXIMAGE_SUPPORT_MNG | mng,zlib,jpeg | 148 |
TIFF | CXIMAGE_SUPPORT_TIF | tiff,zlib,jpeg | 124 |
JBIG | CXIMAGE_SUPPORT_JBG | jbig | 28 |
PNM,PPM,PGM RAS | CXIMAGE_SUPPORT_PNM CXIMAGE_SUPPORT_RAS | jasper | 176 |
JPEG_2000 | CXIMAGE_SUPPORT_JP2 CXIMAGE_SUPPORT_JPC CXIMAGE_SUPPORT_PGX | jasper | 176 |
RAW | CXIMAGE_SUPPORT_RAW | libdcr | 132 |
选项 | 定义#define | 尺寸[KB] |
CxImage核心 | 所有开关关闭 | 20 |
几何变换 (geometric transformations) | CXIMAGE_SUPPORT_TRANSFORMATION | 16 |
图像处理 (image processing) | CXIMAGE_SUPPORT_DSP | 24 |
绘制和特殊的窗口函数 (drawing and windows specific functions) | CXIMAGE_SUPPORT_WINDOWS | 12 |
透明 (transparency) | CXIMAGE_SUPPORT_ALPHA | 4 |
选择 (selections) | CXIMAGE_SUPPORT_SELECTION | 4 |
多层支持 (multiple layers) | CXIMAGE_SUPPORT_LAYERS | <4 |
图像格式转换 (graphic formats conversion) | CXIMAGE_SUPPORT_DECODE CXIMAGE_SUPPORT_ENCODE | <4 |
插值函数 (interpolation functions) | CXIMAGE_SUPPORT_INTERPOLATION | <4 |
异常处理 (exception handling) | CXIMAGE_SUPPORT_EXCEPTION_HANDLING | <4 |
在你的项目中使用CxImage
如下图所示,CxImgLib.dsw工作空间展示了构建一个包含绝大多数功能和支持大多数图像格式的应用程序(demo.exe)所需要的所有库。你必须先编译所有的库,然后才可以链接你最终的应用程序。
CxImgLib.dsw工作空间
在相同的工作空间中,你可以找到用于构建不同库和应用程序的项目:
·CxImage : cximage.lib - 静态库
·CxImageCrtDll : cximagecrt.dll - DLL,不使用MFC
·CxImageMfcDll : cximage.dll - DLL,使用MFC
·Demo : 示例程序demo.exe,跟cximage.lib和C库链接。
·DemoDll : demodll.exe - 跟cximagecrt.dll链接
·libdcr,jasper,jbig,jpeg,png,tiff,zlib : 静态的C库
构建这些项目需要几分钟时间,当所有项目构建完成后,你可以选择demo项目并执行应用程序。
要想在你自己的项目中使用CxImage,你必须编辑下面这些项目设置设置(针对Visual C++ 6.0):
Project Settings(项目设置)
|- C/C++
| |- Code Generation
| | |- 运行时库 : 多线程DLL(所有链接的库都必须使用相同的设置)
| | |- 结构成员对齐方式 : 所有链接的库都必须相同
| |- 预编译头文件 : 不使用预编译头文件
| |- 预处理器:
| |- 添加额外的包含(Include)路径: ../cximage
|- Link
|- General
|- Object/library modules(附加的依赖库): ../png/Debug/png.lib
../raw/Debug/libdcr.lib
../jpeg/Debug/jpeg.lib
../zlib/Debug/zlib.lib
../tiff/Debug/tiff.lib
../jasper/Debug/jasper.lib
../cximage/Debug/cximage.lib ...
在你的源代码中,你必须引入CxImage的头文件ximage.h。在你的代码中添加如下语句:
#include "ximage.h"。
注意,不要混合debug和release模块,每个配置必须使用各自相应的库文件。
在CxImage中添加自定义的函数
为CxImage添加一个新的图像处理函数并不困难。在这里,我将以CxImage::Jitter为例子,描述如何为CxImage添加自定义的函数。虽然这个函数很简单, 但是它却展示了使用CxImage时所需要注意的方方面面。
首先,我们需要声明这个函数:
bool Jitter(long radius=2) 在ximage.h头文件的CXIMAGE_SUPPORT_DSP部分,你可以在public区域的任何部分声明这个函数。
现在,我们开始定义这个函数:
bool CxImage::Jitter(long radius)
{
// 检查图像是否合法,这应当是这个函数的第一行
if (!pDib) return false;
// 局部变量
long nx,ny;
// 临时图像,用于存储算法的部分结果
CxImage tmp(*this,pSelection!=0,true,true);
// 限制函数仅仅作用在选区(通过Selection...()函数定义)的最小区域
// 这将加快整个循环的速度,提高算法效率
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
// 主循环 : 垂直方向扫描图像
for(long y=ymin; y <ymax; y++){
// 监视循环的进度
info.nProgress = (long)(100*y/head.biHeight);
// 检查应用程序是否已经退出
if (info.nEscape) break;
// 主循环 : 水平方向扫描图像
for(long x=xmin; x<xmax; x++){
// 如果选区功能启用了,则仅仅处理选区内部的像素
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
// 主算法
nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
if (!IsInside(nx,ny)) {
nx=x;
ny=y;
}
// 保存结果到临时图像中.
// 如果可以,24位图像请使用PixelColor,
// 而8,4和1位图像请使用PixelIndex,这样可以加快速度。
if (head.biClrUsed==0){
tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));
} else {
tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));
}
// 如果启用了透明度功能,则处理透明图层中的像素
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaSet(x,y,AlphaGet(nx,ny));
#endif //CXIMAGE_SUPPORT_ALPHA
}
}
}
// 保存结果并退出
Transfer(tmp);
return true;
}示例: 如何转换一种格式到另外一种格式
CxImage image;
// bmp -> jpg
image.Load("image.bmp", CXIMAGE_FORMAT_BMP);
if (image.IsValid()){
if(!image.IsGrayScale()) image.IncreaseBpp(24);
image.SetJpegQuality(80);
image.Save("image.jpg",CXIMAGE_FORMAT_JPG);
}
// png -> tif
image.Load("image.png", CXIMAGE_FORMAT_PNG);
if (image.IsValid()){
image.Save("image.tif",CXIMAGE_FORMAT_TIF);
} 如何从资源中加载图像
//Load the resource IDR_PNG1 from the PNG resource type
CxImage* newImage = new CxImage();
newImage->LoadResource(FindResource(NULL,MAKEINTRESOURCE(IDR_PNG1),
"PNG"),CXIMAGE_FORMAT_PNG);
或者
//Load the resource IDR_JPG1 from DLL
CxImage* newImage = new CxImage();
HINSTANCE hdll=LoadLibrary("imagelib.dll");
if (hdll){
HRSRC hres=FindResource(hdll,MAKEINTRESOURCE(IDR_JPG1),"JPG");
newImage->LoadResource(hres,CXIMAGE_FORMAT_JPG,hdll);
FreeLibrary(hdll);
}
或者
//Load a bitmap resource;
HBITMAP bitmap = ::LoadBitmap(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1)));
CxImage *newImage = new CxImage();
newImage->CreateFromHBITMAP(bitmap); 如何解码内存中的图像
CxImage image((BYTE*)buffer,size,image_type);
或者
CxMemFile memfile((BYTE*)buffer,size);
CxImage image(&memfile,image_type);
或者
CxMemFile memfile((BYTE*)buffer,size);
CxImage* image = new CxImage();
image->Decode(&memfile,type); 如何对内存中的图像编码
long size=0;
BYTE* buffer=0;
image.Encode(buffer,size,image_type);
...
image.FreeMemory(buffer);
或者
CxMemFile memfile;
memfile.Open();
image.Encode(&memfile,image_type);
BYTE* buffer = memfile.GetBuffer();
long size = memfile.Size();
...
image.FreeMemory(buffer); 如何创建一副多页的TIFF
CxImage *pimage[3];
pimage[0]=&image1;
pimage[1]=&image2;
pimage[2]=&image3;
FILE* hFile;
hFile = fopen("multipage.tif","w+b");
CxImageTIF multiimage;
multiimage.Encode(hFile,pimage,3);
fclose(hFile);
或者
FILE* hFile;
hFile = fopen("c://multi.tif","w+b");
CxImageTIF image;
image.Load("c://1.tif",CXIMAGE_FORMAT_TIF);
image.Encode(hFile,true);
image.Load("c://2.bmp",CXIMAGE_FORMAT_BMP);
image.Encode(hFile,true);
image.Load("c://3.png",CXIMAGE_FORMAT_PNG);
image.Encode(hFile);
fclose(hFile); 如何复制和粘贴图像
//复制(copy)
HANDLE hDIB = image->CopyToHandle();
if (::OpenClipboard(AfxGetApp()->m_pMainWnd->GetSafeHwnd())) {
if(::EmptyClipboard()) {
if (::SetClipboardData(CF_DIB,hDIB) == NULL ) {
AfxMessageBox( "Unable to set Clipboard data" );
} } }
CloseClipboard();
//粘贴(paste)
HANDLE hBitmap=NULL;
CxImage *newima = new CxImage();
if (OpenClipboard()) hBitmap=GetClipboardData(CF_DIB);
if (hBitmap) newima->CreateFromHANDLE(hBitmap);
CloseClipboard(); 如何在图片框控件(Picture Box)中显示图像
HBITMAP m_bitmap = NULL;
CxImage image("myfile.png", CXIMAGE_FORMAT_PNG);
...
CDC* hdc = m_picture.GetDC();
HBITMAP m_bitmap = image.MakeBitmap(hdc->m_hDC);
HBITMAP hOldBmp = m_picture.SetBitmap(m_bitmap);
if (hOldBmp) DeleteObject(hOldBmp);
if (hdc->m_hDC) m_picture.ReleaseDC(hdc);
...
if (m_bitmap) DeleteObject(m_bitmap); 译后序:
关于图像处理库,我相信大家有一个共同的疑问:这么多图像处理库,我该如何选择?在CSDN的blog中有这样一段文字,比较透彻地回答了这个问题,感谢作者的透彻解释:
"CxImage类库是一 个优秀的图像操作类库。它可以快捷地存取、显示、转换各种图像。有的读者可能说,有那么多优秀的图形库,如OpenIL,FreeImage, PaintLib等等,它们可谓是功能强大,齐全,没必要用其它的类库。但我要说,这些类库基本上没有免费的,使用这些类库,你要被这样那样的许可协议所 束缚。
在这点上,CxImage类库是完全免费的。另外,在使用上述类库时,你会遇到重重麻烦。因为它们大部分是平台无关的,且用C语言写成,有的还夹杂 着基本的C++ wrapper和成堆德编译选项的声明需要你去处理。而CxImage类库在这方面做得很好。还有让我最看好的,就是作者完全公开了源代码。相对于那些封 装好的图形库和GDI+来说,这一点使我们可以进一步学习各种编解码技术,而不再浮于各种技术的表面。"
相关文章:

设计模式学习2 工厂模式
工厂模式其实就是简单模式的升级版本, 简单模式将界面与业务逻辑区分开,但是如果不停的增加计算器的运算方式,简单模式中的工厂Factory 中判断的业务逻辑会变非常复杂,这不符合封装的原则。 所以在此之上将Factory抽象了出来&…

输入字符串,包含数字,大小写字母,编程输出出现做多的数字的和
题目描述: 输入字符串,包含数字,大小写字母,编程输出出现做多的数字的和。 思路: 1.创建输入对象2.输入字符串3.利用正则将字母分离出,剩余的每一个字符串即为待统计的每一个数字,存入字符串数组…

优化思路千万种,基于下界函数的最优化效率如何?
作者丨stephenDC来源 | 大数据与人工智能(ID:ai-big-data)导读:生活中我们处处面临最优化的问题,比如,怎么样一个月减掉的体重最高?怎么样学习效率最高?怎么样可以最大化实现个人价值࿱…

Quintum 语音网关设置方法
Quintum 网关基本配置 Quintum 网关基本配置 登陆方式:方法一:串口登陆(1).用配套的串口线连接网关的CONSOLE口和电脑的串口。 (2).开启电脑的的超级终端,路径如下&#…

Activex test contact failed to create control 未指定的错误 控件无法加载的原因
转自:http://blog.csdn.net/phker/archive/2009/12/25/5073402.aspx 本文指的是vc项目的activex 出现这个问题, 我总结了总共有以下几点,可能还有其他原因: 1.中文问题:如果你的项目类型是多字节的,而不是unicode编码的,你可能要注意这个问题了,我就发生了这个问题…

人工智能技术在内容行业的应用:AI对中长尾内容平台还是奢侈品
整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)导读:随着人工智能技术的发展,媒体行业本身在不断地发生变化,从传统媒体到新媒体,改变的不仅是信息载体,更是一种新的逻辑,无论是内容…

QQ爬虫-爬取QQ空间
背景:在一篇个人博客看到了相关的爬虫的知识,个人比较有兴趣,就花了点时间研究了一下,主要通过好友空间的互动(相互访问量,点赞,评论,以及其他互动),以及好友之间聊天的活跃度&#…

perl编程手册
2019独角兽企业重金招聘Python工程师标准>>> perl编程手册: -------------------------------手册-------------------------------- perl手册.chm http://vdisk.weibo.com/s/moN-p -------------------------------视频-------------------------------- 俺的…

VC使用ActiveX控件常见问题
转自:http://lingchuangsong.blog.163.com/blog/static/126932322008631104133309/ 一方面,它表示将你联系到Microsoft、Internet和业界的新技术的小型快速的可重用组件。它与开发语言无关,任何支持 ActiveX控件的软件开发平台(如…

你绝没用过的一款高级空间可视化工具
作者 | Shan He转载自高级农民工(ID: Mocun6)说起 Python 中的可视化,我们一般用的最多的是 Matplotlib,绘制一般的图效果都很好。有时候也会用风格比较好看的 Pyecharts 库,尤其是在展示空间地图上的数据时。不过它的…

揭秘vue——vue-cli3全面配置
★ vue-cli3 全面配置 ★ Nuxt.js 全面配置 创建项目 配置环境变量 通过在package.json里的scripts配置项中添加--mode xxx来选择不同环境 在项目根目录中新建.env, .env.production, .env.analyz等文件 只有以 VUE_APP_ 开头的变量会被 webpack.DefinePlugin 静态嵌入到客户端…

周礼栋:现在是计算机系统和网络研究“最好的时代”
编者按:随时随地使用各种系统和工具,对现代人来说早已是司空见惯的事,但这一切完美工作的技术和服务并不是凭空出现的。正是因为微软亚洲研究院副院长周礼栋博士和他带领的团队这样从事系统和网络研究工作的研发人员在幕后不断的努力和创新&a…

ChaLearn Gesture Challenge_2:examples体验
前言: 在上一篇博文ChaLearn Gesture Challenge_1:CGD数据库简单介绍中已经简单介绍过CGD2011数据库,了解到该数据库可以作为公开的数据库来测试在深度信息和RGB信息上的手势识别。当然了,也可以通过参加这个挑战赛来对比自己的手…

vs2008 外部调用ActiveX控件接口方法
转自:http://topic.csdn.net/u/20090605/16/018e26e9-06e2-4e0d-8099-bc8eb326afde.html sndaxdrs: 初学activeX ,我写的一个 activeX控件测试程序。 分别调用两个 自定义方法, 分别出现 “找不到成员”,和“非选择性的参数”的提…

设计模式之禅笔记
2019独角兽企业重金招聘Python工程师标准>>> 1.设计原则 1)单一职责原则 There should never be more than one reason for a class to change (就一个类而言,应该只有一个引起它变化的原因) 用于控制类的粒度大小,防止类过于复杂…

vs2008部署问题
转自:http://tangxingqt.blog.163.com/blog/static/2771087220098214755269/ 参考资料 1、VS2005解决"应用程序配置不正确,程序无法启动"问题 2、VS2005安装文件 "由于应用程序配置不正确,应用程序未能启动" 3、Micro…

expdp数据泵导出操作
数据泵需要在本地执行,不可以远程登录操作。 数据泵需要建立目录directory --sys下 create directory su as d:\xs 目录的数据字典是dba_directories SYSncbeta>select owner,directory_name,directory_path from dba_directories; 要求导出scott用户下的emp表…
slf4j 日志监控
问题描述 监控系统 新系统起步,旨在监控原有系统的各种问题。主要的一部分,就是监视原有系统的日志。 日志,是Java企业级应用开发必不可少的一部分,市场上有诸多日志框架。我们选用slf4j。 日志有以下级别: TRACE, DEB…

阿里90后科学家研发,达摩院开源新一代AI算法模型
整理 | 一一出品 | AI科技大本营(ID:rgznai100)AI科技大本营7月5日消息,阿里达摩院宣布开源新一代人机对话模型ESIM。该算法模型提出两年多,已被200多篇论文引用,更曾在国际顶级对话系统评测大赛(DSTC7&…

在vs2008中配置OpenCV2.2
1、下载OpenCV2.2:http://www.opencv.org.cn/index.php/Download 2、下载后解压缩OpenCV-2.2.0-win.zip; 3、下载CMake:http://www.cmake.org/cmake/resources/software.html 4、安装CMake; 5、运行cmake-gui,在wh…

开发者,什么是你真正关心的问题?| AI ProCon 2019
2018 年,上千名开发者与上百名技术专家齐聚一堂,在 CSDN 2018 AI开发者大会上以“AI技术与应用”为核心,深度聚焦人工智能的技术创新与行业应用,真正做到了“只讲技术,拒绝空谈”。今年,在产业智能化的浪潮…

C语言程序的结构
1.一个程序由一个或多个源程序文件组成。 a.预处理指令 b.全局声明 c.函数定义 2.函数是C程序的主要组成部分。 3.一个函数包括两个部分。 a.函数首部 int 函数类型 max 函数名 (int 函数参数类型 x, 函数参数名 int 函数参数类型 y…
flask 核心 之 应用上下文 及 请求上下文
Werkzeugs 是 Flask 的底层WSGI库。什么是WSGI? 一段简单的app: def dispath_request(self, request):return Response(Hello World!)def wsgi_app(self, environ, start_response):request Request(environ)response self.dispath_request(request)re…

vs2008中常见错误解决方法汇总
1、error C2859 vc90.idb is not the idb file that was used when this precompiled header was created。 解决方法:选中工程-->点击右键属性-->Configuration Properties-->C/C-->Output Files-->Program Database File Name中的$(IntDir)/vc90.p…

加速AI应用落地,英特尔AI 2.0的进阶之道
人工智能模型的复杂度不断增加,对内存的需求也越来越大。深度学习的进一步发展需要解决内存限制问题,而当前的解决方案无法利用所有可用计算,业内人士逐渐意识到需要专用芯片来支持深度学习训练和推理。英特尔则在人工智能方面提供优越的硬件…

MySQL基础之 恢复数据和数据库迁移
1、mysql命令或者source命令恢复数据 这两个命令在进行恢复数据的时候要检查是否创建数据库。如果数据库不存在,则恢复失败。 数据库迁移 1、相同版本的mysql数据库之间的迁移。 mysqldump -h host1 -uroot -ppwd --all-databases | mysql -h host2 -uroot -ppw…

.Net 文件流 System.IO之Stream
转自 :http://www.cnblogs.com/yukaizhao/archive/2011/07/28/stream.html Stream在msdn的定义:提供字节序列的一般性视图(provides a generic view of a sequence of bytes)。这个解释太抽象了,不容易理解;…

Hinton等人最新研究:大幅提升模型准确率,标签平滑技术到底怎么用?
作者 | Rafael Mller , Simon Kornblith, Geoffrey Hinton译者 | Rachel责编 | Jane出品 | AI科技大本营(ID: rgznai100)【导读】损失函数对神经网络的训练有显著影响,也有很多学者人一直在探讨并寻找可以和损失函数一样使模型效果更好的函数…

WaitForSingleObject和WaitForMultipleObjects用法
转自:http://www.360doc.com/content/10/0512/09/1072296_27178529.shtml 等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止。这些等待函数中最常用的是WaitForSingleObject: DWORD WaitForSingleObject(HANDLE hObject, DW…

【面试必问】支撑百万并发的IO多路复用技术你了解吗?
多路复用其实并不是什么新技术,它的作用是在一个通讯连接的基础上可以同时进行多个请求响应处理。对于网络通讯来其实不存在这一说法,因为网络层面只负责数据传输;由于上层应用协议的制订问题,导致了很多传统服务并不能支持多路复…