julia中的vcat StackOverflowError

时间:2015-11-11 22:17:56

标签: julia

我编写了一个检测数组中对象的函数。在这种情况下,我用它来清除触摸图像边框的白色物体。但问题是,vcat中始终存在StackOverFlowError,它出现在不同的行(取决于图像)。这是一个最低限度的工作示例。它适用于第二个图像,但不适用于第一个图像: Test.png Test2.png

using Images


function getImChars(I::Array)
  charAr=copy(I);
  indexMax=find(x->(x==1),charAr);
  (h,w)=size(charAr);
  # check border values
  (r,c)=ind2sub(size(charAr),indexMax);
  indexBorderR1=find(x->(x==1),r);
  indexBorderR2=find(x->(x==h),r);
  indexBorderR=[indexBorderR1;indexBorderR2];
  indexBorderC1=find(x->(x==1),c);
  indexBorderC2=find(x->(x==w),c);
  indexBorderC=[indexBorderC1;indexBorderC2];
  borderPixels=[999;999]; # initialize def value FIX
  for bRc=1:length(indexBorderR)
    borderPixels=[borderPixels [r[indexBorderR[bRc]];c[indexBorderR[bRc]]]];
  end
  for bCc=1:length(indexBorderC)
     borderPixels=[borderPixels [r[indexBorderC[bCc]];c[indexBorderC[bCc]]]];
  end
 borderPixels=borderPixels[:,2:end];
  (rbP,cbP)=size(borderPixels);
  fcharAr=[];
  for k=1:cbP
  bP=[borderPixels[:,k];false;false;false;false];
  locObj1=[];
  locObj2=[];
  locObj3=[];
  locObj4=[];
  locObj5=[];
  locObj6=[];
  if(charAr[bP[1],bP[2]]==0)
   continue;
  else
   charAr[bP[1],bP[2]]=0;
  end
  recGetCharClearBorders(true,false,h,w,bP,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,charAr);
  end
return charAr;
end



function recGetCharClearBorders(firstFlag::Bool,doNotAdd::Bool,h::Int,w::Int,hP::Array,locObj1::Array,locObj2::Array,locObj3::Array,locObj4::Array,locObj5::Array,locObj6::Array,imAr::Array)
  leftPoint=[hP[1];hP[2]-1;0;0;0;0];
  rightPoint=[hP[1];hP[2]+1;0;0;0;0];
  topPoint=[hP[1]-1;hP[2];0;0;0;0];
  bottomPoint=[hP[1]+1;hP[2];0;0;0;0];
 # check if it is not out of bounds and relative directions
  if(topPoint[1]!=0)
    if(imAr[topPoint[1],topPoint[2]]==1)
     hP[4]=1;
    end
  end
  if(bottomPoint[1]!=(h+1))
   if(imAr[bottomPoint[1],bottomPoint[2]]==1)
     hP[6]=1;
  end
  end
  if(leftPoint[2]!=0)
   if(imAr[leftPoint[1],leftPoint[2]]==1)
    hP[3]=1;
   end
  end
   if(rightPoint[2]!=(w+1))
  if(imAr[rightPoint[1],rightPoint[2]]==1)
      hP[5]=1;
  end
  end
  # add first elements
  if(firstFlag)
  locObj1=collect(hP[1]);
    locObj2=collect(hP[2]);
    locObj3=collect(hP[3]);
    locObj4=collect(hP[4]);
    locObj5=collect(hP[5]);
    locObj6=collect(hP[6]);
  firstFlag=false;
  else
    # if first element of locObj was deleted actual point should not get pushed to array
  if(!doNotAdd)
  push!(locObj1,hP[1]);
  push!(locObj2,hP[2]);
  push!(locObj3,hP[3]);
  push!(locObj4,hP[4]);
  push!(locObj5,hP[5]);
  push!(locObj6,hP[6]);
  imAr[hP[1],hP[2]]=0;
  end
  end

  goL=false;
  goT=false;
  goR=false;
  goB=false;
  doNotAdd=false;


  if(length(locObj1)!=0)
    # always take and check first elements of locObj
   hPfInLoc=[locObj1[1],locObj2[1],locObj3[1],locObj4[1],locObj5[1],locObj6[1]];
    hPl=[hPfInLoc[1];hPfInLoc[2]-1;0;0;0;0];
    hPt=[hPfInLoc[1]-1;hPfInLoc[2];0;0;0;0];
    hPr=[hPfInLoc[1];hPfInLoc[2]+1;0;0;0;0];
    hPb=[hPfInLoc[1]+1;hPfInLoc[2];0;0;0;0];

    compL=false;
    compT=false;
    compR=false;
    compB=false;
    # check bounds and if array values have changed
    if(hPt[1]!=0)
      if(imAr[hPt[1],hPt[2]]!=0)
        compT=true;
      end
  end
  if(hPb[1]!=(h+1))
    if(imAr[hPb[1],hPb[2]]!=0)
        compB=true;
      end
  end
  if(hPl[2]!=0)
    if(imAr[hPl[1],hPl[2]]!=0)
        compL=true;
      end
  end
   if(hPr[2]!=(w+1))
   if(imAr[hPr[1],hPr[2]]!=0)
        compR=true;
      end
  end
  # define directions and set defined direction false in locObj
  if((locObj3[1]==1)& compL)
      locObj3[1]=0;
      goL=true;
  elseif((locObj4[1]==1)& compT)
      locObj4[1]=0;
      goT=true;
  elseif((locObj5[1]==1)& compR)
      locObj5[1]=0;
      goR=true;
  elseif((locObj6[1]==1)& compB)
      locObj6[1]=0;
      goB=true;
  else

    if (length(locObj1)==1)
    locObj=[];
    else # if everything is zero delete first rows of arrays
    deleteat!(locObj1,1);
    deleteat!(locObj2,1);
    deleteat!(locObj3,1);
    deleteat!(locObj4,1);
    deleteat!(locObj5,1);
    deleteat!(locObj6,1);
    doNotAdd=true;
    return recGetCharClearBorders(firstFlag,doNotAdd,h,w,hP,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,imAr);
    end
    end
  end

  #execute choosen direction
  if(goL)
    return recGetCharClearBorders(firstFlag,doNotAdd,h,w,hPl,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,imAr);
  end
  if(goT)
    return recGetCharClearBorders(firstFlag,doNotAdd,h,w,hPt,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,imAr);
  end
  if(goR)
    return recGetCharClearBorders(firstFlag,doNotAdd,h,w,hPr,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,imAr);
  end
  if(goB)
    return recGetCharClearBorders(firstFlag,doNotAdd,h,w,hPb,locObj1,locObj2,locObj3,locObj4,locObj5,locObj6,imAr);
  end
end

# execute test procedure
Im=Images.load("Test.png");
 Im=data(Im);
imAr=map(Float64,Im);
resIm=getImChars(imAr);
save("Imout.png",resIm);

您只需要在我的代码中更改图像的名称。如果您需要更多信息,请告诉我。非常感谢。

干杯,clax

2 个答案:

答案 0 :(得分:4)

与许多函数式编程语言不同,Julia不优化尾递归(当函数以调用结束时重用堆栈帧)。因此,在您的情况下,您的递归函数很可能会达到最大堆栈深度,具体取决于您的操作系统的线程堆栈大小。

不幸的是,Julia核心团队决定不优先考虑Tail呼叫优化,因为他们认为这种功能不是必须的。实际上,人们通常可以将代码重构为循环。

Afaik,尾部调用优化非常困难,许多其他具有函数式编程范式的编程语言也缺乏它。

答案 1 :(得分:2)

Took a few minutes needed to run and fixup the tail recursion. Is the following replacement for recGetCharClearBorders performing correctly:

    function recGetCharClearBorders(firstFlag::Bool,doNotAdd::Bool,h::Int,w::Int,hP::Array,locObj1::Array,locObj2::Array,locObj3::Array,locObj4::Array,locObj5::Array,locObj6::Array,imAr::Array,recdepth,recloc)
        while true
            leftPoint=[hP[1];hP[2]-1;0;0;0;0];
            rightPoint=[hP[1];hP[2]+1;0;0;0;0];
            topPoint=[hP[1]-1;hP[2];0;0;0;0];
            bottomPoint=[hP[1]+1;hP[2];0;0;0;0];
            # check if it is not out of bounds and relative directions
            if(topPoint[1]!=0)
                if(imAr[topPoint[1],topPoint[2]]==1)
                    hP[4]=1;
                end
            end
            if(bottomPoint[1]!=(h+1))
                if(imAr[bottomPoint[1],bottomPoint[2]]==1)
                    hP[6]=1;
                end
            end
            if(leftPoint[2]!=0)
                if(imAr[leftPoint[1],leftPoint[2]]==1)
                    hP[3]=1;
                end
            end
            if(rightPoint[2]!=(w+1))
                if(imAr[rightPoint[1],rightPoint[2]]==1)
                    hP[5]=1;
                end
            end
            # add first elements
            if(firstFlag)
                locObj1=collect(hP[1]);
                locObj2=collect(hP[2]);
                locObj3=collect(hP[3]);
                locObj4=collect(hP[4]);
                locObj5=collect(hP[5]);
                locObj6=collect(hP[6]);
                firstFlag=false;
            else
                # if first element of locObj was deleted actual point should not get pushed to array
                if(!doNotAdd)
                    push!(locObj1,hP[1]);
                    push!(locObj2,hP[2]);
                    push!(locObj3,hP[3]);
                    push!(locObj4,hP[4]);
                    push!(locObj5,hP[5]);
                    push!(locObj6,hP[6]);
                    imAr[hP[1],hP[2]]=0;
                end
            end

        goL=false;
        goT=false;
        goR=false;
        goB=false;
        doNotAdd=false;

        if(length(locObj1)!=0)
            # always take and check first elements of locObj
            hPfInLoc=[locObj1[1],locObj2[1],locObj3[1],locObj4[1],locObj5[1],locObj6[1]];
            hPl=[hPfInLoc[1];hPfInLoc[2]-1;0;0;0;0];
            hPt=[hPfInLoc[1]-1;hPfInLoc[2];0;0;0;0];
            hPr=[hPfInLoc[1];hPfInLoc[2]+1;0;0;0;0];
            hPb=[hPfInLoc[1]+1;hPfInLoc[2];0;0;0;0];

            compL=false;
            compT=false;
            compR=false;
            compB=false;
            # check bounds and if array values have changed
            if(hPt[1]!=0)
                if(imAr[hPt[1],hPt[2]]!=0)
                    compT=true;
                end
            end
            if(hPb[1]!=(h+1))
                if(imAr[hPb[1],hPb[2]]!=0)
                    compB=true;
                end
            end
            if(hPl[2]!=0)
                if(imAr[hPl[1],hPl[2]]!=0)
                    compL=true;
                end
            end
            if(hPr[2]!=(w+1))
                if(imAr[hPr[1],hPr[2]]!=0)
                    compR=true;
                end
            end
            # define directions and set defined direction false in locObj
            if((locObj3[1]==1)& compL)
                locObj3[1]=0;
                goL=true;
            elseif((locObj4[1]==1)& compT)
                locObj4[1]=0;
                goT=true;
            elseif((locObj5[1]==1)& compR)
                locObj5[1]=0;
                goR=true;
            elseif((locObj6[1]==1)& compB)
                locObj6[1]=0;
                goB=true;
            else

                if (length(locObj1)==1)
                    locObj=[];
                else # if everything is zero delete first rows of arrays
                deleteat!(locObj1,1);
                deleteat!(locObj2,1);
                deleteat!(locObj3,1);
                deleteat!(locObj4,1);
                deleteat!(locObj5,1);
                deleteat!(locObj6,1);
                doNotAdd=true;
                continue
            end
        end
    end

    #execute choosen direction
    if(goL)
        hP = hPl
        continue
    end
    if(goT)
        hP = hPt
        continue
    end
    if(goR)
        hP = hPr
        continue
    end
    if(goB)
        hP = hPb
        continue
    end
    break
end
end

Somehow the output image turned on its side in my run.