perl中的图像细化算法?

时间:2010-12-15 08:52:47

标签: image perl image-processing image-manipulation

我从网上阅读张舜的细化算法,并编写perl代码来细化图像。但是当代码运行时,代码会导致区域的过度侵蚀。下面的ascii图片就是例子。有人会告诉我代码有什么问题。非常感谢。

Before thinning
**********
**********
**********
**********
**********
**********
**********
**********
***###*#**
**##**###*
*##****###
*#******#*
*##****##*
*##****##*
**######**
***####***
**##*###**
*##****##*
*#******##
##******##
##*****###
*##****##*
**######**
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********

After thinning          
**********
**********
**********
**********
**********
**********
**********
**********
***###****
**#***##**
*#*****###
**********
**********
*******#**
******#***
***###****
**#**###**
*#*****##*
********##
#*******##
##*******#
*##****##*
**#####***
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********
**********

代码如下。

##image array length: 0-37,image array width: $div[$idx]->{'R'}和$div[$idx]->{'L'}
##image array: $div[$idx]->{'A'}
while($flag eq 'Y'){
  my $diff= $div[$idx]->{'R'} - $div[$idx]->{'L'};
  my $ra= $div[$idx]->{'A'};
  $flag= 'N';      
  for($y=1; $y<= 36; $y++){
    for($x=1; $x<= $diff-1; $x++){
      my $np1=0;
      my $sp1=0;
      my $cond1= 0;
      my $cond2= 0;
      my $p1= $ra->[$y][$x];
      my $p2= $ra->[$y-1][$x];
      my $p3= $ra->[$y-1][$x+1];
      my $p4= $ra->[$y][$x+1];
      my $p5= $ra->[$y+1][$x+1];
      my $p6= $ra->[$y+1][$x];
      my $p7= $ra->[$y+1][$x-1];
      my $p8= $ra->[$y][$x-1];
      my $p9= $ra->[$y-1][$x-1];

      if($p1 ne $mark){next;}
      if($p2 eq $mark){$np1++;}
      if($p3 eq $mark){$np1++;}
      if($p4 eq $mark){$np1++;}
      if($p5 eq $mark){$np1++;}
      if($p6 eq $mark){$np1++;}
      if($p7 eq $mark){$np1++;}
      if($p8 eq $mark){$np1++;}
      if($p9 eq $mark){$np1++;}
      if(($p2 eq $unmark)&&($p3 eq $mark)){$sp1++;}
      if(($p3 eq $unmark)&&($p4 eq $mark)){$sp1++;}
      if(($p4 eq $unmark)&&($p5 eq $mark)){$sp1++;}
      if(($p5 eq $unmark)&&($p6 eq $mark)){$sp1++;}
      if(($p6 eq $unmark)&&($p7 eq $mark)){$sp1++;}
      if(($p7 eq $unmark)&&($p8 eq $mark)){$sp1++;}
      if(($p8 eq $unmark)&&($p9 eq $mark)){$sp1++;}
      if(($np1 >= 2)&&($np1 <= 6)){$cond1++; $cond2++;}
      if($sp1 eq 1){$cond1++; $cond2++;}
      if(($p2 eq $unmark)||($p4 eq $unmark)||($p6 eq $unmark)){$cond1++;}
      if(($p4 eq $unmark)||($p6 eq $unmark)||($p8 eq $unmark)){$cond1++;}
      if(($p2 eq $unmark)||($p4 eq $unmark)||($p8 eq $unmark)){$cond2++;}
      if(($p2 eq $unmark)||($p6 eq $unmark)||($p8 eq $unmark)){$cond2++;}

      if($cond1 eq 4){
        $div[$idx]->{'A'}->[$y][$x]= $unmark;
        $flag= 'Y';
      }
      if($cond2 eq 4){
        $div[$idx]->{'A'}->[$y][$x]= $unmark;
        $flag= 'Y';
      }
    }
  }
}

更新 我修改了我的代码。它似乎工作。但我不知道它是否正常工作。 任何建议。非常感谢。

sub thinning{
  my $idx= shift;
  my $flag= 'Y';
  my @unmarklist;
  my $aheight= 37;  ##0..37  
  my $awidth= $div[$idx]->{'R'} - $div[$idx]->{'L'};

  while($flag eq 'Y'){    
    $flag= 'N';
    my $ra= $div[$idx]->{'A'};

    for $y(1..$aheight-1){      
      for $x(1..$awidth-1){        
        my $np1=0;
        my $sp1=0;
        my @neighbors;
        my $pixel= $ra->[$y][$x];
        $neighbors[2]= $ra->[$y-1][$x];
        $neighbors[3]= $ra->[$y-1][$x+1];
        $neighbors[4]= $ra->[$y][$x+1];
        $neighbors[5]= $ra->[$y+1][$x+1];
        $neighbors[6]= $ra->[$y+1][$x];
        $neighbors[7]= $ra->[$y+1][$x-1];
        $neighbors[8]= $ra->[$y][$x-1];
        $neighbors[9]= $ra->[$y-1][$x-1];

        if($pixel ne $mark){next;}        
        for $i(2..9){if($neighbors[$i] eq $mark){$np1++;}}
        if(($np1 >= 2)&&($np1 <= 6)){
          for $i(2..8){if(($neighbors[$i] eq $unmark)&&($neighbors[$i+1] eq $mark)){$sp1++;}}          
          if(($neighbors[9] eq $unmark)&&($neighbors[2] eq $mark)){$sp1++;}
          if($sp1 == 1){  
            if((($neighbors[2] eq $unmark)||($neighbors[4] eq $unmark)||($neighbors[6] eq $unmark))&&
               (($neighbors[4] eq $unmark)||($neighbors[6] eq $unmark)||($neighbors[8] eq $unmark))){
              push(@unmarklist, [$y, $x]);
              $flag= 'Y';
            }
          }
        }        
      }
    }

    for $i(0..$#unmarklist){
      my $y= $unmarklist[$i]->[0];
      my $x= $unmarklist[$i]->[1];
      $div[$idx]->{'A'}->[$y][$x]= $unmark; 
    }
    @unmarklist=();

    my $ra= $div[$idx]->{'A'};
    for $y(1..$aheight-1){      
      for $x(1..$awidth-1){        
        my $np1=0;
        my $sp1=0;
        my @neighbors;
        my $pixel= $ra->[$y][$x];
        $neighbors[2]= $ra->[$y-1][$x];
        $neighbors[3]= $ra->[$y-1][$x+1];
        $neighbors[4]= $ra->[$y][$x+1];
        $neighbors[5]= $ra->[$y+1][$x+1];
        $neighbors[6]= $ra->[$y+1][$x];
        $neighbors[7]= $ra->[$y+1][$x-1];
        $neighbors[8]= $ra->[$y][$x-1];
        $neighbors[9]= $ra->[$y-1][$x-1];

        if($pixel ne $mark){next;}        
        for $i(2..9){if($neighbors[$i] eq $mark){$np1++;}}
        if(($np1 >= 2)&&($np1 <= 6)){
          for $i(2..8){if(($neighbors[$i] eq $unmark)&&($neighbors[$i+1] eq $mark)){$sp1++;}}          
          if(($neighbors[9] eq $unmark)&&($neighbors[2] eq $mark)){$sp1++;}
          if($sp1 == 1){  
            if((($neighbors[2] eq $unmark)||($neighbors[4] eq $unmark)||($neighbors[8] eq $unmark))&&
               (($neighbors[2] eq $unmark)||($neighbors[6] eq $unmark)||($neighbors[8] eq $unmark))){
              push(@unmarklist, [$y, $x]);
              $flag= 'Y';
            }
          }
        }        
      }
    }

    for $i(0..$#unmarklist){
      my $y= $unmarklist[$i]->[0];
      my $x= $unmarklist[$i]->[1];
      $div[$idx]->{'A'}->[$y][$x]= $unmark;
    }
    @unmarklist=();
  }
}

1 个答案:

答案 0 :(得分:6)

您在实施算法时犯了几个错误:

  1. 您无法修改$ra。如果这样做,那么当您擦除一个像素时,您将更改其后处理的像素的条件,这会导致错误向下和向右蔓延。

  2. 不应在同一循环中检查您的$cond1$cond2条件。相反,必须使用$cond1条件处理整个图像,然后使用$cond2条件处理整个图像,并根据需要重复。

  3. 当您计算连通性时,您错过了$p9为“取消标记”并且$p2为“标记”的情况 - 您忘记绕圈子走了一圈。

  4. 在纠正所有这些错误后,看起来事情正在发挥作用。

    还有一些建议:

    1. 您不应该将eq用于数字 - 请使用==运算符进行数字比较。
    2. 不使用$cond1$cond2变量,而是使用&&and逻辑运算符 - 它们将使您的代码更易于阅读,并避免不必要的工作
    3. 您可以写for ($x = lower; $x <= $upper; $x++)
    4. 而不是for $x (lower .. upper)
    5. 如果您在输入时将*#更改为0和1,然后在输出中再次返回,则可以通过将if ($pixel eq $mark)替换为if ($pixel)来使更多逻辑更容易阅读$p1等等。
    6. 使用数组而不是$p9$p1等一系列编号变量。如果调用$pixel $p2$p9@neighbors是一个名为$np1的数组,则可以重写十八行以计算$sp1和{ {1}}分为三行。
    7. 一般来说,更好的变量名称是一个不错的主意:)