-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzhang_suen.cpp
More file actions
113 lines (102 loc) · 3.72 KB
/
zhang_suen.cpp
File metadata and controls
113 lines (102 loc) · 3.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
* Vectorix -- line-based image vectorizer
* (c) 2016 Jan Hadrava <had@atrey.karlin.mff.cuni.cz>
*/
#include <opencv2/opencv.hpp>
#include <vector>
#include <string>
#include "zhang_suen.h"
using namespace cv;
namespace vectorix {
int zhang_suen::skeletonize(const Mat &input, Mat &it, Mat &distance) {
it = input.clone();
inq = Mat::zeros(it.rows, it.cols, CV_8UC(1));
distance = Mat::zeros(it.rows, it.cols, CV_32SC1);
itp = ⁢
init_queue();
bool first_iteration = 1;
int iteration = 1;
while (border_queue.size()) {
log.log<log_level::info>("Skeletonizer (Zhang-Suen) iteration: %i (%i points)\n", iteration, border_queue.size());
if (!param_save_peeled_name->empty()) { // Save every step of skeletonization
size_t number_sign = param_save_peeled_name->find("#");
std::string filename = std::to_string(iteration);
int zero = 3 - filename.length();
zero = (zero >= 0) ? zero : 0;
filename = param_save_peeled_name->substr(0, number_sign)
+ std::string(zero, '0')
+ filename
+ param_save_peeled_name->substr(number_sign + 1);
imwrite(filename, it);
}
delete_queue.clear();
border_queue.insert(border_queue.end(), to_next_step_queue.begin(), to_next_step_queue.end());
to_next_step_queue.clear();
for (auto p: border_queue) {
int i = p.y;
int j = p.x;
if (2 <= B(p) && B(p) <= 6 &&
A(p) == 1 &&
it.at<uint8_t>(i - 1, j) * it.at<uint8_t>(i, j + 1) * (it.at<uint8_t>(i + 1, j) + !first_iteration) * (it.at<uint8_t>(i, j - 1) + first_iteration) == 0 &&
(it.at<uint8_t>(i - 1, j) + first_iteration) * (it.at<uint8_t>(i, j + 1) + !first_iteration) * it.at<uint8_t>(i + 1, j) * it.at<uint8_t>(i, j - 1) == 0) {
delete_queue.emplace_back(Point(j, i));
inq.at<uint8_t>(i, j) = 0;
}
else if (inq.at<uint8_t>(i, j) == 2)
to_next_step_queue.emplace_back(Point(j, i));
inq.at<uint8_t>(i, j)--;
}
border_queue.clear();
for (auto p: delete_queue) {
it.at<uint8_t>(p) = 0;
distance.at<int32_t>(p) = iteration;
for (int i = p.y - 1; i <= p.y + 1; i++) {
for (int j = p.x - 1; j <= p.x + 1; j++) {
if (inq.at<uint8_t>(i, j) != 2 && it.at<uint8_t>(i, j)) {
border_queue.emplace_back(Point(j, i));
}
inq.at<uint8_t>(i, j) = 2;
}
}
}
first_iteration ^= 1;
iteration++;
}
return iteration;
}
int zhang_suen::B(Point pt) const {
int i = pt.y;
int j = pt.x;
return !!itp->at<uint8_t>(i - 1, j) +
!!itp->at<uint8_t>(i - 1, j + 1) +
!!itp->at<uint8_t>(i, j + 1) +
!!itp->at<uint8_t>(i + 1, j + 1) +
!!itp->at<uint8_t>(i + 1, j) +
!!itp->at<uint8_t>(i + 1, j - 1) +
!!itp->at<uint8_t>(i, j - 1) +
!!itp->at<uint8_t>(i - 1, j - 1);
}
int zhang_suen::A(Point pt) const {
int i = pt.y;
int j = pt.x;
return (int)(!itp->at<uint8_t>(i - 1, j ) && itp->at<uint8_t>(i - 1, j + 1)) +
(int)(!itp->at<uint8_t>(i - 1, j + 1) && itp->at<uint8_t>(i, j + 1)) +
(int)(!itp->at<uint8_t>(i, j + 1) && itp->at<uint8_t>(i + 1, j + 1)) +
(int)(!itp->at<uint8_t>(i + 1, j + 1) && itp->at<uint8_t>(i + 1, j )) +
(int)(!itp->at<uint8_t>(i + 1, j ) && itp->at<uint8_t>(i + 1, j - 1)) +
(int)(!itp->at<uint8_t>(i + 1, j - 1) && itp->at<uint8_t>(i, j - 1)) +
(int)(!itp->at<uint8_t>(i, j - 1) && itp->at<uint8_t>(i - 1, j - 1)) +
(int)(!itp->at<uint8_t>(i - 1, j - 1) && itp->at<uint8_t>(i - 1, j ));
}
void zhang_suen::init_queue() {
border_queue.clear();
for (int i = 1 ; i < itp->rows - 1; i++) {
for (int j = 1 ; j < itp->cols - 1; j++) {
if (itp->at<uint8_t>(i, j) && B(Point(j, i)) <= 6) {
border_queue.emplace_back(Point(j, i));
inq.at<uint8_t>(i, j) = 2;
}
}
}
}
}; // namespace