18 const std::vector<double> Gaussian3 = {0.25, 0.5, 0.25};
19 const std::vector<double> Gaussian5 = {0.0625, 0.25, 0.375, 0.25, 0.0625};
20 const std::vector<double> Gaussian7 = {0.03125, 0.109375, 0.21875, 0.28125,
21 0.21875, 0.109375, 0.03125};
22 const std::vector<double> Sobel31 = {-1.0, 0.0, 1.0};
23 const std::vector<double> Sobel32 = {1.0, 2.0, 1.0};
40 return Eigen::Vector2d(0.0, 0.0);
53 double inner_margin )
const {
54 return (u >= inner_margin && u <
width_ - inner_margin &&
55 v >= inner_margin && v <
height_ - inner_margin);
60 (u < 0.0 || u > (
double)(
width_ - 1) || v < 0.0 ||
64 int ui = std::max(std::min((
int)u,
width_ - 2), 0);
65 int vi = std::max(std::min((
int)v,
height_ - 2), 0);
68 float value[4] = {*PointerAt<float>(ui, vi), *PointerAt<float>(ui, vi + 1),
69 *PointerAt<float>(ui + 1, vi),
70 *PointerAt<float>(ui + 1, vi + 1)};
72 (value[0] * (1 - pv) + value[1] * pv) * (1 - pu) +
73 (value[2] * (1 - pv) + value[3] * pv) * pu);
78 return (T *)(
data_.data() + (v *
width_ + u) *
sizeof(T));
81 template float *Image::PointerAt<float>(
int u,
int v)
const;
82 template int *Image::PointerAt<int>(
int u,
int v)
const;
83 template uint8_t *Image::PointerAt<uint8_t>(
int u,
int v)
const;
84 template uint16_t *Image::PointerAt<uint16_t>(
int u,
int v)
const;
88 return (T *)(
data_.data() +
92 template float *Image::PointerAt<float>(
int u,
int v,
int ch)
const;
93 template int *Image::PointerAt<int>(
int u,
int v,
int ch)
const;
94 template uint8_t *Image::PointerAt<uint8_t>(
int u,
int v,
int ch)
const;
95 template uint16_t *Image::PointerAt<uint16_t>(
int u,
int v,
int ch)
const;
98 double depth_scale ,
double depth_trunc )
const {
102 for (
int y = 0;
y < output->height_;
y++) {
103 for (
int x = 0;
x < output->width_;
x++) {
104 float *p = output->PointerAt<
float>(
x,
y);
105 *p /= (
float)depth_scale;
106 if (*p >= depth_trunc) *p = 0.0f;
118 float *p = PointerAt<float>(
x,
y);
119 if (*p > max) *p = (
float)max;
120 if (*p < min) *p = (
float)min;
132 float *p = PointerAt<float>(
x,
y);
140 auto output = std::make_shared<Image>();
146 output->Prepare(half_width, half_height, 1, 4);
150 #pragma omp parallel for schedule(static) \
151 num_threads(utility::EstimateMaxThreads())
153 #pragma omp parallel for collapse(2) schedule(static) \
154 num_threads(utility::EstimateMaxThreads())
157 for (
int y = 0;
y < output->height_;
y++) {
158 for (
int x = 0;
x < output->width_;
x++) {
159 float *p1 = PointerAt<float>(
x * 2,
y * 2);
160 float *p2 = PointerAt<float>(
x * 2 + 1,
y * 2);
161 float *p3 = PointerAt<float>(
x * 2,
y * 2 + 1);
162 float *p4 = PointerAt<float>(
x * 2 + 1,
y * 2 + 1);
163 float *p = output->PointerAt<
float>(
x,
y);
164 *p = (*p1 + *p2 + *p3 + *p4) / 4.0f;
171 const std::vector<double> &kernel)
const {
172 auto output = std::make_shared<Image>();
174 kernel.size() % 2 != 1) {
176 "[FilterHorizontal] Unsupported image format or kernel "
181 const int half_kernel_size = (int)(
floor((
double)kernel.size() / 2.0));
185 #pragma omp parallel for schedule(static) \
186 num_threads(utility::EstimateMaxThreads())
188 #pragma omp parallel for collapse(2) schedule(static) \
189 num_threads(utility::EstimateMaxThreads())
194 float *po = output->PointerAt<
float>(
x,
y, 0);
196 for (
int i = -half_kernel_size; i <= half_kernel_size; i++) {
198 if (x_shift < 0) x_shift = 0;
200 float *pi = PointerAt<float>(x_shift,
y, 0);
201 temp += (*pi * (
float)kernel[i + half_kernel_size]);
210 auto output = std::make_shared<Image>();
217 output =
Filter(Gaussian3, Gaussian3);
220 output =
Filter(Gaussian5, Gaussian5);
223 output =
Filter(Gaussian7, Gaussian7);
226 output =
Filter(Sobel31, Sobel32);
229 output =
Filter(Sobel32, Sobel31);
240 std::vector<std::shared_ptr<Image>> output;
241 for (
size_t i = 0; i < input.size(); i++) {
242 auto layer_filtered = input[i]->Filter(
type);
243 output.push_back(layer_filtered);
249 const std::vector<double> &dy)
const {
250 auto output = std::make_shared<Image>();
256 auto temp2 = temp1->Transpose();
257 auto temp3 = temp2->FilterHorizontal(dy);
258 auto temp4 = temp3->Transpose();
263 auto output = std::make_shared<Image>();
266 int out_bytes_per_line = output->BytesPerLine();
272 #pragma omp parallel for schedule(static) \
273 num_threads(utility::EstimateMaxThreads())
275 #pragma omp parallel for collapse(2) schedule(static) \
276 num_threads(utility::EstimateMaxThreads())
282 data_.data() +
y * in_bytes_per_line +
x * bytes_per_pixel,
283 data_.data() +
y * in_bytes_per_line +
284 (
x + 1) * bytes_per_pixel,
285 output->data_.data() +
x * out_bytes_per_line +
286 y * bytes_per_pixel);
294 auto output = std::make_shared<Image>();
299 #pragma omp parallel for schedule(static) \
300 num_threads(utility::EstimateMaxThreads())
304 data_.data() + (
y + 1) * bytes_per_line,
305 output->data_.data() + (
height_ -
y - 1) * bytes_per_line);
311 auto output = std::make_shared<Image>();
318 #pragma omp parallel for schedule(static) \
319 num_threads(utility::EstimateMaxThreads())
321 #pragma omp parallel for collapse(2) schedule(static) \
322 num_threads(utility::EstimateMaxThreads())
328 data_.data() +
y * bytes_per_line +
329 (
x + 1) * bytes_per_pixel,
330 output->data_.data() +
y * bytes_per_line +
331 (
width_ -
x - 1) * bytes_per_pixel);
339 auto output = std::make_shared<Image>();
347 #pragma omp parallel for schedule(static) \
348 num_threads(utility::EstimateMaxThreads())
350 #pragma omp parallel for collapse(2) schedule(static) \
351 num_threads(utility::EstimateMaxThreads())
356 for (
int yy = -half_kernel_size; yy <= half_kernel_size; yy++) {
357 for (
int xx = -half_kernel_size; xx <= half_kernel_size; xx++) {
360 pi = PointerAt<unsigned char>(
x + xx,
y + yy);
362 *output->PointerAt<
unsigned char>(
x,
y, 0) = 255;
363 xx = half_kernel_size;
364 yy = half_kernel_size;
375 double depth_threshold_for_discontinuity_check,
376 int half_dilation_kernel_size_for_discontinuity_map)
const {
378 int width = depth_image->width_;
379 int height = depth_image->height_;
380 auto depth_image_gradient_dx =
382 auto depth_image_gradient_dy =
384 auto mask = std::make_shared<Image>();
389 #pragma omp parallel for schedule(static) \
390 num_threads(utility::EstimateMaxThreads())
392 #pragma omp parallel for collapse(2) schedule(static) \
393 num_threads(utility::EstimateMaxThreads())
396 for (
int v = 0; v <
height; v++) {
397 for (
int u = 0; u <
width; u++) {
398 double dx = *depth_image_gradient_dx->PointerAt<
float>(u, v);
399 double dy = *depth_image_gradient_dy->PointerAt<
float>(u, v);
400 double mag = sqrt(dx * dx + dy * dy);
401 if (mag > depth_threshold_for_discontinuity_check) {
402 *mask->PointerAt<
unsigned char>(u, v) = 255;
404 *mask->PointerAt<
unsigned char>(u, v) = 0;
408 if (half_dilation_kernel_size_for_discontinuity_map >= 1) {
410 mask->Dilate(half_dilation_kernel_size_for_discontinuity_map);
Hierarchical CLOUDVIEWER Object.
virtual void onDeletionOf(const ccHObject *obj)
This method is called when another object is deleted.
virtual ccBBox GetAxisAlignedBoundingBox() const
Returns an axis-aligned bounding box of the geometry.
The Image class stores image with customizable width, height, num of channels and bytes per channel.
std::shared_ptr< Image > FlipVertical() const
Function to flip image vertically (upside down).
Image & LinearTransform(double scale=1.0, double offset=0.0)
Image & ClipIntensity(double min=0.0, double max=1.0)
int num_of_channels_
Number of chanels in the image.
virtual Eigen::Vector2d GetMax2DBound() const override
std::shared_ptr< Image > FilterHorizontal(const std::vector< double > &kernel) const
std::pair< bool, double > FloatValueAt(double u, double v) const
std::shared_ptr< Image > Downsample() const
Function to 2x image downsample using simple 2x2 averaging.
virtual void onDeletionOf(const ccHObject *obj) override
This method is called when another object is deleted.
std::shared_ptr< Image > CreateFloatImage(Image::ColorToIntensityConversionType type=Image::ColorToIntensityConversionType::Weighted) const
Return a gray scaled float type image.
int height_
Height of the image.
std::shared_ptr< Image > Dilate(int half_kernel_size=1) const
Function to dilate 8bit mask map.
virtual ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
int BytesPerLine() const
Returns data size per line (row, or the width) in bytes.
int bytes_per_channel_
Number of bytes per channel.
std::shared_ptr< Image > ConvertDepthToFloatImage(double depth_scale=1000.0, double depth_trunc=3.0) const
int width_
Width of the image.
bool TestImageBoundary(double u, double v, double inner_margin=0.0) const
Test if coordinate (u, v) is located in the inner_marge of the image.
std::vector< uint8_t > data_
Image storage buffer.
static ImagePyramid FilterPyramid(const ImagePyramid &input, Image::FilterType type)
Function to filter image pyramid.
std::shared_ptr< Image > FlipHorizontal() const
Function to flip image horizontally (from left to right).
std::shared_ptr< Image > Transpose() const
FilterType
Specifies the Image filter type.
@ Gaussian3
Gaussian filter of size 3 x 3.
@ Gaussian5
Gaussian filter of size 5 x 5.
@ Sobel3Dx
Sobel filter along X-axis.
@ Sobel3Dy
Sobel filter along Y-axis.
@ Gaussian7
Gaussian filter of size 7 x 7.
virtual Eigen::Vector2d GetMin2DBound() const override
T * PointerAt(int u, int v) const
Function to access the raw data of a single-channel Image.
std::shared_ptr< Image > CreateDepthBoundaryMask(double depth_threshold_for_discontinuity_check=0.1, int half_dilation_kernel_size_for_discontinuity_map=3) const
Function to create a depthmap boundary mask from depth image.
std::shared_ptr< Image > Filter(Image::FilterType type) const
Function to filter image with pre-defined filtering type.
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
std::vector< std::shared_ptr< Image > > ImagePyramid
Typedef and functions for ImagePyramid.
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Generic file read and write utility for python interface.