【opencv】二值图像细化


139 lines (115 sloc)    3.3 KB
  /**
  * Code for thinning a binary image using Zhang-Suen algorithm.
  *
  * Author:  Nash (nash [at] opencv-code [dot] com)
  * Website: http://opencv-code.com
  */
  #include <opencv2/opencv.hpp>
   
  /**
  * Perform one thinning iteration.
  * Normally you wouldn't call this function directly from your code.
  *
  * Parameters:
  * im    Binary image with range = [0,1]
  * iter  0=even, 1=odd
  */
  void thinningIteration(cv::Mat& img, int iter)
  {
      CV_Assert(img.channels() == 1);
      CV_Assert(img.depth() != sizeof(uchar));
      CV_Assert(img.rows > 3 && img.cols > 3);
   
      cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);
   
      int nRows = img.rows;
      int nCols = img.cols;
   
      if (img.isContinuous()) {
          nCols *= nRows;
          nRows = 1;
      }
   
      int x, y;
      uchar *pAbove;
      uchar *pCurr;
      uchar *pBelow;
      uchar *nw, *no, *ne;    // north (pAbove)
      uchar *we, *me, *ea;
      uchar *sw, *so, *se;    // south (pBelow)
   
      uchar *pDst;
   
      // initialize row pointers
      pAbove = NULL;
      pCurr  = img.ptr(0);
      pBelow = img.ptr(1);
   
      for (y = 1; y < img.rows-1; ++y) {
          // shift the rows up by one
          pAbove = pCurr;
          pCurr  = pBelow;
          pBelow = img.ptr(y+1);
   
          pDst = marker.ptr(y);
   
          // initialize col pointers
          no = &(pAbove[0]);
          ne = &(pAbove[1]);
          me = &(pCurr[0]);
          ea = &(pCurr[1]);
          so = &(pBelow[0]);
          se = &(pBelow[1]);
   
          for (x = 1; x < img.cols-1; ++x) {
              // shift col pointers left by one (scan left to right)
              nw = no;
              no = ne;
              ne = &(pAbove[x+1]);
              we = me;
              me = ea;
              ea = &(pCurr[x+1]);
              sw = so;
              so = se;
              se = &(pBelow[x+1]);
   
              int A  = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) +
                       (*ea == 0 && *se == 1) + (*se == 0 && *so == 1) +
                       (*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) +
                       (*we == 0 && *nw == 1) + (*nw == 0 && *no == 1);
              int B  = *no + *ne + *ea + *se + *so + *sw + *we + *nw;
              int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we);
              int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we);
   
              if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
                  pDst[x] = 1;
          }
      }
   
      img &= ~marker;
  }
   
  /**
  * Function for thinning the given binary image
  *
  * Parameters:
  * src  The source image, binary with range = [0,255]
  * dst  The destination image
  */
  void thinning(const cv::Mat& src, cv::Mat& dst)
  {
      dst = src.clone();
      dst /= 255;         // convert to binary image
   
      cv::Mat prev = cv::Mat::zeros(dst.size(), CV_8UC1);
      cv::Mat diff;
   
      do {
          thinningIteration(dst, 0);
          thinningIteration(dst, 1);
          cv::absdiff(dst, prev, diff);
          dst.copyTo(prev);
      }
      while (cv::countNonZero(diff) > 0);
   
      dst *= 255;
  }
   
  /**
  * This is an example on how to call the thinning funciton above
  */
  int main()
  {
  cv::Mat src = cv::imread("image.png");
  if (!src.data)
  return -1;
   
  cv::Mat bw;
  cv::cvtColor(src, bw, CV_BGR2GRAY);
  cv::threshold(bw, bw, 10, 255, CV_THRESH_BINARY);
   
  thinning(bw, bw);
   
  cv::imshow("src", src);
  cv::imshow("dst", bw);
  cv::waitKey();
  return 0;
  }

你可能感兴趣的:(Opencv)