CImg中文手册3

现在开始一个基于CImg的程序的例子;演示了如何使用CImg来加载、创建图像实例;以及如何显示图像和处理鼠标事件;下面的程序实现了如下功能:加载一张彩色图像“lena.jpg”,然后执行平滑操作,并将它显示在窗口上,创建事件循环并在鼠标点击图片的时候,在另一个窗口绘制图片被点击对应的这一行像素点的R、G、B像素值统计信息,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;
  }

示例图(略)
下面是对上述代码的详细解释:

  • #include "CImg.h"
    包含CImg的唯一头文件;
  • using namespace cimg_library;
    使用CImg的主命名空间
  • int main() {
    定义主函数
  • CImg<unsigned char> image("lena.jpg"), visu(500,400,1,3,0);
    创建两个unsigned char类型的图像对象;第一个图像对象从磁盘上的lena.jpg文件读取而来;此处lena.jpg和当前可执行文件放在同一个目录;同时ImageMagick必须已经安装,用来读取JPG格式的文件;
    第二个图片对象visu初始化成一个5004001(2D图像)的彩色图像(有RGB三个通道);最后一个参数表示图像visu所有像素全部置为0;因此visu将被初始化为纯黑色;
  • const unsigned char red[3]={255,0,0}, green[3]={0,255,0}, blue[3]={0,0,255};
    此处以数组的方式定义了三种不同的unsigned char类型的颜色变量;这些颜色变量将被用于接下来的绘制;
  • image.blur(2.5);
    对图像进行平滑;使用方差为2.5的高斯平滑函数来平滑图像;注意,很多CImg的函数有两个版本;不带get_前缀的函数(例如blur)是直接处理传入的图像对象;带get_前缀的函数(例如get_blur)会将处理后的图像对象返回(会花费更长的时间,因为需要额外的像素值拷贝操作,通过image = image.get_blur(2.5);这样的方式调用);
  • CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile");
    创建两个显示窗口,第一个用来显示输入图像,第二个显示visu对象,显示相对应的信息;
    默认情况下,CImg显示对象将处理用户鼠标和键盘事件;同时在Windows上,能够创建全屏显示窗口;
  • while (!main_disp.closed && !draw_disp.closed) {
    进入事件循环,当显示窗口关闭时,将退出事件循环;
  • main_disp.wait();
    在事件循环中等待接收main_disp的鼠标和键盘事件;
  • if (main_disp.button && main_disp.mouse_y>=0) {
    检测鼠标是否点击在图像显示区域,鼠标事件可以区分不同类型的鼠标点击事件,但是在此并不需要区分;
  • const int y = main_disp.mouse_y;
    获取被点击的图像的y座标;
  • visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,0,256,0);
    该行演示了大部分CImg类函数都支持的链式调用处理;第一个函数fill(0)将图像所有像素值设为0,然后将visu对象返回,从而可以进行链式调用draw_graph()函数;draw_graph()函数在图像中绘制一个多边形;多边形数据来自image.get_crop函数的返回值,此处get_crop返回image对象的R通道第y行的数据。注意:CImg<T>对于彩色图像是4维数据;R,G,B通道的数据通过设置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); **
    绘制鼠标点击行处原始图像的G通道信息;
  • visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,0,256,0).display(draw_disp);
    同上行,绘制鼠标点击行处原始图像的B通道信息;
  • ...till the end
    后续代码,无需解释。
    如上,使用CImg库能够写出精简直观的代码,同时写出的代码能够正常运行在Windows和Unix系统中;
    CImg库提供了一系列的示例程序在源码的examples目录下,展示了更多精简的CImg库方法使用示例;总能找到你需要示例;
    同时,CImg_test.cpp文件包含了很多简短而又多样化的关于CImg的使用示例;在该文件中,所有的CImg库中的类都被使用到,并且这些代码都非常易读。建议从该文件开始学习如何使用CImg。

CImg图形绘制函数

从CImg的HTML文档里能找到详细的图形绘制函数列表和用法;使用前需要注意的几点:

  • 图形绘制函数会直接绘制在传入参数中,并且会将传入的图像实例返回,从而实现图形绘制函数的链式调用(后面有示例用法);绘制函数通过发生在2D图像上,但是也可以进行3D图像的绘制;
  • 绘制的时候通常需要一个颜色参数,颜色参数必须以C数组的形式定义。

使用CImg访问和操作图像像素

CImg定义了一系列宏来简化繁琐的for循环嵌套逐点访问和操作图像像素数据;使用CImg预定义的宏可以写出简洁的代码实现逐点访问和操作图像像素数据的功能(副作用是如果你不懂这些宏,基本看不懂使用CImg写出来代码);下面是这些宏的介绍,主要分为四类:

  • 逐点访问图像像素
    cimg_map(img,ptr,T): 该宏定义了使用类型为T的指针ptr最末尾像素到最开始像素依次访问img的像素数据,ptr指针每次指向图像像素数据;注意:
    • img必须是非空的cimg_library::CImg类实例变量,像素数据类型必须为T
    • ptr为T*类型的指针;
      该宏不经常使用,需要用到该宏的地方一般都可以用CImg的类函数实现,例如:
  CImg<float> img(320,200);
  cimg_map(img,ptr,float) { *ptr=0; }      // Equivalent to 'img.fill(0);'

cimg_mapoff(img,off): 该宏通过off访问像素数据,从图像起始到图像末尾;注意: off是内部循环变量;访问图像第一个像素位置时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项目中已有详细的中文入门PDF文档,所以后续不再翻译入门文档。CImg.h最新版本有5万8千行代码,有时间对CImg的具体函数进行介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容