CImg库中CImg,CImgList,CImgDisplay三个类的介绍
轉(zhuǎn)自:http://www.cppprog.com/2009/0426/108.html
?
本文簡單介紹了CImg庫中的三個(gè)大類:CImg,CImgList,CImgDisplay。然后給出了讓CImg在HDC上繪圖以及與HBITMAP互換的方法,為部署CImg到Windows?GUI程序中提供了基本支持。
上回介紹了CImg模板類的一些函數(shù),象我這種不在圖像處理行業(yè)混的人來說很多術(shù)語實(shí)在是太專業(yè)了-_-,不理不理,看不懂就直接寫測試代碼看它們的作用是什么不就知道啦~~嘿嘿^_^。
上測試代碼先:
- #include?"CImg.h"
- using?namespace?cimg_library;
- ?
- int?main()?
- {
- ?
- ????CImg<unsigned?char>?src("test.bmp");
- ????//?設(shè)置原圖大小,貌似haar計(jì)算要求圖像寬高是4的倍數(shù)
- ????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)會(huì)生成一個(gè)新的CImgList
- ????????//左邊是原圖,右邊是處理圖,外加寫了個(gè)序號在上面以便區(qū)別
- ????????disp.display(?src?<<?(+visu[i]).draw_text(0,0,buf,textcolor)?).wait();
- ????????//按方向鍵下則顯示下一個(gè)
- ????????if(disp.is_keyARROWDOWN)?i++;
- ????????//方向鍵上則顯示上一個(gè)
- ????????if(disp.is_keyARROWUP)
- ????????{
- ????????????i--;
- ????????????if(i<0)?i=visu.size-1;
- ????????}
- ????}
- ????return?0;
- }
這個(gè)例子用到了CImg、CImgList、CImgDisplay三個(gè)類。
CImg類前面已有介紹。
CImgList是CImg的容器,用來保存一組CImg,主要方法有:
- CImgList<T>&?remove(const?unsigned?int?pos)?//刪除指定位置
- CImgList<T>&?pop_back()????????????//刪除最后一個(gè)
- 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)?//取指定位置的圖像
上面這些是它作為容器的基本功能,同時(shí)它也重載了一些操作符以便于使用,比如本例中的"<<"操作其實(shí)就是push_back方法。另外,它還有大量的運(yùn)算功能用于給容器中的圖像批量運(yùn)算。最后,還有一些好玩的方法不可錯(cuò)過:從視頻中載入或把圖像保存到視頻中:
- 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)
這兩個(gè)方法要求鏈接ffmpeg庫,如果沒有這個(gè)庫文件,還可以使用load_ffmpeg_external和save_ffmpeg_external方法調(diào)用已外部安裝的ffmpeg程序編解碼。
CImgDisplay類是一個(gè)窗口類,它主要用來顯示CImg和CImgList。一般使用它的流程是:
- 新建CImgDisplay對象
- 設(shè)置它的大小,除直接輸入寬高外也能用直接用CImg、CImgList或另一個(gè)CImgDisplay對象作為調(diào)整大小的依據(jù)。這時(shí),CImgDisplay對象內(nèi)部已經(jīng)建立了一個(gè)窗口了。
- 使用display方法顯示圖像
- 使用wait方法等待事件發(fā)生(鍵盤、鼠標(biāo)、超時(shí)等)
- 檢查is_keyXXXX、is_closed、button、wheel等成員變量確定是什么事件,再?zèng)Q定我們該做什么操作。
- 如果需要,循環(huán)回第三步
- 析構(gòu)時(shí)窗口收回。
在本例中,如果窗體關(guān)閉或按了Q鍵或按了ESC鍵則退出循環(huán),程序結(jié)束。或者顯示由原圖和處理后的圖組成的CImgList圖像,如果按了上下方向鍵,則改變當(dāng)前顯示的處理圖。
這是本例運(yùn)行時(shí)的截圖:
水墨畫風(fēng)格的《清明上河圖》
CImg的圖像處理方法絕不止上面例子中寫的那么一點(diǎn)點(diǎn),如果都寫上去的話光運(yùn)算就得等很長的時(shí)間,內(nèi)存資源就更不用說了。所以建議大家一批批地寫上去試驗(yàn)。或者可以修改一下代碼,用逐次運(yùn)算來試驗(yàn)效果。當(dāng)然,如果你是圖像處理領(lǐng)域的大牛,看方法名應(yīng)試就知道是干啥的了,上面的代碼就當(dāng)熟悉一下CImg庫吧。
?
在Windows里使用CImg
現(xiàn)在,我們已經(jīng)可以使用CImg的現(xiàn)成方法做一些圖像處理了。不過,有一個(gè)大問題需要解決,怎樣把CImg的強(qiáng)大功能和我們的GUI程序相結(jié)合呢?我們總不能只使用CImgDisplay作為最終產(chǎn)品的顯示界面吧?我們急需一個(gè)把CImg顯示到指定HDC上的方法!
好在CImg庫就一個(gè)頭文件,所有的源代碼都在這個(gè)頭文件里。只要看一下它是怎么把CImg對象顯示到CImgDisplay上的,我們就能依樣畫葫蘆地把它顯示到指定HDC上。
經(jīng)過一番摸索,終于發(fā)現(xiàn)可以這樣把一個(gè)CImg對象顯示到HDC上:
- template<class?T>
- void?DrawToHDC(HDC?dc,?const?CImg<T>?&src)
- {
- ????CImgDisplay?disp;
- ????disp.assign(src,0,3,false,true);?//最后一個(gè)true指明m_disp不要顯示
- ????disp.render(m_src);?//把src的內(nèi)容解析到disp的data中
- ????SetDIBitsToDevice(dc,0,0,disp.width,disp.height,0,0,
- ????????0,disp.height,disp.data,&disp.bmi,DIB_RGB_COLORS);
- }
CImgDisplay在顯示過程中會(huì)填充bmi和data成員變量,而這兩個(gè)變量正好是DIB數(shù)據(jù),這段代碼正好利用了這點(diǎn)。
但是它的運(yùn)行效率實(shí)在是不怎樣,經(jīng)調(diào)試發(fā)現(xiàn)disp.assign方法會(huì)生成窗體、互斥量等東東,析構(gòu)時(shí)又要?jiǎng)h除它們,我們在這里根本用不著這些東西,浪費(fèi)啊~~,于是不得不寫一個(gè)新的畫圖方法了。
在說新版本的畫圖方法之前,得先說一下CImg庫的另一個(gè)好功能:插件支持。只要在#include "CImg.h"之前
?
#define cimg_plugin "插件文件"
#define cimg_plugin1 "插件文件1"
#define cimg_plugin2 "插件文件2"
...
#define cimg_plugin8 "插件文件8"
CImg庫就會(huì)把插件文件中的方法加入到CImg類中,看來起很酷,其實(shí)工作原理很簡單,頭文件中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
- ...
- }
當(dāng)我們?nèi)缦露x時(shí)
#define cimg_plugin "cimg4hdc.h"cimg4hdc.h"
cimg4hdc.h文件的內(nèi)容就插入到了CImg類的定義中間。
我們現(xiàn)在就可以寫一個(gè)插件文件為CImg類加入與Windows GUI交互的方法了,下面的代碼是我寫的插件文件,文件名為“cimg4hdc.h”,新加了五個(gè)方法:
- HBITMAP?to_bmp(HDC?dc?=?0)?const??????//??從CImg產(chǎn)生一個(gè)HBITMAP,使用完要記得DeleteObject
- CImg<T>&?display(HDC?dc,?RECT?&rc)?????//?把CImg顯示到HDC上,rc指定顯示位置和大小
- CImg(HBITMAP?bmp)???????????????//?從HBITMAP直接生成一個(gè)CImg,HBITMAP必須是16位色以上
- CImg<T>&?assign(HBITMAP?bmp)???????????//?同上
- CImg<T>&?load_bmp(HBITMAP?bmp)?????????//?同上
插件文件代碼(點(diǎn)擊下載,標(biāo)準(zhǔn)做法是右擊,鏈接另存為...):
- #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;
- ???
- ????//?生成部分
- ????{
- ????//?生成一個(gè)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生成一個(gè)CImg
- ????CImg<unsigned?char>?src(bmp);
- ????//?模糊計(jì)算,結(jié)果與原圖并排送給m_show
- ????m_show?=?(src?<<?src.get_blur(2)).get_append('x');
- ????//?刪除HBITMAP和內(nèi)存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;
- ????}
效果如下:
總結(jié)
以上是生活随笔為你收集整理的CImg库中CImg,CImgList,CImgDisplay三个类的介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CImg库介绍
- 下一篇: opencv图像旋转