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
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "./linearFlowWarper.hpp"
#include "backend/cuda/deviceBuffer.hpp"
#include "core1/imageMerger.hpp"
#include "cuda/error.hpp"
#include "cuda/util.hpp"
#include "gpu/core1/voronoi.hpp"
#include "gpu/uniqueBuffer.hpp"
#include "parse/json.hpp"
#include "libvideostitch/parse.hpp"
//#define WARPER_DEBUG
#ifdef WARPER_DEBUG
#ifndef NDEBUG
#include "util/debugUtils.hpp"
#include <sstream>
#endif
#endif
namespace VideoStitch {
namespace Core {
#define LINEAR_FLOW_WRAPER_MAX_TRANSITION_DISTANCE 150
#define LINEAR_FLOW_WRAPER_POWER 1.0
Potential<ImageWarperFactory> LinearFlowWarper::Factory::parse(const Ptv::Value& value) {
int maxTransitionDistance = LINEAR_FLOW_WRAPER_MAX_TRANSITION_DISTANCE;
if (Parse::populateInt("LinearFlowWarperFactory", value, "maxTransitionDistance", maxTransitionDistance, false) ==
Parse::PopulateResult_WrongType) {
return {Origin::Stitcher, ErrType::InvalidConfiguration,
"Invalid type for 'maxTransitionDistance' configuration, expected int"};
}
double power = LINEAR_FLOW_WRAPER_POWER;
if (Parse::populateDouble("LinearFlowWarperFactory", value, "power", power, false) ==
Parse::PopulateResult_WrongType) {
return {Origin::Stitcher, ErrType::InvalidConfiguration,
"Invalid type for 'maxTransitionDistance' configuration, expected double"};
}
return Potential<ImageWarperFactory>(new LinearFlowWarper::Factory((float)maxTransitionDistance, power));
}
LinearFlowWarper::Factory::Factory(const float maxTransitionDistance, const double power)
: maxTransitionDistance(maxTransitionDistance), power(power) {}
Ptv::Value* LinearFlowWarper::Factory::serialize() const {
Ptv::Value* res = Ptv::Value::emptyObject();
res->push("type", new Parse::JsonValue(LinearFlowWarper::getName()));
res->push("maxTransitionDistance", new Parse::JsonValue(maxTransitionDistance));
res->push("power", new Parse::JsonValue(power));
return res;
}
std::string LinearFlowWarper::Factory::getImageWarperName() const { return LinearFlowWarper::getName(); }
std::string LinearFlowWarper::Factory::hash() const {
std::stringstream ss;
ss << "LinearFlowWarper "
<< "maxTransitionDistance " << maxTransitionDistance << "power " << power;
return ss.str();
}
Potential<ImageWarper> LinearFlowWarper::Factory::create() const {
std::map<std::string, float> parameters;
parameters["maxTransitionDistance"] = (float)maxTransitionDistance;
parameters["power"] = (float)power;
return Potential<ImageWarper>(new LinearFlowWarper(parameters));
}
bool LinearFlowWarper::Factory::needsInputPreProcessing() const { return true; }
ImageWarperFactory* LinearFlowWarper::Factory::clone() const { return new Factory(maxTransitionDistance, power); }
LinearFlowWarper::LinearFlowWarper(const std::map<std::string, float>& parameters_) : ImageWarper(parameters_) {
if (parameters.find("maxTransitionDistance") == parameters.end()) {
parameters["maxTransitionDistance"] = LINEAR_FLOW_WRAPER_MAX_TRANSITION_DISTANCE;
}
if (parameters.find("power") == parameters.end()) {
parameters["power"] = LINEAR_FLOW_WRAPER_POWER;
}
}
std::string LinearFlowWarper::getName() { return std::string("linearflow"); }
const GPU::Buffer<const unsigned char> LinearFlowWarper::getLinearMaskWeight() const {
return linearMaskWeight.borrow_const();
}
Rect LinearFlowWarper::getMaskRect() const { return mergerPair->getBoundingPanosIRect(); }
bool LinearFlowWarper::needImageFlow() const { return true; }
Status LinearFlowWarper::setupCommon(GPU::Stream gpuStream) {
if (!mergerPair->doesOverlap()) {
return Status::OK();
}
const float maxTransitionDistance = parameters["maxTransitionDistance"];
const double power = parameters["power"];
// Use Voronoi mask generated from voronoiKernel to generate a smooth transition
// from the first to the second image
// Prepare our own devMask
Rect iRect = mergerPair->getBoundingPanosIRect();
GPU::UniqueBuffer<uint32_t> work1;
GPU::UniqueBuffer<uint32_t> work2;
GPU::UniqueBuffer<uint32_t> devMask;
FAIL_RETURN(devMask.alloc(iRect.getWidth() * iRect.getHeight(), "Linear Flow Warper"));
FAIL_RETURN(work1.alloc(iRect.getWidth() * iRect.getHeight(), "Linear Flow Warper"));
FAIL_RETURN(work2.alloc(iRect.getWidth() * iRect.getHeight(), "Linear Flow Warper"));
FAIL_RETURN(linearMaskWeight.alloc(iRect.getWidth() * iRect.getHeight(), "Linear Flow Warper"));
FAIL_RETURN(mergerPair->setupPairMappingMask(devMask.borrow(), gpuStream));
#ifdef WARPER_DEBUG
{
std::stringstream ss;
ss.str("");
ss << "C:/Users/Chuong.VideoStitch-09/Documents/GitHub/VideoStitch/VideoStitch-master/lib/src/test/data/flow/";
ss << "panoToInput0-";
ss << mergerPair->getImIdString(0) << " - " << mergerPair->getImIdString(1) << ".png";
Debug::dumpRGBACoordinateDeviceBuffer(ss.str().c_str(), mergerPair->getPanoToInputSpaceCoordMapping(0),
mergerPair->getBoundingPanoRect(0).getWidth(),
mergerPair->getBoundingPanoRect(0).getHeight());
}
{
std::stringstream ss;
ss.str("");
ss << "C:/Users/Chuong.VideoStitch-09/Documents/GitHub/VideoStitch/VideoStitch-master/lib/src/test/data/flow/";
ss << "warperMaskDev-";
ss << mergerPair->getImIdString(0) << " - " << mergerPair->getImIdString(1) << ".png";
Debug::dumpRGBAIndexDeviceBuffer(ss.str().c_str(), devMask.borrow_const(), iRect.getWidth(), iRect.getHeight());
}
#endif
FAIL_RETURN(computeEuclideanDistanceMap(linearMaskWeight.borrow(), devMask.borrow(), work1.borrow(), work2.borrow(),
iRect.getWidth(), iRect.getHeight(), 1 << 2, 1 << 1, false,
maxTransitionDistance, (float)power, gpuStream));
#ifdef WARPER_DEBUG
{
std::stringstream ss;
ss.str("");
ss << "C:/Users/Chuong.VideoStitch-09/Documents/GitHub/VideoStitch/VideoStitch-master/lib/src/test/data/flow/";
ss << "warperMaskWeight-";
ss << mergerPair->getImIdString(0) << " - " << mergerPair->getImIdString(1) << ".png";
Debug::dumpMonochromeDeviceBuffer<Debug::linear>(ss.str().c_str(), linearMaskWeight.borrow_const(),
iRect.getWidth(), iRect.getHeight());
}
#endif
return CUDA_STATUS;
}
ImageWarper::ImageWarperAlgorithm LinearFlowWarper::getWarperAlgorithm() const {
return ImageWarper::ImageWarperAlgorithm::LinearFlowWarper;
}
} // namespace Core
} // namespace VideoStitch