在掌握了RGB与HSB颜色空间转换后,我们可以指定任意颜色作为伪彩。
我们知道一个成像数据可能有多个通道,但是一个通道如果使用最简单的单色伪彩来表示,通常就是选择 RGB 中一个或者两个通道来进行线性映射:
-
R:红色伪彩
-
G:绿色伪彩
-
B:蓝色伪彩
-
RG:黄色伪彩
-
RB:粉色伪彩(Magenta)
-
GB:青色伪彩(Cyan)
如果我们做多色成像时,通道数量超过 6,其它通道也想使用单色伪彩来表示,该怎么办呢?这个时候可以通过指定 HSB 中任意一个色度,然后把信号的强度,映射为颜色的亮度或者对比度。
首先可以利用 HSB颜色空间来绘制一个 colormap,看看颜色的线性分布情况:
这里我们其实按照 Hue、Saturation、Brightness 三个分量,分别线性采样,看看颜色的分布。图像从左到右横轴是 Hue 从 0 到 360,可以很明显地看到颜色0的分区。从上到下是 Brightness,亮度从0-255;然后不同的 slice 从前往后,对应的色彩饱和度不断增大。其主体逻辑代码如下:
newImage("map","RGB white",360,255,10);for(k=0;k<10;k++){ setSlice(k+1); sat=(k+1)/10; for(i=0;i<360;i++){ hue=i; for(j=0;j<255;j++){ bri=j; hsb = newArray(hue,sat,bri); rgb = HSB2RGB(hsb); // 具体函数代码见下方 setColor(rgb[0],rgb[1],rgb[2]); fillRect(i,j,1,1); } }}然后我们找一个单通道荧光图像,尝试使用任意颜色:
接下来放上主要逻辑代码:
imgtype = bitDepth();if (imgtype!=24){ exit("Error: Input is not RGB image.");}
hues = newArray(30, 80, 130, 180, 230, 280, 330);n = lengthOf(hues);
for (i = 0; i < n; i++) { hue = hues[i]; main(hue);}
/* --- 自定义函数 --- */function main(hue){ w = getWidth(); h = getHeight(); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { hsb = getHSB(i,j); v = hsb[2]; // 提取原图像亮度 if (v>0){ hsb = newArray(hue, 1, v); // 保持原图像亮度,固定饱和度,修改色度 rgb = HSB2RGB(hsb); setColor(rgb[0], rgb[1], rgb[2]); fillRect(i, j, 1, 1); } } }}这里整理一下RGB和HSB颜色空间互换和取值的函数:
function getHSB(x,y){ rgb = getRGB(x,y); HSB = RGB2HSB(rgb); return HSB;}
function RGB2HSB(rgb){ r = rgb[0]; // red g = rgb[1]; // green b = rgb[2]; // blue Array.getStatistics(rgb, min, max, mean, stdDev); if (max==min) h = NaN; //h(0-360) else if (max==r && g>=b) h = 60*(g-b)/(max-min); else if (max==r && g<b) h = 60*(g-b)/(max-min)+360; else if (max==g) h = 60*(b-r)/(max-min)+120; else if (max==b) h = 60*(r-g)/(max-min)+240; if (max==0) s = 0; //s(0-1) else s = 1-min/max; b = max; //b(0-255) HSB = newArray(h,s,b); return HSB;}
function getRGB(x,y){ RGB = newArray(3); v = getPixel(x,y); RGB[0] = (v>>16)&0xff; // extract red byte (bits 23-17) RGB[1] = (v>>8)&0xff; // extract green byte (bits 15-8) RGB[2] = v&0xff; // extract blue byte (bits 7-0) return RGB;}
function HSB2RGB(hsb){ h = hsb[0]; //0~360 s = hsb[1]; //0~1 v = hsb[2]; //0~255
hi = floor(h/60); f = h/60-hi; p = v*(1-s); q = v*(1-f*s); t = v*(1-(1-f)*s);
if (hi==0) rgb=newArray(v,t,p); if (hi==1) rgb=newArray(q,v,p); if (hi==2) rgb=newArray(p,v,t); if (hi==3) rgb=newArray(p,q,v); if (hi==4) rgb=newArray(t,p,v); if (hi==5) rgb=newArray(v,p,q);
return rgb;}另外加上一段网上收集的输入波长输出颜色的转换 ImageJ Macro代码:
/* * This script implements the wavelength to RGB conversion * illustrated at http://www.physics.sfasu.edu/astro/color/ * by linear approximation of the curves. */function setColorByWavelength(wavelength) { // These values will be between 0 and 1 red = green = blue = 0; if (wavelength < 380 || wavelength > 780) abort("Only wavelengths between 380 and 780 are supported"); else if (wavelength <= 440) { red = (440 - wavelength) / (440 - 380); blue = 1; } else if (wavelength <= 490) { green = (wavelength - 440) / (490 - 440); blue = 1; } else if (wavelength <= 510) { green = 1; blue = (510 - wavelength) / (510 - 490); } else if (wavelength <= 580) { red = (wavelength - 510) / (580 - 510); green = 1; } else if (wavelength <= 645) { red = 1; green = (645 - wavelength) / (645 - 580); } else red = 1; intensity = 1; if (wavelength > 700) intensity = 0.3 + 0.7 * (780 - wavelength) / (780 - 700); else if (wavelength < 420) intensity = 0.3 + 0.7 * (wavelength - 380) / (420 - 380); red *= intensity; green *= intensity; blue *= intensity; // assuming gamma == 1 setForegroundColor(red * 255, green * 255, blue * 255);}
wavelength = getNumber("Wavelength", 480);setColorByWavelength(wavelength);