有一段时间没有写代码跑程序了
再来看看以前的东西,简直就是头大
于是用了大半天的时间,来搞代码美化并重新debug
总结了一些经验如下:
- 好的工具很重要,我的用是sublime(Docblockr插件),快速插入函数注释
- 明确函数名命名规则,驼峰命名法,前面是动作后面是对象,如findMaxima(寻找极大值点)
- 明确变量命名规则,使用下划线如maxima_noise(注意从属关系)或驼峰命名法如nPoints
- 代码模块清晰:先是程序说明,然后是全局参数(方便调试),然后是函数集,然后是debug区域
效果如下:
/*
* ### 通用版暗场成像数据处理程序pHunter ###
*
* Description:该程序可以对暗场细胞内纳米金纳米银成像结果进行分析,
* 获得纳米粒子的位置,数量和聚集状态信息
* Author: Xie.XD
* Date: 2018-8-8
*
* # 数据要求
* 1. 暗场显微镜下同一视野,采集两张图像,先采集一张高曝光(>=50 ms),
* 后采集一张低曝光(<=10 ms)
* 2. 图像格式应当为(像素偏移4*4:4080*3072 pixels^2)
* 3. 将同组实验采集到的多个视野的图片放到同一个文件夹下
*
* # 数据输入
* 1. 选择包含单个实验组的所有照片的文件夹
* 2. 如果是从未分析过的数据,先调用divideFiles进行分组,则会打开high和low两个stack
* 2. 单击高曝光(high)的图像,再调用readRoi圈选细胞roi
*
* # 参数调试
* 1. 选取细胞内少量粒子光斑,选择能容纳该粒子光斑的15*15矩形区域,获得单粒子截图
* 2. 对粒子光斑判断结果进行校验,调整saturationT的值以达到较好识别效果
* 3. 调试完成后,将debug开关全部改为false
*
* # 结果导出
* 1. roi记录保存为zip
* 2. 单细胞统计数据打印在Log窗口
*/
/**
* 重要的全局参数
*/
maxima_noise = 20;
brightnessT = 17;
saturationT = 180; //高曝光图像180,低曝光100
pixelCountRatio = 0.5;
debugging = newArray(false,false); //debug开关
/**
* [findMaxima description]
* 调用imageJ>Find Maxima寻找所有maxima点并返回其坐标
* @param noise int
* @return array
*/
function findMaxima(noise){
run("Find Maxima...", "noise="+noise+" output=List");
selectWindow("Results");
num = nResults;
loc = newArray(2*num);
for (j=0;j<num;j++){
loc[2*j] = getResult("X",j);
loc[2*j+1] = getResult("Y",j);
}
run("Close");
return loc;
}
/**
* [chooseParticle description]
* @return 返回鼠标选中点的坐标
*/
function chooseParticle(){
leftButton = 16;
flags = 0;
while(flags&leftButton == 0) getCursorLoc(x,y,z,flags);
showMessage("Mark Particle Center:"+x+","+y);
ans = newArray(x,y);
return ans;
}
/**
* [markParticle description]
* @param img 图像窗口句柄
* @param x 粒子横坐标
* @param y 粒子纵坐标
* @param type 粒子类型
* @return 执行动作,在图像上做标记
*/
function markParticle(img,x,y,type){
d = 7;
selectWindow(img);
if (type=="blue") setColor(0,0,255);
else if (type=="green") setColor(0,255,0);
else if (type=="yellow") setColor(255,255,0);
else if (type=="noise") setColor(255,255,255);
else setColor(255,0,255);
fillRect(x+d,y,3,3);
}
/**
* [cropParticle description]
* @param x [description]
* @param y [description]
* @return a 15*15 or smaller particle image
*/
function cropParticle(x,y){
s = 7;
w = getWidth();
h = getHeight();
while (x<s||y<s||x>w-s||y>h-s) s=s-1;
makeRectangle(x-s,y-s,2*s+1,2*s+1);
run("Duplicate...","title=particle");
particle = getTitle();
return particle;
}
/**
* [getParticleColor description]
* @param x [description]
* @param y [description]
* @return 获得粒子光斑整体的颜色特征,返回hsb
*/
function getParticleColor(x,y){
img = getTitle();
particle = cropParticle(x,y);
wp = getWidth();
hp = getHeight();
run("HSB Stack"); //将particle变成HSB stack
setSlice(3);
bri = getPixel(wp/2,hp/2); //亮度取中央
hue = 0;
sat = 0;
briCount = 0+(1e-6);
pixelCount = 0+(1e-6); //避免除以0的情况导致程序崩溃
for(i=0;i<wp;i++){
for(j=0;j<hp;j++){
setSlice(3);
b = getPixel(i,j);
if(b>brightnessT){//只在亮的地方找
setSlice(2);
s = getPixel(i,j);
briCount ++;
if(s>saturationT){//只在颜色好辨别的地方找
setSlice(1);
h = getPixel(i,j);
pixelCount ++;
hue = hue+h;
sat = sat+s;
}
}
}
}
if (pixelCount/briCount>pixelCountRatio){//有颜色的占有亮度的较多才算
hue = hue/pixelCount;
sat = sat/pixelCount;
}
else if (bri==255 && (pixelCount/briCount)>(pixelCountRatio-0.15)){ //中央过曝
hue = hue/pixelCount;
sat = sat/pixelCount;
}
else {
hue = NaN;
sat = NaN;
}
HSB = newArray(hue,sat,bri);
selectWindow(particle);
close();
selectWindow(img);
return HSB;
}
/**
* [judgeColor description]
* 通过hue的值来判断颜色类型
* @param hue int
* @return string
*/
function judgeColor(hue){
if (hue>0 && hue<15) ans = "red";
else if (hue>15 && hue<=30) ans = "orange";
else if (hue>30 && hue<=60) ans = "yellow";
else if (hue>60 && hue<=120) ans = "green";
else if (hue>=140 && hue<=190) ans = "blue";
else if (hue>200 && hue<=220) ans = "purple";
else ans = "noise";
return ans;
}
/**
* [getParticleType description]
* @param img [description]
* @param x [description]
* @param y [description]
* @return type string
*/
function getParticleType(img,x,y){
selectWindow(img);
hsb = getParticleColor(x,y);
hue = hsb[0];
sat = hsb[1];
bri = hsb[2];
if (bri==255){
if (isNaN(hue)) type = "white";
else type = judgeColor(hue);
}
else if (!isNaN(hue)) type = judgeColor(hue);
else type = "noise";
return type;
}
/**
* debug测试区域
*/
if (debugging[0]){//单点函数测试
showMessage("下面进行参数校正,请单击单个粒子光斑");
img = getTitle();
loc = chooseParticle();
x = loc[0];
y = loc[1];
type = getParticleType(img,x,y);
showMessage(type);
}
if (!debugging[0]){//增加细胞面积计算
img = getTitle();
if(getBoolean("请确认stack已打开并且roi管理器列表不为空!")){
nCells = roiManager("count");
setBatchMode(true);
class_name = newArray("cell","blue","green","yellow","white");
Array.print(class_name);
for (k=0;k<nCells;k++){
roiManager("Select", k);
getStatistics(area);
loc = findMaxima(maxima_noise);
nPoints = lengthOf(loc)/2;
class_count = newArray(5);
class_count[0] = floor(area*pow(0.03578,2)); //修改cell ID为cell Area
for(i=0;i<nPoints;i++){
x = loc[2*i];
y = loc[2*i+1];
type = getParticleType(img,x,y);
if (type=="blue") class_count[1]++;
else if (type=="green") class_count[2]++;
else if (type=="yellow" || type=="red" || type=="purple") class_count[3]++;
else if (type=="white") class_count[4]++;
}
Array.print(class_count);
}
setBatchMode(false);
}
}