Skip to content

Commit

Permalink
faster thinning implement
Browse files Browse the repository at this point in the history
  • Loading branch information
LiuPeiqiCN committed Mar 8, 2024
1 parent 6b5142f commit ca90d3e
Showing 1 changed file with 160 additions and 50 deletions.
210 changes: 160 additions & 50 deletions modules/ximgproc/src/thinning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,175 @@ using namespace std;
namespace cv {
namespace ximgproc {

// look up table - there is one entry for each of the 2^8=256 possible
// combinations of 8 binary neighbors.
static uint8_t lut_zhang_iter0[] = {
1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1};

static uint8_t lut_zhang_iter1[] = {
1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1,
0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1,
0, 1, 1, 1};

static uint8_t lut_guo_iter0[] = {
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1,
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1};

static uint8_t lut_guo_iter1[] = {
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
1, 1, 1, 1};

// Applies a thinning iteration to a binary image
static void thinningIteration(Mat img, int iter, int thinningType){
Mat marker = Mat::zeros(img.size(), CV_8UC1);
int rows = img.rows;
int cols = img.cols;

if(thinningType == THINNING_ZHANGSUEN){
for (int i = 1; i < img.rows-1; i++)
{
for (int j = 1; j < img.cols-1; j++)
{
uchar p2 = img.at<uchar>(i-1, j);
uchar p3 = img.at<uchar>(i-1, j+1);
uchar p4 = img.at<uchar>(i, j+1);
uchar p5 = img.at<uchar>(i+1, j+1);
uchar p6 = img.at<uchar>(i+1, j);
uchar p7 = img.at<uchar>(i+1, j-1);
uchar p8 = img.at<uchar>(i, j-1);
uchar p9 = img.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;
}
}
marker.forEach<uchar>([=](uchar& value, const int postion[]) {
int i = postion[0];
int j = postion[1];
if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
return;

auto ptr = img.ptr(i, j); // p1

// p9 p2 p3
// p8 p1 p4
// p7 p6 p5
uchar p2 = ptr[-cols];
uchar p3 = ptr[-cols + 1];
uchar p4 = ptr[1];
uchar p5 = ptr[cols + 1];
uchar p6 = ptr[cols];
uchar p7 = ptr[cols - 1];
uchar p8 = ptr[-1];
uchar p9 = ptr[-cols - 1];

int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);

if (iter == 0)
value = lut_zhang_iter0[neighbors];
else
value = lut_zhang_iter1[neighbors];

//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) value = 0;
});
}
if(thinningType == THINNING_GUOHALL){
for (int i = 1; i < img.rows-1; i++)
{
for (int j = 1; j < img.cols-1; j++)
{
uchar p2 = img.at<uchar>(i-1, j);
uchar p3 = img.at<uchar>(i-1, j+1);
uchar p4 = img.at<uchar>(i, j+1);
uchar p5 = img.at<uchar>(i+1, j+1);
uchar p6 = img.at<uchar>(i+1, j);
uchar p7 = img.at<uchar>(i+1, j-1);
uchar p8 = img.at<uchar>(i, j-1);
uchar p9 = img.at<uchar>(i-1, j-1);

int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
int N = N1 < N2 ? N1 : N2;
int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);

if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0)))
marker.at<uchar>(i,j) = 1;
}
}
marker.forEach<uchar>([=](uchar& value, const int postion[]) {
int i = postion[0];
int j = postion[1];
if (i == 0 || j == 0 || i == rows - 1 || j == cols - 1)
return;

auto ptr = img.ptr(i, j); // p1

// p9 p2 p3
// p8 p1 p4
// p7 p6 p5
uchar p2 = ptr[-cols];
uchar p3 = ptr[-cols + 1];
uchar p4 = ptr[1];
uchar p5 = ptr[cols + 1];
uchar p6 = ptr[cols];
uchar p7 = ptr[cols - 1];
uchar p8 = ptr[-1];
uchar p9 = ptr[-cols - 1];

int neighbors = p9 | (p2 << 1) | (p3 << 2) | (p4 << 3) | (p5 << 4) | (p6 << 5) | (p7 << 6) | (p8 << 7);

if (iter == 0)
value = lut_guo_iter0[neighbors];
else
value = lut_guo_iter1[neighbors];

//int C = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
// ((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
//int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
//int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
//int N = N1 < N2 ? N1 : N2;
//int m = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);
//if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0))) value = 0;
});
}

img &= ~marker;
img &= marker;
}

// Apply the thinning procedure to a given image
Expand Down

0 comments on commit ca90d3e

Please sign in to comment.