Move all eigen serialization to basalt-headers.
**Note:** Binary representation of eigen matrices has changed!
This commit is contained in:
		
							parent
							
								
									77100b99f2
								
							
						
					
					
						commit
						cae794d6af
					
				| @ -155,39 +155,6 @@ class DatasetIoFactory { | ||||
| 
 | ||||
| namespace cereal { | ||||
| 
 | ||||
| template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, | ||||
|           int _MaxRows, int _MaxCols> | ||||
| static inline | ||||
|     typename std::enable_if<_Rows == Eigen::Dynamic || _Cols == Eigen::Dynamic, | ||||
|                             void>::type | ||||
|     save(Archive &ar, const Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, | ||||
|                                           _MaxRows, _MaxCols> &matrix) { | ||||
|   const std::int32_t rows = static_cast<std::int32_t>(matrix.rows()); | ||||
|   const std::int32_t cols = static_cast<std::int32_t>(matrix.cols()); | ||||
|   ar(rows); | ||||
|   ar(cols); | ||||
|   ar(binary_data(matrix.data(), rows * cols * sizeof(_Scalar))); | ||||
| }; | ||||
| 
 | ||||
| template <class Archive, class _Scalar, int _Rows, int _Cols, int _Options, | ||||
|           int _MaxRows, int _MaxCols> | ||||
| static inline | ||||
|     typename std::enable_if<_Rows == Eigen::Dynamic || _Cols == Eigen::Dynamic, | ||||
|                             void>::type | ||||
|     load(Archive &ar, | ||||
|          Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> | ||||
|              &matrix) { | ||||
|   std::int32_t rows; | ||||
|   std::int32_t cols; | ||||
|   ar(rows); | ||||
|   ar(cols); | ||||
| 
 | ||||
|   matrix.resize(rows, cols); | ||||
| 
 | ||||
|   ar(binary_data(matrix.data(), | ||||
|                  static_cast<std::size_t>(rows * cols * sizeof(_Scalar)))); | ||||
| }; | ||||
| 
 | ||||
| template <class Archive> | ||||
| void serialize(Archive &archive, basalt::ManagedImage<uint8_t> &m) { | ||||
|   archive(m.w); | ||||
|  | ||||
| @ -1,688 +0,0 @@ | ||||
| /**
 | ||||
| BSD 3-Clause License | ||||
| 
 | ||||
| This file is part of the Basalt project. | ||||
| https://gitlab.com/VladyslavUsenko/basalt.git
 | ||||
| 
 | ||||
| Copyright (c) 2019, Vladyslav Usenko and Nikolaus Demmel. | ||||
| All rights reserved. | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
| * Redistributions of source code must retain the above copyright notice, this | ||||
|   list of conditions and the following disclaimer. | ||||
| 
 | ||||
| * Redistributions in binary form must reproduce the above copyright notice, | ||||
|   this list of conditions and the following disclaimer in the documentation | ||||
|   and/or other materials provided with the distribution. | ||||
| 
 | ||||
| * Neither the name of the copyright holder nor the names of its | ||||
|   contributors may be used to endorse or promote products derived from | ||||
|   this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
| */ | ||||
| 
 | ||||
| // This file is adapted from Pangolin. Original license:
 | ||||
| 
 | ||||
| /* This file is part of the Pangolin Project.
 | ||||
|  * http://github.com/stevenlovegrove/Pangolin
 | ||||
|  * | ||||
|  * Copyright (c) 2011 Steven Lovegrove | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person | ||||
|  * obtaining a copy of this software and associated documentation | ||||
|  * files (the "Software"), to deal in the Software without | ||||
|  * restriction, including without limitation the rights to use, | ||||
|  * copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following | ||||
|  * conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be | ||||
|  * included in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||||
|  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||||
|  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
|  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
|  * OTHER DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <basalt/utils/assert.h> | ||||
| 
 | ||||
| // Renamed Pangoling defines to avoid clash
 | ||||
| #define BASALT_HOST_DEVICE | ||||
| #define BASALT_EXTENSION_IMAGE | ||||
| #ifdef BASALT_ENABLE_BOUNDS_CHECKS | ||||
| #define BASALT_BOUNDS_ASSERT(...) BASALT_ASSERT(##__VA_ARGS__) | ||||
| #else | ||||
| #define BASALT_BOUNDS_ASSERT(...) ((void)0) | ||||
| #endif | ||||
| 
 | ||||
| namespace basalt { | ||||
| 
 | ||||
| template <typename T> | ||||
| struct CopyObject { | ||||
|   CopyObject(const T& obj) : obj(obj) {} | ||||
|   const T& obj; | ||||
| }; | ||||
| 
 | ||||
| inline void PitchedCopy(char* dst, unsigned int dst_pitch_bytes, | ||||
|                         const char* src, unsigned int src_pitch_bytes, | ||||
|                         unsigned int width_bytes, unsigned int height) { | ||||
|   if (dst_pitch_bytes == width_bytes && src_pitch_bytes == width_bytes) { | ||||
|     std::memcpy(dst, src, height * width_bytes); | ||||
|   } else { | ||||
|     for (unsigned int row = 0; row < height; ++row) { | ||||
|       std::memcpy(dst, src, width_bytes); | ||||
|       dst += dst_pitch_bytes; | ||||
|       src += src_pitch_bytes; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| struct Image { | ||||
|   inline Image() : pitch(0), ptr(0), w(0), h(0) {} | ||||
| 
 | ||||
|   inline Image(T* ptr, size_t w, size_t h, size_t pitch) | ||||
|       : pitch(pitch), ptr(ptr), w(w), h(h) {} | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline size_t SizeBytes() const { return pitch * h; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline size_t Area() const { return w * h; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline bool IsValid() const { return ptr != 0; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline bool IsContiguous() const { | ||||
|     return w * sizeof(T) == pitch; | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Iterators
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline T* begin() { return ptr; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline T* end() { return RowPtr(h - 1) + w; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const T* begin() const { return ptr; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const T* end() const { return RowPtr(h - 1) + w; } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline size_t size() const { return w * h; } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Image transforms
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   template <typename UnaryOperation> | ||||
|   BASALT_HOST_DEVICE inline void Transform(UnaryOperation unary_op) { | ||||
|     BASALT_ASSERT(IsValid()); | ||||
| 
 | ||||
|     for (size_t y = 0; y < h; ++y) { | ||||
|       T* el = RowPtr(y); | ||||
|       const T* el_end = el + w; | ||||
|       for (; el != el_end; ++el) { | ||||
|         *el = unary_op(*el); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline void Fill(const T& val) { | ||||
|     Transform([&](const T&) { return val; }); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline void Replace(const T& oldval, const T& newval) { | ||||
|     Transform([&](const T& val) { return (val == oldval) ? newval : val; }); | ||||
|   } | ||||
| 
 | ||||
|   inline void Memset(unsigned char v = 0) { | ||||
|     BASALT_ASSERT(IsValid()); | ||||
|     if (IsContiguous()) { | ||||
|       std::memset((char*)ptr, v, pitch * h); | ||||
|     } else { | ||||
|       for (size_t y = 0; y < h; ++y) { | ||||
|         std::memset((char*)RowPtr(y), v, pitch); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inline void CopyFrom(const Image<T>& img) { | ||||
|     if (IsValid() && img.IsValid()) { | ||||
|       BASALT_ASSERT(w >= img.w && h >= img.h); | ||||
|       PitchedCopy((char*)ptr, pitch, (char*)img.ptr, img.pitch, | ||||
|                   std::min(img.w, w) * sizeof(T), std::min(img.h, h)); | ||||
|     } else if (img.IsValid() != IsValid()) { | ||||
|       BASALT_ASSERT(false && "Cannot copy from / to an unasigned image."); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Reductions
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   template <typename BinaryOperation> | ||||
|   BASALT_HOST_DEVICE inline T Accumulate(const T init, | ||||
|                                          BinaryOperation binary_op) { | ||||
|     BASALT_ASSERT(IsValid()); | ||||
| 
 | ||||
|     T val = init; | ||||
|     for (size_t y = 0; y < h; ++y) { | ||||
|       T* el = RowPtr(y); | ||||
|       const T* el_end = el + w; | ||||
|       for (; el != el_end; ++el) { | ||||
|         val = binary_op(val, *el); | ||||
|       } | ||||
|     } | ||||
|     return val; | ||||
|   } | ||||
| 
 | ||||
|   std::pair<T, T> MinMax() const { | ||||
|     BASALT_ASSERT(IsValid()); | ||||
| 
 | ||||
|     std::pair<T, T> minmax(std::numeric_limits<T>::max(), | ||||
|                            std::numeric_limits<T>::lowest()); | ||||
|     for (size_t r = 0; r < h; ++r) { | ||||
|       const T* ptr = RowPtr(r); | ||||
|       const T* end = ptr + w; | ||||
|       while (ptr != end) { | ||||
|         minmax.first = std::min(*ptr, minmax.first); | ||||
|         minmax.second = std::max(*ptr, minmax.second); | ||||
|         ++ptr; | ||||
|       } | ||||
|     } | ||||
|     return minmax; | ||||
|   } | ||||
| 
 | ||||
|   template <typename Tout = T> | ||||
|   Tout Sum() const { | ||||
|     return Accumulate((T)0, | ||||
|                       [](const T& lhs, const T& rhs) { return lhs + rhs; }); | ||||
|   } | ||||
| 
 | ||||
|   template <typename Tout = T> | ||||
|   Tout Mean() const { | ||||
|     return Sum<Tout>() / Area(); | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Direct Pixel Access
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline T* RowPtr(size_t y) { | ||||
|     return (T*)((unsigned char*)(ptr) + y * pitch); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const T* RowPtr(size_t y) const { | ||||
|     return (T*)((unsigned char*)(ptr) + y * pitch); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline T& operator()(size_t x, size_t y) { | ||||
|     BASALT_BOUNDS_ASSERT(InBounds(x, y)); | ||||
|     return RowPtr(y)[x]; | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const T& operator()(size_t x, size_t y) const { | ||||
|     BASALT_BOUNDS_ASSERT(InBounds(x, y)); | ||||
|     return RowPtr(y)[x]; | ||||
|   } | ||||
| 
 | ||||
|   template <typename TVec> | ||||
|   BASALT_HOST_DEVICE inline T& operator()(const TVec& p) { | ||||
|     BASALT_BOUNDS_ASSERT(InBounds(p[0], p[1])); | ||||
|     return RowPtr(p[1])[p[0]]; | ||||
|   } | ||||
| 
 | ||||
|   template <typename TVec> | ||||
|   BASALT_HOST_DEVICE inline const T& operator()(const TVec& p) const { | ||||
|     BASALT_BOUNDS_ASSERT(InBounds(p[0], p[1])); | ||||
|     return RowPtr(p[1])[p[0]]; | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline T& operator[](size_t ix) { | ||||
|     BASALT_BOUNDS_ASSERT(InImage(ptr + ix)); | ||||
|     return ptr[ix]; | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const T& operator[](size_t ix) const { | ||||
|     BASALT_BOUNDS_ASSERT(InImage(ptr + ix)); | ||||
|     return ptr[ix]; | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Interpolated Pixel Access
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   template <typename S> | ||||
|   inline S interp(const Eigen::Matrix<S, 2, 1>& p) const { | ||||
|     return interp<S>(p[0], p[1]); | ||||
|   } | ||||
| 
 | ||||
|   template <typename S> | ||||
|   inline Eigen::Matrix<S, 3, 1> interpGrad( | ||||
|       const Eigen::Matrix<S, 2, 1>& p) const { | ||||
|     return interpGrad<S>(p[0], p[1]); | ||||
|   } | ||||
| 
 | ||||
|   template <typename S> | ||||
|   inline float interp(S x, S y) const { | ||||
|     int ix = x; | ||||
|     int iy = y; | ||||
| 
 | ||||
|     S dx = x - ix; | ||||
|     S dy = y - iy; | ||||
| 
 | ||||
|     S ddx = 1.0f - dx; | ||||
|     S ddy = 1.0f - dy; | ||||
| 
 | ||||
|     return ddx * ddy * (*this)(ix, iy) + ddx * dy * (*this)(ix, iy + 1) + | ||||
|            dx * ddy * (*this)(ix + 1, iy) + dx * dy * (*this)(ix + 1, iy + 1); | ||||
|   } | ||||
| 
 | ||||
|   template <typename S> | ||||
|   inline Eigen::Matrix<S, 3, 1> interpGrad(S x, S y) const { | ||||
|     int ix = x; | ||||
|     int iy = y; | ||||
| 
 | ||||
|     S dx = x - ix; | ||||
|     S dy = y - iy; | ||||
| 
 | ||||
|     S ddx = 1.0f - dx; | ||||
|     S ddy = 1.0f - dy; | ||||
| 
 | ||||
|     Eigen::Matrix<S, 3, 1> res; | ||||
| 
 | ||||
|     const T& px0y0 = (*this)(ix, iy); | ||||
|     const T& px1y0 = (*this)(ix + 1, iy); | ||||
|     const T& px0y1 = (*this)(ix, iy + 1); | ||||
|     const T& px1y1 = (*this)(ix + 1, iy + 1); | ||||
| 
 | ||||
|     res[0] = ddx * ddy * px0y0 + ddx * dy * px0y1 + dx * ddy * px1y0 + | ||||
|              dx * dy * px1y1; | ||||
| 
 | ||||
|     const T& pxm1y0 = (*this)(ix - 1, iy); | ||||
|     const T& pxm1y1 = (*this)(ix - 1, iy + 1); | ||||
| 
 | ||||
|     S res_mx = ddx * ddy * pxm1y0 + ddx * dy * pxm1y1 + dx * ddy * px0y0 + | ||||
|                dx * dy * px0y1; | ||||
| 
 | ||||
|     const T& px2y0 = (*this)(ix + 2, iy); | ||||
|     const T& px2y1 = (*this)(ix + 2, iy + 1); | ||||
| 
 | ||||
|     S res_px = ddx * ddy * px1y0 + ddx * dy * px1y1 + dx * ddy * px2y0 + | ||||
|                dx * dy * px2y1; | ||||
| 
 | ||||
|     res[1] = 0.5 * (res_px - res_mx); | ||||
| 
 | ||||
|     const T& px0ym1 = (*this)(ix, iy - 1); | ||||
|     const T& px1ym1 = (*this)(ix + 1, iy - 1); | ||||
| 
 | ||||
|     S res_my = ddx * ddy * px0ym1 + ddx * dy * px0y0 + dx * ddy * px1ym1 + | ||||
|                dx * dy * px1y0; | ||||
| 
 | ||||
|     const T& px0y2 = (*this)(ix, iy + 2); | ||||
|     const T& px1y2 = (*this)(ix + 1, iy + 2); | ||||
| 
 | ||||
|     S res_py = ddx * ddy * px0y1 + ddx * dy * px0y2 + dx * ddy * px1y1 + | ||||
|                dx * dy * px1y2; | ||||
| 
 | ||||
|     res[2] = 0.5 * (res_py - res_my); | ||||
| 
 | ||||
|     return res; | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Bounds Checking
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE | ||||
|   bool InImage(const T* ptest) const { | ||||
|     return ptr <= ptest && ptest < RowPtr(h); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline bool InBounds(int x, int y) const { | ||||
|     return 0 <= x && x < (int)w && 0 <= y && y < (int)h; | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline bool InBounds(float x, float y, | ||||
|                                           float border) const { | ||||
|     return border <= x && x < (w - border) && border <= y && y < (h - border); | ||||
|   } | ||||
| 
 | ||||
|   template <typename TVec, typename TBorder> | ||||
|   BASALT_HOST_DEVICE inline bool InBounds( | ||||
|       const TVec& p, const TBorder border = (TBorder)0) const { | ||||
|     return border <= p[0] && p[0] < ((int)w - border) && border <= p[1] && | ||||
|            p[1] < ((int)h - border); | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Obtain slices / subimages
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline const Image<const T> SubImage(size_t x, size_t y, | ||||
|                                                           size_t width, | ||||
|                                                           size_t height) const { | ||||
|     BASALT_ASSERT((x + width) <= w && (y + height) <= h); | ||||
|     return Image<const T>(RowPtr(y) + x, width, height, pitch); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline Image<T> SubImage(size_t x, size_t y, size_t width, | ||||
|                                               size_t height) { | ||||
|     BASALT_ASSERT((x + width) <= w && (y + height) <= h); | ||||
|     return Image<T>(RowPtr(y) + x, width, height, pitch); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline Image<T> Row(int y) const { | ||||
|     return SubImage(0, y, w, 1); | ||||
|   } | ||||
| 
 | ||||
|   BASALT_HOST_DEVICE inline Image<T> Col(int x) const { | ||||
|     return SubImage(x, 0, 1, h); | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Data mangling
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   template <typename TRecast> | ||||
|   BASALT_HOST_DEVICE inline Image<TRecast> Reinterpret() const { | ||||
|     BASALT_ASSERT_STREAM(sizeof(TRecast) == sizeof(T), | ||||
|                          "sizeof(TRecast) must match sizeof(T): " | ||||
|                              << sizeof(TRecast) << " != " << sizeof(T)); | ||||
|     return UnsafeReinterpret<TRecast>(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename TRecast> | ||||
|   BASALT_HOST_DEVICE inline Image<TRecast> UnsafeReinterpret() const { | ||||
|     return Image<TRecast>((TRecast*)ptr, w, h, pitch); | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Deprecated methods
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   //    PANGOLIN_DEPRECATED inline
 | ||||
|   Image(size_t w, size_t h, size_t pitch, T* ptr) | ||||
|       : pitch(pitch), ptr(ptr), w(w), h(h) {} | ||||
| 
 | ||||
|   // Use RAII/move aware pangolin::ManagedImage instead
 | ||||
|   //    PANGOLIN_DEPRECATED inline
 | ||||
|   void Dealloc() { | ||||
|     if (ptr) { | ||||
|       ::operator delete(ptr); | ||||
|       ptr = nullptr; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Use RAII/move aware pangolin::ManagedImage instead
 | ||||
|   //    PANGOLIN_DEPRECATED inline
 | ||||
|   void Alloc(size_t w, size_t h, size_t pitch) { | ||||
|     Dealloc(); | ||||
|     this->w = w; | ||||
|     this->h = h; | ||||
|     this->pitch = pitch; | ||||
|     this->ptr = (T*)::operator new(h* pitch); | ||||
|   } | ||||
| 
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
|   // Data members
 | ||||
|   //////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|   size_t pitch; | ||||
|   T* ptr; | ||||
|   size_t w; | ||||
|   size_t h; | ||||
| 
 | ||||
|   BASALT_EXTENSION_IMAGE | ||||
| }; | ||||
| 
 | ||||
| template <class T> | ||||
| using DefaultImageAllocator = std::allocator<T>; | ||||
| 
 | ||||
| // Image that manages it's own memory, storing a strong pointer to it's memory
 | ||||
| template <typename T, class Allocator = DefaultImageAllocator<T>> | ||||
| class ManagedImage : public Image<T> { | ||||
|  public: | ||||
|   typedef std::shared_ptr<ManagedImage<T>> Ptr; | ||||
| 
 | ||||
|   // Destructor
 | ||||
|   inline ~ManagedImage() { Deallocate(); } | ||||
| 
 | ||||
|   // Null image
 | ||||
|   inline ManagedImage() {} | ||||
| 
 | ||||
|   // Row image
 | ||||
|   inline ManagedImage(size_t w) | ||||
|       : Image<T>(Allocator().allocate(w), w, 1, w * sizeof(T)) {} | ||||
| 
 | ||||
|   inline ManagedImage(size_t w, size_t h) | ||||
|       : Image<T>(Allocator().allocate(w * h), w, h, w * sizeof(T)) {} | ||||
| 
 | ||||
|   inline ManagedImage(size_t w, size_t h, size_t pitch_bytes) | ||||
|       : Image<T>(Allocator().allocate((h * pitch_bytes) / sizeof(T) + 1), w, h, | ||||
|                  pitch_bytes) {} | ||||
| 
 | ||||
|   // Not copy constructable
 | ||||
|   inline ManagedImage(const ManagedImage<T>& other) = delete; | ||||
| 
 | ||||
|   // Move constructor
 | ||||
|   inline ManagedImage(ManagedImage<T, Allocator>&& img) { | ||||
|     *this = std::move(img); | ||||
|   } | ||||
| 
 | ||||
|   // Move asignment
 | ||||
|   inline void operator=(ManagedImage<T, Allocator>&& img) { | ||||
|     Deallocate(); | ||||
|     Image<T>::pitch = img.pitch; | ||||
|     Image<T>::ptr = img.ptr; | ||||
|     Image<T>::w = img.w; | ||||
|     Image<T>::h = img.h; | ||||
|     img.ptr = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   // Explicit copy constructor
 | ||||
|   template <typename TOther> | ||||
|   ManagedImage(const CopyObject<TOther>& other) { | ||||
|     CopyFrom(other.obj); | ||||
|   } | ||||
| 
 | ||||
|   // Explicit copy assignment
 | ||||
|   template <typename TOther> | ||||
|   void operator=(const CopyObject<TOther>& other) { | ||||
|     CopyFrom(other.obj); | ||||
|   } | ||||
| 
 | ||||
|   inline void Swap(ManagedImage<T>& img) { | ||||
|     std::swap(img.pitch, Image<T>::pitch); | ||||
|     std::swap(img.ptr, Image<T>::ptr); | ||||
|     std::swap(img.w, Image<T>::w); | ||||
|     std::swap(img.h, Image<T>::h); | ||||
|   } | ||||
| 
 | ||||
|   inline void CopyFrom(const Image<T>& img) { | ||||
|     if (!Image<T>::IsValid() || Image<T>::w != img.w || Image<T>::h != img.h) { | ||||
|       Reinitialise(img.w, img.h); | ||||
|     } | ||||
|     Image<T>::CopyFrom(img); | ||||
|   } | ||||
| 
 | ||||
|   inline void Reinitialise(size_t w, size_t h) { | ||||
|     if (!Image<T>::ptr || Image<T>::w != w || Image<T>::h != h) { | ||||
|       *this = ManagedImage<T, Allocator>(w, h); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inline void Reinitialise(size_t w, size_t h, size_t pitch) { | ||||
|     if (!Image<T>::ptr || Image<T>::w != w || Image<T>::h != h || | ||||
|         Image<T>::pitch != pitch) { | ||||
|       *this = ManagedImage<T, Allocator>(w, h, pitch); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inline void Deallocate() { | ||||
|     if (Image<T>::ptr) { | ||||
|       Allocator().deallocate(Image<T>::ptr, | ||||
|                              (Image<T>::h * Image<T>::pitch) / sizeof(T)); | ||||
|       Image<T>::ptr = nullptr; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Move asignment
 | ||||
|   template <typename TOther, typename AllocOther> | ||||
|   inline void OwnAndReinterpret(ManagedImage<TOther, AllocOther>&& img) { | ||||
|     Deallocate(); | ||||
|     Image<T>::pitch = img.pitch; | ||||
|     Image<T>::ptr = (T*)img.ptr; | ||||
|     Image<T>::w = img.w; | ||||
|     Image<T>::h = img.h; | ||||
|     img.ptr = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   template <typename T1> | ||||
|   inline void ConvertFrom(const ManagedImage<T1>& img) { | ||||
|     Reinitialise(img.w, img.h); | ||||
| 
 | ||||
|     for (size_t j = 0; j < img.h; j++) { | ||||
|       T* this_row = this->RowPtr(j); | ||||
|       const T1* other_row = img.RowPtr(j); | ||||
|       for (size_t i = 0; i < img.w; i++) { | ||||
|         this_row[i] = T(other_row[i]); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inline void operator-=(const ManagedImage<T>& img) { | ||||
|     for (size_t j = 0; j < img.h; j++) { | ||||
|       T* this_row = this->RowPtr(j); | ||||
|       const T* other_row = img.RowPtr(j); | ||||
|       for (size_t i = 0; i < img.w; i++) { | ||||
|         this_row[i] -= other_row[i]; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, class Allocator = DefaultImageAllocator<T>> | ||||
| class ManagedImagePyr { | ||||
|  public: | ||||
|   inline ManagedImagePyr() {} | ||||
| 
 | ||||
|   inline ManagedImagePyr(ManagedImage<T>& other, size_t num_levels) { | ||||
|     setFromImage(other, num_levels); | ||||
|   } | ||||
| 
 | ||||
|   inline void setFromImage(const ManagedImage<T>& other, size_t num_levels) { | ||||
|     orig_w = other.w; | ||||
|     image.Reinitialise(other.w + other.w / 2, other.h); | ||||
|     image.Fill(0); | ||||
|     lvl_internal(0).CopyFrom(other); | ||||
| 
 | ||||
|     for (size_t i = 0; i < num_levels; i++) { | ||||
|       const Image<const T> l = lvl(i); | ||||
|       Image<T> lp1 = lvl_internal(i + 1); | ||||
|       subsample(l, lp1); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   static inline int border101(int x, int h) { | ||||
|     return h - 1 - std::abs(h - 1 - x); | ||||
|   } | ||||
| 
 | ||||
|   static void subsample(const Image<const T>& img, Image<T>& img_sub) { | ||||
|     static_assert(std::is_same<T, uint16_t>::value || | ||||
|                   std::is_same<T, uint8_t>::value); | ||||
| 
 | ||||
|     constexpr int kernel[5] = {1, 4, 6, 4, 1}; | ||||
| 
 | ||||
|     // accumulator
 | ||||
|     ManagedImage<int> tmp(img_sub.h, img.w); | ||||
| 
 | ||||
|     // Vertical convolution
 | ||||
|     { | ||||
|       for (int r = 0; r < int(img_sub.h); r++) { | ||||
|         const T* row_m2 = img.RowPtr(std::abs(2 * r - 2)); | ||||
|         const T* row_m1 = img.RowPtr(std::abs(2 * r - 1)); | ||||
|         const T* row = img.RowPtr(2 * r); | ||||
|         const T* row_p1 = img.RowPtr(border101(2 * r + 1, img.h)); | ||||
|         const T* row_p2 = img.RowPtr(border101(2 * r + 2, img.h)); | ||||
| 
 | ||||
|         for (int c = 0; c < int(img.w); c++) { | ||||
|           tmp(r, c) = kernel[0] * int(row_m2[c]) + kernel[1] * int(row_m1[c]) + | ||||
|                       kernel[2] * int(row[c]) + kernel[3] * int(row_p1[c]) + | ||||
|                       kernel[4] * int(row_p2[c]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Horizontal convolution
 | ||||
|     { | ||||
|       for (int c = 0; c < int(img_sub.w); c++) { | ||||
|         const int* row_m2 = tmp.RowPtr(std::abs(2 * c - 2)); | ||||
|         const int* row_m1 = tmp.RowPtr(std::abs(2 * c - 1)); | ||||
|         const int* row = tmp.RowPtr(2 * c); | ||||
|         const int* row_p1 = tmp.RowPtr(border101(2 * c + 1, tmp.h)); | ||||
|         const int* row_p2 = tmp.RowPtr(border101(2 * c + 2, tmp.h)); | ||||
| 
 | ||||
|         for (int r = 0; r < int(tmp.w); r++) { | ||||
|           int val_int = kernel[0] * row_m2[r] + kernel[1] * row_m1[r] + | ||||
|                         kernel[2] * row[r] + kernel[3] * row_p1[r] + | ||||
|                         kernel[4] * row_p2[r]; | ||||
|           T val = ((val_int + (1 << 7)) >> 8); | ||||
|           img_sub(c, r) = val; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   inline const Image<const T> lvl(size_t lvl) const { | ||||
|     size_t x = (lvl == 0) ? 0 : orig_w; | ||||
|     size_t y = (lvl <= 1) ? 0 : (image.h - (image.h >> (lvl - 1))); | ||||
|     size_t width = (orig_w >> lvl); | ||||
|     size_t height = (image.h >> lvl); | ||||
| 
 | ||||
|     return image.SubImage(x, y, width, height); | ||||
|   } | ||||
| 
 | ||||
|   template <typename S> | ||||
|   inline Eigen::Matrix<S, 2, 1> lvl_offset(size_t lvl) { | ||||
|     size_t x = (lvl == 0) ? 0 : orig_w; | ||||
|     size_t y = (lvl <= 1) ? 0 : (image.h - (image.h >> (lvl - 1))); | ||||
| 
 | ||||
|     return Eigen::Matrix<S, 2, 1>(x, y); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   inline Image<T> lvl_internal(size_t lvl) { | ||||
|     size_t x = (lvl == 0) ? 0 : orig_w; | ||||
|     size_t y = (lvl <= 1) ? 0 : (image.h - (image.h >> (lvl - 1))); | ||||
|     size_t width = (orig_w >> lvl); | ||||
|     size_t height = (image.h >> lvl); | ||||
| 
 | ||||
|     return image.SubImage(x, y, width, height); | ||||
|   } | ||||
| 
 | ||||
|   size_t orig_w; | ||||
|   ManagedImage<T> image; | ||||
| }; | ||||
| 
 | ||||
| }  // namespace basalt
 | ||||
| @ -5,9 +5,6 @@ cmake_minimum_required(VERSION 3.10) | ||||
| include_directories(../thirdparty/basalt-headers/test/include) | ||||
| 
 | ||||
| 
 | ||||
| add_executable(test_image src/test_image.cpp) | ||||
| target_link_libraries(test_image gtest gtest_main basalt) | ||||
| 
 | ||||
| add_executable(test_spline_opt src/test_spline_opt.cpp) | ||||
| target_link_libraries(test_spline_opt gtest gtest_main basalt) | ||||
| 
 | ||||
| @ -22,12 +19,10 @@ enable_testing() | ||||
| 
 | ||||
| include(GoogleTest) | ||||
| 
 | ||||
| #gtest_discover_tests(test_image DISCOVERY_TIMEOUT 60) | ||||
| #gtest_discover_tests(test_spline_opt DISCOVERY_TIMEOUT 60) | ||||
| #gtest_discover_tests(test_vio DISCOVERY_TIMEOUT 60) | ||||
| #gtest_discover_tests(test_nfr DISCOVERY_TIMEOUT 60) | ||||
| 
 | ||||
| gtest_add_tests(TARGET test_image AUTO) | ||||
| gtest_add_tests(TARGET test_spline_opt AUTO) | ||||
| gtest_add_tests(TARGET test_vio AUTO) | ||||
| gtest_add_tests(TARGET test_nfr AUTO) | ||||
|  | ||||
| @ -1,128 +0,0 @@ | ||||
| 
 | ||||
| #include <Eigen/Dense> | ||||
| 
 | ||||
| #include <basalt/utils/image.h> | ||||
| 
 | ||||
| #include "gtest/gtest.h" | ||||
| #include "test_utils.h" | ||||
| 
 | ||||
| void setImageData(uint16_t *imageArray, int size) { | ||||
|   double norm = RAND_MAX; | ||||
|   norm /= (double)std::numeric_limits<uint16_t>::max(); | ||||
| 
 | ||||
|   for (int i = 0; i < size; i++) { | ||||
|     imageArray[i] = (unsigned char)(rand() / norm); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST(Pattern, ImageInterp) { | ||||
|   Eigen::Vector2d offset(231.234242, 123.23424); | ||||
| 
 | ||||
|   basalt::ManagedImage<uint16_t> img(640, 480); | ||||
|   setImageData(img.ptr, img.size()); | ||||
| 
 | ||||
|   Eigen::Vector3d vg = img.interpGrad(offset); | ||||
| 
 | ||||
|   Eigen::Matrix<double, 1, 2> J = vg.tail<2>(); | ||||
| 
 | ||||
|   // std::cerr << "vg\n" << vg << std::endl;
 | ||||
| 
 | ||||
|   test_jacobian( | ||||
|       "d_val_d_p", J, | ||||
|       [&](const Eigen::Vector2d &x) { | ||||
|         Eigen::Matrix<double, 1, 1> res; | ||||
|         Eigen::Vector2d p1 = offset + x; | ||||
|         res[0] = img.interpGrad(p1)[0]; | ||||
|         return res; | ||||
|       }, | ||||
|       Eigen::Vector2d::Zero(), 1.0); | ||||
| } | ||||
| 
 | ||||
| TEST(Image, ImageInterpolate) { | ||||
|   Eigen::Vector2i offset(231, 123); | ||||
| 
 | ||||
|   basalt::ManagedImage<uint16_t> img(640, 480); | ||||
|   setImageData(img.ptr, img.size()); | ||||
| 
 | ||||
|   double eps = 1e-12; | ||||
|   double threshold = 1e-8; | ||||
| 
 | ||||
|   { | ||||
|     Eigen::Vector2i pi = offset; | ||||
|     Eigen::Vector2d pd = pi.cast<double>() + Eigen::Vector2d(eps, eps); | ||||
| 
 | ||||
|     uint16_t val1 = img(pi); | ||||
|     double val2 = img.interp(pd); | ||||
|     double val3 = img.interpGrad(pd)[0]; | ||||
| 
 | ||||
|     EXPECT_LE(std::abs(val2 - val1), threshold); | ||||
|     EXPECT_FLOAT_EQ(val2, val3); | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     Eigen::Vector2i pi = offset; | ||||
|     Eigen::Vector2d pd = pi.cast<double>() + Eigen::Vector2d(eps, eps); | ||||
| 
 | ||||
|     uint16_t val1 = img(pi); | ||||
|     double val2 = img.interp(pd); | ||||
|     double val3 = img.interpGrad(pd)[0]; | ||||
| 
 | ||||
|     EXPECT_LE(std::abs(val2 - val1), threshold); | ||||
|     EXPECT_FLOAT_EQ(val2, val3); | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     Eigen::Vector2i pi = offset + Eigen::Vector2i(1, 0); | ||||
|     Eigen::Vector2d pd = pi.cast<double>() + Eigen::Vector2d(-eps, eps); | ||||
| 
 | ||||
|     uint16_t val1 = img(pi); | ||||
|     double val2 = img.interp(pd); | ||||
|     double val3 = img.interpGrad(pd)[0]; | ||||
| 
 | ||||
|     EXPECT_LE(std::abs(val2 - val1), threshold); | ||||
|     EXPECT_FLOAT_EQ(val2, val3); | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     Eigen::Vector2i pi = offset + Eigen::Vector2i(0, 1); | ||||
|     Eigen::Vector2d pd = pi.cast<double>() + Eigen::Vector2d(eps, -eps); | ||||
| 
 | ||||
|     uint16_t val1 = img(pi); | ||||
|     double val2 = img.interp(pd); | ||||
|     double val3 = img.interpGrad(pd)[0]; | ||||
| 
 | ||||
|     EXPECT_LE(std::abs(val2 - val1), threshold); | ||||
|     EXPECT_FLOAT_EQ(val2, val3); | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     Eigen::Vector2i pi = offset + Eigen::Vector2i(1, 1); | ||||
|     Eigen::Vector2d pd = pi.cast<double>() + Eigen::Vector2d(-eps, -eps); | ||||
| 
 | ||||
|     uint16_t val1 = img(pi); | ||||
|     double val2 = img.interp(pd); | ||||
|     double val3 = img.interpGrad(pd)[0]; | ||||
| 
 | ||||
|     EXPECT_LE(std::abs(val2 - val1), threshold); | ||||
|     EXPECT_FLOAT_EQ(val2, val3); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST(Image, ImageInterpolateGrad) { | ||||
|   Eigen::Vector2i offset(231, 123); | ||||
| 
 | ||||
|   basalt::ManagedImage<uint16_t> img(640, 480); | ||||
|   setImageData(img.ptr, img.size()); | ||||
| 
 | ||||
|   Eigen::Vector2d pd = offset.cast<double>() + Eigen::Vector2d(0.4, 0.34345); | ||||
| 
 | ||||
|   Eigen::Vector3d valGrad = img.interpGrad<double>(pd); | ||||
|   Eigen::Matrix<double, 1, 2> J = valGrad.tail<2>(); | ||||
| 
 | ||||
|   test_jacobian( | ||||
|       "d_res_d_x", J, | ||||
|       [&](const Eigen::Vector2d &x) { | ||||
|         return Eigen::Matrix<double, 1, 1>(img.interp<double>(pd + x)); | ||||
|       }, | ||||
|       Eigen::Vector2d::Zero(), 1); | ||||
| } | ||||
							
								
								
									
										2
									
								
								thirdparty/basalt-headers
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								thirdparty/basalt-headers
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| Subproject commit c339ea747a29881271cfcbc559937b81dcf76324 | ||||
| Subproject commit 792c0e9b5a2ccffac60c80f29905cfde145d4042 | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user