这是问题的延续在这里 。
我重新张贴的答案之一 ,以保持清洁的话题。
原来的问题(和持续的问题)是user6406828 。
试图执行一些(挂绕)颗粒分析,一对夫妇的错误,现在再抛出每一个。 什么在代码中得到改善呢?
下面是一些代码:
// $BACKGROUND$
number useBadImage, stopAtSrcImage // flags for test
image histogram, src, stack
taggroup imgLst
number i, imgCt,imgID,x0,y0,x1,y1, z1
if (OkCancelDialog("Generate a bad image?")) useBadImage=1
else useBadImage=0
if (OkCancelDialog("Stop at testing image generation?")) stopAtSrcImage=1
else stopAtSrcImage=0
x0=128;y0=128
x1=512;y1=512
image img:=exprSize(x0,y0,0)
z1=10
stack:=exprSize(x1,y1,z1)
img=random()*100
src:=exprSize(x1,y1,0)
if (useBadImage) {
src=img.warp(icol*x0/x1,irow*y0/y1)
for (i=0;i<z1;i++) {
stack[0,0,i,x1,y1,i+1]=src+10
}
}
else {
src=sin(icol/pi())+cos(irow/pi())
for (i=0;i<z1;i++) {
stack[0,0,i,x1,y1,i+1]=src+0.1
}
}
if (stopAtSrcImage) {
src.showImage()
exit(0)
}
void doThreshold(image histogram, number PctOffPeak, number AdditionalShift) {
number max, lf,rt,maxX,maxY, i, val, threshold,d0,d1
ROI r = NewROI(); // foreground ROI
histogram.getSize(d0,d1)
//histogram[0,0,1,5]=0 //remove zero peak
max=histogram.max(maxX,maxY)
threshold=max*PctOffPeak/100
//okdialog("After trim zero peak, maxX=" +maxX)
lf=0;rt=d0
for (i=maxX;i<d0;i++) {
val=histogram.getPixel(i,0)
if (val<=threshold) {
lf=i
i=d0
}
}
lf=lf+AdditionalShift
r.ROISetRange(lf,rt);
histogram.ImageGetImageDisplay(0).ImageDisplayAddRoi(r);
}
//main loop
for (i=0;i<z1;i++) {
src:=stack[0,0,i,x1,y1,i+1].imageclone()
src.showImage()
ChooseMenuItem( "Analysis", "Particles", "Start Threshold" )
histogram := GetFrontImage();
doThreshold(histogram, 20,2)
if( !_FloatingModelessDialog( "Adjust threshold level","Proceed!" ) ) {; histogram.deleteimage(); exit(0); };
else {
src.showImage()
delay(60)
ChooseMenuItem( "Analysis", "Particles", "Remove Edge Particles" )
delay(60)
ChooseMenuItem( "Analysis", "Particles", "Find Particles" )
delay(60)
ChooseMenuItem( "Analysis", "Particles", "Analyze Particles" )
delay(60)
histogram.deleteImage()
}
}
如果选择“useBadImage”和“stopAtSrcImage”,第一SRC图像被示出。 这将是一个非常糟糕的一个粒子分析。 所述UI操作将产生多个“无效索引”的错误(在尝试选择直方图顶部15%的强度)。 如果useBadImage == 0,则图像表现更好。
我扩展代码运行通过图像堆栈一些循环。 对于具有“良好”的图像的图像栈,手动颗粒分析可以经过很好地没有问题的所有层,但循环几乎总是产生“例外”(在结果窗口示出)中循环的某个地方。 似乎将长期拖延不能帮助。 但是,如果没有延迟肯定崩溃循环。 该doThreshold(image histogram, number PctOffPeak, number AdditionalShift)
是假设“查找直方图最大,从那里开始,向右走一些折扣百分比的高峰期,加上AdditionalShift,并设置了‘投资回报率范围LF’值有但这并不总是像预期的那样。
虽然试图对付隐藏的错误,我计算出我自己的颗粒分析的版本。 速度是不是一个大问题。 下面是一些核心功能,
image dxImg,dyImg
void getSearchImg() {
dxImg:=[8,1]:
{
{-1, 0, 1, 1, 1, 0,-1,-1}
}
dyImg:=[8,1]:
{
{-1,-1,-1, 0, 1, 1, 1, 0}
}
}
number pop(taggroup &tg, number &x, number &y) {
number n, mode
n=tg.TagGroupCountTags()
if (n==0) return -1
else { //stack, last in, first out
tg.TagGroupGetIndexedTagAsLongPoint(n-1,x,y)
tg.TagGroupDeleteTagWithIndex(n-1)
}
return 1
}
void push(taggroup &tg, number x, number y) {
tg.TagGroupInsertTagAsLongPoint(infinity(),x,y)
}
taggroup dfs(image img) {//Depth-first search, Using stack
number isOn, i,xInc, yInc,d0,d1
number status, x0, y0,x1,y1, x, y, val
taggroup tgStack=newtaglist()
taggroup tgClusters=newtaglist()
taggroup tgSingleCluster=newTaglist() //this is global
roi r
image imgTemp:=img.ImageClone()
imgTemp.getSize(d0,d1)
getSearchImg()
imgTemp=tert(icol==0||irow==0||icol==d0-1||irow==d1-1, 0, imgTemp)
while (1) {
status=1
val = imgTemp.max(x, y)
if (val<=0) break
else {
tgSingleCluster.TagGroupInsertTagAsLongPoint(infinity(),x,y)
tgStack.push(x,y)
imgTemp[x,y]=0
x0=x;y0=y
while (status==1) {
for (i=0;i<8;i++) {
xInc=dxImg.getPixel(i,0)
yInc=dyImg.getPixel(i,0)
x=x0+xInc;y=y0+yInc
isOn=imgTemp.getPixel(x,y)
if (isOn) {
imgTemp[x,y]=0
tgSingleCluster.TagGroupInsertTagAsLongPoint(infinity(),x,y)
tgStack.push(x,y)
}
}
status=tgStack.pop(x0,y0)
}
tgClusters.TagGroupInsertTagAsTagGroup(infinity(), tgSingleCluster)
tgSingleCluster=newTaglist()
tgStack=newtaglist()
}
}
return tgClusters
}
虽然DM scirpting没有获得“粒子解析”本身-并且因此ChooseMenutItem()
特技需要使用-它具有用于threasholding和获得的阈值掩码脚本命令。
为了清楚:“阈值”创建的图像,这确实是仅仅用于每个像素的布尔阵列的顶部绿色“掩模”:
此(二进制)掩模用于通过粒子分析找到的颗粒。 的例程生成从掩模,其被显示为红色(与黄色边框和白色编号)多颗粒的注解:
第一步 - 创建和修改绿色掩模 - 可以通过脚本完全crontrolled。
第二步-从绿色掩模到红色/黄色粒子越来越-不能与需要ChooseMenuItem()
第三步-从红色/黄色颗粒计算值掩蔽-也不能直接脚本,并且需要ChooseMenuItem()
和一些创造性的编码。
该DM帮助文档(在最近的版本至少)有使用阈值并获得通过脚本面膜中的RasterImageDisplay对象的部分的示例
我在这里简单地复制示例脚本:
// open image
image myImage := GetFrontImage()
ImageDisplay imageDisp = myImage.ImageGetImageDisplay( 0 )
number low, high
imageDisp.ImageDisplayGetContrastLimits( low, high )
number width = myImage.ImageGetDimensionSize( 0 )
number height = myImage.ImageGetDimensionSize( 1 )
// trun thresholding on
imageDisp.RasterImageDisplaySetThresholdOn( 1 )
// set limits
imageDisp.RasterImageDisplaySetThresholdLimits( low, (low + high)/2 )
// create mask image, should be binary or 8 bit signed or unsigned
image mask := IntegerImage("Mask", 1, 0, width, height )
imageDisp.RasterImageDisplayAddThresholdToMask( mask, 0, 0, height, width )
// turn thresholding off
imageDisp.RasterImageDisplaySetThresholdOn( 0 )
// display the mask
ShowImage( mask )
上面的脚本可以用于简单tresholding面膜。
然而,我发现有一些奇怪的行为,如果
ChooseMenuItem( "Analysis", "Particles", "Remove Edge Particles" )
被调用,并移除面具的部分。 于是,人们不再能得到使用正确的面具RasterImageDisplayAddThresholdToMask()
命令。
然而,一个可以解决这个问题,通过使用通用命令对组件访问所需的信息。 下面的脚本正确创建蒙版图像:
image GetThresholdMaskFromDisplay( imageDisplay disp )
{
number kRasterMaskType = 3633 // DM defined constant
if ( !disp.ImageDisplayIsValid() ) Throw( "Invalid display")
number sx = disp.ImageDisplayGetImage().ImageGetDimensionSize(0)
number sy = disp.ImageDisplayGetImage().ImageGetDimensionSize(1)
image mask := IntegerImage( "Mask", 1, 0, sx, sy )
component rasterMask = disp.ComponentGetNthChildOfType( kRasterMaskType, 0 )
if ( rasterMask.ComponentIsValid() )
{
TagGroup compTgs = NewTagGroup()
rasterMask.ComponentExternalizeProperties( compTgs )
compTgs.TagGroupGetTagAsArray( "MaskData", mask )
}
return mask
}
GetFrontImage().ImageGetImageDisplay(0).GetThresholdMaskFromDisplay().ShowImage()
随着获得thresholdmask的能力,可以检查该掩码调用颗粒分析命令之前实际上包含任何像素。 这避免了被抛出的错误。
原来的剧本修改,以避免该问题:
// $BACKGROUND$
number _fModelessDialog(string prompt, string buttonName){
number sem = NewSemaphore()
ModelessDialog(prompt, buttonName, sem)
try GrabSemaphore(sem)
catch return 0
return 1
}
image GetThresholdMaskFromDisplay( imageDisplay disp )
{
number kRasterMaskType = 3633 // DM defined constant
if ( !disp.ImageDisplayIsValid() ) Throw( "Invalid display")
number sx = disp.ImageDisplayGetImage().ImageGetDimensionSize(0)
number sy = disp.ImageDisplayGetImage().ImageGetDimensionSize(1)
image mask := IntegerImage( "Mask", 1, 0, sx, sy )
component rasterMask = disp.ComponentGetNthChildOfType( kRasterMaskType, 0 )
if ( rasterMask.ComponentIsValid() )
{
TagGroup compTgs = NewTagGroup()
rasterMask.ComponentExternalizeProperties( compTgs )
compTgs.TagGroupGetTagAsArray( "MaskData", mask )
}
return mask
}
number useBadImage, stopAtSrcImage // flags for test
image histogram, src, stack
taggroup imgLst
number i, imgCt,imgID,x0,y0,x1,y1, z1
if (OkCancelDialog("Generate a bad image?")) useBadImage=1
else useBadImage=0
if (OkCancelDialog("Stop at testing image generation?")) stopAtSrcImage=1
else stopAtSrcImage=0
x0=128;y0=128
x1=512;y1=512
image img:=exprSize(x0,y0,0)
z1=10
stack:=exprSize(x1,y1,z1,0)
img=random()*100
src:=exprSize(x1,y1,0)
if (useBadImage) {
src=img.warp(icol*x0/x1,irow*y0/y1)
for (i=0;i<z1;i++) {
stack[0,0,i,x1,y1,i+1]=src+10
}
}
else {
src=sin(icol/pi())+cos(irow/pi())
for (i=0;i<z1;i++) {
stack[0,0,i,x1,y1,i+1]=src+0.1
}
}
if (stopAtSrcImage) {
src.showImage()
exit(0)
}
void doThreshold(image histogram, number PctOffPeak, number AdditionalShift) {
number max, lf,rt,maxX,maxY, i, val, threshold,d0,d1
ROI r = NewROI(); // foreground ROI
histogram.getSize(d0,d1)
//histogram[0,0,1,5]=0 //remove zero peak
max=histogram.max(maxX,maxY)
threshold=max*PctOffPeak/100
//okdialog("After trim zero peak, maxX=" +maxX)
lf=0;rt=d0
for (i=maxX;i<d0;i++) {
val=histogram.getPixel(i,0)
if (val<=threshold) {
lf=i
i=d0
}
}
lf=lf+AdditionalShift
r.ROISetRange(lf,rt);
histogram.ImageGetImageDisplay(0).ImageDisplayAddRoi(r);
}
//main loop
for (i=0;i<z1;i++) {
src:=stack[0,0,i,x1,y1,i+1].imageclone()
src.showImage()
ChooseMenuItem( "Analysis", "Particles", "Start Threshold" )
histogram := GetFrontImage();
doThreshold(histogram, 20,2)
if( !_fModelessDialog( "Adjust threshold level", "Proceed" ) ) {; histogram.deleteimage(); exit(0); };
else {
src.showImage()
delay(60)
ChooseMenuItem( "Analysis", "Particles", "Remove Edge Particles" )
delay(60)
// Check if there even is a particle mask now!
number validPixelsInMask = sum( src.ImageGetImageDisplay(0).GetThresholdMaskFromDisplay() )
if ( !validPixelsInMask )
Result("\n Skipping plane, no particles found." )
else
{
ChooseMenuItem( "Analysis", "Particles", "Find Particles" )
delay(60)
ChooseMenuItem( "Analysis", "Particles", "Analyze Particles" )
delay(60)
histogram.deleteImage()
}
}
}
张贴到脚本几点意见:
stack:=exprSize(x1,y1,z1)
不创建尺寸X1 / Y1 / Z1但尺寸X1 / Y1与在每个像素值Z1的2D图像的3D图像。 你可能想
stack:=exprSize(x1,y1,z1,0)
_FloatingModelessDialog( message, buttontext )
是一个自定义脚本命令不适用于其他。 不过,我想这应该是有两个按钮,一个无模式对话框,所以我用下面的脚本代码:
number _fModelessDialog(string prompt, string buttonName){
number sem = NewSemaphore()
ModelessDialog(prompt, buttonName, sem)
try GrabSemaphore(sem)
catch return 0
return 1
}
我居然没碰上运行使用“坏”的形象这些更改后的脚本的问题
唯一一次我没有碰到下面的错误抛出
是,当我有这就产生了二元掩模,然后,在删除边缘颗粒步骤中,完全是由于没有颗粒不接触的边缘除去的treshold值。 “查找粒子”常规则理所当然地引发错误,因为没有粒子可以发现(不再有二进制掩码)。
但是,您可以通过脚本访问threashold面罩,所以它可能是调用find粒子之前执行对检查一个好主意。 然后你避免这个错误。 (见对方的回答)