現(xiàn)在開始一個基于CImg的程序的例子桥氏;演示了如何使用CImg來加載、創(chuàng)建圖像實例猛铅;以及如何顯示圖像和處理鼠標(biāo)事件字支;下面的程序?qū)崿F(xiàn)了如下功能:加載一張彩色圖像“l(fā)ena.jpg”,然后執(zhí)行平滑操作奸忽,并將它顯示在窗口上祥款,創(chuàng)建事件循環(huán)并在鼠標(biāo)點(diǎn)擊圖片的時候,在另一個窗口繪制圖片被點(diǎn)擊對應(yīng)的這一行像素點(diǎn)的R月杉、G、B像素值統(tǒng)計信息抠艾,so,let's go:
#include "CImg.h"
using namespace cimg_library;
int main() {
CImg<unsigned char> image("lena.jpg"), visu(500,400,1,3,0);
const unsigned char red[3]={255,0,0}, green[3]={0,255,0}, blue[3]={0,0,255};
image.blur(2.5);
CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile");
while (!main_disp.closed && !draw_disp.closed) {
main_disp.wait();
if (main_disp.button && main_disp.mouse_y>=0) {
const int y = main_disp.mouse_y;
visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,0,256,0);
visu.draw_graph(image.get_crop(0,y,0,1,image.dimx()-1,y,0,1),green,0,256,0);
visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,0,256,0).display(draw_disp);
}
}
return 0;
}
示例圖(略)
下面是對上述代碼的詳細(xì)解釋:
-
#include "CImg.h"
包含CImg的唯一頭文件苛萎; -
using namespace cimg_library;
使用CImg的主命名空間 -
int main() {
定義主函數(shù) -
CImg<unsigned char> image("lena.jpg"), visu(500,400,1,3,0);
創(chuàng)建兩個unsigned char
類型的圖像對象;第一個圖像對象從磁盤上的lena.jpg
文件讀取而來检号;此處lena.jpg
和當(dāng)前可執(zhí)行文件放在同一個目錄腌歉;同時ImageMagick
必須已經(jīng)安裝,用來讀取JPG格式的文件齐苛;
第二個圖片對象visu
初始化成一個5004001(2D圖像)的彩色圖像(有RGB三個通道)翘盖;最后一個參數(shù)表示圖像visu
所有像素全部置為0;因此visu
將被初始化為純黑色凹蜂; -
const unsigned char red[3]={255,0,0}, green[3]={0,255,0}, blue[3]={0,0,255};
此處以數(shù)組的方式定義了三種不同的unsigned char
類型的顏色變量馍驯;這些顏色變量將被用于接下來的繪制; -
image.blur(2.5);
對圖像進(jìn)行平滑玛痊;使用方差為2.5的高斯平滑函數(shù)來平滑圖像汰瘫;注意,很多CImg的函數(shù)有兩個版本擂煞;不帶get_前綴的函數(shù)(例如blur)是直接處理傳入的圖像對象混弥;帶get_前綴的函數(shù)(例如get_blur)會將處理后的圖像對象返回(會花費(fèi)更長的時間,因為需要額外的像素值拷貝操作对省,通過image = image.get_blur(2.5);
這樣的方式調(diào)用)蝗拿; -
CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile");
創(chuàng)建兩個顯示窗口晾捏,第一個用來顯示輸入圖像,第二個顯示visu
對象哀托,顯示相對應(yīng)的信息惦辛;
默認(rèn)情況下,CImg顯示對象將處理用戶鼠標(biāo)和鍵盤事件萤捆;同時在Windows上裙品,能夠創(chuàng)建全屏顯示窗口; -
while (!main_disp.closed && !draw_disp.closed) {
進(jìn)入事件循環(huán)俗或,當(dāng)顯示窗口關(guān)閉時市怎,將退出事件循環(huán); -
main_disp.wait();
在事件循環(huán)中等待接收main_disp
的鼠標(biāo)和鍵盤事件辛慰; -
if (main_disp.button && main_disp.mouse_y>=0) {
檢測鼠標(biāo)是否點(diǎn)擊在圖像顯示區(qū)域区匠,鼠標(biāo)事件可以區(qū)分不同類型的鼠標(biāo)點(diǎn)擊事件,但是在此并不需要區(qū)分帅腌; -
const int y = main_disp.mouse_y;
獲取被點(diǎn)擊的圖像的y座標(biāo)驰弄; -
visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,0,256,0);
該行演示了大部分CImg類函數(shù)都支持的鏈?zhǔn)秸{(diào)用處理;第一個函數(shù)fill(0)
將圖像所有像素值設(shè)為0速客,然后將visu對象返回戚篙,從而可以進(jìn)行鏈?zhǔn)秸{(diào)用draw_graph()
函數(shù);draw_graph()
函數(shù)在圖像中繪制一個多邊形溺职;多邊形數(shù)據(jù)來自image.get_crop函數(shù)的返回值岔擂,此處get_crop返回image對象的R通道第y行的數(shù)據(jù)。注意:CImg<T>
對于彩色圖像是4維數(shù)據(jù)浪耘;R乱灵,G,B通道的數(shù)據(jù)通過設(shè)置v=0,v=1,v=2獲取到七冲; - ** visu.draw_graph(image.get_crop(0,y,0,1,image.dimx()-1,y,0,1),green,0,256,0); **
繪制鼠標(biāo)點(diǎn)擊行處原始圖像的G通道信息痛倚; -
visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,0,256,0).display(draw_disp);
同上行,繪制鼠標(biāo)點(diǎn)擊行處原始圖像的B通道信息澜躺; -
...till the end
后續(xù)代碼蝉稳,無需解釋。
如上苗踪,使用CImg
庫能夠?qū)懗鼍喼庇^的代碼颠区,同時寫出的代碼能夠正常運(yùn)行在Windows和Unix系統(tǒng)中;
CImg庫提供了一系列的示例程序在源碼的examples
目錄下通铲,展示了更多精簡的CImg庫方法使用示例毕莱;總能找到你需要示例;
同時,CImg_test.cpp
文件包含了很多簡短而又多樣化的關(guān)于CImg的使用示例朋截;在該文件中蛹稍,所有的CImg庫中的類都被使用到,并且這些代碼都非常易讀部服。建議從該文件開始學(xué)習(xí)如何使用CImg唆姐。
CImg圖形繪制函數(shù)
從CImg的HTML文檔里能找到詳細(xì)的圖形繪制函數(shù)列表和用法;使用前需要注意的幾點(diǎn):
- 圖形繪制函數(shù)會直接繪制在傳入?yún)?shù)中廓八,并且會將傳入的圖像實例返回奉芦,從而實現(xiàn)圖形繪制函數(shù)的鏈?zhǔn)秸{(diào)用(后面有示例用法);繪制函數(shù)通過發(fā)生在2D圖像上剧蹂,但是也可以進(jìn)行3D圖像的繪制声功;
- 繪制的時候通常需要一個顏色參數(shù),顏色參數(shù)必須以C數(shù)組的形式定義宠叼。
使用CImg訪問和操作圖像像素
CImg定義了一系列宏來簡化繁瑣的for循環(huán)嵌套逐點(diǎn)訪問和操作圖像像素數(shù)據(jù)先巴;使用CImg預(yù)定義的宏可以寫出簡潔的代碼實現(xiàn)逐點(diǎn)訪問和操作圖像像素數(shù)據(jù)的功能(副作用是如果你不懂這些宏,基本看不懂使用CImg寫出來代碼)冒冬;下面是這些宏的介紹伸蚯,主要分為四類:
- 逐點(diǎn)訪問圖像像素
cimg_map(img,ptr,T)
: 該宏定義了使用類型為T
的指針ptr
從最末尾像素到最開始像素依次訪問img
的像素數(shù)據(jù),ptr指針每次指向圖像像素數(shù)據(jù)简烤;注意:-
img
必須是非空的cimg_library::CImg
類實例變量剂邮,像素數(shù)據(jù)類型必須為T
; - ptr為T*類型的指針横侦;
該宏不經(jīng)常使用抗斤,需要用到該宏的地方一般都可以用CImg的類函數(shù)實現(xiàn),例如:
-
CImg<float> img(320,200);
cimg_map(img,ptr,float) { *ptr=0; } // Equivalent to 'img.fill(0);'
cimg_mapoff(img,off)
: 該宏通過off
訪問像素數(shù)據(jù)丈咐,從圖像起始到圖像末尾;注意: off
是內(nèi)部循環(huán)變量龙宏;訪問圖像第一個像素位置時off=0棵逊,訪問到圖像最后一個像素位置時,off=img.size()-1银酗。示例:
CImg<float> img(320,200);
cimg_mapoff(img,off) { img[off]=0; } // Equivalent to 'img.fill(0);'
Github上CImg項目中已有詳細(xì)的中文入門PDF文檔辆影,所以后續(xù)不再翻譯入門文檔。CImg.h最新版本有5萬8千行代碼黍特,有時間對CImg的具體函數(shù)進(jìn)行介紹蛙讥。