q64:Hilditch细化算法(C++)

因为在opencv100wen后续没有看到C++解答,这题按原本的思路自己写了,但图像细化的有问题变得像梳子一样,参考了一些发现判断条件都有所区别。

大致思路如下:(分了3段)

  1. 从左上角开始光栅扫描

  2. 如果(x,y)=0不处理,为1,满足下面五个条件时设-1
    a.4-近邻像素的取值有一个以上为0
    b.8-连接数为1,即端点
    c.8-近邻的绝对值之和大于2
    d.8-近邻中有1个以上取值为1 (这个条件在函数中去掉了)
    e. 对所有8个近邻点xn满足任意一个(xn值不为-1 || 当xn值为0时(x,y)的8-连接数为1)

  3. 将每个像素的-1更改为0

  4. 重复光栅扫描,直到步骤3中像素值改变次数为0

Mat hilditch(Mat otsu) {
 int height = otsu.rows;
 int width = otsu.cols;
 Mat out = otsu.clone();
 for (int y = 0; y < height; ++y) {
  for (int x = 0; x < width; ++x) {
   if (out.at<uchar>(y, x) == 255)
    out.at<uchar>(y, x) = 1;
  }
 }
 int count = 1;
 while (count > 0) {
  count = 0;
  Mat tmp = out.clone();
  Mat tmp8 = out.clone();
  for (int y = 0; y < height; ++y) {
   for (int x = 0; x < width; ++x) {
    tmp8.at<uchar>(y, x) = 1 - tmp8.at<uchar>(y, x); //8-连接数
   }
  }
  Mat _tmp8 = tmp8.clone();
  for (int y = 0; y < height; ++y) {
   for (int x = 0; x < width; ++x) {
    if (tmp.at<uchar>(y, x) == 0)   //背景为0黑底,跳过
     continue;
    int judge = 0;
    //condition 1: 4-近邻像素的取值有一个以上为0
    if (tmp.at<uchar>(y, min(x + 1, width - 1)) * tmp.at<uchar>(y, max(x - 1, 0))
     * tmp.at<uchar>(min(y + 1, height - 1), x) * tmp.at<uchar>(max(y - 1, 0), x) == 0)
     ++judge;
    //condition 2: 8-连接数为1
    int S = 0;
    S += tmp8.at<uchar>(y, min(x + 1, width - 1)) - tmp8.at<uchar>(y, min(x + 1, width - 1))
     *tmp8.at<uchar>(max(y - 1, 0), min(x + 1, width - 1))*tmp8.at<uchar>(max(y - 1, 0), x);
    S += tmp8.at<uchar>(max(y - 1, 0), x) - tmp8.at<uchar>(max(y - 1, 0), x)
     *tmp8.at<uchar>(max(y - 1, 0), max(x - 1, 0))*tmp8.at<uchar>(y, max(x - 1, 0));
    S += tmp8.at<uchar>(y, max(x - 1, 0)) - tmp8.at<uchar>(y, max(x - 1, 0))
     *tmp8.at<uchar>(min(y + 1, height - 1), max(x - 1, 0))*tmp8.at<uchar>(min(y + 1, height - 1), x);
    S += tmp8.at<uchar>(min(y + 1, height - 1), x) - tmp8.at<uchar>(min(y + 1, height - 1), x)
     *tmp8.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1))*tmp8.at<uchar>(y, min(x + 1, width - 1));
    if (S == 1)
     ++judge;
    //condition 3: 8-近邻的绝对值之和大于2   tmp只有0 1所以不用abs  这里在其他博客看到有>=根据这张图没啥区别,回头再验证,我想如果正好是对称位置的两点那就不那被标记为背景
    if (tmp.at<uchar>(y, min(x + 1, width - 1)) + tmp.at<uchar>(y, max(x - 1, 0))
     + tmp.at<uchar>(min(y + 1, height - 1), x) + tmp.at<uchar>(max(y - 1, 0), x)
     + tmp.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)) + tmp.at<uchar>(max(y - 1, 0), max(x - 1, 0))
     + tmp.at<uchar>(min(y + 1, height - 1), max(x - 1, 0)) + tmp.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1)) > 2)
     ++judge;
    //condition 4: 8-近邻中有1个以上取值为1  把条件4去掉得出的结果就比较优秀了
    /*
    int condition4 = 0;
    for (int dy = -1; dy < 2; ++dy) {
     for (int dx = -1; dx < 2; ++dx) {
      if (dy == 0 && dx == 0)
       continue;
      else if (out.at(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1)) == 1)
       ++condition4;
      if (condition4 > 1) {
       ++judge;
       break;
      }
     }
     if (judge == 4)
      break;
    }*/
    if (judge < 3)//条件不满足可以直接下一个点
     continue;
    //condition 5: 对所有8个近邻点xn满足任意一个
    //             xn值不为 - 1 || 当xn值为0时,x连接数为1(但没有判断值为0,判断了有问题)
    //重新计算8-连接数
    for (int dy = -1; dy < 2; ++dy) {
     for (int dx = -1; dx < 2; ++dx) {
      _tmp8.at<uchar>(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1)) = 1 - out.at<uchar>(min(max(y + dy, 0), height - 1), min(max(x + dx, 0), width - 1));
     }
    }
    S = 0;
    S += _tmp8.at<uchar>(y, min(x + 1, width - 1)) - _tmp8.at<uchar>(y, min(x + 1, width - 1))
     *_tmp8.at<uchar>(max(y - 1, 0), min(x + 1, width - 1))*_tmp8.at<uchar>(max(y - 1, 0), x);
    S += _tmp8.at<uchar>(max(y - 1, 0), x) - _tmp8.at<uchar>(max(y - 1, 0), x)
     *_tmp8.at<uchar>(max(y - 1, 0), max(x - 1, 0))*_tmp8.at<uchar>(y, max(x - 1, 0));
    S += _tmp8.at<uchar>(y, max(x - 1, 0)) - _tmp8.at<uchar>(y, max(x - 1, 0))
     *_tmp8.at<uchar>(min(y + 1, height - 1), max(x - 1, 0))*_tmp8.at<uchar>(min(y + 1, height - 1), x);
    S += _tmp8.at<uchar>(min(y + 1, height - 1), x) - _tmp8.at<uchar>(min(y + 1, height - 1), x)
     *_tmp8.at<uchar>(min(y + 1, height - 1), min(x + 1, width - 1))*_tmp8.at<uchar>(y, min(x + 1, width - 1));
    //leftup
    if (S == 1 || tmp.at<uchar>(max(y - 1, 0), max(x - 1, 0)) != out.at<uchar>(max(y - 1, 0), max(x - 1, 0)))
     ++judge;
    //up
    if (S == 1 || tmp.at<uchar>(max(y - 1, 0), x) != out.at<uchar>(max(y - 1, 0), x))
     ++judge;
    //rightup
    if (S == 1 || tmp.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)) != out.at<uchar>(max(y - 1, 0), min(x + 1, width - 1)))
     ++judge;
    //left
    if (S == 1 || tmp.at<uchar>(y, max(x - 1, 0)) != out.at<uchar>(y, max(x - 1, 0)))
     ++judge;
    if (judge == 7) {
     out.at<uchar>(y, x) = 0;  //-1但是负数转为255后面还给0,就直接给0 
     ++count;
    }
   }
  }
 }
 for (int y = 0; y < height; ++y) {
  for (int x = 0; x < width; ++x) {
   if (out.at<uchar>(y, x) == 1)
    out.at<uchar>(y, x) = 255;
  }
 }
 return out;
}

效果图:(交接处问题比较大)
q64:Hilditch细化算法(C++)_第1张图片

你可能感兴趣的:(q64:Hilditch细化算法(C++))