C++ 图像处理库 CxImage 简介 (迁移至OpenCV)

发布于:2025-05-30 ⋅ 阅读:(22) ⋅ 点赞:(0)


CxImage 是一款功能强大的图像处理类库,主要用于 Windows 平台的图像处理任务。它支持多种图像格式的加载、保存、编辑及特效处理,在早期的 Windows 应用开发中较为常见,尤其是在需要处理图像的桌面应用程序中。

源码下载 :https://sourceforge.net/projects/cximage/files/7.02/cximage702_full.7z/download
编译使用:Win32图片库CxImage在vs2022下的编译和使用

核心功能特点

  • 多格式支持:
    • 支持 BMP、JPEG、PNG、GIF、TIFF、ICO、WMF、EMF 等常见图像格式的读写操作。
    • 可处理动画 GIF、多帧图像等特殊格式。
  • 图像处理能力:
    • 基础操作:缩放、旋转、裁剪、翻转、镜像等。
    • 像素级编辑:调整亮度、对比度、饱和度,支持色彩空间转换(如 RGB 与 HSV 互转)。
    • 特效处理:模糊、锐化、边缘检测、浮雕、素描等滤镜效果。
    • 图像变换:透视变换、扭曲变形等几何操作。
  • 实用功能:
    • 图像叠加与混合:支持 alpha 通道处理,实现图像透明叠加。
    • 缩略图生成:可快速生成指定尺寸的缩略图,保持比例或强制缩放。
    • 图像信息获取:读取图像分辨率、色彩深度、文件大小等元数据。
  • Windows平台的特殊支持
    • 可以直接与DC交互。

局限性与替代方案

  • 局限性:
    • 仅支持 Windows 平台,跨平台兼容性差。
    • 开发维护逐渐停滞,对新图像格式(如 WebP、HEIC)支持有限。
    • 相比现代图像处理库,性能和内存管理存在优化空间。
  • 现代替代方案:
    • OpenCV:跨平台、功能全面的计算机视觉库,支持深度学习集成。
    • libpng/libjpeg/tiff:专注于单一格式处理的底层库,稳定性高。
    • Qt Image Processing:Qt 框架内置的图像处理模块,适合 Qt 应用开发。
    • Magick++:ImageMagick 的 C++ 封装,支持丰富的图像特效与批处理。

常用方法

构造函数

CxImage(uint32_t imagetype = 0);
CxImage(uint32_t dwWidth, uint32_t dwHeight, uint32_t wBpp, uint32_t imagetype = 0);
CxImage(const CxImage &src, bool copypixels = true, bool copyselection = true, bool copyalpha = true);

从数组创建图像

bool	CreateFromArray(uint8_t* pArray,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);
bool	CreateFromMatrix(uint8_t** ppMatrix,uint32_t dwWidth,uint32_t dwHeight,uint32_t dwBitsperpixel, uint32_t dwBytesperline, bool bFlipImage);

访问属性


/** \addtogroup Attributes */ //@{
	int32_t		GetSize();
	uint8_t*	GetBits(uint32_t row = 0);
	uint8_t		GetColorType();
	void*		GetDIB() const;
	uint32_t	GetHeight() const;
	uint32_t	GetWidth() const;
	uint16_t	GetBpp() const;
	uint32_t	GetType() const;
	const char*	GetLastError();

	void	GetOffset(int32_t *x,int32_t *y);
	void	SetOffset(int32_t x,int32_t y);

访问像素点

/** \addtogroup Pixel */ //@{
	bool	IsInside(int32_t x, int32_t y);
	bool	IsTransparent(int32_t x,int32_t y);
	bool	GetTransparentMask(CxImage* iDst = 0);
	RGBQUAD GetPixelColor(int32_t x,int32_t y, bool bGetAlpha = true);
	uint8_t	GetPixelIndex(int32_t x,int32_t y);
	uint8_t	GetPixelGray(int32_t x, int32_t y);
	void	SetPixelColor(int32_t x,int32_t y,RGBQUAD c, bool bSetAlpha = false);
	void	SetPixelColor(int32_t x,int32_t y,COLORREF cr);
	void	SetPixelIndex(int32_t x,int32_t y,uint8_t i);
	void	DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, RGBQUAD color, bool bSetAlpha=false);
	void	DrawLine(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, COLORREF cr);
	void	BlendPixelColor(int32_t x,int32_t y,RGBQUAD c, float blend, bool bSetAlpha = false);
	bool	SetRectColor(int32_t left, int32_t top, int32_t right, int32_t bottom, RGBQUAD color, bool bSetAlpha = false);
	bool	SetRectColor(RECT& rect, RGBQUAD color, bool bSetAlpha = false);
//@}

Windows平台支持

#if CXIMAGE_SUPPORT_WINDOWS
	int32_t	Blt(HDC pDC, int32_t x=0, int32_t y=0);
	HBITMAP Draw2HBITMAP(HDC hdc, int32_t x, int32_t y, int32_t cx, int32_t cy, RECT* pClipRect, bool bSmooth);
	HBITMAP MakeBitmap(HDC hdc = NULL, bool bTransparency = false);
	HICON   MakeIcon(HDC hdc = NULL, bool bTransparency = false);
	HANDLE	CopyToHandle();
	bool	CreateFromHANDLE(HANDLE hMem);		//Windows objects (clipboard)
	bool	CreateFromHBITMAP(HBITMAP hbmp, HPALETTE hpal=0, bool bTransparency = false);	//Windows resource
	bool	CreateFromHICON(HICON hico, bool bTransparency = false);
	int32_t	Draw(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1, RECT* pClipRect = 0, bool bSmooth = false, bool bFlipY = false);
	int32_t	Draw(HDC hdc, const RECT& rect, RECT* pClipRect=NULL, bool bSmooth = false, bool bFlipY = false);
	int32_t	Stretch(HDC hdc, int32_t xoffset, int32_t yoffset, int32_t xsize, int32_t ysize, uint32_t dwRop = SRCCOPY);
	int32_t	Stretch(HDC hdc, const RECT& rect, uint32_t dwRop = SRCCOPY);
	int32_t	Tile(HDC hdc, RECT *rc);
	int32_t	Draw2(HDC hdc, int32_t x=0, int32_t y=0, int32_t cx = -1, int32_t cy = -1);
	int32_t	Draw2(HDC hdc, const RECT& rect);
	//int32_t	DrawString(HDC hdc, int32_t x, int32_t y, const char* text, RGBQUAD color, const char* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);
	int32_t	DrawString(HDC hdc, int32_t x, int32_t y, const TCHAR* text, RGBQUAD color, const TCHAR* font, int32_t lSize=0, int32_t lWeight=400, uint8_t bItalic=0, uint8_t bUnderline=0, bool bSetAlpha=false);
	// <VATI> extensions
	int32_t    DrawStringEx(HDC hdc, int32_t x, int32_t y, CXTEXTINFO *pTextType, bool bSetAlpha=false );
	void    InitTextInfo( CXTEXTINFO *txt );
protected:
	bool IsHBITMAPAlphaValid( HBITMAP hbmp );
public:
#endif //CXIMAGE_SUPPORT_WINDOWS
//@}

	// file operations
#if CXIMAGE_SUPPORT_DECODE
/** \addtogroup Decode */ //@{
#ifdef WIN32
	//bool Load(LPCWSTR filename, uint32_t imagetype=0);
	bool LoadResource(HRSRC hRes, uint32_t imagetype, HMODULE hModule=NULL);
#endif

常用方法迁移至OpenCV

CxImage创建图像

CxImage* mpCxImage; 
mpCxImage->CreateFromArray(pArray, width, height, BitCount, dwBytesPerLine, TRUE);

OpenCV创建图像

cv::Mat	  mCvImage;
mCvImage = cv::Mat(height, width, CV_8UC3, pArray);

CxImage访问像素

RGBQUAD rgb = mpCxImage->GetPixelColor(pt.x, pt.y, false);
mpCxImage->SetPixelColor((int32_t)logicPt.x, (int32_t)logicPt.y, refColor);

OpenCV访问像素

RGBQUAD rgb;
const cv::Vec3b& pixel = mCvImage.at<cv::Vec3b>(pt.y, pt.x);
rgb.rgbBlue = pixel[0];
rgb.rgbGreen = pixel[1];
rgb.rgbRed = pixel[2];

cv::Vec3b& pixel = mCvImage.at<cv::Vec3b>(pt.Y, pt.X);
pixel[0] = GetBValue(refColor);
pixel[1] = GetGValue(refColor);
pixel[2] = GetRValue(refColor);

CxImage绘制文字

CxImage::CXTEXTINFO info;
mpCxImage->InitTextInfo(&info);
_stprintf(info.lfont.lfFaceName, _T("Times New Roman"));
info.lfont.lfCharSet = GB2312_CHARSET;
info.lfont.lfHeight = 10;
info.fcolor = rgb;
info.opaque = 0;
sprintf_s(info.text, "%s", strinfo.c_str());

//Y方向要镜像
mpCxImage->DrawStringEx(0, (int32_t)logicPt.x, GetHeight() - (int32_t)logicPt.y, &info);

OpenCV绘制文字

// 绘制文本
COLORREF rgb = theApp.GetMainFrame().GetImageMeasureTextColor();
cv::Scalar bgr = cv::Scalar(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
cv::putText(mCvImage,
			strinfo,
			cv::Point(sOutput.ShowPt[i].X, sOutput.ShowPt[i].Y),
			cv::FONT_HERSHEY_SIMPLEX,
			0.4,
			bgr,
			1,
			cv::LINE_AA
		);
		
// 绘制文本背景
cv::rectangle(
			mCvImage,
			pos + cv::Point(0, baseline),
			pos + cv::Point(textSize.width, -textSize.height),
			bgr,
			cv::FILLED
		);

CxImage绘制到DC

mpCxImage->Draw(
				dc.GetSafeHdc(), 
				CRect(pos.x - imageWidth / 2, pos.y - imageHeight / 2, pos.x + imageWidth / 2, pos.y + imageHeight / 2), 
				NULL, 
				IsSmoothMode()
			);

OpenCV绘制到DC

//if (IsSmoothMode()) {
//	cv::resize(originalImage, resizedImage, cv::Size(imageWidth, imageHeight), 0, 0, cv::INTER_LINEAR);
//}
//else {
//	cv::resize(originalImage, resizedImage, cv::Size(imageWidth, imageHeight), 0, 0, cv::INTER_NEAREST);
//}
// 禁用GDI的平滑,因为已在OpenCV处理
Draw(dc.GetSafeHdc(), CRect(pos.x - imageWidth / 2, pos.y - imageHeight / 2, pos.x + imageWidth / 2, pos.y + imageHeight / 2), IsSmoothMode());

// 转换为 BGRA 格式(兼容 GDI 的 Alpha 混合)
cv::Mat bgraImage;
switch (mCvImage.channels()) {
	case 1: cv::cvtColor(mCvImage, bgraImage, cv::COLOR_GRAY2BGRA); break;
	case 3: cv::cvtColor(mCvImage, bgraImage, cv::COLOR_BGR2BGRA);  break;
	case 4: bgraImage = mCvImage.clone();                           break;
	default: return false;
}

// 创建 BITMAPINFO 结构
BITMAPINFOHEADER bi = { 0 };
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bgraImage.cols;
bi.biHeight = -bgraImage.rows;  // 负值表示从上到下布局
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;

// 设置缩放模式
SetStretchBltMode(hdc, smooth ? HALFTONE : COLORONCOLOR);
SetBrushOrgEx(hdc, 0, 0, NULL);  // HALFTONE 模式需要重置原点

// 绘制图像
int result = StretchDIBits(
		hdc,
		destRect.left, destRect.top,      // 目标左上角
		destRect.Width(), destRect.Height(), // 目标尺寸
		0, 0,                            // 源图像起点
		bgraImage.cols, bgraImage.rows,   // 源图像尺寸
		bgraImage.data,                   // 图像数据
		(BITMAPINFO*)&bi,                 // BITMAPINFO
		DIB_RGB_COLORS,                   // 颜色格式
		SRCCOPY                           // 直接拷贝
	);

CxImage从资源ID读取图像

//bool LoadResource(HRSRC hRes, uint32_t imagetype, HMODULE hModule=NULL);
mCxImage.LoadResource(FindResource(hModule, MAKEINTRESOURCE(IDB_xxxxxx), _T("PNG")), 0);

OpenCV从资源ID读取图像

// 替换为你的资源ID,例如 IDB_PNG1
HRSRC hResource = FindResource(hModule, MAKEINTRESOURCE(IDB_xxxxxx), _T("PNG"));
if (!hResource) {
    // 资源未找到
    return;
}

DWORD imageSize = SizeofResource(hModule, hResource);
HGLOBAL hMemory = LoadResource(hModule, hResource);
if (!hMemory) {
    // 加载资源失败
    return;
}

void* pData = LockResource(hMemory);
if (!pData) {
    // 锁定资源失败
    return;
}

// 复制到 std::vector<uchar> 中
std::vector<uchar> buffer((uchar*)pData, (uchar*)pData + imageSize);

// 使用 OpenCV 解码图像
cv::Mat image = cv::imdecode(buffer, cv::IMREAD_UNCHANGED);
if (image.empty()) {
    // 图像解码失败
    return;
}

// 现在你可以使用 image 进行后续操作
cv::imshow("Loaded Image", image);
cv::waitKey(0);