选择save(保存)项时,将从IDL获取当前颜色表,然后用DIALOG_WRITE_IMAGE应用程序将图像写入标准格式的图像文件,默认设置是存为TIFF文件。记得要为顶层基底的组件标识设置DIALOG_PARENT关键字,在这里必须这样做,因为它会将DIALOG_WRITE_IMAGE联结到IMAGEPROCESSOR应用程序。若无此关键字,DIALOG_WRITE_IMAGE将独立于IMAGEPROCESSOR运行,也就是说,一经调用它就不再跟IMAGEPROCESSOR有信息交流了。
选择open(打开)项时,就需要一组复杂些的指令了。下面代码被分为了几块,每块后面紧跟对此段代码的简单解释。 imageprocessor_file
'open': begin
; Read an image. If reading s cancelled, then return.
Ok = dialog_read_image(image=new_image, path=!dir, $ red=r, green=g, blue=b, dialog_paront=event.top) If ok eq 0 then return
用DIALOG_READ_IMAGE应用程序打开并读入一幅图像文件。为有名变量new_image设置了IMAGE关键字以便获取在DIALOG_READ_IMAGE中选取的图像文件。存在颜色向量时为其设置RED,GREEN,及 BLUE关键字。与使用DIALOG_WRITE_IMAGE的情况类似,也要为顶层基底标识设置DIALOG_PARENT关键字,这样就能保持DIALOG_READ_IMAGE和IMAGEPROCESSOR的联系。若未设置此关键字则不会有任何图像数据传回IMAGEPROCESSOR。若在DIALOG_READ_IMAGE中成功的选中了一幅图像,返回1,否则返回0。若未选择任何图像,则会退出事件处理器并将控制权返回到XMANAGER。 imageprocessor_file
; Test the dimensions of the new image. isize = size(new_image, /structure) if isize.n_dimensions ne 2 then begin imageprocessor_error return endif
检查new_image的维数,若其维数超过2,则拒绝此文件并返回到XMANAGER。此处我们假设不允许按分解模式查看图像,但如前所述,只要多加一点代码就可去掉这种限制。注意到重新使用了IMAGEPROCESSOR_ERROR例程。 imageprocessor_file
; Test color table information for the new image, if present. if n_elements(r) le I then begin loadct, 0, /silent tvlct, r, g, b, /get endif else tvlct, r, g, b
用TVLCT测试一下是否已读取并加载了new_image的颜色向量。若未加载,则加载IDL的0颜色表(灰度颜色表)。 imageprocessor_file
; Update the state pointer with info for the new image.
36
(*pstate).new_colors = [ [r], [g], [b] ] (*pstate).image = new_image (*pstate).copy = new_image (*pstate).curr_x = 0 (*pstate).curr_y = 0
(*pstate).draw_xsize = isize.dimensions[0] (*pstate).draw_ysize = isize.dimensions[1]
因为已经为IMAGEPROCESSOR读入了一幅新图像,所以需要更新state指针中的信息。这些信息将用于更新绘制组件的大小,重置滚动条的位置。
imageprocessor_file
; Resize the draw widget based on the new image size. widget_control, (*pstate). wdraw, $ draw_xsize=(*pstate).draw_xsize, $ draw_ysize=(*pstate).draw_ysize
widget_control, (*pstate). wdraw, set_draw_view=[0,0]
; Make a new pixmap window & display the image. imageprocessor_setpixmap, pstate imageprocessor_dodisplay, pstate end endcase end
最后这两段代码是选择Open项时的结束部分,也是事件处理器IMAGEPROCESSOR_FILE的最后部分。此处使用了WIDGET_CONTROL改变绘制组件的尺寸以适应新图像并将滚动条设置到其最小位置。调用IMAGEPROCESSOR_SETPIXMAP时销毁旧的pixmap窗口,生成一个新的pixmap并在其内显示出新图像。最后在IMAGEPROCESSOR_DODISPLAY中,使用设备拷贝技术将图像由内存中的pixmap窗口拷贝到绘制窗口。
到此为止就完成了IMAGEPROCESSOR_FILE的代码编写,为了测试新添加的代码,保存,编译并调用IMAGEPROCESSOR。试着用File下拉菜单中的Open项读取一幅图像,例如,试着从training目录或examples/data目录中读取一个图像文件。也可试着将IMAGEPROCESSOR中的图像文件保存到你自己的某个目录中。
图像处理工具 最后,我们要为图像处理工具的事件处理器编写代码。在定义模块中找出创建wtoolbase(图像处理工具的基底)的指令,用EVENT_PRO关键字为其指定一个事件处理器。 Imageprocessor
;make a base with controls for image processing. wtoolsbase=widget_base(wtop,/column,$
event_pro=?imageprocessor_tools?)
现在再用同样的方式将此事件处理器作为一个过程与其他的事件处理器组合起来。 imageprocessor_tools
pro imageprocessor_tools, event compile_opt idl2
37
; Retrieve the state pointer &the user value of the widget that ; generated the event.
widget_control, event.top, get_uvalue=pstate widget_control, event.id, get_uvalue=uval
; If there's no image to process, then return. if n_elements(*(*pstate).image) eq 0 then return
与其他事件处理器一样,从顶层基底用户值获取state(状态)。此外还应获取生成事件的组件的用户值,这些用户值都是用于区分生成事件组件的字符串。
下面为图像处理工具编写代码。代码中包含一个CASE结构,其选项是触发事件组件的用户值。
imageprocessor_tools
; process the image according to which control was selected. Case uval of
' smooth': *(*pstate). image = amooth(*(*pstate).image, 5, /edge) 'umask': *(*pstate).image = *(*pstate).image - $ smooth(*(*pstate).image, 5, /edge)
'sobel': *(*pstate).image = sobel(*(*pstate).image) 'roberts': *(*pstate).image =roberts(*(*pstate).image) 'median': *(*pstate).image =madian(*(*pstate).image, 5) 'negative':begin tvlct, r, g, b, /get
tvlct, -(r+1B), -(g+1B), -(b+1B) end
'ahisteq': *(*pstate).image =adapt_hist_equal(*(*pstate).image) 'thresh': *(*pstate).image = bytscl(*(*pstate).copy gt event.value) 'scale': *(*pstate).image = *(*pstate).copy > event.value 'bscale': *(*pstate).image = bytscl(*(*pstate).image) 'loadct': xloadct, /modal, group=event.top 'revert':begin
tvlat, *(*pstate).new_colors
*(*pstate).image = *(*pstate).copy end endcase
按顺序,上面各项将执行如下操作: ·Smooth:
·Unsharp Mask:
·Sobel:此函数用一个微分过滤器和Sobel运算符锐化图像边缘,Sobel运算符用于计算水平和垂直差。 · · ·
38
· · · · · · ·
p73表
最后写出显示经处理后图像的代码。 imageprocessor_tools
; Refresh the pixmap &display the image. imageprocessor_setpixmap, pstate, /update imageprocessor_dodisplay, pstate end
处理后的图像将显示在pixmap窗口中,然后再用设备拷贝技术将其复制到绘制组件窗口。 此时结束了IMAGEPROCESSOR_TOOLS过程并完成了IMAGEPROCESSOR应用程序。保存、编译并运行IMAGEPROCESSOR以测试新添加的代码。加载一幅图像并试着使用各种图像处理工具。图6-4所示的是对endocell.jpg中的一幅细胞图像取负并进行适应性直方图平直化后的效果。试试PROCESSED关键字,例如: IDL>imageprocessor,cells,processed=pcells
在处理此图像后,退出IMAGEPROCESSOR并查看结果。 IDL>tv,*pcells
注意到变量pcells是一个指针引用,记得一定要在结束前将其释放。
39
图6-4
40