-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
Image.h
228 lines (189 loc) · 7.98 KB
/
Image.h
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// ----------------------------------------------------------------------------
// - Open3D: www.open3d.org -
// ----------------------------------------------------------------------------
// Copyright (c) 2018-2023 www.open3d.org
// SPDX-License-Identifier: MIT
// ----------------------------------------------------------------------------
#pragma once
#include <Eigen/Core>
#include <memory>
#include <vector>
#include "open3d/geometry/Geometry2D.h"
#include "open3d/utility/Logging.h"
namespace open3d {
namespace camera {
class PinholeCameraIntrinsic;
}
namespace geometry {
class Image;
/// Typedef and functions for ImagePyramid.
typedef std::vector<std::shared_ptr<Image>> ImagePyramid;
/// \class Image
///
/// \brief The Image class stores image with customizable width, height, num of
/// channels and bytes per channel.
class Image : public Geometry2D {
public:
/// \enum ColorToIntensityConversionType
///
/// \brief Specifies whether R, G, B channels have the same weight when
/// converting to intensity. Only used for Image with 3 channels.
///
/// When `Weighted` is used R, G, B channels are weighted according to the
/// Digital ITU BT.601 standard: I = 0.299 * R + 0.587 * G + 0.114 * B.
enum class ColorToIntensityConversionType {
/// R, G, B channels have equal weights.
Equal,
/// Weighted R, G, B channels: I = 0.299 * R + 0.587 * G + 0.114 * B.
Weighted,
};
/// \enum FilterType
///
/// \brief Specifies the Image filter type.
enum class FilterType {
/// Gaussian filter of size 3 x 3.
Gaussian3,
/// Gaussian filter of size 5 x 5.
Gaussian5,
/// Gaussian filter of size 7 x 7.
Gaussian7,
/// Sobel filter along X-axis.
Sobel3Dx,
/// Sobel filter along Y-axis.
Sobel3Dy
};
public:
/// \brief Default Constructor.
Image() : Geometry2D(Geometry::GeometryType::Image) {}
~Image() override {}
public:
Image &Clear() override;
bool IsEmpty() const override;
Eigen::Vector2d GetMinBound() const override;
Eigen::Vector2d GetMaxBound() const override;
/// \brief Test if coordinate `(u, v)` is located in the inner_marge of the
/// image.
///
/// \param u Coordinate along the width dimension.
/// \param v Coordinate along the height dimension.
/// \param inner_margin The inner margin from the image boundary.
/// \return Returns `true` if coordinate `(u, v)` is located in the
/// inner_marge of the image.
bool TestImageBoundary(double u, double v, double inner_margin = 0.0) const;
public:
/// Returns `true` if the Image has valid data.
virtual bool HasData() const {
return width_ > 0 && height_ > 0 &&
data_.size() == size_t(height_ * BytesPerLine());
}
/// \brief Prepare Image properties and allocate Image buffer.
Image &Prepare(int width,
int height,
int num_of_channels,
int bytes_per_channel) {
width_ = width;
height_ = height;
num_of_channels_ = num_of_channels;
bytes_per_channel_ = bytes_per_channel;
AllocateDataBuffer();
return *this;
}
/// \brief Returns data size per line (row, or the width) in bytes.
int BytesPerLine() const {
return width_ * num_of_channels_ * bytes_per_channel_;
}
/// Function to access the bilinear interpolated float value of a
/// (single-channel) float image.
/// Returns a tuple, where the first bool indicates if the u,v coordinates
/// are within the image dimensions, and the second double value is the
/// interpolated pixel value.
std::pair<bool, double> FloatValueAt(double u, double v) const;
/// Factory function to create a float image composed of multipliers that
/// convert depth values into camera distances (ImageFactory.cpp)
/// The multiplier function M(u,v) is defined as:
/// M(u, v) = sqrt(1 + ((u - cx) / fx) ^ 2 + ((v - cy) / fy) ^ 2)
/// This function is used as a convenient function for performance
/// optimization in volumetric integration (see
/// Core/Integration/TSDFVolume.h).
static std::shared_ptr<Image>
CreateDepthToCameraDistanceMultiplierFloatImage(
const camera::PinholeCameraIntrinsic &intrinsic);
/// Return a gray scaled float type image.
std::shared_ptr<Image> CreateFloatImage(
Image::ColorToIntensityConversionType type =
Image::ColorToIntensityConversionType::Weighted) const;
/// Function to access the raw data of a single-channel Image.
template <typename T>
T *PointerAt(int u, int v) const;
/// Function to access the raw data of a multi-channel Image.
template <typename T>
T *PointerAt(int u, int v, int ch) const;
/// Reinterpret the internal data buffer. The resulting type's size must be
/// the same as bytes_per_channel_. This is similar to PointerAt<T>(0, 0).
template <class T>
T *PointerAs() const {
if (sizeof(T) != bytes_per_channel_) {
utility::LogError("sizeof(T) != byte_per_channel_: {} != {}.",
sizeof(T), bytes_per_channel_);
}
return (T *)(data_.data());
}
std::shared_ptr<Image> ConvertDepthToFloatImage(
double depth_scale = 1000.0, double depth_trunc = 3.0) const;
std::shared_ptr<Image> Transpose() const;
/// Function to flip image horizontally (from left to right).
std::shared_ptr<Image> FlipHorizontal() const;
/// Function to flip image vertically (upside down).
std::shared_ptr<Image> FlipVertical() const;
/// Function to filter image with pre-defined filtering type.
std::shared_ptr<Image> Filter(Image::FilterType type) const;
/// Function to filter image with arbitrary dx, dy separable filters.
std::shared_ptr<Image> Filter(const std::vector<double> &dx,
const std::vector<double> &dy) const;
std::shared_ptr<Image> FilterHorizontal(
const std::vector<double> &kernel) const;
/// Function to 2x image downsample using simple 2x2 averaging.
std::shared_ptr<Image> Downsample() const;
/// Function to dilate 8bit mask map.
std::shared_ptr<Image> Dilate(int half_kernel_size = 1) const;
/// Function to linearly transform pixel intensities
/// image_new = scale * image + offset.
Image &LinearTransform(double scale = 1.0, double offset = 0.0);
/// Function to clipping pixel intensities.
///
/// \param min is lower bound.
/// \param max is upper bound.
Image &ClipIntensity(double min = 0.0, double max = 1.0);
/// Function to change data types of image
/// crafted for specific usage such as
/// single channel float image -> 8-bit RGB or 16-bit depth image.
template <typename T>
std::shared_ptr<Image> CreateImageFromFloatImage() const;
/// Function to filter image pyramid.
static ImagePyramid FilterPyramid(const ImagePyramid &input,
Image::FilterType type);
/// Function to create image pyramid.
ImagePyramid CreatePyramid(size_t num_of_levels,
bool with_gaussian_filter = true) const;
/// Function to create a depthmap boundary mask from depth image.
std::shared_ptr<Image> CreateDepthBoundaryMask(
double depth_threshold_for_discontinuity_check = 0.1,
int half_dilation_kernel_size_for_discontinuity_map = 3) const;
protected:
void AllocateDataBuffer() {
data_.resize(width_ * height_ * num_of_channels_ * bytes_per_channel_);
}
public:
/// Width of the image.
int width_ = 0;
/// Height of the image.
int height_ = 0;
/// Number of channels in the image.
int num_of_channels_ = 0;
/// Number of bytes per channel.
int bytes_per_channel_ = 0;
/// Image storage buffer.
std::vector<uint8_t> data_;
};
} // namespace geometry
} // namespace open3d