-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvectorizer_vectorix.cpp
More file actions
178 lines (160 loc) · 4.96 KB
/
vectorizer_vectorix.cpp
File metadata and controls
178 lines (160 loc) · 4.96 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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Vectorix -- line-based image vectorizer
* (c) 2016 Jan Hadrava <had@atrey.karlin.mff.cuni.cz>
*/
#include <opencv2/opencv.hpp>
#include "v_image.h"
#include "geom.h"
#include "pnm_handler.h"
#include "vectorizer.h"
#include "vectorizer_vectorix.h"
#include "timer.h"
#include "parameters.h"
#include <string>
#include <cmath>
#include <algorithm>
#include <tuple>
#include <vector>
#include "logger.h"
#include "thresholder.h"
#include "skeletonizer.h"
#include "tracer.h"
#include "approximation.h"
#include "zoom_window.h"
// Vectorizer
using namespace cv;
namespace vectorix {
int vectorizer_vectorix::interactive(int state, int key) { // Process key press and decide what to do
int ret = state;
switch (key & ((2 << 16) - 1)) {
case 0:
case 0xFF:
case 0xFFFF:
case 0xFF51:
case 0xFF52:
case 0xFF53:
case 0xFF54:
break; // Nothing
case 'q':
case 'Q':
case 27: // Esc
ret = 0; // Quit program
break;
case 'r':
case 'R':
ret = 1; // Rerun from step 1
break;
case '\n':
ret++; // Next vectorization step
break;
case 'h':
case 'H':
default:
log.log<log_level::info>("Help:\n");
log.log<log_level::info>("\tEnter\tContinue with next step\n");
log.log<log_level::info>("\tr\tRerun vectorization from begining\n");
log.log<log_level::info>("\tq, Esc\tQuit\n");
log.log<log_level::info>("\th\tHelp\n");
break;
}
return ret;
}
void vectorizer_vectorix::step1_changed(int, void *ptr) { // Parameter in step 1 changed, rerun
volatile int *state = static_cast<volatile int *> (ptr);
*state = 2; // first step
}
void vectorizer_vectorix::step2_changed(int, void *ptr) { // Parameter in step 2 changed, rerun from this state
volatile int *state = static_cast<volatile int *> (ptr);
if (*state >= 4)
*state = 2; // second step
}
void vectorizer_vectorix::load_image(const pnm_image &original) {
// Original should be PPM image (color)
orig = Mat(original.height, original.width, CV_8UC(3));
if (param_custom_input_name->empty()) {
for (int j = 0; j < original.height; j++) { // Copy data from PNM image to OpenCV image structures
for (int i = 0; i<original.width; i++) {
orig.at<Vec3b>(j, i)[2] = original.data[(i+j*original.width)*3 + 0];
orig.at<Vec3b>(j, i)[1] = original.data[(i+j*original.width)*3 + 1];
orig.at<Vec3b>(j, i)[0] = original.data[(i+j*original.width)*3 + 2];
}
}
}
else {
// Configuration tell us to read image from file directly by OpenCV
orig = imread(*param_custom_input_name, CV_LOAD_IMAGE_COLOR);
if (!orig.data) {
log.log<log_level::error>("Unable to read image from file \"%s\"\n", param_custom_input_name->c_str());
throw("Unable to read input image");
}
}
}
v_image vectorizer_vectorix::vectorize(const pnm_image &original) {
load_image(original);
v_image vect = v_image(orig.cols, orig.rows); // Vector output
thresholder thr(*par);
skeletonizer ske(*par);
tracer tra(*par);
approximation apx(*par);
if (*param_interactive) {
timer threshold_timer;
timer skeletonization_timer;
timer tracing_timer;
timer approximation_timer;
volatile int state = 2; // State of vectorizer, remembers in which step we are
while (state) { // state 0 = end
switch (state) {
case 2: // First step
zoom_imshow("Original", orig, true); // Show original color image
waitKey(1); // interactive == 1: wait until the key is pressed; interactive == 0: Continue after one milisecond
threshold_timer.start();
thr.run(orig, binary);
threshold_timer.stop();
log.log<log_level::info>("Threshold time: %fs\n", threshold_timer.read());
thr.interactive(step1_changed, (void*) &state);
state++; // ... and wait in odd state for Enter
break;
case 4:
skeletonization_timer.start();
ske.run(binary, skeleton, distance); // Second step -- skeletonization
skeletonization_timer.stop();
log.log<log_level::info>("Skeletonization time: %fs\n", skeletonization_timer.read());
ske.interactive(step2_changed, (void*) &state);
state++; // ... and wait in odd state for Enter
break;
case 6:
tracing_timer.start();
tra.run(orig, skeleton, distance, vect);
tracing_timer.stop();
log.log<log_level::info>("Tracing time: %fs\n", tracing_timer.read());
state++; // ... and wait in odd state for Enter
break;
case 8:
approximation_timer.start();
apx.run(vect);
approximation_timer.stop();
log.log<log_level::info>("Approximation time: %fs\n", approximation_timer.read());
state++; // ... and wait in odd state for Enter
break;
case 10:
state = 0;
break;
default:
int key = waitKey(1);
if (key >= 0) {
log.log<log_level::debug>("Key: %i\n", key);
state = interactive(state, key);
}
}
}
}
else {
thr.run(orig, binary);
ske.run(binary, skeleton, distance); // Second step -- skeletonization
tra.run(orig, skeleton, distance, vect);
apx.run(vect);
}
log.log<log_level::debug>("end of vectorization\n");
return vect;
}
}; // namespace