文章目錄
- 核心功能特點
- 局限性與替代方案
- 常用方法
- 構造函數
- 從數組創建圖像
- 訪問屬性
- 訪問像素點
- Windows平臺支持
- 常用方法遷移至OpenCV
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_WINDOWSint32_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 resourcebool 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> extensionsint32_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, // BITMAPINFODIB_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);