本文以制作colorbar为例展示AI辅助的ImageJ编程实践
当我们使用一些除了红绿蓝黄之外不太常见的伪彩来展示图片时,通常需要附加一个 colorbar。这个 colorbar 也叫做颜色查找表 (look up table, LUT),在 ImageJ 可以很方便地点击 Image > Color > Show LUT 查看:
可以看到,不同的灰度值通过什么颜色,就是通过 LUT 中定义的映射关系来决定的。有的 LUT 是线性映射关系,能够忠实地反映信号强度地变化;有的 LUT 是非线性的映射关系,主要是为了对感兴趣的信号强度区间进行强调。如果我们要在文章中放 colorbar,则可以对该窗口中展示的colorbar进行截图,复制到作图软件中。
事实上,我们也可以准备一个渐变的灰度图,然后 apply LUT 直接生成 colorbar。要制作一张数值从 0 依次增加到 255 的灰度图(以 8-bit为例),这个事情怎么完成呢?我觉得这是一个很好的入门级编程题目,因为需要应用到很多基础的编程知识,比如使用for循环遍历像素。
需求已经明确,接下来就是分析拆解。
我们要制作一个 colorbar,有哪些输入变量呢?我们可以默认 8-bit 位图,默认精度为 1,默认是竖着的 colorbar,那么高度就是 256。colorbar一般是长条形,所以我们可以给一个合适的宽度,比如20。然后 colorbar 的渐变一般是从下往上数值递增。以上都是控制一个 colorbar 的变量。
然后是这个程序的基本过程:创建一个指定尺寸的空白图像,然后遍历像素位进行赋值。这里就包括了三个关键问题:
-
创建空白图像的命令是什么?
-
遍历使用的语法是怎样的?
-
对指定位置的像素进行赋值是什么命令?
一般来说,所有的手动操作都有对应的命令,所以创建空白图像可以开启 recorder 获得相应的命令。但是像遍历语法,像素赋值这种都属于 Scripting 部分,需要到 ImageJ Developer 的网页上查询语法(Macro Language)和内置函数(Built-in Functions)。
newImage("cmap", "8-bit black", 512, 512, 1);// 创建一个名称为 cmap 的 8-bit,黑色背景的图像,width=512, height=512, slice=1setPixel(x, y, value);//Stores _value_ at location (x, y) of the current image. The screen is updated when the macro exits or call updateDisplay() to have it updated immediately.for (i=0; i<10; i++) { doSomething(s);}// 很经典的for循环语法好的,准备完毕,接下来整理下我们要做的事情,然后咨询 AI 助手(llama3.1:70b,因为 ImageJ Macro比较小众且多为英文资料,所以询问国外的AI更合适)先生成一段代码,然后再改一改。
使用 ImageJ Macro 制作一个 colormap 图像。这个图像的宽度为 20, 高度为 256 像素。图像中每一行像素值从下往上从0到255依次递增,图像每一列的像素值保持一致。
看着应该没什么问题,我们点击 ImageJ 窗口,按快捷键 Ctrl+Shift+N 打开 ImageJ 的编程窗口,然后复制进去,点击 Run 运行看一下:
基本符合要求,关键命令都是正确的,说明现在大语言模型是真的强。但是它这个像素值是从上往下递增的,然后代码把变量都写死了,不利于我们对宽度进行调整。所以可以再改一下,得到最终的代码如下:
width = 20;// 用户可修改宽度height = 256;newImage("Colormap", "8-bit black", width, height, 1);for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { setPixel(j, i, height-1-i); }}基于大语言模型的AI对于编程的帮助确实很大,可以帮我们快速生成完成度较高的草稿,然后我们再稍稍改改就可以了。但是需要注意:
-
编程的关键是分析和拆解需求,这个仍然需要人来完成。这个做好了,才能给出合适的 prompt,才能得到合适的答案。
-
AI给出的答案,要进行检查测试,这同样需要掌握关键信息,所以有时候还是要去查原始文档。
最后,关于 ImageJ 编程,虽然只是宏语言,但相对完整地覆盖了面向过程编程各种基本概念,甚至能制作简单的用户界面。我觉得对于有相应的图像分析需求的同学来说,是比 python 更简单实用的编程入门语言。
而编程这件事情本身,就是为了提高效率,因为程序能够将 for循环 和 if条件判断组合起来,自动地完成大量任务。此外,程序地操作,可以非常精准到某个像素位置,这个也是人难以办到的。所以我认为学习一下编程是非常必要的。
不过编程入门之后最容易犯的一个毛病是为了炫技而炫技。这个要提前打好预防针。关于是否要通过编程解决问题的简单标准就是:
-
预计编程所花费的时间是否小于不编程的十分之一?
-
这个程序后续是否可能会被再次使用?
为啥是十分之一呢?因为程序要 test & debug,这个比较费时间,我就经常出现觉得只要花半个小时实际却花了两个小时才搞定的编程。所以千万不要乐观估计自己对编程要花费的时间。