Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
eos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Richard Torenvliet
eos
Commits
1ff4cd40
Commit
1ff4cd40
authored
Aug 01, 2015
by
patrikhuber
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved the internal texture extraction functions to a file in the detail namespace
parent
86d44ed2
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
153 additions
and
112 deletions
+153
-112
CMakeLists.txt
CMakeLists.txt
+1
-0
include/eos/render/detail/texture_extraction_detail.hpp
include/eos/render/detail/texture_extraction_detail.hpp
+147
-0
include/eos/render/texture_extraction.hpp
include/eos/render/texture_extraction.hpp
+5
-112
No files found.
CMakeLists.txt
View file @
1ff4cd40
...
...
@@ -91,6 +91,7 @@ set(HEADERS
include/eos/render/render_affine.hpp
include/eos/render/detail/render_detail.hpp
include/eos/render/texture_extraction.hpp
include/eos/render/detail/texture_extraction_detail.hpp
)
# Add header includes:
...
...
include/eos/render/detail/texture_extraction_detail.hpp
0 → 100644
View file @
1ff4cd40
/*
* Eos - A 3D Morphable Model fitting library written in modern C++11/14.
*
* File: include/eos/render/detail/texture_extraction_detail.hpp
*
* Copyright 2014, 2015 Patrik Huber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#ifndef TEXTURE_EXTRACTION_DETAIL_HPP_
#define TEXTURE_EXTRACTION_DETAIL_HPP_
#include "eos/render/detail/render_detail.hpp"
#include "opencv2/core/core.hpp"
/**
* Implementations of internal functions, not part of the
* API we expose and not meant to be used by a user.
*/
namespace
eos
{
namespace
render
{
namespace
detail
{
/**
* Computes whether the given point is inside (or on the border of) the triangle
* formed out of the given three vertices.
*
* @param[in] point The point to check.
* @param[in] triV0 First vertex.
* @param[in] triV1 Second vertex.
* @param[in] triV2 Third vertex.
* @return Whether the point is inside the triangle.
*/
inline
bool
is_point_in_triangle
(
cv
::
Point2f
point
,
cv
::
Point2f
triV0
,
cv
::
Point2f
triV1
,
cv
::
Point2f
triV2
)
{
// See http://www.blackpawn.com/texts/pointinpoly/
// Compute vectors
cv
::
Point2f
v0
=
triV2
-
triV0
;
cv
::
Point2f
v1
=
triV1
-
triV0
;
cv
::
Point2f
v2
=
point
-
triV0
;
// Compute dot products
float
dot00
=
v0
.
dot
(
v0
);
float
dot01
=
v0
.
dot
(
v1
);
float
dot02
=
v0
.
dot
(
v2
);
float
dot11
=
v1
.
dot
(
v1
);
float
dot12
=
v1
.
dot
(
v2
);
// Compute barycentric coordinates
float
invDenom
=
1
/
(
dot00
*
dot11
-
dot01
*
dot01
);
float
u
=
(
dot11
*
dot02
-
dot01
*
dot12
)
*
invDenom
;
float
v
=
(
dot00
*
dot12
-
dot01
*
dot02
)
*
invDenom
;
// Check if point is in triangle
return
(
u
>=
0
)
&&
(
v
>=
0
)
&&
(
u
+
v
<
1
);
};
/**
* Checks whether all pixels in the given triangle are visible and
* returns true if and only if the whole triangle is visible.
* The vertices should be given in screen coordinates, but with their
* z-values preserved, so they can be compared against the depthbuffer.
*
* @param[in] v0 First vertex, in screen coordinates (but still with their z-value).
* @param[in] v1 Second vertex.
* @param[in] v2 Third vertex.
* @param[in] depthbuffer Pre-calculated depthbuffer.
* @return True if the whole triangle is visible in the image.
*/
bool
is_triangle_visible
(
const
cv
::
Vec4f
&
v0
,
const
cv
::
Vec4f
&
v1
,
const
cv
::
Vec4f
&
v2
,
cv
::
Mat
depthbuffer
)
{
// #Todo: Actually, only check the 3 vertex points, don't loop over the pixels - this should be enough.
auto
viewport_width
=
depthbuffer
.
cols
;
auto
viewport_height
=
depthbuffer
.
rows
;
// Well, in in principle, we'd have to do the whole stuff as in render(), like
// clipping against the frustums etc.
// But as long as our model is fully on the screen, we're fine. Todo: Doublecheck that.
if
(
!
detail
::
are_vertices_ccw_in_screen_space
(
v0
,
v1
,
v2
))
return
false
;
cv
::
Rect
bbox
=
detail
::
calculate_clipped_bounding_box
(
v0
,
v1
,
v2
,
viewport_width
,
viewport_height
);
int
minX
=
bbox
.
x
;
int
maxX
=
bbox
.
x
+
bbox
.
width
;
int
minY
=
bbox
.
y
;
int
maxY
=
bbox
.
y
+
bbox
.
height
;
//if (t.maxX <= t.minX || t.maxY <= t.minY) // Note: Can the width/height of the bbox be negative? Maybe we only need to check for equality here?
// continue; // Also, I'm not entirely sure why I commented this out
bool
whole_triangle_is_visible
=
true
;
for
(
int
yi
=
minY
;
yi
<=
maxY
;
yi
++
)
{
for
(
int
xi
=
minX
;
xi
<=
maxX
;
xi
++
)
{
// we want centers of pixels to be used in computations. Do we?
const
float
x
=
static_cast
<
float
>
(
xi
)
+
0.5
f
;
const
float
y
=
static_cast
<
float
>
(
yi
)
+
0.5
f
;
// these will be used for barycentric weights computation
const
double
one_over_v0ToLine12
=
1.0
/
detail
::
implicit_line
(
v0
[
0
],
v0
[
1
],
v1
,
v2
);
const
double
one_over_v1ToLine20
=
1.0
/
detail
::
implicit_line
(
v1
[
0
],
v1
[
1
],
v2
,
v0
);
const
double
one_over_v2ToLine01
=
1.0
/
detail
::
implicit_line
(
v2
[
0
],
v2
[
1
],
v0
,
v1
);
// affine barycentric weights
const
double
alpha
=
detail
::
implicit_line
(
x
,
y
,
v1
,
v2
)
*
one_over_v0ToLine12
;
const
double
beta
=
detail
::
implicit_line
(
x
,
y
,
v2
,
v0
)
*
one_over_v1ToLine20
;
const
double
gamma
=
detail
::
implicit_line
(
x
,
y
,
v0
,
v1
)
*
one_over_v2ToLine01
;
// if pixel (x, y) is inside the triangle or on one of its edges
if
(
alpha
>=
0
&&
beta
>=
0
&&
gamma
>=
0
)
{
const
double
z_affine
=
alpha
*
static_cast
<
double
>
(
v0
[
2
])
+
beta
*
static_cast
<
double
>
(
v1
[
2
])
+
gamma
*
static_cast
<
double
>
(
v2
[
2
]);
if
(
z_affine
<
depthbuffer
.
at
<
double
>
(
yi
,
xi
))
{
whole_triangle_is_visible
=
false
;
break
;
}
}
}
if
(
!
whole_triangle_is_visible
)
{
break
;
}
}
if
(
!
whole_triangle_is_visible
)
{
return
false
;
}
return
true
;
};
}
/* namespace detail */
}
/* namespace render */
}
/* namespace eos */
#endif
/* TEXTURE_EXTRACTION_DETAIL_HPP_ */
include/eos/render/texture_extraction.hpp
View file @
1ff4cd40
...
...
@@ -22,6 +22,7 @@
#ifndef TEXTURE_EXTRACTION_HPP_
#define TEXTURE_EXTRACTION_HPP_
#include "eos/render/detail/texture_extraction_detail.hpp"
#include "eos/render/Mesh.hpp"
#include "eos/render/detail/render_detail.hpp"
...
...
@@ -33,39 +34,6 @@
namespace
eos
{
namespace
render
{
/**
* Computes whether the given point is inside (or on the border of) the triangle
* formed out of the given three vertices.
*
* @param[in] point The point to check.
* @param[in] triV0 First vertex.
* @param[in] triV1 Second vertex.
* @param[in] triV2 Third vertex.
* @return Whether the point is inside the triangle.
*/
inline
bool
is_point_in_triangle
(
cv
::
Point2f
point
,
cv
::
Point2f
triV0
,
cv
::
Point2f
triV1
,
cv
::
Point2f
triV2
)
{
// See http://www.blackpawn.com/texts/pointinpoly/
// Compute vectors
cv
::
Point2f
v0
=
triV2
-
triV0
;
cv
::
Point2f
v1
=
triV1
-
triV0
;
cv
::
Point2f
v2
=
point
-
triV0
;
// Compute dot products
float
dot00
=
v0
.
dot
(
v0
);
float
dot01
=
v0
.
dot
(
v1
);
float
dot02
=
v0
.
dot
(
v2
);
float
dot11
=
v1
.
dot
(
v1
);
float
dot12
=
v1
.
dot
(
v2
);
// Compute barycentric coordinates
float
invDenom
=
1
/
(
dot00
*
dot11
-
dot01
*
dot01
);
float
u
=
(
dot11
*
dot02
-
dot01
*
dot12
)
*
invDenom
;
float
v
=
(
dot00
*
dot12
-
dot01
*
dot02
)
*
invDenom
;
// Check if point is in triangle
return
(
u
>=
0
)
&&
(
v
>=
0
)
&&
(
u
+
v
<
1
);
};
/**
* The interpolation types that can be used to map the
* texture from the original image to the isomap.
...
...
@@ -76,81 +44,6 @@ enum class TextureInterpolation {
Area
};
/**
* Checks whether all pixels in the given triangle are visible and
* returns true if and only if the whole triangle is visible.
* The vertices should be given in screen coordinates, but with their
* z-values preserved, so they can be compared against the depthbuffer.
*
* #Todo: Move to detail namespace
*
* @param[in] v0 First vertex, in screen coordinates (but still with their z-value).
* @param[in] v1 Second vertex.
* @param[in] v2 Third vertex.
* @param[in] depthbuffer Pre-calculated depthbuffer.
* @return True if the whole triangle is visible in the image.
*/
bool
is_triangle_visible
(
const
cv
::
Vec4f
&
v0
,
const
cv
::
Vec4f
&
v1
,
const
cv
::
Vec4f
&
v2
,
cv
::
Mat
depthbuffer
)
{
// #Todo: Actually, only check the 3 vertex points, don't loop over the pixels - this should be enough.
auto
viewport_width
=
depthbuffer
.
cols
;
auto
viewport_height
=
depthbuffer
.
rows
;
// Well, in in principle, we'd have to do the whole stuff as in render(), like
// clipping against the frustums etc.
// But as long as our model is fully on the screen, we're fine. Todo: Doublecheck that.
if
(
!
detail
::
are_vertices_ccw_in_screen_space
(
v0
,
v1
,
v2
))
return
false
;
cv
::
Rect
bbox
=
detail
::
calculate_clipped_bounding_box
(
v0
,
v1
,
v2
,
viewport_width
,
viewport_height
);
int
minX
=
bbox
.
x
;
int
maxX
=
bbox
.
x
+
bbox
.
width
;
int
minY
=
bbox
.
y
;
int
maxY
=
bbox
.
y
+
bbox
.
height
;
//if (t.maxX <= t.minX || t.maxY <= t.minY) // Note: Can the width/height of the bbox be negative? Maybe we only need to check for equality here?
// continue; // Also, I'm not entirely sure why I commented this out
bool
whole_triangle_is_visible
=
true
;
for
(
int
yi
=
minY
;
yi
<=
maxY
;
yi
++
)
{
for
(
int
xi
=
minX
;
xi
<=
maxX
;
xi
++
)
{
// we want centers of pixels to be used in computations. Do we?
const
float
x
=
static_cast
<
float
>
(
xi
)
+
0.5
f
;
const
float
y
=
static_cast
<
float
>
(
yi
)
+
0.5
f
;
// these will be used for barycentric weights computation
const
double
one_over_v0ToLine12
=
1.0
/
detail
::
implicit_line
(
v0
[
0
],
v0
[
1
],
v1
,
v2
);
const
double
one_over_v1ToLine20
=
1.0
/
detail
::
implicit_line
(
v1
[
0
],
v1
[
1
],
v2
,
v0
);
const
double
one_over_v2ToLine01
=
1.0
/
detail
::
implicit_line
(
v2
[
0
],
v2
[
1
],
v0
,
v1
);
// affine barycentric weights
const
double
alpha
=
detail
::
implicit_line
(
x
,
y
,
v1
,
v2
)
*
one_over_v0ToLine12
;
const
double
beta
=
detail
::
implicit_line
(
x
,
y
,
v2
,
v0
)
*
one_over_v1ToLine20
;
const
double
gamma
=
detail
::
implicit_line
(
x
,
y
,
v0
,
v1
)
*
one_over_v2ToLine01
;
// if pixel (x, y) is inside the triangle or on one of its edges
if
(
alpha
>=
0
&&
beta
>=
0
&&
gamma
>=
0
)
{
const
double
z_affine
=
alpha
*
static_cast
<
double
>
(
v0
[
2
])
+
beta
*
static_cast
<
double
>
(
v1
[
2
])
+
gamma
*
static_cast
<
double
>
(
v2
[
2
]);
if
(
z_affine
<
depthbuffer
.
at
<
double
>
(
yi
,
xi
))
{
whole_triangle_is_visible
=
false
;
break
;
}
}
}
if
(
!
whole_triangle_is_visible
)
{
break
;
}
}
if
(
!
whole_triangle_is_visible
)
{
return
false
;
}
return
true
;
};
/**
* Extracts the texture of the face from the given image
* and stores it as isomap (a rectangular texture map).
...
...
@@ -199,7 +92,7 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat affine_camera_matrix, int view
Vec4f
v1
=
Mat
(
affine_camera_matrix
*
Mat
(
mesh
.
vertices
[
triangle_indices
[
1
]]));
Vec4f
v2
=
Mat
(
affine_camera_matrix
*
Mat
(
mesh
.
vertices
[
triangle_indices
[
2
]]));
if
(
!
is_triangle_visible
(
v0
,
v1
,
v2
,
depthbuffer
))
if
(
!
detail
::
is_triangle_visible
(
v0
,
v1
,
v2
,
depthbuffer
))
{
continue
;
}
...
...
@@ -231,7 +124,7 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat affine_camera_matrix, int view
// We now loop over all pixels in the triangle and select, depending on the mapping type, the corresponding texel(s) in the source image
for
(
int
x
=
min
(
dst_tri
[
0
].
x
,
min
(
dst_tri
[
1
].
x
,
dst_tri
[
2
].
x
));
x
<
max
(
dst_tri
[
0
].
x
,
max
(
dst_tri
[
1
].
x
,
dst_tri
[
2
].
x
));
++
x
)
{
for
(
int
y
=
min
(
dst_tri
[
0
].
y
,
min
(
dst_tri
[
1
].
y
,
dst_tri
[
2
].
y
));
y
<
max
(
dst_tri
[
0
].
y
,
max
(
dst_tri
[
1
].
y
,
dst_tri
[
2
].
y
));
++
y
)
{
if
(
is_point_in_triangle
(
cv
::
Point2f
(
x
,
y
),
dst_tri
[
0
],
dst_tri
[
1
],
dst_tri
[
2
]))
{
if
(
detail
::
is_point_in_triangle
(
cv
::
Point2f
(
x
,
y
),
dst_tri
[
0
],
dst_tri
[
1
],
dst_tri
[
2
]))
{
if
(
mapping_type
==
TextureInterpolation
::
Area
){
// calculate positions of 4 corners of pixel in image (src)
...
...
@@ -257,7 +150,7 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat affine_camera_matrix, int view
{
for
(
int
b
=
ceil
(
min_b
);
b
<=
floor
(
max_b
);
++
b
)
{
if
(
is_point_in_triangle
(
cv
::
Point2f
(
a
,
b
),
src_texel_upper_left
,
src_texel_lower_left
,
src_texel_upper_right
)
||
is_point_in_triangle
(
cv
::
Point2f
(
a
,
b
),
src_texel_lower_left
,
src_texel_upper_right
,
src_texel_lower_right
))
{
if
(
detail
::
is_point_in_triangle
(
cv
::
Point2f
(
a
,
b
),
src_texel_upper_left
,
src_texel_lower_left
,
src_texel_upper_right
)
||
detail
::
is_point_in_triangle
(
cv
::
Point2f
(
a
,
b
),
src_texel_lower_left
,
src_texel_upper_right
,
src_texel_lower_right
))
{
if
(
a
<
image
.
cols
&&
b
<
image
.
rows
)
{
// if src_texel in triangle and in image
num_texels
++
;
color
+=
image
.
at
<
cv
::
Vec3b
>
(
b
,
a
);
...
...
@@ -326,4 +219,4 @@ inline cv::Mat extract_texture(Mesh mesh, cv::Mat affine_camera_matrix, int view
}
/* namespace render */
}
/* namespace eos */
#endif
/* TEXTURE_EXTRACTION_HPP_ */
\ No newline at end of file
#endif
/* TEXTURE_EXTRACTION_HPP_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment