CImg库中CImg,CImgList,CImgDisplay三个类的介绍
轉自:http://www.cppprog.com/2009/0426/108.html
?
本文簡單介紹了CImg庫中的三個大類:CImg,CImgList,CImgDisplay。然后給出了讓CImg在HDC上繪圖以及與HBITMAP互換的方法,為部署CImg到Windows?GUI程序中提供了基本支持。
上回介紹了CImg模板類的一些函數,象我這種不在圖像處理行業混的人來說很多術語實在是太專業了-_-,不理不理,看不懂就直接寫測試代碼看它們的作用是什么不就知道啦~~嘿嘿^_^。
上測試代碼先:
- #include?"CImg.h"
- using?namespace?cimg_library;
- ?
- int?main()?
- {
- ?
- ????CImg<unsigned?char>?src("test.bmp");
- ????//?設置原圖大小,貌似haar計算要求圖像寬高是4的倍數
- ????src.resize(?src.width-src.width%4,?src.height-src.height%4);
- ????CImgList<unsigned?char>?visu;
- ????visu
- ????????<<src.get_crop(0,0,src.width/2,src.height/2)
- ????????<<src.get_quantize(5)
- ????????<<src.get_rotate(45,1)
- ????????<<src.get_permute_axes("yxzv")
- ????????<<src.get_erode(5)
- ????????<<src.get_haar()
- ????????<<src.get_dilate(3)
- ????????<<src.get_blur(3)
- ????????<<src.get_noise(3)
- ????????<<src.get_deriche(3)
- ????????<<src.get_blur_anisotropic(8)
- ????????<<src.get_blur_bilateral(1,2)
- ????????<<src.get_blur_patch(4,3)
- ????????<<src.get_sharpen(3)
- ????????<<src.get_blur_median(3)
- ????????;?//如果愿意可以測試更多CImg的圖像處理方法
- ???
- ????//?用來顯示效果
- ????CImgDisplay?disp(src.width*2,?src.height);
- ????int?i=0;
- ????unsigned?char?textcolor[]?=?{?255,255,255?};
- ????while(!disp.is_closed?&&?!disp.is_keyQ?&&?!disp.is_keyESC)
- ????{
- ????????i?=?i?%?visu.size;
- ????????char?buf[20];
- ????????::sprintf(buf,"img:%d",i);
- ????????//顯示效果,(CImg?<<?CImg)會生成一個新的CImgList
- ????????//左邊是原圖,右邊是處理圖,外加寫了個序號在上面以便區別
- ????????disp.display(?src?<<?(+visu[i]).draw_text(0,0,buf,textcolor)?).wait();
- ????????//按方向鍵下則顯示下一個
- ????????if(disp.is_keyARROWDOWN)?i++;
- ????????//方向鍵上則顯示上一個
- ????????if(disp.is_keyARROWUP)
- ????????{
- ????????????i--;
- ????????????if(i<0)?i=visu.size-1;
- ????????}
- ????}
- ????return?0;
- }
這個例子用到了CImg、CImgList、CImgDisplay三個類。
CImg類前面已有介紹。
CImgList是CImg的容器,用來保存一組CImg,主要方法有:
- CImgList<T>&?remove(const?unsigned?int?pos)?//刪除指定位置
- CImgList<T>&?pop_back()????????????//刪除最后一個
- CImgList<T>&?pop_front()????????//刪除前端
- CImgList<T>&?push_back(const?CImg<t>&?img)//從后面添加
- CImgList<T>&?push_front(const?CImg<t>&?img)//從前面添加
- CImgList<T>&?insert(const?CImg<t>&?img,?const?unsigned?int?pos)????//插入到指定位置之前
- CImgList<T>&?clear()????//清空
- CImg<T>&?operator[](const?unsigned?int?pos)?//取指定位置的圖像
上面這些是它作為容器的基本功能,同時它也重載了一些操作符以便于使用,比如本例中的"<<"操作其實就是push_back方法。另外,它還有大量的運算功能用于給容器中的圖像批量運算。最后,還有一些好玩的方法不可錯過:從視頻中載入或把圖像保存到視頻中:
- CImgList<T>&?load_ffmpeg(const?char?*const?filename,
- ????const?unsigned?int?first_frame=0,
- ????const?unsigned?int?last_frame=~0U,
- ????const?unsigned?int?step_frame=1,
- ????const?bool?pixel_format=true,
- ????const?bool?resume=false)
- ?
- const?CImgList<T>&?save_ffmpeg(
- ????const?char?*const?filename,
- ????const?unsigned?int?first_frame=0,
- ????const?unsigned?int?last_frame=~0U,
- ????const?unsigned?int?fps=25)
這兩個方法要求鏈接ffmpeg庫,如果沒有這個庫文件,還可以使用load_ffmpeg_external和save_ffmpeg_external方法調用已外部安裝的ffmpeg程序編解碼。
CImgDisplay類是一個窗口類,它主要用來顯示CImg和CImgList。一般使用它的流程是:
- 新建CImgDisplay對象
- 設置它的大小,除直接輸入寬高外也能用直接用CImg、CImgList或另一個CImgDisplay對象作為調整大小的依據。這時,CImgDisplay對象內部已經建立了一個窗口了。
- 使用display方法顯示圖像
- 使用wait方法等待事件發生(鍵盤、鼠標、超時等)
- 檢查is_keyXXXX、is_closed、button、wheel等成員變量確定是什么事件,再決定我們該做什么操作。
- 如果需要,循環回第三步
- 析構時窗口收回。
在本例中,如果窗體關閉或按了Q鍵或按了ESC鍵則退出循環,程序結束。或者顯示由原圖和處理后的圖組成的CImgList圖像,如果按了上下方向鍵,則改變當前顯示的處理圖。
這是本例運行時的截圖:
水墨畫風格的《清明上河圖》
CImg的圖像處理方法絕不止上面例子中寫的那么一點點,如果都寫上去的話光運算就得等很長的時間,內存資源就更不用說了。所以建議大家一批批地寫上去試驗。或者可以修改一下代碼,用逐次運算來試驗效果。當然,如果你是圖像處理領域的大牛,看方法名應試就知道是干啥的了,上面的代碼就當熟悉一下CImg庫吧。
?
在Windows里使用CImg
現在,我們已經可以使用CImg的現成方法做一些圖像處理了。不過,有一個大問題需要解決,怎樣把CImg的強大功能和我們的GUI程序相結合呢?我們總不能只使用CImgDisplay作為最終產品的顯示界面吧?我們急需一個把CImg顯示到指定HDC上的方法!
好在CImg庫就一個頭文件,所有的源代碼都在這個頭文件里。只要看一下它是怎么把CImg對象顯示到CImgDisplay上的,我們就能依樣畫葫蘆地把它顯示到指定HDC上。
經過一番摸索,終于發現可以這樣把一個CImg對象顯示到HDC上:
- template<class?T>
- void?DrawToHDC(HDC?dc,?const?CImg<T>?&src)
- {
- ????CImgDisplay?disp;
- ????disp.assign(src,0,3,false,true);?//最后一個true指明m_disp不要顯示
- ????disp.render(m_src);?//把src的內容解析到disp的data中
- ????SetDIBitsToDevice(dc,0,0,disp.width,disp.height,0,0,
- ????????0,disp.height,disp.data,&disp.bmi,DIB_RGB_COLORS);
- }
CImgDisplay在顯示過程中會填充bmi和data成員變量,而這兩個變量正好是DIB數據,這段代碼正好利用了這點。
但是它的運行效率實在是不怎樣,經調試發現disp.assign方法會生成窗體、互斥量等東東,析構時又要刪除它們,我們在這里根本用不著這些東西,浪費啊~~,于是不得不寫一個新的畫圖方法了。
在說新版本的畫圖方法之前,得先說一下CImg庫的另一個好功能:插件支持。只要在#include "CImg.h"之前
?
#define cimg_plugin "插件文件"
#define cimg_plugin1 "插件文件1"
#define cimg_plugin2 "插件文件2"
...
#define cimg_plugin8 "插件文件8"
CImg庫就會把插件文件中的方法加入到CImg類中,看來起很酷,其實工作原理很簡單,頭文件中CImg類是這樣定義的:
- template<typename?T>
- struct?CImg?{
- ????...
- ????#ifdef?cimg_plugin
- ????????#include?cimg_plugin
- ????#endif
- ????#ifdef?cimg_plugin1
- ????????#include?cimg_plugin1
- ????#endif
- ????#ifdef?cimg_plugin2
- ????????#include?cimg_plugin2
- ????#endif
- ????#ifdef?cimg_plugin3
- ????????#include?cimg_plugin3
- ????#endif
- ????#ifdef?cimg_plugin4
- ????????#include?cimg_plugin4
- ????#endif
- ????#ifdef?cimg_plugin5
- ????????#include?cimg_plugin5
- ????#endif
- ????#ifdef?cimg_plugin6
- ????????#include?cimg_plugin6
- ????#endif
- ????#ifdef?cimg_plugin7
- ????????#include?cimg_plugin7
- ????#endif
- ????#ifdef?cimg_plugin8
- ????????#include?cimg_plugin8
- ????#endif
- ...
- }
當我們如下定義時
#define cimg_plugin "cimg4hdc.h"cimg4hdc.h"
cimg4hdc.h文件的內容就插入到了CImg類的定義中間。
我們現在就可以寫一個插件文件為CImg類加入與Windows GUI交互的方法了,下面的代碼是我寫的插件文件,文件名為“cimg4hdc.h”,新加了五個方法:
- HBITMAP?to_bmp(HDC?dc?=?0)?const??????//??從CImg產生一個HBITMAP,使用完要記得DeleteObject
- CImg<T>&?display(HDC?dc,?RECT?&rc)?????//?把CImg顯示到HDC上,rc指定顯示位置和大小
- CImg(HBITMAP?bmp)???????????????//?從HBITMAP直接生成一個CImg,HBITMAP必須是16位色以上
- CImg<T>&?assign(HBITMAP?bmp)???????????//?同上
- CImg<T>&?load_bmp(HBITMAP?bmp)?????????//?同上
插件文件代碼(點擊下載,標準做法是右擊,鏈接另存為...):
- #ifndef?cimg_plugin_cimg4hdc
- #define?cimg_plugin_cimg4hdc
- ?
- HBITMAP?to_bmp(HDC?dc)?const
- {
- ????CImgDisplay?disp;
- ????disp.width?=?width;
- ????disp.height?=?height;
- ????disp.normalization?=?3;
- ????disp.is_closed?=?true;
- ?
- ????BITMAPINFO?bmi;
- ????BITMAPINFOHEADER?&bh?=?bmi.bmiHeader;
- ????bh.biSize?=?sizeof(BITMAPINFOHEADER);
- ????bh.biWidth?=?disp.width;
- ????bh.biHeight?=?-(int)disp.height;
- ????bh.biPlanes?=?1;
- ????bh.biBitCount?=?32;
- ????bh.biCompression?=?BI_RGB;
- ????bh.biSizeImage?=?0;
- ????bh.biXPelsPerMeter?=?1;
- ????bh.biYPelsPerMeter?=?1;
- ????bh.biClrUsed?=?0;
- ????bh.biClrImportant?=?0;
- ????void?*pvBits;
- ?
- ????HBITMAP?bmp?=?CreateDIBSection(dc,
- ??????&bmi,
- ??????DIB_RGB_COLORS,
- ??????&pvBits,
- ??????NULL,0
- ????);???
- ????if(bmp?==?NULL)?return?bmp;
- ?
- ????disp.bmi?=?bmi;???
- ????disp.data?=?(unsigned?int*)pvBits;
- ????disp.render(*this);
- ????disp.width?=?disp.height?=?0;
- ????disp.data?=?NULL;
- ????return?bmp;
- }
- ?
- CImg<T>&?display(HDC?dc,?RECT?&rc)
- {
- ????CImgDisplay?disp;
- ?
- ????disp.width?=?rc.right?-?rc.left;
- ????disp.height?=?rc.bottom?-?rc.top;
- ????disp.normalization?=?3;
- ????disp.is_closed?=?true;
- ???
- ????BITMAPINFOHEADER?&bh?=?disp.bmi.bmiHeader;
- ????bh.biSize?=?sizeof(BITMAPINFOHEADER);
- ????bh.biWidth?=?disp.width;
- ????bh.biHeight?=?-(int)disp.height;
- ????bh.biPlanes?=?1;
- ????bh.biBitCount?=?32;
- ????bh.biCompression?=?BI_RGB;
- ????bh.biSizeImage?=?0;
- ????bh.biXPelsPerMeter?=?1;
- ????bh.biYPelsPerMeter?=?1;
- ????bh.biClrUsed?=?0;
- ????bh.biClrImportant?=?0;
- ????disp.data?=?new?unsigned?int[disp.width*disp.height];
- ?
- ????disp.render(*this);
- ????::SetDIBitsToDevice(dc,rc.left,rc.top,
- ????????disp.width,disp.height,0,0,
- ????????0,disp.height,disp.data,&disp.bmi,DIB_RGB_COLORS);
- ?
- ????disp.width?=?disp.height?=?0;
- ????delete?[]disp.data;
- ?
- ????return?*this;
- }
- ?
- CImg(HBITMAP?bmp)
- ????:width(0),height(0),depth(0),dim(0),is_shared(false),data(0)
- {
- ????load_bmp(bmp);
- }
- ?
- CImg<T>&?assign(HBITMAP?bmp)
- {
- ????return?load_bmp(bmp);
- }
- ?
- CImg<T>&?load_bmp(HBITMAP?bmp)
- {
- ????BITMAP?bmpobj;
- ????if(!::GetObject(bmp,sizeof(bmpobj),&bmpobj)?||?bmpobj.bmBitsPixel<16)?return?*this;
- ?
- ????LONG?cbBuffer?=?bmpobj.bmWidthBytes*(bmpobj.bmHeight);
- ????BYTE?*lvbit?=?new?BYTE[cbBuffer];
- ?
- ????if(!::GetBitmapBits(bmp,?cbBuffer,?lvbit))
- ????{
- ????????delete?[]lvbit;
- ????????return??*this;
- ????}
- ?
- ????unsigned?char*?ptrs?=?lvbit;
- ????int?align?= (4 - bmpobj.bmWidthBytes%4)%4;
- ?
- ????//?Read?pixel?data
- ????assign(bmpobj.bmWidth,bmpobj.bmHeight,1,3);
- ????switch?(bmpobj.bmBitsPixel)?{
- ????case?16?:?{?//?16?bits?colors
- ????for?(int?y=height-1;?y>=0;?--y)?{?cimg_forX(*this,x)?{
- ??????const?unsigned?char?c1?=?*(ptrs++),?c2?=?*(ptrs++);
- ??????const?unsigned?short?col?=?(unsigned?short)(c1|(c2<<8));
- ??????(*this)(x,y,2)?=?(T)(col&0x1F);
- ??????(*this)(x,y,1)?=?(T)((col>>5)&0x1F);
- ??????(*this)(x,y,0)?=?(T)((col>>10)&0x1F);
- ????}?ptrs+=align;?}
- ????}?break;
- ????case?24?:?{?//?24?bits?colors
- ????for?(int?y=height-1;?y>=0;?--y)?{?cimg_forX(*this,x)?{
- ??????(*this)(x,y,2)?=?(T)*(ptrs++);
- ??????(*this)(x,y,1)?=?(T)*(ptrs++);
- ??????(*this)(x,y,0)?=?(T)*(ptrs++);
- ????}?ptrs+=align;?}
- ????}?break;
- ????case?32?:?{?//?32?bits?colors
- ????for?(int?y=height-1;?y>=0;?--y)?{?cimg_forX(*this,x)?{
- ??????(*this)(x,y,2)?=?(T)*(ptrs++);
- ??????(*this)(x,y,1)?=?(T)*(ptrs++);
- ??????(*this)(x,y,0)?=?(T)*(ptrs++);
- ??????++ptrs;
- ????}?ptrs+=align;?}
- ????}?break;
- ????}
- ????mirror('y');
- ???
- ????delete?[]lvbit;
- ????return?*this;
- }
- #endif
測試代碼(在WTL里測試):
- #define?cimg_plugin?"cimg4hdc.h"
- #include?"CImg.h"
- using?namespace?cimg_library;
- ????CImg<unsigned?char>?m_show;
- ???
- ????//?生成部分
- ????{
- ????//?生成一個100*100的HBITMAP
- ????HDC?dc?=?::CreateCompatibleDC(0);
- ????HBITMAP?bmp?=?::CreateCompatibleBitmap(::GetDC(0),?100,100);
- ????::SelectObject(dc,?bmp);
- ????::TextOut(dc,?10,?10,?_T("Hello?World"),?11);
- ????//?從HBITMAP生成一個CImg
- ????CImg<unsigned?char>?src(bmp);
- ????//?模糊計算,結果與原圖并排送給m_show
- ????m_show?=?(src?<<?src.get_blur(2)).get_append('x');
- ????//?刪除HBITMAP和內存DC
- ????::DeleteObject(bmp);
- ????::DeleteDC(dc);
- ????}
- ???
- ????//?顯示部分
- ????LRESULT?OnPaint(UINT?/*uMsg*/,?WPARAM?/*wParam*/,?LPARAM?/*lParam*/,?BOOL&?/*bHandled*/)
- ????{
- ????????CPaintDC?dc(m_hWnd);
- ????????RECT?rc={
- ????????????10,10,10+m_show.width,10+m_show.height
- ????????};
- ????????//?在HDC上顯示m_show
- ????????m_show.display(dc,?rc);
- ????????return?0;
- ????}
效果如下:
總結
以上是生活随笔為你收集整理的CImg库中CImg,CImgList,CImgDisplay三个类的介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CImg库介绍
- 下一篇: opencv图像旋转