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
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "gpu/testing.hpp"
#include <util/pngutil.hpp>
#include <util/geometryProcessingUtils.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <cassert>
#include <iostream>
#include <memory>
#include <math.h>
#include <random>
#include <string>
//#define DUMP_TEST_RESULT
#if defined(DUMP_TEST_RESULT)
#undef NDEBUG
#ifdef NDEBUG
#error "This is not supposed to be included in non-debug mode."
#endif
#include "../util/debugUtils.hpp"
#endif
namespace VideoStitch {
namespace Testing {
void testNearestPair() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> di(-100.0f, 100.0f);
gen.seed(0);
for (int sampleCount = 1; sampleCount < 500; sampleCount++) {
cv::Vec2i nearestPair;
std::vector<cv::Point2f> point0s, point1s;
const int n = sampleCount;
const int m = sampleCount;
for (int i = 0; i < n; i++) {
point0s.push_back(cv::Point2f(di(gen), di(gen)));
}
for (int i = 0; i < m; i++) {
point1s.push_back(cv::Point2f(di(gen), di(gen)));
}
Util::GeometryProcessing::findNearestPair(point0s, point1s, nearestPair);
double minDist = std::numeric_limits<double>::max();
for (size_t i = 0; i < point0s.size(); i++) {
for (size_t j = 0; j < point1s.size(); j++) {
double dist = cv::norm(point0s[i] - point1s[j]);
if (dist < minDist) {
minDist = dist;
}
}
}
double nearestPairDist = cv::norm(point0s[nearestPair[0]] - point1s[nearestPair[1]]);
ENSURE(std::abs(nearestPairDist - minDist) < 0.001f);
}
std::cout << "*** Test nearest pair passed." << std::endl;
}
Status loadBoundaryCoords(const std::string& filename, int64_t& width, int64_t& height,
std::vector<cv::Point2f>& points) {
std::vector<unsigned char> data;
Util::PngReader::readRGBAFromFile(filename.c_str(), width, height, data);
cv::Mat image(cv::Size((int)width, (int)height), CV_8UC4, &data[0]);
const int thresh = 100;
cv::Mat src_gray;
cv::Mat canny_output;
cv::cvtColor(image, src_gray, CV_RGBA2GRAY);
// Detect edges using canny
cv::Canny(src_gray, canny_output, thresh, thresh * 2, 3);
// Find contours
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(canny_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, cv::Point(0, 0));
points.clear();
if (contours.size() > 0) {
for (size_t i = 0; i < contours[0].size(); i++) {
points.push_back(contours[0][i]);
}
contours.resize(1);
}
return Status::OK();
}
void testContourMatching() {
#ifdef DUMP_TEST_RESULT
std::string workingPath =
"C:/Users/Chuong.VideoStitch-09/Documents/GitHub/VideoStitch/VideoStitch-master/lib/src/test/";
#else
std::string workingPath = "";
#endif
std::vector<float> matchingCosts = {0.127777740f, 0.835167468f};
for (int test = 0; test <= 1; test++) {
std::vector<cv::Point2f> point0s, point1s;
std::vector<int> matchIndices;
int64_t width0, height0, width1, height1;
loadBoundaryCoords(workingPath + "data/contourmatching/" + std::to_string(test) + "-a.png", width0, height0,
point0s);
loadBoundaryCoords(workingPath + "data/contourmatching/" + std::to_string(test) + "-b.png", width1, height1,
point1s);
float cost = Util::GeometryProcessing::contourMatching(point0s, point1s, matchIndices);
#ifdef DUMP_TEST_RESULT
std::cout << "*** Test contour " << cost << " passed." << std::endl;
#else
ENSURE(std::abs(cost - matchingCosts[test]) < 0.001f, "Matching costs do not match");
#endif
std::cout << "*** Test contour " << test << " passed." << std::endl;
}
}
} // namespace Testing
} // namespace VideoStitch
int main() {
VideoStitch::Testing::testNearestPair();
VideoStitch::Testing::testContourMatching();
return 0;
}