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
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "libvideostitch/imageWarperFactory.hpp"
#include "parallax/noWarper.hpp"
#include "parallax/noFlow.hpp"
#ifndef VS_OPENCL
#include "parallax/linearFlowWarper.hpp"
#include "parallax/simpleFlow.hpp"
#endif
#include "libvideostitch/logging.hpp"
#include "libvideostitch/parse.hpp"
#include <cassert>
#include <mutex>
#include <iostream>
namespace VideoStitch {
namespace Core {
Potential<Core::ImageWarperFactory> ImageWarperFactory::createWarperFactory(const Ptv::Value* value) {
if (!value) {
std::unique_ptr<Ptv::Value> emptyObject = std::unique_ptr<Ptv::Value>(Ptv::Value::emptyObject());
return NoWarper::Factory::parse(*emptyObject.get());
}
// Make sure value is an object, if not, return nowarper
if (!Parse::checkType("ImageWarperFactory", *value, Ptv::Value::OBJECT)) {
return Potential<Core::ImageWarperFactory>(new NoWarper::Factory());
}
std::string type;
if (Parse::populateString("ImageWarperFactory", *value, "type", type, false) == Parse::PopulateResult_WrongType) {
return {Origin::ImageWarper, ErrType::InvalidConfiguration,
"Invalid type for 'type' configuration, expected string"};
}
if (type == NoWarper::getName() || type == "") {
return NoWarper::Factory::parse(*value);
#ifndef VS_OPENCL
} else if (type == LinearFlowWarper::getName()) {
return LinearFlowWarper::Factory::parse(*value);
#endif
} else {
Logger::get(Logger::Error) << "Unknown warper type: '" << type << "'." << std::endl;
return {Origin::ImageWarper, ErrType::InvalidConfiguration, "Invalid warper type"};
}
}
const std::vector<std::string>& ImageWarperFactory::availableWarpers() {
static std::vector<std::string> availableWarpers;
// Lazily fill in the list of mergers. TODO: use a better, macro-based, registration pattern.
static std::mutex mutex;
{
std::unique_lock<std::mutex> lock(mutex);
if (availableWarpers.empty()) {
availableWarpers.push_back(NoWarper::getName());
#ifndef VS_OPENCL
availableWarpers.push_back(LinearFlowWarper::getName());
#endif
}
}
return availableWarpers;
}
std::vector<std::string> ImageWarperFactory::compatibleWarpers(const std::string& flow) {
std::vector<std::string> compatibleWarpers;
// Lazily fill in the list of mergers. TODO: use a better, macro-based, registration pattern.
static std::mutex mutex;
{
std::unique_lock<std::mutex> lock(mutex);
compatibleWarpers.clear();
if (flow == NoFlow::getName()) {
compatibleWarpers.push_back(NoWarper::getName());
}
#ifndef VS_OPENCL
if (flow == SimpleFlow::getName()) {
compatibleWarpers.push_back(LinearFlowWarper::getName());
}
#endif
}
return compatibleWarpers;
}
bool ImageWarperFactory::equal(const ImageWarperFactory& other) const { return hash() == other.hash(); }
namespace {
/**
* A merger factory that cannot instantiate a merger. This can be useful when creating a merger without stitchers.
*/
class ImpotentWarperFactory : public ImageWarperFactory {
public:
virtual Potential<ImageWarper> create() const override {
return {Origin::ImageWarper, ErrType::ImplementationError, "ImpotentWarper is not implemented properly"};
}
virtual ~ImpotentWarperFactory() {}
virtual Ptv::Value* serialize() const override { return nullptr; }
virtual std::string getImageWarperName() const override { return "ImpotentWarper"; }
virtual bool needsInputPreProcessing() const override { return false; }
virtual ImpotentWarperFactory* clone() const override { return new ImpotentWarperFactory(); }
virtual std::string hash() const override { return "ImpotentWarper"; }
};
} // namespace
Potential<ImageWarperFactory> ImageWarperFactory::newImpotentWarperFactory() {
return Potential<ImageWarperFactory>(new ImpotentWarperFactory);
}
} // namespace Core
} // namespace VideoStitch