-
Notifications
You must be signed in to change notification settings - Fork 0
/
showsegments.cpp
249 lines (220 loc) · 9.14 KB
/
showsegments.cpp
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/*
* Author: Artur Dobrogowski
* 2020-01-05
*/
#include <iostream>
#include <iomanip>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <cstdio>
#include <fstream>
#include "configuration.h"
#include "point.h"
#include "segment.h"
#include "segmentfiller.h"
#include "maskoperators.h"
#include "preprocessing.h"
//#include <cstring>
#include <string>
using namespace std;
const int N_COEFFICIENTS=12;
const std::string shapes[] = {"u", "p", "s", "r"};
constexpr int N_SHAPES = sizeof(shapes)/sizeof(std::string);
class Shape {
public:
Shape(std::string name_="") : name(name_) {}
std::string name;
double mean[N_COEFFICIENTS];
double stdev[N_COEFFICIENTS];
float weights[N_COEFFICIENTS];
//weights
double get_distance(Segment &s);
void load();
};
double Shape::get_distance(Segment &s) {
double dist = 0;
for(int i=0; i<N_COEFFICIENTS; ++i) {
double normalized = (s.getIMCoeff(i)-mean[i])/stdev[i];
dist += weights[i] * abs(normalized);
}
return dist;
}
void Shape::load() {
std::ifstream file;
file.open((name + std::string(".shape")).c_str());
for(int i=0; i<N_COEFFICIENTS; ++i)
file >> mean[i];
for(int i=0; i<N_COEFFICIENTS; ++i)
file >> stdev[i];
for(int i=0; i<N_COEFFICIENTS; ++i)
file >> weights[i];
}
int check_for_string(const int n, char ** argv, char const* str) {
int result = 0;
for(int i=0; i < n; ++i)
if((strcmp(argv[i], str) == 0))
result = i;
return result;
}
char const * get_basename(char const *path) {
int n = strlen(path);
while(n--) {
if(path[n] == '/')
break;
}
if(n < 0)
return path;
else
return path+n+1;
}
int main(int argc, char **argv) {
if(check_for_string(argc, argv, "-h") || check_for_string(argc, argv, "--help") || argc < 2) {
cout << "Usage: <command> [options] <path for processing>\nOptions: \n\t-d,--debug - for extra info\n\t-m,--mask - treat input image as a mask to segmentate\n\t-s,--source - for displaying image path as source\n\t-c,--central - for displaying non-zero central moments\n\t-t,--test compare values with opencv builtin HuMoments, requires --debug\n\t-r,--header - display in first row the header for printed values\n\t-o,--output - save segmentation result with given path\n\t--contrast <C> <L> - adjusts contrast and lightness before processing the image C from range <-128:1280>, L from range <-255:255>\n\t--detect - flag to use shape values to detect u, p, s, border shapes\n\nCurrently there are " << N_COEFFICIENTS << " coefficients." << endl;
return 0;
}
ifstream f(argv[argc-1]);
if(f.good())
f.close();
else {
cout << "Cannot open " << argv[1] << endl;
return -1;
}
int debug = check_for_string(argc, argv, "-d") + check_for_string(argc, argv, "--debug");
int mask_as_input = check_for_string(argc, argv, "-m") + check_for_string(argc, argv, "--mask");
int display_source = check_for_string(argc, argv, "-s") + check_for_string(argc, argv, "--source");
int display_central = check_for_string(argc, argv, "-c") + check_for_string(argc, argv, "--central");
int display_header = check_for_string(argc, argv, "-r") + check_for_string(argc, argv, "--header");
// bool display_basic = check_for_string(argc, argv, "-b") || check_for_string(argc, argv, "--basic");
int test = check_for_string(argc, argv, "-t") + check_for_string(argc, argv, "--test");
int output_mask = check_for_string(argc, argv, "-o") + check_for_string(argc, argv, "--output");
int improve_contrast = check_for_string(argc, argv, "--contrast");
int detect = check_for_string(argc, argv, "--detect");
vector<Segment> segments;
int discarded_segments = 0;
// Reading the image
std::string input_file(argv[argc-1]);
cv::Mat image = cv::imread(input_file.c_str(), cv::IMREAD_COLOR);
cv::Mat segmentated_image_mask = image;
// Segmentation
if(mask_as_input)
cv::cvtColor(image, segmentated_image_mask, cv::COLOR_BGR2GRAY);
else {
if(improve_contrast) {
int lightness;
int contrast;
if(improve_contrast+2 < argc && sscanf(argv[improve_contrast+2], "%d", &lightness) && sscanf(argv[improve_contrast+1], "%d", &contrast) ) {
lighten_rgb(image, lightness);
contrast_rgb(image, contrast);
} else {
std::cerr << "Error in parsing contrast parameters, provide two integer values, see --help for reference\n";
return 1;
}
}
segmentated_image_mask = ups_segmentate(image);
}
if(output_mask) {
std::string output_file = "output_mask.png";//input_file;
//output_file.insert(output_file.end()-4, "_mask");
cv::imwrite(output_file.c_str(), segmentated_image_mask);
}
// Separating segments and calculating moments
discarded_segments += separate_segments(segmentated_image_mask, segments);
// Displaying segmentation results
if(debug) cout << "Found segments: \n";
cout << std::setprecision(12);
cout.setf(std::ios_base::scientific, std::ios_base::showpos);
char const *basename = get_basename(argv[argc-1]);
int k = 0;
// Tables for non-zero central moments values
int a[] = {0, 1, 2, 0, 2, 1, 3, 0};
int b[] = {0, 1, 0, 2, 1, 2, 0, 3};
constexpr size_t central_moments_num = sizeof(a)/sizeof(int);
// Handle displaying header table for values
if(display_header) {
if(display_source) cout << "sourcefile " << "n-th_segment ";
if(display_central) for(int i=0; i<central_moments_num; ++i) cout << "M" << a[i] << b[i] << " ";
for(int i=0; i<N_COEFFICIENTS; ++i) cout << "M" << i << " ";
cout << endl;
}
if( !detect) {
for( auto &s : segments ) {
if(display_source) cout << basename << " " << k++ << " ";
if(debug) cout << s << endl;
if(debug) {
cout << "Basic moments: " << endl;
for (int l = 0; l < 4; ++l) {
for (int j = 0; j < 4; ++j)
cout << s.m[l][j] << " ";
} cout << endl;
}
if(display_central) {
s.updateMomentsCentralMoments();
if(debug) cout << "Central moments: \n";
for (int i=0; i<central_moments_num; ++i)
cout << s.M[a[i]][b[i]] << " ";
}
if(debug) cout << " Invariants: " << endl;
for(int i=0; i<N_COEFFICIENTS; ++i)
cout << s.getIMCoeff(i) << " ";
cout << endl;
}
}
// Comparison with library implementation
if(test && debug) {
cout << "Library calculated HuMoments\n";
// Calculate Moments
cv::Moments moments = cv::moments(segmentated_image_mask, false);
// Calculate Hu Moments
double huMoments[7];
cv::HuMoments(moments, huMoments);
for(int i=0; i<7; ++i)
cout << huMoments[i] << " ";
cout << endl;
cout << "Difference between HuMoments and invariants of 1st segment:\n";
for(int i=0; i<7; ++i)
cout << huMoments[i]-segments[0].getIMCoeff(i) << " ";
cout << endl;
}
if(detect) {
Shape shp[N_SHAPES];
for(int i=0; i<N_SHAPES; ++i) {
shp[i].name = shapes[i];
shp[i].load();
if(debug) {
cout << shp[i].name << endl;
for(int j=0; j<N_COEFFICIENTS; ++j) {
cout << shp[i].mean[j] << " " << shp[i].stdev[j] << " " << shp[i].weights[j] << endl;
}
}
}
for (int i=0; i<N_SHAPES; ++i) {
vector<pair<double, Segment*> > order;
for ( auto &a : segments) {
order.push_back(make_pair(shp[i].get_distance(a), &a));
}
std::sort(order.begin(), order.end());
cout << "Minimal " << shp[i].name << " distance = " << order[0].first << endl;
if(debug) {
cout << "Least distance 3 samples:\n";
for(int k=0; k<3; ++k) {
cout << order[k].first << " ";
for(int j=0; j<N_COEFFICIENTS; ++j) {
cout << std::setprecision(2) << order[k].second->getIMCoeff(j) << " ";
}
cout << endl;
cout << order[k].second->start << order[k].second->end << endl;
}
cv::rectangle(image, cv::Point(order[0].second->start.x, order[0].second->start.y), cv::Point(order[0].second->end.x, order[0].second->end.y), cv::Scalar(0, 80*i, 255 - 80*i));
}
}
if(debug && output_mask) {
std::string output_file = input_file;
output_file.insert(output_file.length()-4, "_detected");
cv::imwrite(output_file.c_str(), image);
}
}
if(debug) cout << "Discarded segments = " << discarded_segments << endl;
discarded_segments = 0;
return 0;
}