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
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#include "libvideostitch/imageProcessingUtils.hpp"
#include "pngutil.hpp"
#include "autocrop/autoCrop.hpp"
#include "backend/common/imageOps.hpp"
#include <cmath>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
namespace VideoStitch {
namespace Util {
Status ImageProcessing::findCropCircle(const int& width, const int& height, void* data, int& x, int& y, int& r,
const VideoStitch::Ptv::Value* algoConfig, const std::string* dumpFile) {
x = 0;
y = 0;
r = 0;
cv::Mat originalImage(cv::Size(width, height), CV_8UC4, data);
cv::Mat inputImage;
cv::cvtColor(originalImage, inputImage, CV_RGBA2BGR);
std::unique_ptr<VideoStitch::Ptv::Value> fake(VideoStitch::Ptv::Value::stringObject("fake"));
VideoStitch::AutoCrop::AutoCropConfig config(algoConfig ? algoConfig : fake.get());
AutoCrop::AutoCrop autoCrop(config);
cv::Point3i circle;
FAIL_RETURN(autoCrop.findCropCircle(inputImage, circle));
if (dumpFile) {
FAIL_RETURN(autoCrop.dumpCircleFile(circle, *dumpFile));
}
x = circle.x;
y = circle.y;
r = circle.z;
return Status::OK();
}
Status ImageProcessing::readImage(const std::string& filename, int64_t& width, int64_t& height, int& channelCount,
std::vector<unsigned char>& data) {
std::string lowerStr = filename;
std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower);
if (lowerStr.substr(lowerStr.size() - 3) == "png") {
if (!Util::PngReader::readRGBAFromFile(filename.c_str(), width, height, data)) {
channelCount = 4;
return {Origin::Input, ErrType::InvalidConfiguration, "Could not read RGBA image: '" + filename + "'"};
}
} else {
return {Origin::Input, ErrType::ImplementationError, "Expected PNG image, got: '" + filename + "'"};
}
return Status::OK();
}
#define COLOR_COUNT 10
const float reds[COLOR_COUNT] = {0, 123, 235, 67, 12, 234, 233, 52, 90, 192};
const float greens[COLOR_COUNT] = {32, 65, 128, 12, 0, 223, 178, 96, 182, 155};
const float blues[COLOR_COUNT] = {128, 0, 53, 23, 245, 111, 103, 120, 32, 96};
template <class T>
void ImageProcessing::convertIndexToRGBA(const std::vector<T>& hostRGBA, std::vector<unsigned char>& data,
const int displayBit) {
data.resize(hostRGBA.size() * 4, 0);
for (size_t j = 0; j < hostRGBA.size(); j++) {
int value = hostRGBA[j];
if (displayBit >= 0) {
value = (value & displayBit);
}
int count = 0;
float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
while (value > 0) {
if ((value & 1) > 0) {
r += reds[count % COLOR_COUNT];
g += greens[count % COLOR_COUNT];
b += blues[count % COLOR_COUNT];
a += 1.0f;
}
value = value >> 1;
count++;
}
if (a == 0.0f) {
data[4 * j + 3] = 0;
a = 1;
} else {
data[4 * j + 3] = 255;
}
data[4 * j + 0] = (unsigned char)(std::min(r / a, 255.0f));
data[4 * j + 1] = (unsigned char)(std::min(g / a, 255.0f));
data[4 * j + 2] = (unsigned char)(std::min(b / a, 255.0f));
}
}
template void ImageProcessing::convertIndexToRGBA(const std::vector<uint32_t>& hostRGBA,
std::vector<unsigned char>& data, const int displayBit);
template void ImageProcessing::convertIndexToRGBA(const std::vector<int>& hostRGBA, std::vector<unsigned char>& data,
const int displayBit);
template void ImageProcessing::convertIndexToRGBA(const std::vector<unsigned char>& hostRGBA,
std::vector<unsigned char>& data, const int displayBit);
Status ImageProcessing::packImageRGBA(const std::vector<unsigned char>& data, std::vector<uint32_t>& rgba) {
if (data.size() % 4 != 0) {
return {Origin::Unspecified, ErrType::InvalidConfiguration,
"ImageProcessing::packImageRGBA - Input size is invalid"};
}
rgba.clear();
for (size_t i = 0; i < data.size() / 4; i++) {
rgba.push_back(Image::RGBA::pack(data[4 * i], data[4 * i + 1], data[4 * i + 2], data[4 * i + 3]));
}
return Status::OK();
}
void ImageProcessing::unpackImageRGBA(const std::vector<uint32_t>& rgba, std::vector<unsigned char>& data) {
data.clear();
for (size_t i = 0; i < rgba.size(); i++) {
data.push_back((unsigned char)Image::RGBA::r(rgba[i]));
data.push_back((unsigned char)Image::RGBA::g(rgba[i]));
data.push_back((unsigned char)Image::RGBA::b(rgba[i]));
data.push_back((unsigned char)Image::RGBA::a(rgba[i]));
}
}
uint32_t ImageProcessing::packRGBAColor(const uint32_t r, const uint32_t g, const uint32_t b, const uint32_t a) {
return Image::RGBA::pack(r, g, b, a);
}
uint32_t ImageProcessing::packRGB210Color(const uint32_t r, const uint32_t g, const uint32_t b, const uint32_t a) {
return Image::RGB210::pack(r, g, b, a);
}
} // namespace Util
} // namespace VideoStitch