/
StereoView.h
230 lines (196 loc) · 9.36 KB
/
StereoView.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
229
230
// __BEGIN_LICENSE__
// Copyright (c) 2006-2012, United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration. All
// rights reserved.
//
// The NASA Vision Workbench is 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.
// __END_LICENSE__
#ifndef __VW_STEREO_STEREOVIEW_H__
#define __VW_STEREO_STEREOVIEW_H__
#include <vw/Image/ImageViewBase.h>
#include <vw/Stereo/StereoModel.h>
#include <vw/Camera/CameraModel.h>
#include <limits>
namespace vw {
// Registering point cloud for FileIO
template<> struct PixelFormatID<Vector3> { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
template<> struct PixelFormatID<Vector3f> { static const PixelFormatEnum value = VW_PIXEL_GENERIC_3_CHANNEL; };
namespace stereo {
// Class definition
template <class DisparityImageT>
class StereoView : public ImageViewBase<StereoView<DisparityImageT> >
{
DisparityImageT m_disparity_map;
StereoModel m_stereo_model;
typedef typename DisparityImageT::pixel_type dpixel_type;
template <class PixelT>
struct NotSingleChannel {
static const bool value = (1 != CompoundNumChannels<typename UnmaskedPixelType<PixelT>::type>::value);
};
template <class T>
inline typename boost::enable_if<IsScalar<T>,Vector3>::type
StereoModelHelper( StereoModel const& model, Vector2 const& index,
T const& disparity, double& error ) const {
return model( index, Vector2( index[0] + disparity, index[1] ), error );
}
template <class T>
inline typename boost::enable_if_c<IsCompound<T>::value && (CompoundNumChannels<typename UnmaskedPixelType<T>::type>::value == 1),Vector3>::type
StereoModelHelper( StereoModel const& model, Vector2 const& index,
T const& disparity, double& error ) const {
return model( index, Vector2( index[0] + disparity, index[1] ), error );
}
template <class T>
inline typename boost::enable_if_c<IsCompound<T>::value && (CompoundNumChannels<typename UnmaskedPixelType<T>::type>::value != 1),Vector3>::type
StereoModelHelper( StereoModel const& model, Vector2 const& index,
T const& disparity, double& error ) const {
return model( index, Vector2( index[0] + disparity[0],
index[1] + disparity[1] ), error );
}
public:
typedef Vector3 pixel_type;
typedef const Vector3 result_type;
typedef ProceduralPixelAccessor<StereoView> pixel_accessor;
StereoView( DisparityImageT const& disparity_map,
vw::camera::CameraModel const* camera_model1,
vw::camera::CameraModel const* camera_model2,
bool least_squares_refine = false) :
m_disparity_map(disparity_map),
m_stereo_model(camera_model1, camera_model2, least_squares_refine) {}
StereoView( DisparityImageT const& disparity_map,
StereoModel const& stereo_model) :
m_disparity_map(disparity_map),
m_stereo_model(stereo_model) {}
inline int32 cols() const { return m_disparity_map.cols(); }
inline int32 rows() const { return m_disparity_map.rows(); }
inline int32 planes() const { return 1; }
inline pixel_accessor origin() const { return pixel_accessor(*this); }
inline result_type operator()( size_t i, size_t j, size_t p=0 ) const {
double error;
if ( is_valid(m_disparity_map(i,j,p)) )
return StereoModelHelper( m_stereo_model, Vector2(i,j),
m_disparity_map(i,j,p), error );
// For missing pixels in the disparity map, we return a null 3D position.
return Vector3();
}
// Returns the distance between the two stereo rays at their
// closest point of intersection. A value of zero is returned if
// the requested pixel is missing in the disparity map or if the
// stereo geometry returns a bad match (e.g. if the rays
// diverged).
inline double error( int32 i, int32 j, int32 p=0 ) const {
double error = 1e-10;
if ( is_valid(m_disparity_map(i,j,p)) )
StereoModelHelper( m_stereo_model, Vector2(i,j),
m_disparity_map(i,j,p), error );
if ( error < 0 )
return 0;
return error;
}
DisparityImageT const& disparity_map() const { return m_disparity_map; }
/// \cond INTERNAL
typedef StereoView<typename DisparityImageT::prerasterize_type> prerasterize_type;
inline prerasterize_type prerasterize( BBox2i const& bbox ) const { return prerasterize_type( m_disparity_map.prerasterize(bbox), m_stereo_model ); }
template <class DestT> inline void rasterize( DestT const& dest, BBox2i const& bbox ) const { vw::rasterize( prerasterize(bbox), dest, bbox ); }
/// \endcond
};
template <class ImageT>
StereoView<ImageT> stereo_triangulate( ImageViewBase<ImageT> const& v,
vw::camera::CameraModel const* camera1,
vw::camera::CameraModel const* camera2 ) {
return StereoView<ImageT>( v.impl(), camera1, camera2 );
}
template <class ImageT>
StereoView<ImageT> lsq_stereo_triangulate( ImageViewBase<ImageT> const& v,
vw::camera::CameraModel const* camera1,
vw::camera::CameraModel const* camera2 ) {
return StereoView<ImageT>( v.impl(), camera1, camera2, true );
}
// This per pixel functor applies a universe radius to a point
// image. Points that fall outside of the annulus specified with
// the near and far radii are set to the "missing" pixel value
// of (0,0,0).
//
// You can disable either the near or far universe radius
// computation by setting either near_radius or far_radius to 0.0.
class UniverseRadiusFunc: public vw::UnaryReturnSameType {
private:
// This small subclass gives us the wiggle room we need to update
// the state of this object from within the PerPixelView, where
// the UniverseRadius object itself is treated as a const copy of
// the original functor. By maintaining a smart pointer to this
// small status class, we can change state that is shared between
// any copies of the UniverseRadius object and the original.
struct UniverseRadiusState {
int32 rejected_points, total_points;
};
Vector3 m_origin;
double m_near_radius, m_far_radius;
boost::shared_ptr<UniverseRadiusState> m_state;
public:
UniverseRadiusFunc(Vector3 universe_origin, double near_radius = 0, double far_radius = std::numeric_limits<double>::max()):
m_origin(universe_origin), m_near_radius(near_radius), m_far_radius(far_radius),
m_state( new UniverseRadiusState() ) {
VW_ASSERT(m_near_radius >= 0 && m_far_radius >= 0,
vw::ArgumentErr() << "UniverseRadius: radii must be >= to zero.");
VW_ASSERT(m_near_radius <= m_far_radius,
vw::ArgumentErr() << "UniverseRadius: near radius must be <= to far radius.");
m_state->rejected_points = m_state->total_points = 0;
}
double near_radius() const { return m_near_radius; }
double far_radius() const { return m_far_radius; }
int32 rejected_points() const { return m_state->rejected_points; }
int32 total_points() const { return m_state->total_points; }
template <class ElemT>
Vector<ElemT,3> operator() (Vector<ElemT,3> const& pix) const {
m_state->total_points++;
if (pix != Vector<ElemT,3>() ) {
double dist = norm_2(pix - m_origin);
if ((m_near_radius != 0 && dist < m_near_radius) ||
(m_far_radius != 0 && dist > m_far_radius)) {
m_state->rejected_points++;
return Vector<ElemT,3>();
} else {
return pix;
}
}
return Vector<ElemT,3>();
}
// A version that is carrying error
template <class ElemT>
Vector<ElemT,4> operator() (Vector<ElemT,4> const& pix) const {
m_state->total_points++;
if (subvector(pix,0,3) != Vector<ElemT,3>() ) {
double dist = norm_2(subvector(pix,0,3) - m_origin);
if ((m_near_radius != 0 && dist < m_near_radius) ||
(m_far_radius != 0 && dist > m_far_radius)) {
m_state->rejected_points++;
return Vector<ElemT,4>();
} else {
return pix;
}
}
return Vector<ElemT,4>();
}
};
// Useful routine for printing how many points have been rejected
// using a particular UniverseRadius funtor.
inline std::ostream& operator<<(std::ostream& os, UniverseRadiusFunc const& u) {
os << "Universe Radius Limits: [ " << u.near_radius() << ", ";
if (u.far_radius() == 0)
os << "Inf ]\n" ;
else
os << u.far_radius() << "]\n";
os << "\tRejected " << u.rejected_points() << "/" << u.total_points() << " vertices (" << double(u.rejected_points())/u.total_points()*100 << "%).\n";
return os;
}
}} // namespace vw::stereo
#endif // __VW_STEREO_STEREOVIEW_H__