Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/modules/imgcodecs/src/grfmt_pfm.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
5
#include "precomp.hpp"
6
#include "utils.hpp"
7
#include "grfmt_pfm.hpp"
8
#include <iostream>
9
10
#ifdef HAVE_IMGCODEC_PFM
11
12
namespace {
13
14
static_assert(sizeof(float) == 4, "float must be 32 bit.");
15
16
17
bool is_byte_order_swapped(double scale)
18
{
19
// ".pfm" format file specifies that:
20
// positive scale means big endianess;
21
// negative scale means little endianess.
22
23
#ifdef WORDS_BIGENDIAN
24
return scale < 0.0;
25
#else
26
return scale >= 0.0;
27
#endif
28
}
29
30
void swap_endianess(uint32_t& ui)
31
{
32
static const uint32_t A(0x000000ffU);
33
static const uint32_t B(0x0000ff00U);
34
static const uint32_t C(0x00ff0000U);
35
static const uint32_t D(0xff000000U);
36
37
ui = ( (ui & A) << 24 )
38
| ( (ui & B) << 8 )
39
| ( (ui & C) >> 8 )
40
| ( (ui & D) >> 24 );
41
}
42
43
template<typename T> T atoT(const std::string& s);
44
template<> int atoT<int>(const std::string& s) { return std::atoi(s.c_str()); }
45
template<> double atoT<double>(const std::string& s) { return std::atof(s.c_str()); }
46
47
template<typename T>
48
T read_number(cv::RLByteStream& strm)
49
{
50
// should be enogh to take string representation of any number
51
const size_t buffer_size = 2048;
52
53
std::vector<char> buffer(buffer_size, 0);
54
for (size_t i = 0; i < buffer_size; ++i) {
55
const int intc = strm.getByte();
56
CV_Assert(intc >= -128 && intc < 128);
57
char c = static_cast<char>(intc);
58
if (std::isspace(c)) {
59
break;
60
}
61
buffer[i] = c;
62
}
63
const std::string str(buffer.begin(), buffer.end());
64
return atoT<T>(str);
65
}
66
67
template<typename T> void write_anything(cv::WLByteStream& strm, const T& t)
68
{
69
std::ostringstream ss;
70
ss << t;
71
strm.putBytes(ss.str().c_str(), static_cast<int>(ss.str().size()));
72
}
73
74
}
75
76
namespace cv {
77
78
PFMDecoder::~PFMDecoder()
79
{
80
}
81
82
PFMDecoder::PFMDecoder() : m_scale_factor(0), m_swap_byte_order(false)
83
{
84
m_strm.close();
85
}
86
87
bool PFMDecoder::readHeader()
88
{
89
if (m_buf.empty()) {
90
if (!m_strm.open(m_filename)) {
91
return false;
92
}
93
} else {
94
if (!m_strm.open(m_buf)) {
95
return false;
96
}
97
}
98
99
if (m_strm.getByte() != 'P') {
100
CV_Error(Error::StsError, "Unexpected file type (expected P)");
101
}
102
103
switch (m_strm.getByte()) {
104
case 'f':
105
m_type = CV_32FC1;
106
break;
107
case 'F':
108
m_type = CV_32FC3;
109
break;
110
default:
111
CV_Error(Error::StsError, "Unexpected file type (expected `f` or `F`)");
112
}
113
114
if ('\n' != m_strm.getByte()) {
115
CV_Error(Error::StsError, "Unexpected header format (expected line break)");
116
}
117
118
119
m_width = read_number<int>(m_strm);
120
m_height = read_number<int>(m_strm);
121
m_scale_factor = read_number<double>(m_strm);
122
m_swap_byte_order = is_byte_order_swapped(m_scale_factor);
123
124
return true;
125
}
126
127
bool PFMDecoder::readData(Mat& mat)
128
{
129
if (!m_strm.isOpened()) {
130
CV_Error(Error::StsError, "Unexpected status in data stream");
131
}
132
133
Mat buffer(mat.size(), m_type);
134
for (int y = m_height - 1; y >= 0; --y) {
135
m_strm.getBytes(buffer.ptr(y), static_cast<int>(m_width * buffer.elemSize()));
136
if (is_byte_order_swapped(m_scale_factor)) {
137
for (int i = 0; i < m_width * buffer.channels(); ++i) {
138
static_assert( sizeof(uint32_t) == sizeof(float),
139
"uint32_t and float must have same size." );
140
swap_endianess(buffer.ptr<uint32_t>(y)[i]);
141
}
142
}
143
}
144
145
if (buffer.channels() == 3) {
146
cv::cvtColor(buffer, buffer, cv::COLOR_BGR2RGB);
147
}
148
149
CV_Assert(fabs(m_scale_factor) > 0.0f);
150
buffer *= 1.f / fabs(m_scale_factor);
151
152
buffer.convertTo(mat, mat.type());
153
154
return true;
155
}
156
157
size_t PFMDecoder::signatureLength() const
158
{
159
return 3;
160
}
161
162
bool PFMDecoder::checkSignature( const String& signature ) const
163
{
164
return signature.size() >= 3
165
&& signature[0] == 'P'
166
&& ( signature[1] == 'f' || signature[1] == 'F' )
167
&& isspace(signature[2]);
168
}
169
170
void PFMDecoder::close()
171
{
172
// noop
173
}
174
175
//////////////////////////////////////////////////////////////////////////////////////////
176
177
PFMEncoder::PFMEncoder()
178
{
179
m_description = "Portable image format - float (*.pfm)";
180
}
181
182
PFMEncoder::~PFMEncoder()
183
{
184
}
185
186
bool PFMEncoder::isFormatSupported(int depth) const
187
{
188
// any depth will be converted into 32-bit float.
189
CV_UNUSED(depth);
190
return true;
191
}
192
193
bool PFMEncoder::write(const Mat& img, const std::vector<int>& params)
194
{
195
CV_UNUSED(params);
196
197
WLByteStream strm;
198
if (m_buf) {
199
if (!strm.open(*m_buf)) {
200
return false;
201
} else {
202
m_buf->reserve(alignSize(256 + sizeof(float) * img.channels() * img.total(), 256));
203
}
204
} else if (!strm.open(m_filename)) {
205
return false;
206
}
207
208
Mat float_img;
209
strm.putByte('P');
210
switch (img.channels()) {
211
case 1:
212
strm.putByte('f');
213
img.convertTo(float_img, CV_32FC1);
214
break;
215
case 3:
216
strm.putByte('F');
217
img.convertTo(float_img, CV_32FC3);
218
break;
219
default:
220
CV_Error(Error::StsBadArg, "Expected 1 or 3 channel image.");
221
}
222
strm.putByte('\n');
223
224
225
write_anything(strm, float_img.cols);
226
strm.putByte(' ');
227
write_anything(strm, float_img.rows);
228
strm.putByte('\n');
229
#ifdef WORDS_BIGENDIAN
230
write_anything(strm, 1.0);
231
#else
232
write_anything(strm, -1.0);
233
#endif
234
235
strm.putByte('\n');
236
237
// Comments are not officially supported in this file format.
238
// write_anything(strm, "# Generated by OpenCV " CV_VERSION "\n");
239
240
for (int y = float_img.rows - 1; y >= 0; --y)
241
{
242
if (float_img.channels() == 3) {
243
const float* bgr_row = float_img.ptr<float>(y);
244
size_t row_size = float_img.cols * float_img.channels();
245
std::vector<float> rgb_row(row_size);
246
for (int x = 0; x < float_img.cols; ++x) {
247
rgb_row[x*3+0] = bgr_row[x*3+2];
248
rgb_row[x*3+1] = bgr_row[x*3+1];
249
rgb_row[x*3+2] = bgr_row[x*3+0];
250
}
251
strm.putBytes( reinterpret_cast<const uchar*>(rgb_row.data()),
252
static_cast<int>(sizeof(float) * row_size) );
253
} else if (float_img.channels() == 1) {
254
strm.putBytes(float_img.ptr(y), sizeof(float) * float_img.cols);
255
}
256
}
257
return true;
258
}
259
260
261
}
262
263
264
#endif // HAVE_IMGCODEC_PFM
265
266