http://en.wikipedia.org/wiki/Topological_skeleton
计算图像骨骼方法
1 形态学http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/
2 straight skeletons
3 Voronoi diagram
1)中轴medial 与 voronoi顶点的位置
2)voronoi顶点 收敛至中轴
3)形成骨骼
4 Zhang-Suen algorithm
Zhang-Suen thinning steps:
- While points are deleted do
- For all pixels p(i,j) do
- if (a) 2 ≤ B(P1) ≤ 6
(b) A(P1) = 1
(c) Apply one of the following:
1. P2 x P4 x P6 = 0 in odd iterations
2. P2 x P4 x P8 = 0 in even iterations
(d) Apply one of the following:
1. P4 x P6 x P8 = 0 in odd iterations
2. P2 x P6 x P8 = 0 in even iterations
then- Delete pixel p(i,j)
- end if
- end for
- end while
/** * Code for thinning a binary image using Zhang-Suen algorithm. */ #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> /** * Perform one thinning iteration. * Normally you wouldn't call this function directly from your code. * * @param im Binary image with range = 0-1 * @param iter 0=even, 1=odd */ void thinningIteration(cv::Mat& im, int iter) { cv::Mat marker = cv::Mat::zeros(im.size(), CV_8UC1); for (int i = 1; i < im.rows-1; i++) { for (int j = 1; j < im.cols-1; j++) { uchar p2 = im.at<uchar>(i-1, j); uchar p3 = im.at<uchar>(i-1, j+1); uchar p4 = im.at<uchar>(i, j+1); uchar p5 = im.at<uchar>(i+1, j+1); uchar p6 = im.at<uchar>(i+1, j); uchar p7 = im.at<uchar>(i+1, j-1); uchar p8 = im.at<uchar>(i, j-1); uchar p9 = im.at<uchar>(i-1, j-1); int A = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) + (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) + (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) + (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1); int B = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9; int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8); int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8); if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0) marker.at<uchar>(i,j) = 1; } } im &= ~marker; } /** * Function for thinning the given binary image * * @param im Binary image with range = 0-255 */ void thinning(cv::Mat& im) { im /= 255; cv::Mat prev = cv::Mat::zeros(im.size(), CV_8UC1); cv::Mat diff; do { thinningIteration(im, 0); thinningIteration(im, 1); cv::absdiff(im, prev, diff); im.copyTo(prev); } while (cv::countNonZero(diff) > 0); im *= 255; } /** * This is an example on how to call the thinning function above. */ int main() { cv::Mat src = cv::imread("test_image.png"); if (src.empty()) return -1; cv::Mat bw; cv::cvtColor(src, bw, CV_BGR2GRAY); cv::threshold(bw, bw, 10, 255, CV_THRESH_BINARY); thinning(bw); cv::imshow("src", src); cv::imshow("dst", bw); cv::waitKey(0); return 0; }