CImg库介绍
轉自:http://www.cppprog.com/2009/0424/106.html
?
CImg是一個跨平臺的C++的圖像處理庫,提供了加載、處理、顯示、保存等一系列功能,其中的圖像處理功能尤其強大。
首先,建議先到這里欣賞一下使用CImg代碼做的Demo,就是它使我這個沒有圖像處理經驗的童鞋也心動得以致于研究了一星期^_^
主頁地址:http://cimg.sourceforge.net/
下載地址:http://cimg.sourceforge.net/download.shtml
下載時注意應該下載源碼包,里面附帶的大量的例程。而實際上CImg庫只是一個頭文件CImg.h,這個頭文件里包含了CImg庫所有的代碼。
另外不要錯過下載列表中的一個部分完成的《CImg中文參考手冊》。
CImg的Hello World
這段代碼是從《CImg參考手冊》里抄的,可以大致了解一下CImg的框架。
以VC為例:新建控制臺程序,輸入下面的代碼。項目屬性的鏈接器附加依賴項加入kernel.lib user32.lib gdi32.lib。最后,把CImg.h拷貝到項目路徑下,即可成功編譯運行
- #include?"CImg.h"
- using?namespace?cimg_library;
- int?main()?
- {
- ????//?定義一個每個顏色?8?位(bit)的?640x400?的彩色圖像
- ????CImg<unsigned?char>?img(640,400,1,3);??
- ????//將像素值設為?0(黑色)
- ????img.fill(0);?
- ????//?定義一個紫色
- ????unsigned?char?purple[]?=?{?255,0,255?};
- ????
- ????//?在坐標(100,?100)處畫一個紫色的“Hello?world”
- ????img.draw_text(100,100,"Hello?World",purple);??
- ????//?在一個標題為“My?first?CImg?code”的窗口中顯示這幅圖像
- ????img.display("My?first?CImg?code");??????????????????
- ????
- ????return?0;
- }?
運行這段代碼,顯示結果:
在CImg體系中,圖像有x,y,z,v四個軸,前三個當然是3維空間的三個方向(知道了吧?CImg可以處理3維圖像),第四個v一般表示色彩通道數,比如RGB三色就是3。
上面的代碼每行的注釋已經寫得很詳細,從代碼里可以看出CImg處于namespace cimg_library名空間之下;模板類CImg<>是主要的圖像類,提供了大量的圖像處理方法。
在CImg庫里,還有一個重要的類是CImgDisplay,它提供了一個顯示窗口,不僅可以顯示CImg的內容,還可以接收鍵盤鼠標事件,我們可以暫時把它看成是一個CImg專用窗體類。
CImg類介紹
CImg類提供的方法非常多,為了便于查閱,我用Doxygen重新生成了一份CImg庫的說明文檔,并做成chm格式,可以本文后面找到下載地址。
CImg模板類提供了圖像的載入、保存、處理功能,是整個庫的核心組件。它的聲明如下:
template<typename T>
struct cimg_library::CImg;<typename T>
struct cimg_library::CImg;
模板參數T指明CImg中元素的類型。在自帶的參考手冊中稱這些元素為像素(pixel),不過因為這里的像素和我們平時的像素概念稍微有點不同。因為前面說過CImg體系中有xyzv四個軸,CImg手冊稱它為4維圖像,把4維圖像里的單個元素稱為像素。而事實上第四維的v通常就是我們的色彩通道,所以要在屏幕上顯示出一個真正的像素往往要取同一xyz軸上所有v軸的點(所有色彩通道合成一個真正的彩色像素)。在本文中我決定把這個組成圖像的最小單位稱為元素,由所有色彩通道v組成一個像素。
CImg類中的6個成員變量:
- //?分別對應x,y,z,v四個軸的大小,即寬度、高度、深度和通道數。
- unsigned?int?width,?height,?depth,?dim;
- //?指向內存中的圖像數據
- T?*data;
- //?指明data是否是共用的,即是否有data的擁有權。
- bool?is_shared;
CImg類里的成員變量都是public的,我們可以直接存取它們,不過為了防止破壞完整性,建議使用成員方法如dimx(), dimy(), dimz(), dimv() 和ptr()來操作。
CImg的構造函數,大部分構造函數都很直白,就不列出了,可以查看手冊,下面列出的是一些特殊的構造函數。
- //?以字符串指定的數據填充,其中的values字符串包含了一串十進制數字表示的數據。
- //?比如參數values為字符串"20,30,40,50",?repeat_pattern為true時
- //?圖像內的數據就以20,30,40,50,20,30,40,50,20...填充。
- CImg?(
- ????const?unsigned?int?dx,
- ????const?unsigned?int?dy,
- ????const?unsigned?int?dz,
- ????const?unsigned?int?dv,
- ????const?char?*const?values,
- ????const?bool?repeat_pattern)
?
- //?由shared參數決定是否直接引用img中的data數據還是自己持有一份拷貝(是否共享)
- CImg?(const?CImg<?T?>?&img,?const?bool?shared)
?
- //?參考img的大小構造一個新的CImg對象
- CImg?(const?CImg<?t?>?&img,?const?char?*const?dimensions)
這個構造函數的dimensions參數由一串數字或轉義符組成,分別對應x,y,z,v的大小。比如:
參數為"20 20 1 3"時新CImg對象的x,y,z,v的大小分別是20 20 1 3。
轉義符以%開頭,后綴可以是:
x, dx, dimx, width 表示img.width
y, dy, dimy, height 表示img.height
z, dz, dimz, depth 表示img.depth
v, dv, dimv, dim 表示img.dim
比如CImg(img, "%y %x 1 3");可以生成一個和img的寬高正好互換的CImg對象。
- //?從文件里載入圖像,文件類型由擴展名確定
- CImg?(const?char?*const?filename)
CImg庫本身支持BMP,RAW,HDR,INR,PGM,PPM,PAN,DLM格式
安裝了ImageMagick(Unix系)后可支持JPG,GIF,PNG,TIF等多種格式
CImg也能使用jpeg庫,zlib/png庫,tiff庫等來支持多種圖像格式,只需編譯時加入這些庫即可。可以到這里下載這些庫文件。
- //?從CImgDisplay對象的內容創建圖像
- CImg?(const?CImgDisplay?&disp)
?
CImg部分成員方法
CImg提供了豐富的成員方法,在這里全部列出是不可能的,這里只作一些簡單介紹。更多方法請參考手冊。
- //?賦值,它有多個重載的版本,參數和構造函數一樣,實際上構造函數最終都是調用它來實現的。
- CImg<?T?>?&??assign?();
- ?
- //?把data數據轉交給img,自己不再有data數據的擁有權
- CImg<?T?>?&??transfer_to?(CImg<?T?>?&img);
- ?
- //?清除數據
- CImg<?T?>?&??clear?();
- ?
- //?獲得所有元素總數
- unsigned?long??size?()?const
- ?
- //?獲得某個軸向的大小
- int??dimx?()?const;
- int??dimy?()?const;
- int??dimz?()?const;
- int??dimv?()?const;
- ?
- //?取得遍歷元素的迭代器,這里的iterator其實就是T*。
- iterator??begin?();
- iterator??end?();
- ?
- //?取得首尾數據
- T?&??first?();
- T?&??last?();
- ?
- //?取得圖像內部數據(第二個版本取得數據并定位到指定位置)
- T?*??ptr?();
- T?*??ptr?(
- ????const?unsigned?int?x,
- ????const?unsigned?int?y=0,
- ????const?unsigned?int?z=0,
- ????const?unsigned?int?v=0);
- ?
- //?快速存取指定位置上的數據
- T?&??operator()?(
- ????const?unsigned?int?x,
- ????const?unsigned?int?y=0,
- ????const?unsigned?int?z=0,
- ????const?unsigned?int?v=0);
- ?
- //?按索引直接存取data數組
- T?&??operator[]?(const?unsigned?long?off)
- ?
- //?得到指定位置的索引
- long??offset?(
- ????const?int?x,
- ????const?int?y=0,
- ????const?int?z=0,
- ????const?int?v=0)?const;
- ?
- //?存取指定位置上的數據,當指定的軸的超出邊界時返回最邊上的值
- T?&??at?(const?int?off);
- T&?atX(const?int?x,?const?int?y,?const?int?z,?const?int?v);
- T&?atXY(const?int?x,?const?int?y,?const?int?z,?const?int?v);
- T&?atXYZ(const?int?x,?const?int?y,?const?int?z,?const?int?v);
- T&?atXYZV(const?int?x,?const?int?y,?const?int?z,?const?int?v);
- ?
- //?存取指定位置上的數據,當指定的軸的超出邊界時返回out_val
- T?&??at?(const?int?off,?const?T?out_val);
- T&?atX(const?int?x,?const?int?y,?const?int?z,?const?int?v,?const?T?out_val);
- T&?atXY(const?int?x,?const?int?y,?const?int?z,?const?int?v,?const?T?out_val);
- T&?atXYZ(const?int?x,?const?int?y,?const?int?z,?const?int?v,?const?T?out_val);
- T&?atXYZV(const?int?x,?const?int?y,?const?int?z,?const?int?v,?const?T?out_val);
值得一提的是還有兩種插值版本的at方法,分別是線性插值和三次插值。其中線性插值以linear_作為前綴,三次插值以cubic_作為前綴。參數和上面的類似,只是各軸位置的類型不是int而是float,這批方法會按插值法算出小數點位置上的數據。
到這里可以發現CImg類實際上提供了類似于vector容器的編程接口,這樣我們的STL算法也能用于CImg的操作了,隨后就可以看到庫里有時也會把CImg類直接當作數據容器來使用。比如下面CImg中就有這個方法:
- //?返回字符串的形式的圖像中的數據,默認是逗號分隔的一長串數字。
- //這里返回的CImg<charT>不代表圖像,而是一個一維的字符串數據,這時它只是一個容器而已,可以把它看作是vector<charT>。
- CImg<?charT?>??value_string?(const?char?separator=',',?const?unsigned?int?max_size=0);
CImg類的畫圖方法
draw_point
draw_line
draw_polygon
draw_spline
draw_arrow
draw_image
draw_rectangle
draw_triangle
draw_ellipse
draw_circle
draw_text
draw_quiver
draw_graph
draw_axis
draw_grid
draw_fill
draw_plasma
draw_mandelbrot
draw_gaussian
draw_object3d
CImg的畫圖方法真的是非常多,每種方法都有2D和3D的重載,具體可以參考手冊。
CImg類的圖像處理方法
CImg類的圖像處理方法分兩種版本:一種是直接在自己的數據上計算和保存;另一種是返回一個計算后的CImg對象,自己的數據不會改變,這個版本以get_作為前綴并且總是const方法。
- //?填充圖像,其中的valx參數用于順序填充圖像,最多可以有15個。
- CImg<?T?>?&??fill?(const?T?val0,?const?T?val1,?...);
- //?以values指定的字符串來填充圖像,values格式參考上文的構造函數參數
- CImg<?T?>?&??fill?(const?char?*const?values,?const?bool?repeat_pattern)
- //?以values圖像里的值填充。
- CImg<?T?>?&??fill?(const?CImg<?t?>?&values,?const?bool?repeat_pattern=true)
相應的,有get_fill方法,返回填充后的新CImg對象。后面的方法同相也有get_方法,不再累述。
- //?只填充指定的yzv位置上的x軸的數據
- CImg<?T?>?&??fillX?(
- ????const?unsigned?int?y,
- ????const?unsigned?int?z,
- ????const?unsigned?int?v,
- ????const?int?a0,...);
當然,也有fillY,fillZ,fillV。
- //?線性規格化圖像,即把圖像中的所有元素數值線性放大或減小到a和b之間。
- CImg<?T?>?&??normalize?(const?T?a,?const?T?b)?
?
- //?把圖像中的所有元素數值大小限制在a和b之間,若有超出,則直接限制在邊界上。
- CImg<?T?>?&??cut?(const?T?a,?const?T?b);
?
- //?把圖像像素數據數字化到n級上,即圖像元素數值從小到大被分成n個級別。(類似AD轉換)
- CImg<?T?>?&??quantize?(const?unsigned?int?n,?const?bool?keep_range=true)
?
- //?閾值化圖像,小于value的為0,大于value的為1。
- //?若soft=true,則小于value元素加上value,大于value的元素減去value。
- //?strict決定比較時使用<操作還是<=操作。
- CImg<?T?>?&??threshold?(const?T?value,?const?bool?soft=false,?const?bool?strict=false)?
?
- //?旋轉圖像,以cx,cy指定點為中心,旋轉angle度,放大zoom倍。
- CImg<?T?>?&??rotate?(
- ????const?float?angle,
- ????const?float?cx,
- ????const?float?cy,
- ????const?float?zoom,
- ????const?unsigned?int?border_conditions=3,
- ????const?unsigned?int?interpolation=1);
參數border_conditions指定怎樣處理邊界外的值,0-邊界以外以0值填充,1-重復邊界點的值,2-重復圖像
參數interpolation指定采用何種插值方法,0-不插值,1-線性插值,2-三次插值
- //?改變大小
- CImg<?T?>?&??resize?(
- ????const?int?pdx,
- ????const?int?pdy=-100,
- ????const?int?pdz=-100,
- ????const?int?pdv=-100,
- ????const?int?interpolation_type=1,
- ????const?int?border_condition=-1,
- ????const?bool?center=false)
改變圖像到指定大小,當pdx,pdy,pdz或pdv<0時,使用百分比。interpolation_type指定插值方法,分別是:
-1 = 不插值 : 圖像直接按大小剪切
0 = 不插值 : 多余空間依據border_condition決定。
1 = 臨近點插值。
2 = 移動平均數插值。
3 = 線性插值。
4 = 刪格插值。
5 = 雙三次插值。
另外,還有幾個優化的resize版本:
- //?優化的縮小至原來的1/2
- CImg<?T?>?&??resize_halfXY?()
- //?優化的放大至原來的2倍
- CImg<?T?>?&??resize_doubleXY?()
- //?優化的放大至原來的3倍
- CImg<?T?>?&??resize_tripleXY?()
?
- //?扭曲圖像,由參數warp中相同位置的數據決定該位置元素的去向。
- CImg<?T?>?&??warp?(
- ????const?CImg<?t?>?&warp,
- ????const?bool?relative=false,
- ????const?bool?interpolation=true,
- ????const?unsigned?int?border_conditions=0)?
參數warp在這里只是一個容器(不要把它看成圖像)的作用,其x,y,z點上的數據決定了當前圖像x,y,z點上元素的新位置,這個新位置由warp的x,y,z點上的v軸數據給出。如果warp的v軸長度是1時,當前圖像元素只會在x軸上移動。如果warp的v軸長度是2時,當前圖像元素在x,y軸上移動...relative=ture時,表示wrap中的數據是相對位置。
- //?按指定軸鏡像,axis可以是'x','y','z','v'
- CImg<?T?>?&??mirror?(const?char?axis);
?
- //?偏移圖像
- CImg<?T?>?&??translate?(
- ????const?int?deltax,
- ????const?int?deltay=0,
- ????const?int?deltaz=0,
- ????const?int?deltav=0,
- ????const?int?border_condition=0)
?
- //?取原圖像中的一塊子圖
- CImg<?T?>?&??crop?(
- ????const?int?x0,?const?int?y0,?const?int?z0,?const?int?v0,
- ????const?int?x1,?const?int?y1,?const?int?z1,?const?int?v1,
- ????const?bool?border_condition=false)?
crop方法還有其它的版本,分別是省略v軸,z軸和y軸的版本。
- //?把3D圖像轉成2D視圖。
- CImg<?T?>?&??projections2d?(
- ????const?unsigned?int?x0,?const?unsigned?int?y0,?const?unsigned?int?z0,
- ????const?int?dx=-100,?const?int?dy=-100,?const?int?dz=-100);
最后,下面的這些方法提供類似Photoshop的濾鏡功能,強啊~~:
noise 噪聲
deriche Canny-Deriche算法
blur 模糊
blur_anisotropic 各向異性模糊
blur_bilateral 對稱模糊
blur_patch 面片模糊
blur_median 中值模糊
sharpen 尖銳
haar 小波分析
...還有好多
看了上面的介紹,我想大家肯定對CImg的強大能力有了初步的了解(要知道上面列出的方法只是CImg方法中的冰山一角,而且更強的是CImg庫還能通過指定Plugin宏的方式插入新的方法,當CImg自帶的方法不能滿足我們的要求時,也許已經有人提供了對應的插件了),下次我們開始學習CImg的具體使用吧^_^
最后放上前面說的CImg的Doxygen手冊,猛擊這里下載。
總結
- 上一篇: CImg库中部分函数的作用和用法
- 下一篇: CImg库中CImg,CImgList,