├── lycon ├── __init__.py ├── core.py └── enum.py ├── MANIFEST.in ├── src └── lycon │ ├── util │ ├── file.h │ ├── singleton.cc │ ├── parallel.h │ ├── string.cc │ ├── alloc.h │ ├── alloc.cc │ ├── singleton.h │ ├── file.cc │ ├── macros.h │ ├── error.h │ ├── util.h │ ├── tls.h │ ├── hardware.h │ ├── fast_math.h │ ├── color.h │ ├── auto_buffer.h │ ├── hardware.cc │ ├── saturate_cast.h │ └── tls.cc │ ├── types.h │ ├── mat │ ├── convert.h │ ├── buffer_pool.h │ ├── step.h │ ├── size.h │ ├── shared.h │ ├── allocator.h │ ├── umat_data.h │ ├── umat_data.cc │ ├── iterator.cc │ ├── allocator.cc │ ├── iterator.h │ ├── io_array.h │ └── io_array_impl.h │ ├── python │ ├── numpy.h │ ├── module.cc │ ├── gil.h │ ├── compat.h │ ├── module.io.h │ ├── module.transform.h │ ├── macros.h │ ├── module.init.h │ └── interop.h │ ├── transform │ ├── rotate.h │ ├── resize.cc │ ├── resize │ │ ├── common.h │ │ ├── nearest.h │ │ └── interp.lut.h │ └── resize.h │ ├── io │ ├── jpeg.h │ ├── io.h │ ├── png.h │ ├── base.cc │ ├── base.h │ ├── bitstream.h │ ├── options.h │ └── exif.h │ ├── types │ ├── numeric.h │ ├── range.h │ ├── size.h │ ├── traits.h │ ├── rect.h │ ├── point.h │ └── scalar.h │ ├── arch.h │ └── defs.h ├── .gitignore ├── .clang-format ├── cmake ├── LyconUtils.cmake └── LocatePythonLibs.cmake ├── CMakeLists.txt ├── test └── test.py ├── perf └── benchmark.py ├── LICENSE ├── setup.py └── README.md /lycon/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | 3 | __version__ = '0.2.0' 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include src * 2 | recursive-include cmake * 3 | include CMakeLists.txt 4 | include LICENSE 5 | include README.md 6 | -------------------------------------------------------------------------------- /src/lycon/util/file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/util/string.h" 4 | 5 | namespace lycon 6 | { 7 | String tempfile(const char *suffix = 0); 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS temporary files 2 | .DS_Store 3 | 4 | # Python compiled files 5 | *.pyc 6 | 7 | # Build files 8 | build 9 | dist 10 | *.egg-info 11 | 12 | # Perf test data files 13 | perf/data 14 | -------------------------------------------------------------------------------- /src/lycon/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/types/numeric.h" 4 | #include "lycon/types/point.h" 5 | #include "lycon/types/range.h" 6 | #include "lycon/types/rect.h" 7 | #include "lycon/types/scalar.h" 8 | #include "lycon/types/size.h" 9 | -------------------------------------------------------------------------------- /src/lycon/util/singleton.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/singleton.h" 2 | 3 | namespace lycon 4 | { 5 | std::recursive_mutex& getInitializationMutex() 6 | { 7 | static std::recursive_mutex g_init_mutex; 8 | return g_init_mutex; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/lycon/mat/convert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/mat/shared.h" 4 | 5 | namespace lycon 6 | { 7 | void convertAndUnrollScalar(const Mat &sc, int buftype, uchar *scbuf, size_t blocksize); 8 | 9 | BinaryFunc getConvertFunc(int sdepth, int ddepth); 10 | } 11 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AlignOperands: true 3 | AlignTrailingComments: true 4 | AllowShortCaseLabelsOnASingleLine: true 5 | AllowShortBlocksOnASingleLine: false 6 | AllowShortFunctionsOnASingleLine: Empty 7 | BreakBeforeBraces: Allman 8 | ColumnLimit: 120 9 | IndentWidth: 4 10 | Language: Cpp 11 | MaxEmptyLinesToKeep: 1 12 | PointerAlignment: Left 13 | ... 14 | -------------------------------------------------------------------------------- /src/lycon/python/numpy.h: -------------------------------------------------------------------------------- 1 | #ifndef LYCON_IMPORT_ARRAY 2 | // All sources besides the main module that calls import_array need to define this 3 | // before importing the array header. 4 | #define NO_IMPORT_ARRAY 5 | #endif 6 | 7 | #define PY_ARRAY_UNIQUE_SYMBOL LYCON_ARRAY_API 8 | #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 9 | #include 10 | -------------------------------------------------------------------------------- /src/lycon/util/parallel.h: -------------------------------------------------------------------------------- 1 | #include "lycon/defs.h" 2 | #include "lycon/types.h" 3 | 4 | namespace lycon 5 | { 6 | class LYCON_EXPORTS ParallelLoopBody 7 | { 8 | public: 9 | virtual ~ParallelLoopBody(); 10 | virtual void operator()(const Range& range) const = 0; 11 | }; 12 | 13 | LYCON_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body, double nstripes = -1.); 14 | } 15 | -------------------------------------------------------------------------------- /src/lycon/mat/buffer_pool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lycon 4 | { 5 | class BufferPoolController 6 | { 7 | protected: 8 | ~BufferPoolController() {} 9 | 10 | public: 11 | virtual size_t getReservedSize() const = 0; 12 | virtual size_t getMaxReservedSize() const = 0; 13 | virtual void setMaxReservedSize(size_t size) = 0; 14 | virtual void freeAllReservedBuffers() = 0; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/lycon/python/module.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "lycon/io/io.h" 4 | #include "lycon/python/interop.h" 5 | #include "lycon/python/macros.h" 6 | #include "lycon/transform/resize.h" 7 | 8 | #define LYCON_IMPORT_ARRAY 9 | #include "lycon/python/numpy.h" 10 | 11 | using namespace lycon; 12 | 13 | #include "lycon/python/module.io.h" 14 | 15 | #include "lycon/python/module.transform.h" 16 | 17 | #include "lycon/python/module.init.h" 18 | -------------------------------------------------------------------------------- /src/lycon/transform/rotate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/mat/mat.h" 4 | 5 | namespace lycon 6 | { 7 | 8 | enum RotateFlags 9 | { 10 | ROTATE_90_CLOCKWISE = 0, // Rotate 90 degrees clockwise 11 | ROTATE_180 = 1, // Rotate 180 degrees clockwise 12 | ROTATE_90_COUNTERCLOCKWISE = 2, // Rotate 270 degrees clockwise 13 | }; 14 | 15 | void flip(InputArray _src, OutputArray _dst, int flip_mode); 16 | 17 | void transpose(InputArray _src, OutputArray _dst); 18 | 19 | void rotate(InputArray _src, OutputArray _dst, int rotateMode); 20 | } 21 | -------------------------------------------------------------------------------- /src/lycon/io/jpeg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/io/base.h" 4 | 5 | namespace lycon 6 | { 7 | class JpegDecoder : public BaseImageDecoder 8 | { 9 | public: 10 | JpegDecoder(); 11 | virtual ~JpegDecoder(); 12 | 13 | bool readData(Mat &img); 14 | bool readHeader(); 15 | void close(); 16 | 17 | ImageDecoder newDecoder() const; 18 | 19 | protected: 20 | FILE *m_f; 21 | void *m_state; 22 | }; 23 | 24 | class JpegEncoder : public BaseImageEncoder 25 | { 26 | public: 27 | JpegEncoder(); 28 | virtual ~JpegEncoder(); 29 | 30 | bool write(const Mat &img, const std::vector ¶ms); 31 | ImageEncoder newEncoder() const; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/lycon/util/string.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/string.h" 2 | #include "lycon/util/alloc.h" 3 | #include "lycon/util/util.h" 4 | 5 | namespace lycon 6 | { 7 | char* String::allocate(size_t len) 8 | { 9 | size_t totalsize = alignSize(len + 1, (int)sizeof(int)); 10 | int* data = (int*)fastMalloc(totalsize + sizeof(int)); 11 | data[0] = 1; 12 | cstr_ = (char*)(data + 1); 13 | len_ = len; 14 | cstr_[len] = 0; 15 | return cstr_; 16 | } 17 | 18 | void String::deallocate() 19 | { 20 | int* data = (int*)cstr_; 21 | len_ = 0; 22 | cstr_ = 0; 23 | 24 | if (data && 1 == LYCON_XADD(data - 1, -1)) 25 | { 26 | fastFree(data - 1); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lycon/io/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/io/options.h" 5 | #include "lycon/mat/mat.h" 6 | #include "lycon/util/string.h" 7 | 8 | namespace lycon 9 | { 10 | LYCON_EXPORTS Mat imread(const String &filename, int flags = IMREAD_COLOR); 11 | 12 | LYCON_EXPORTS bool imwrite(const String &filename, InputArray img, const std::vector ¶ms = std::vector()); 13 | 14 | LYCON_EXPORTS Mat imdecode(InputArray buf, int flags); 15 | 16 | LYCON_EXPORTS Mat imdecode(InputArray buf, int flags, Mat *dst); 17 | 18 | LYCON_EXPORTS bool imencode(const String &ext, InputArray img, std::vector &buf, 19 | const std::vector ¶ms = std::vector()); 20 | } 21 | -------------------------------------------------------------------------------- /src/lycon/util/alloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | 5 | namespace lycon 6 | { 7 | /** @brief Allocates an aligned memory buffer. 8 | 9 | The function allocates the buffer of the specified size and returns it. When the buffer size is 16 10 | bytes or more, the returned buffer is aligned to 16 bytes. 11 | @param bufSize Allocated buffer size. 12 | */ 13 | LYCON_EXPORTS void *fastMalloc(size_t bufSize); 14 | 15 | /** @brief Deallocates a memory buffer. 16 | 17 | The function deallocates the buffer allocated with fastMalloc . If NULL pointer is passed, the 18 | function does nothing. C version of the function clears the pointer *pptr* to avoid problems with 19 | double memory deallocation. 20 | @param ptr Pointer to the allocated buffer. 21 | */ 22 | LYCON_EXPORTS void fastFree(void *ptr); 23 | } 24 | -------------------------------------------------------------------------------- /src/lycon/transform/resize.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/transform/resize.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "lycon/mat/mat.h" 8 | #include "lycon/util/auto_buffer.h" 9 | #include "lycon/util/fast_math.h" 10 | #include "lycon/util/hardware.h" 11 | #include "lycon/util/parallel.h" 12 | #include "lycon/util/saturate_cast.h" 13 | #include "lycon/util/util.h" 14 | 15 | namespace lycon 16 | { 17 | #include "lycon/transform/resize/interp.lut.h" 18 | 19 | #include "lycon/transform/resize/common.h" 20 | 21 | #include "lycon/transform/resize/nearest.h" 22 | 23 | #include "lycon/transform/resize/linear.h" 24 | 25 | #include "lycon/transform/resize/cubic.h" 26 | 27 | #include "lycon/transform/resize/lanczos.h" 28 | 29 | #include "lycon/transform/resize/area.h" 30 | 31 | #include "lycon/transform/resize/invoker.h" 32 | } 33 | -------------------------------------------------------------------------------- /src/lycon/util/alloc.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/alloc.h" 2 | #include "lycon/util/error.h" 3 | #include "lycon/util/util.h" 4 | 5 | #define LYCON_MALLOC_ALIGN 16 6 | 7 | namespace lycon 8 | { 9 | void* fastMalloc(size_t size) 10 | { 11 | uchar* udata = (uchar*)malloc(size + sizeof(void*) + LYCON_MALLOC_ALIGN); 12 | if (!udata) 13 | LYCON_ERROR("Failed to allocate %lu bytes", (unsigned long)size); 14 | uchar** adata = alignPtr((uchar**)udata + 1, LYCON_MALLOC_ALIGN); 15 | adata[-1] = udata; 16 | return adata; 17 | } 18 | 19 | void fastFree(void* ptr) 20 | { 21 | if (ptr) 22 | { 23 | uchar* udata = ((uchar**)ptr)[-1]; 24 | LYCON_DbgAssert(udata < (uchar*)ptr && 25 | ((uchar*)ptr - udata) <= (ptrdiff_t)(sizeof(void*) + LYCON_MALLOC_ALIGN)); 26 | free(udata); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lycon/python/gil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lycon 6 | { 7 | // RAII style GIL acquisition 8 | // On construction, saves the thread's state and acquires the GIL. 9 | // On destruction, resets the thread state pointer and releases the GIL. 10 | class PyEnsureGIL 11 | { 12 | public: 13 | PyEnsureGIL() : state_(PyGILState_Ensure()) {} 14 | ~PyEnsureGIL() { PyGILState_Release(state_); } 15 | 16 | private: 17 | PyGILState_STATE state_; 18 | }; 19 | 20 | // RAII style GIL release 21 | // On construction, saves the current thread state and releases the GIL. 22 | // On destruction, re-acquires the GIL and restores the thread state. 23 | class PyReleaseGIL 24 | { 25 | public: 26 | PyReleaseGIL() : state_(PyEval_SaveThread()) {} 27 | ~PyReleaseGIL() { PyEval_RestoreThread(state_); } 28 | 29 | private: 30 | PyThreadState *state_; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/lycon/types/numeric.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lycon 4 | { 5 | #if defined __ARM_FP16_FORMAT_IEEE && !defined __CUDACC__ 6 | #define LYCON_FP16_TYPE 1 7 | #else 8 | #define LYCON_FP16_TYPE 0 9 | #endif 10 | 11 | typedef union Lycon16suf { 12 | short i; 13 | #if LYCON_FP16_TYPE 14 | __fp16 h; 15 | #endif 16 | struct _fp16Format 17 | { 18 | unsigned int significand : 10; 19 | unsigned int exponent : 5; 20 | unsigned int sign : 1; 21 | } fmt; 22 | } Lycon16suf; 23 | 24 | typedef union Lycon32suf { 25 | int i; 26 | unsigned u; 27 | float f; 28 | struct _fp32Format 29 | { 30 | unsigned int significand : 23; 31 | unsigned int exponent : 8; 32 | unsigned int sign : 1; 33 | } fmt; 34 | } Lycon32suf; 35 | 36 | typedef union Lycon64suf { 37 | int64 i; 38 | uint64 u; 39 | double f; 40 | } Lycon64suf; 41 | } 42 | -------------------------------------------------------------------------------- /src/lycon/python/compat.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Python 2/3 compatibility layer 4 | 5 | #if PY_MAJOR_VERSION >= 3 6 | 7 | // Python3 treats all ints as longs, PyInt_X functions have been removed. 8 | #define PyInt_Check PyLong_Check 9 | #define PyInt_CheckExact PyLong_CheckExact 10 | #define PyInt_AsLong PyLong_AsLong 11 | #define PyInt_AS_LONG PyLong_AS_LONG 12 | #define PyInt_FromLong PyLong_FromLong 13 | #define PyNumber_Int PyNumber_Long 14 | 15 | // Python3 strings are unicode, these defines mimic the Python2 functionality. 16 | #define PyString_Check PyUnicode_Check 17 | #define PyString_FromString PyUnicode_FromString 18 | #define PyString_FromStringAndSize PyUnicode_FromStringAndSize 19 | #define PyString_Size PyUnicode_GET_SIZE 20 | 21 | // PyUnicode_AsUTF8 isn't available until Python 3.3 22 | #if (PY_VERSION_HEX < 0x03030000) 23 | #define PyString_AsString _PyUnicode_AsString 24 | #else 25 | #define PyString_AsString PyUnicode_AsUTF8 26 | #endif 27 | #endif 28 | -------------------------------------------------------------------------------- /src/lycon/transform/resize/common.h: -------------------------------------------------------------------------------- 1 | struct VResizeNoVec 2 | { 3 | int operator()(const uchar**, uchar*, const uchar*, int) const { return 0; } 4 | }; 5 | 6 | struct HResizeNoVec 7 | { 8 | int operator()(const uchar**, uchar**, int, const int*, const uchar*, int, int, int, int, int) const { return 0; } 9 | }; 10 | 11 | template 12 | struct Cast 13 | { 14 | typedef ST type1; 15 | typedef DT rtype; 16 | 17 | DT operator()(ST val) const { return saturate_cast
(val); } 18 | }; 19 | 20 | template 21 | struct FixedPtCast 22 | { 23 | typedef ST type1; 24 | typedef DT rtype; 25 | enum 26 | { 27 | SHIFT = bits, 28 | DELTA = 1 << (bits - 1) 29 | }; 30 | 31 | DT operator()(ST val) const { return saturate_cast
((val + DELTA) >> SHIFT); } 32 | }; 33 | 34 | static inline int clip(int x, int a, int b) { return x >= a ? (x < b ? x : b - 1) : a; } 35 | 36 | static const int MAX_ESIZE = 16; 37 | -------------------------------------------------------------------------------- /src/lycon/util/singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace lycon 6 | { 7 | std::recursive_mutex &getInitializationMutex(); 8 | 9 | #define LYCON_SINGLETON_LAZY_INIT_(TYPE, INITIALIZER, RET_VALUE) \ 10 | static TYPE *volatile instance = NULL; \ 11 | if (instance == NULL) \ 12 | { \ 13 | std::lock_guard lock(lycon::getInitializationMutex()); \ 14 | if (instance == NULL) instance = INITIALIZER; \ 15 | } \ 16 | return RET_VALUE; 17 | 18 | #define LYCON_SINGLETON_LAZY_INIT(TYPE, INITIALIZER) LYCON_SINGLETON_LAZY_INIT_(TYPE, INITIALIZER, instance) 19 | #define LYCON_SINGLETON_LAZY_INIT_REF(TYPE, INITIALIZER) LYCON_SINGLETON_LAZY_INIT_(TYPE, INITIALIZER, *instance) 20 | } 21 | -------------------------------------------------------------------------------- /src/lycon/util/file.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/file.h" 2 | 3 | #include 4 | #include 5 | 6 | namespace lycon 7 | { 8 | 9 | String tempfile(const char* suffix) 10 | { 11 | String fname; 12 | const char* temp_dir = getenv("LYCON_TEMP_PATH"); 13 | char defaultTemplate[] = "/tmp/__lycon_temp.XXXXXX"; 14 | if (temp_dir == 0 || temp_dir[0] == 0) 15 | { 16 | fname = defaultTemplate; 17 | } 18 | else 19 | { 20 | fname = temp_dir; 21 | char ech = fname[fname.size() - 1]; 22 | if (ech != '/' && ech != '\\') 23 | fname = fname + "/"; 24 | fname = fname + "__lycon_temp.XXXXXX"; 25 | } 26 | const int fd = mkstemp((char*)fname.c_str()); 27 | if (fd == -1) 28 | return String(); 29 | 30 | close(fd); 31 | remove(fname.c_str()); 32 | if (suffix) 33 | { 34 | if (suffix[0] != '.') 35 | return fname + "." + suffix; 36 | else 37 | return fname + suffix; 38 | } 39 | return fname; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/lycon/python/module.io.h: -------------------------------------------------------------------------------- 1 | DEFINE_FUNCTION(load) 2 | { 3 | PyObject* py_path = nullptr; 4 | int flags = IMREAD_COLOR; 5 | if (PyArg_ParseTuple(args, "O|i:load", &py_path, &flags)) 6 | { 7 | std::string path = string_from_pyobject(py_path); 8 | Mat img; 9 | PYCON_WITHOUT_GIL(img = imread(path)); 10 | return ndarray_from_mat(img); 11 | } 12 | return nullptr; 13 | } 14 | 15 | DEFINE_FUNCTION(save) 16 | { 17 | PyObject* py_path = nullptr; 18 | PyObject* py_img = nullptr; 19 | PyObject* py_flags = nullptr; 20 | if (PyArg_ParseTuple(args, "OO|O:save", &py_path, &py_img, &py_flags)) 21 | { 22 | std::string path = string_from_pyobject(py_path); 23 | 24 | Mat img; 25 | mat_from_ndarray(py_img, img, false); 26 | 27 | std::vector options; 28 | if (PYCON_IS_NOT_NONE(py_flags)) 29 | { 30 | options = vector_from_pyobject(py_flags); 31 | } 32 | PYCON_WITHOUT_GIL(imwrite(path, img, options)); 33 | } 34 | return Py_None; 35 | } 36 | -------------------------------------------------------------------------------- /src/lycon/util/macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // --- LYCON_XADD --- 4 | #if defined __GNUC__ 5 | #if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__) 6 | #ifdef __ATOMIC_ACQ_REL 7 | #define LYCON_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int) *)(addr), delta, __ATOMIC_ACQ_REL) 8 | #else 9 | #define LYCON_XADD(addr, delta) __atomic_fetch_add((_Atomic(int) *)(addr), delta, 4) 10 | #endif 11 | #else 12 | #if defined __ATOMIC_ACQ_REL && !defined __clang__ 13 | // version for gcc >= 4.7 14 | #define LYCON_XADD(addr, delta) (int)__atomic_fetch_add((unsigned *)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL) 15 | #else 16 | #define LYCON_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned *)(addr), (unsigned)(delta)) 17 | #endif 18 | #endif 19 | #elif defined _MSC_VER && !defined RC_INVOKED 20 | #include 21 | #define LYCON_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile *)addr, delta) 22 | #else 23 | LYCON_INLINE LYCON_XADD(int *addr, int delta) 24 | { 25 | int tmp = *addr; 26 | *addr += delta; 27 | return tmp; 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /src/lycon/python/module.transform.h: -------------------------------------------------------------------------------- 1 | DEFINE_FUNCTION(resize) 2 | { 3 | PyObject* src_ndarray = nullptr; 4 | PyObject* py_dst_size = nullptr; 5 | PyObject* dst_ndarray = nullptr; 6 | int interpolation = INTER_LINEAR; 7 | 8 | if (PyArg_ParseTuple(args, "OO|iO:resize", &src_ndarray, &py_dst_size, &interpolation, &dst_ndarray)) 9 | { 10 | Mat src_img; 11 | mat_from_ndarray(src_ndarray, src_img, true); 12 | 13 | Size dst_size = size_from_pyobject(py_dst_size); 14 | 15 | Mat dst_img; 16 | if (PYCON_IS_NOT_NONE(dst_ndarray)) 17 | { 18 | mat_from_ndarray(dst_ndarray, dst_img, false); 19 | LYCON_ASSERT(dst_img.type() == src_img.type()); 20 | LYCON_ASSERT(dst_img.rows == dst_size.height); 21 | LYCON_ASSERT(dst_img.cols == dst_size.width); 22 | } 23 | else 24 | { 25 | dst_img.allocator = &(NumpyAllocator::getNumpyAllocator()); 26 | } 27 | PYCON_WITHOUT_GIL(resize(src_img, dst_img, dst_size, 0, 0, interpolation)); 28 | 29 | return ndarray_from_mat(dst_img); 30 | } 31 | return Py_None; 32 | } 33 | -------------------------------------------------------------------------------- /src/lycon/mat/step.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/types.h" 4 | #include "lycon/util/error.h" 5 | 6 | namespace lycon 7 | { 8 | 9 | struct LYCON_EXPORTS MatStep 10 | { 11 | MatStep(); 12 | explicit MatStep(size_t s); 13 | const size_t &operator[](int i) const; 14 | size_t &operator[](int i); 15 | operator size_t() const; 16 | MatStep &operator=(size_t s); 17 | 18 | size_t *p; 19 | size_t buf[2]; 20 | 21 | protected: 22 | MatStep &operator=(const MatStep &); 23 | }; 24 | 25 | inline MatStep::MatStep() 26 | { 27 | p = buf; 28 | p[0] = p[1] = 0; 29 | } 30 | 31 | inline MatStep::MatStep(size_t s) 32 | { 33 | p = buf; 34 | p[0] = s; 35 | p[1] = 0; 36 | } 37 | 38 | inline const size_t &MatStep::operator[](int i) const 39 | { 40 | return p[i]; 41 | } 42 | 43 | inline size_t &MatStep::operator[](int i) 44 | { 45 | return p[i]; 46 | } 47 | 48 | inline MatStep::operator size_t() const 49 | { 50 | LYCON_DbgAssert(p == buf); 51 | return buf[0]; 52 | } 53 | 54 | inline MatStep &MatStep::operator=(size_t s) 55 | { 56 | LYCON_DbgAssert(p == buf); 57 | buf[0] = s; 58 | return *this; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/lycon/util/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lycon/defs.h" 10 | 11 | namespace lycon 12 | { 13 | class RuntimeError : public std::runtime_error 14 | { 15 | public: 16 | RuntimeError(const char *what_arg) : std::runtime_error(what_arg) {} 17 | }; 18 | 19 | #if defined __GNUC__ 20 | #define LYCON_Func __func__ 21 | #elif defined _MSC_VER 22 | #define LYCON_Func __FUNCTION__ 23 | #else 24 | #define LYCON_Func "" 25 | #endif 26 | 27 | #define LYCON_ERROR(...) \ 28 | { \ 29 | char err_msg[2048]; \ 30 | snprintf(err_msg, 2048, __VA_ARGS__); \ 31 | throw RuntimeError(err_msg); \ 32 | } 33 | 34 | #define LYCON_StaticAssert static_assert 35 | #define LYCON_DbgAssert assert 36 | #define LYCON_ASSERT(expr) \ 37 | if (!!(expr)) \ 38 | ; \ 39 | else \ 40 | LYCON_ERROR("Assertion Failure: `%s` evaluated to false in `%s` (%s:%d)", #expr, LYCON_Func, __FILE__, __LINE__) 41 | } 42 | -------------------------------------------------------------------------------- /src/lycon/util/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/util/error.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | /** @brief Aligns a pointer to the specified number of bytes. 11 | 12 | The function returns the aligned pointer of the same type as the input pointer: 13 | \f[\texttt{(_Tp*)(((size_t)ptr + n-1) & -n)}\f] 14 | @param ptr Aligned pointer. 15 | @param n Alignment size that must be a power of two. 16 | */ 17 | template static inline _Tp *alignPtr(_Tp *ptr, int n = (int)sizeof(_Tp)) 18 | { 19 | return (_Tp *)(((size_t)ptr + n - 1) & -n); 20 | } 21 | 22 | /** @brief Aligns a buffer size to the specified number of bytes. 23 | 24 | The function returns the minimum number that is greater or equal to sz and is divisible by n : 25 | \f[\texttt{(sz + n-1) & -n}\f] 26 | @param sz Buffer size to align. 27 | @param n Alignment size that must be a power of two. 28 | */ 29 | static inline size_t alignSize(size_t sz, int n) 30 | { 31 | LYCON_DbgAssert((n & (n - 1)) == 0); // n is a power of 2 32 | return (sz + n - 1) & -n; 33 | } 34 | 35 | static inline bool isBigEndian(void) 36 | { 37 | return (((const int *)"\0\x1\x2\x3\x4\x5\x6\x7")[0] & 255) != 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/lycon/io/png.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/io/base.h" 4 | 5 | namespace lycon 6 | { 7 | class PngDecoder : public BaseImageDecoder 8 | { 9 | public: 10 | PngDecoder(); 11 | virtual ~PngDecoder(); 12 | 13 | bool readData(Mat &img); 14 | bool readHeader(); 15 | void close(); 16 | 17 | ImageDecoder newDecoder() const; 18 | 19 | protected: 20 | static void readDataFromBuf(void *png_ptr, uchar *dst, size_t size); 21 | 22 | int m_bit_depth; 23 | void *m_png_ptr; // pointer to decompression structure 24 | void *m_info_ptr; // pointer to image information structure 25 | void *m_end_info; // pointer to one more image information structure 26 | FILE *m_f; 27 | int m_color_type; 28 | size_t m_buf_pos; 29 | }; 30 | 31 | class PngEncoder : public BaseImageEncoder 32 | { 33 | public: 34 | PngEncoder(); 35 | virtual ~PngEncoder(); 36 | 37 | bool isFormatSupported(int depth) const; 38 | bool write(const Mat &img, const std::vector ¶ms); 39 | 40 | ImageEncoder newEncoder() const; 41 | 42 | protected: 43 | static void writeDataToBuf(void *png_ptr, uchar *src, size_t size); 44 | static void flushBuf(void *png_ptr); 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /cmake/LyconUtils.cmake: -------------------------------------------------------------------------------- 1 | # Provides an option that the user can optionally select. 2 | # Can accept condition to control when option is available for user. 3 | # Usage: 4 | # lycon_option( "help string describing the option" [IF ]) 5 | # Based on OCV_OPTION in OpenCVUtils.cmake. 6 | macro(LYCON_OPTION variable description value) 7 | set(__value ${value}) 8 | set(__condition "") 9 | set(__varname "__value") 10 | foreach(arg ${ARGN}) 11 | if(arg STREQUAL "IF" OR arg STREQUAL "if") 12 | set(__varname "__condition") 13 | else() 14 | list(APPEND ${__varname} ${arg}) 15 | endif() 16 | endforeach() 17 | unset(__varname) 18 | if(__condition STREQUAL "") 19 | set(__condition 2 GREATER 1) 20 | endif() 21 | 22 | if(${__condition}) 23 | if(__value MATCHES ";") 24 | if(${__value}) 25 | option(${variable} "${description}" ON) 26 | else() 27 | option(${variable} "${description}" OFF) 28 | endif() 29 | elseif(DEFINED ${__value}) 30 | if(${__value}) 31 | option(${variable} "${description}" ON) 32 | else() 33 | option(${variable} "${description}" OFF) 34 | endif() 35 | else() 36 | option(${variable} "${description}" ${__value}) 37 | endif() 38 | else() 39 | unset(${variable} CACHE) 40 | endif() 41 | unset(__condition) 42 | unset(__value) 43 | endmacro() 44 | -------------------------------------------------------------------------------- /src/lycon/mat/size.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/types.h" 4 | #include "lycon/util/error.h" 5 | 6 | namespace lycon 7 | { 8 | struct LYCON_EXPORTS MatSize 9 | { 10 | explicit MatSize(int *_p); 11 | Size operator()() const; 12 | const int &operator[](int i) const; 13 | int &operator[](int i); 14 | operator const int *() const; 15 | bool operator==(const MatSize &sz) const; 16 | bool operator!=(const MatSize &sz) const; 17 | 18 | int *p; 19 | }; 20 | 21 | inline MatSize::MatSize(int *_p) : p(_p) 22 | { 23 | } 24 | 25 | inline Size MatSize::operator()() const 26 | { 27 | LYCON_DbgAssert(p[-1] <= 2); 28 | return Size(p[1], p[0]); 29 | } 30 | 31 | inline const int &MatSize::operator[](int i) const 32 | { 33 | return p[i]; 34 | } 35 | 36 | inline int &MatSize::operator[](int i) 37 | { 38 | return p[i]; 39 | } 40 | 41 | inline MatSize::operator const int *() const 42 | { 43 | return p; 44 | } 45 | 46 | inline bool MatSize::operator==(const MatSize &sz) const 47 | { 48 | int d = p[-1]; 49 | int dsz = sz.p[-1]; 50 | if (d != dsz) 51 | return false; 52 | if (d == 2) 53 | return p[0] == sz.p[0] && p[1] == sz.p[1]; 54 | 55 | for (int i = 0; i < d; i++) 56 | if (p[i] != sz.p[i]) 57 | return false; 58 | return true; 59 | } 60 | 61 | inline bool MatSize::operator!=(const MatSize &sz) const 62 | { 63 | return !(*this == sz); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/lycon/util/tls.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/defs.h" 6 | 7 | namespace lycon 8 | { 9 | class LYCON_EXPORTS TLSDataContainer 10 | { 11 | protected: 12 | TLSDataContainer(); 13 | virtual ~TLSDataContainer(); 14 | 15 | void gatherData(std::vector& data) const; 16 | 17 | void* getData() const; 18 | void release(); 19 | 20 | private: 21 | virtual void* createDataInstance() const = 0; 22 | virtual void deleteDataInstance(void* pData) const = 0; 23 | 24 | int key_; 25 | }; 26 | 27 | // Main TLS data class 28 | template 29 | class TLSData : protected TLSDataContainer 30 | { 31 | public: 32 | inline TLSData() {} 33 | inline ~TLSData() { release(); } // Release key and delete associated data 34 | inline T* get() const { return (T*)getData(); } // Get data assosiated with key 35 | 36 | // Get data from all threads 37 | inline void gather(std::vector& data) const 38 | { 39 | std::vector& dataVoid = reinterpret_cast&>(data); 40 | gatherData(dataVoid); 41 | } 42 | 43 | private: 44 | virtual void* createDataInstance() const { return new T; } // Wrapper to allocate data by template 45 | virtual void deleteDataInstance(void* pData) const { delete (T*)pData; } // Wrapper to release data by template 46 | 47 | // Disable TLS copy operations 48 | TLSData(TLSData&) {} 49 | TLSData& operator=(const TLSData&) { return *this; } 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /src/lycon/transform/resize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/mat/mat.h" 4 | 5 | namespace lycon 6 | { 7 | enum InterpolationFlags 8 | { 9 | /** nearest neighbor interpolation */ 10 | INTER_NEAREST = 0, 11 | /** bilinear interpolation */ 12 | INTER_LINEAR = 1, 13 | /** bicubic interpolation */ 14 | INTER_CUBIC = 2, 15 | /** resampling using pixel area relation. It may be a preferred method for 16 | image decimation, as 17 | it gives moire'-free results. But when the image is zoomed, it is similar to 18 | the INTER_NEAREST 19 | method. */ 20 | INTER_AREA = 3, 21 | /** Lanczos interpolation over 8x8 neighborhood */ 22 | INTER_LANCZOS4 = 4, 23 | /** mask for interpolation codes */ 24 | INTER_MAX = 7, 25 | /** flag, fills all of the destination image pixels. If some of them 26 | correspond to outliers in the 27 | source image, they are set to zero */ 28 | WARP_FILL_OUTLIERS = 8, 29 | /** flag, inverse transformation 30 | 31 | For example, @ref cv::linearPolar or @ref cv::logPolar transforms: 32 | - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$ 33 | - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$ 34 | */ 35 | WARP_INVERSE_MAP = 16 36 | }; 37 | 38 | enum InterpolationMasks 39 | { 40 | INTER_BITS = 5, 41 | INTER_BITS2 = INTER_BITS * 2, 42 | INTER_TAB_SIZE = 1 << INTER_BITS, 43 | INTER_TAB_SIZE2 = INTER_TAB_SIZE * INTER_TAB_SIZE 44 | }; 45 | 46 | void resize(InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, double inv_scale_y, int interpolation); 47 | } 48 | -------------------------------------------------------------------------------- /lycon/core.py: -------------------------------------------------------------------------------- 1 | import _lycon 2 | 3 | import itertools 4 | 5 | from .enum import (Decode, Encode, Interpolation) 6 | 7 | def load(path, mode=Decode.UNCHANGED): 8 | """ 9 | Loads and returns the image at the given path as a numpy ndarray. 10 | """ 11 | return _lycon.load(path, mode) 12 | 13 | def save(path, image, options=None): 14 | """ 15 | Saves the given image (a numpy ndarray) at the given path. 16 | The image format is inferred from the extension. 17 | 18 | The options argument, if provided, should be a dictionary where the keys are constants 19 | from the Encode enum and the values are integers. 20 | """ 21 | if options is not None: 22 | # Convert to a flat (key_1, value_1, key_2, value_2, ...) list 23 | options = list(itertools.chain(*options.items())) 24 | _lycon.save(path, image, options) 25 | 26 | def resize(image, width, height, interpolation=Interpolation.LINEAR, output=None): 27 | """ 28 | Resize the image to the given dimensions, resampled using the given interpolation method. 29 | 30 | If an output ndarray is provided, it must be the same type as the input and have the 31 | dimensions of the resized image. 32 | """ 33 | assert 2 <= len(image.shape) <= 4 34 | if output is not None: 35 | assert output.dtype == image.dtype 36 | assert len(output.shape) == len(image.shape) 37 | assert output.shape[:2] == (height, width) 38 | return _lycon.resize(image, (width, height), interpolation, output) 39 | 40 | def get_supported_extensions(): 41 | """ 42 | Returns a list of supported image extensions. 43 | """ 44 | return ('jpeg', 'jpg', 'png') 45 | -------------------------------------------------------------------------------- /src/lycon/mat/shared.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/mat/mat.h" 5 | #include "lycon/types.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | typedef void (*BinaryFunc)(const uchar *src1, size_t step1, const uchar *src2, size_t step2, uchar *dst, size_t step, 11 | Size sz, void *); 12 | 13 | inline Size getContinuousSize_(int flags, int cols, int rows, int widthScale) 14 | { 15 | int64 sz = (int64)cols * rows * widthScale; 16 | return (flags & Mat::CONTINUOUS_FLAG) != 0 && (int)sz == sz ? Size((int)sz, 1) : Size(cols * widthScale, rows); 17 | } 18 | 19 | inline Size getContinuousSize(const Mat &m1, int widthScale = 1) 20 | { 21 | return getContinuousSize_(m1.flags, m1.cols, m1.rows, widthScale); 22 | } 23 | 24 | inline Size getContinuousSize(const Mat &m1, const Mat &m2, int widthScale = 1) 25 | { 26 | return getContinuousSize_(m1.flags & m2.flags, m1.cols, m1.rows, widthScale); 27 | } 28 | 29 | inline Size getContinuousSize(const Mat &m1, const Mat &m2, const Mat &m3, int widthScale = 1) 30 | { 31 | return getContinuousSize_(m1.flags & m2.flags & m3.flags, m1.cols, m1.rows, widthScale); 32 | } 33 | 34 | inline Size getContinuousSize(const Mat &m1, const Mat &m2, const Mat &m3, const Mat &m4, int widthScale = 1) 35 | { 36 | return getContinuousSize_(m1.flags & m2.flags & m3.flags & m4.flags, m1.cols, m1.rows, widthScale); 37 | } 38 | 39 | inline Size getContinuousSize(const Mat &m1, const Mat &m2, const Mat &m3, const Mat &m4, const Mat &m5, 40 | int widthScale = 1) 41 | { 42 | return getContinuousSize_(m1.flags & m2.flags & m3.flags & m4.flags & m5.flags, m1.cols, m1.rows, widthScale); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/lycon/python/macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/python/gil.h" 4 | 5 | namespace lycon 6 | { 7 | PyObject *get_pycon_error(); 8 | 9 | #define ERROR_FENCED(expr) \ 10 | try \ 11 | { \ 12 | expr; \ 13 | } \ 14 | catch (const lycon::RuntimeError &e) \ 15 | { \ 16 | PyErr_SetString(get_pycon_error(), e.what()); \ 17 | return 0; \ 18 | } 19 | 20 | #define DEFINE_FUNCTION(name) \ 21 | static inline PyObject *pycon_impl_##name(PyObject *self, PyObject *args); \ 22 | extern "C" PyObject *pycon_##name(PyObject *self, PyObject *args) \ 23 | { \ 24 | ERROR_FENCED(return pycon_impl_##name(self, args)) \ 25 | } \ 26 | static inline PyObject *pycon_impl_##name(PyObject *self, PyObject *args) 27 | 28 | #define DECLARE_METHOD(name) \ 29 | { \ 30 | #name, pycon_##name, METH_VARARGS, "" \ 31 | } 32 | 33 | #define PYCON_IS_NOT_NONE(obj) (obj != nullptr) && (obj != Py_None) 34 | 35 | #define PYCON_ASSERT_NOT_NONE(obj) LYCON_ASSERT(PYCON_IS_NOT_NONE(obj)) 36 | 37 | #define PYCON_WITHOUT_GIL(expr) \ 38 | { \ 39 | PyReleaseGIL release_gil; \ 40 | expr; \ 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/lycon/util/hardware.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | 5 | namespace lycon 6 | { 7 | /* CPU features and intrinsics support */ 8 | #define LYCON_CPU_NONE 0 9 | #define LYCON_CPU_MMX 1 10 | #define LYCON_CPU_SSE 2 11 | #define LYCON_CPU_SSE2 3 12 | #define LYCON_CPU_SSE3 4 13 | #define LYCON_CPU_SSSE3 5 14 | #define LYCON_CPU_SSE4_1 6 15 | #define LYCON_CPU_SSE4_2 7 16 | #define LYCON_CPU_POPCNT 8 17 | #define LYCON_CPU_FP16 9 18 | #define LYCON_CPU_AVX 10 19 | #define LYCON_CPU_AVX2 11 20 | #define LYCON_CPU_FMA3 12 21 | 22 | #define LYCON_CPU_AVX_512F 13 23 | #define LYCON_CPU_AVX_512BW 14 24 | #define LYCON_CPU_AVX_512CD 15 25 | #define LYCON_CPU_AVX_512DQ 16 26 | #define LYCON_CPU_AVX_512ER 17 27 | #define LYCON_CPU_AVX_512IFMA512 18 28 | #define LYCON_CPU_AVX_512PF 19 29 | #define LYCON_CPU_AVX_512VBMI 20 30 | #define LYCON_CPU_AVX_512VL 21 31 | 32 | #define LYCON_CPU_NEON 100 33 | 34 | // when adding to this list remember to update the following enum 35 | #define LYCON_HARDWARE_MAX_FEATURE 255 36 | 37 | /** @brief Returns true if the specified feature is supported by the host hardware. 38 | 39 | The function returns true if the host hardware supports the specified feature. When user calls 40 | setUseOptimized(false), the subsequent calls to checkHardwareSupport() will return false until 41 | setUseOptimized(true) is called. This way user can dynamically switch on and off the optimized code 42 | in OpenCV. 43 | @param feature The feature of interest, one of cv::CpuFeatures 44 | */ 45 | LYCON_EXPORTS bool checkHardwareSupport(int feature); 46 | 47 | #define USE_SSE2 (checkHardwareSupport(LYCON_CPU_SSE)) 48 | #define USE_SSE4_2 (checkHardwareSupport(LYCON_CPU_SSE4_2)) 49 | #define USE_AVX (checkHardwareSupport(LYCON_CPU_AVX)) 50 | #define USE_AVX2 (checkHardwareSupport(LYCON_CPU_AVX2)) 51 | } 52 | -------------------------------------------------------------------------------- /src/lycon/types/range.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | 5 | namespace lycon 6 | { 7 | 8 | class LYCON_EXPORTS Range 9 | { 10 | public: 11 | Range(); 12 | Range(int _start, int _end); 13 | int size() const; 14 | bool empty() const; 15 | static Range all(); 16 | 17 | int start, end; 18 | }; 19 | 20 | inline Range::Range() : start(0), end(0) 21 | { 22 | } 23 | 24 | inline Range::Range(int _start, int _end) : start(_start), end(_end) 25 | { 26 | } 27 | 28 | inline int Range::size() const 29 | { 30 | return end - start; 31 | } 32 | 33 | inline bool Range::empty() const 34 | { 35 | return start == end; 36 | } 37 | 38 | inline Range Range::all() 39 | { 40 | return Range(INT_MIN, INT_MAX); 41 | } 42 | 43 | static inline bool operator==(const Range &r1, const Range &r2) 44 | { 45 | return r1.start == r2.start && r1.end == r2.end; 46 | } 47 | 48 | static inline bool operator!=(const Range &r1, const Range &r2) 49 | { 50 | return !(r1 == r2); 51 | } 52 | 53 | static inline bool operator!(const Range &r) 54 | { 55 | return r.start == r.end; 56 | } 57 | 58 | static inline Range operator&(const Range &r1, const Range &r2) 59 | { 60 | Range r(std::max(r1.start, r2.start), std::min(r1.end, r2.end)); 61 | r.end = std::max(r.end, r.start); 62 | return r; 63 | } 64 | 65 | static inline Range &operator&=(Range &r1, const Range &r2) 66 | { 67 | r1 = r1 & r2; 68 | return r1; 69 | } 70 | 71 | static inline Range operator+(const Range &r1, int delta) 72 | { 73 | return Range(r1.start + delta, r1.end + delta); 74 | } 75 | 76 | static inline Range operator+(int delta, const Range &r1) 77 | { 78 | return Range(r1.start + delta, r1.end + delta); 79 | } 80 | 81 | static inline Range operator-(const Range &r1, int delta) 82 | { 83 | return r1 + (-delta); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/lycon/mat/allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/mat/buffer_pool.h" 5 | 6 | namespace lycon 7 | { 8 | struct UMatData; 9 | 10 | enum UMatUsageFlags 11 | { 12 | USAGE_DEFAULT = 0, 13 | 14 | // buffer allocation policy is platform and usage specific 15 | USAGE_ALLOCATE_HOST_MEMORY = 1 << 0, 16 | USAGE_ALLOCATE_DEVICE_MEMORY = 1 << 1, 17 | USAGE_ALLOCATE_SHARED_MEMORY = 18 | 1 << 2, // It is not equal to: USAGE_ALLOCATE_HOST_MEMORY | USAGE_ALLOCATE_DEVICE_MEMORY 19 | 20 | __UMAT_USAGE_FLAGS_32BIT = 0x7fffffff // Binary compatibility hint 21 | }; 22 | 23 | class LYCON_EXPORTS MatAllocator 24 | { 25 | public: 26 | MatAllocator() {} 27 | virtual ~MatAllocator() {} 28 | 29 | virtual UMatData *allocate(int dims, const int *sizes, int type, void *data, size_t *step, int flags, 30 | UMatUsageFlags usageFlags) const = 0; 31 | virtual bool allocate(UMatData *data, int accessflags, UMatUsageFlags usageFlags) const = 0; 32 | virtual void deallocate(UMatData *data) const = 0; 33 | virtual void map(UMatData *data, int accessflags) const; 34 | virtual void unmap(UMatData *data) const; 35 | virtual void download(UMatData *data, void *dst, int dims, const size_t sz[], const size_t srcofs[], 36 | const size_t srcstep[], const size_t dststep[]) const; 37 | virtual void upload(UMatData *data, const void *src, int dims, const size_t sz[], const size_t dstofs[], 38 | const size_t dststep[], const size_t srcstep[]) const; 39 | virtual void copy(UMatData *srcdata, UMatData *dstdata, int dims, const size_t sz[], const size_t srcofs[], 40 | const size_t srcstep[], const size_t dstofs[], const size_t dststep[], bool sync) const; 41 | 42 | // default implementation returns DummyBufferPoolController 43 | virtual BufferPoolController *getBufferPoolController(const char *id = NULL) const; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /src/lycon/python/module.init.h: -------------------------------------------------------------------------------- 1 | namespace lycon 2 | { 3 | 4 | // The Python exception class used for Lycon errors 5 | static PyObject* pycon_error = nullptr; 6 | 7 | PyObject* get_pycon_error() 8 | { 9 | return pycon_error; 10 | } 11 | } // namespace lycon 12 | 13 | static const char* module_name = "_lycon"; 14 | 15 | static const char* module_docstring = "Lycon image library"; 16 | 17 | static PyMethodDef module_methods[] = { 18 | DECLARE_METHOD(load), DECLARE_METHOD(save), DECLARE_METHOD(resize), {NULL, NULL, 0, NULL}}; 19 | 20 | #if PY_MAJOR_VERSION >= 3 21 | 22 | static int pycon_traverse(PyObject* m, visitproc visit, void* arg) 23 | { 24 | Py_VISIT(pycon_error); 25 | return 0; 26 | } 27 | 28 | static int pycon_clear(PyObject* m) 29 | { 30 | Py_CLEAR(pycon_error); 31 | return 0; 32 | } 33 | 34 | static struct PyModuleDef module_defs = {PyModuleDef_HEAD_INIT, module_name, NULL, 0, module_methods, NULL, 35 | pycon_traverse, pycon_clear, NULL}; 36 | 37 | #define MODULE_INIT_SIGNATURE PyMODINIT_FUNC PyInit__lycon(void) 38 | #define MODULE_INIT_RETURN_ON_ERROR NULL 39 | 40 | #else 41 | 42 | #define MODULE_INIT_SIGNATURE PyMODINIT_FUNC init_lycon(void) 43 | #define MODULE_INIT_RETURN_ON_ERROR 44 | 45 | #endif 46 | 47 | MODULE_INIT_SIGNATURE 48 | { 49 | #if PY_MAJOR_VERSION >= 3 50 | PyObject* module = PyModule_Create(&module_defs); 51 | #else 52 | PyObject* module = Py_InitModule3(module_name, module_methods, module_docstring); 53 | #endif 54 | if (module == NULL) 55 | { 56 | return MODULE_INIT_RETURN_ON_ERROR; 57 | } 58 | 59 | // Initialize numpy 60 | import_array(); 61 | 62 | // Create exception 63 | PyObject* module_dict = PyModule_GetDict(module); 64 | PyDict_SetItemString(module_dict, "__version__", PyString_FromString(LYCON_VERSION_STRING)); 65 | pycon_error = PyErr_NewException((char*)("_lycon.PyconError"), NULL, NULL); 66 | 67 | #if PY_MAJOR_VERSION >= 3 68 | return module; 69 | #endif 70 | } 71 | -------------------------------------------------------------------------------- /src/lycon/io/base.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/io/base.h" 2 | #include "lycon/io/bitstream.h" 3 | 4 | namespace lycon 5 | { 6 | BaseImageDecoder::BaseImageDecoder() 7 | { 8 | m_width = m_height = 0; 9 | m_type = -1; 10 | m_buf_supported = false; 11 | m_scale_denom = 1; 12 | } 13 | 14 | bool BaseImageDecoder::setSource(const String& filename) 15 | { 16 | m_filename = filename; 17 | m_buf.release(); 18 | return true; 19 | } 20 | 21 | bool BaseImageDecoder::setSource(const Mat& buf) 22 | { 23 | if (!m_buf_supported) 24 | return false; 25 | m_filename = String(); 26 | m_buf = buf; 27 | return true; 28 | } 29 | 30 | size_t BaseImageDecoder::signatureLength() const 31 | { 32 | return m_signature.size(); 33 | } 34 | 35 | bool BaseImageDecoder::checkSignature(const String& signature) const 36 | { 37 | size_t len = signatureLength(); 38 | return signature.size() >= len && memcmp(signature.c_str(), m_signature.c_str(), len) == 0; 39 | } 40 | 41 | int BaseImageDecoder::setScale(const int& scale_denom) 42 | { 43 | int temp = m_scale_denom; 44 | m_scale_denom = scale_denom; 45 | return temp; 46 | } 47 | 48 | ImageDecoder BaseImageDecoder::newDecoder() const 49 | { 50 | return ImageDecoder(); 51 | } 52 | 53 | BaseImageEncoder::BaseImageEncoder() 54 | { 55 | m_buf_supported = false; 56 | } 57 | 58 | bool BaseImageEncoder::isFormatSupported(int depth) const 59 | { 60 | return depth == LYCON_8U; 61 | } 62 | 63 | String BaseImageEncoder::getDescription() const 64 | { 65 | return m_description; 66 | } 67 | 68 | bool BaseImageEncoder::setDestination(const String& filename) 69 | { 70 | m_filename = filename; 71 | m_buf = 0; 72 | return true; 73 | } 74 | 75 | bool BaseImageEncoder::setDestination(std::vector& buf) 76 | { 77 | if (!m_buf_supported) 78 | return false; 79 | m_buf = &buf; 80 | m_buf->clear(); 81 | m_filename = String(); 82 | return true; 83 | } 84 | 85 | ImageEncoder BaseImageEncoder::newEncoder() const 86 | { 87 | return ImageEncoder(); 88 | } 89 | 90 | void BaseImageEncoder::throwOnEror() const 91 | { 92 | if (!m_last_error.empty()) 93 | { 94 | String msg = "Raw image encoder error: " + m_last_error; 95 | throw std::runtime_error(msg.c_str()); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/lycon/io/base.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/defs.h" 6 | #include "lycon/io/bitstream.h" 7 | #include "lycon/mat/mat.h" 8 | 9 | namespace lycon 10 | { 11 | class BaseImageDecoder; 12 | class BaseImageEncoder; 13 | typedef std::shared_ptr ImageEncoder; 14 | typedef std::shared_ptr ImageDecoder; 15 | 16 | ///////////////////////////////// base class for decoders //////////////////////// 17 | class BaseImageDecoder 18 | { 19 | public: 20 | BaseImageDecoder(); 21 | virtual ~BaseImageDecoder() {} 22 | 23 | int width() const { return m_width; } 24 | int height() const { return m_height; } 25 | virtual int type() const { return m_type; } 26 | 27 | virtual bool setSource(const String &filename); 28 | virtual bool setSource(const Mat &buf); 29 | virtual int setScale(const int &scale_denom); 30 | virtual bool readHeader() = 0; 31 | virtual bool readData(Mat &img) = 0; 32 | 33 | /// Called after readData to advance to the next page, if any. 34 | virtual bool nextPage() { return false; } 35 | 36 | virtual size_t signatureLength() const; 37 | virtual bool checkSignature(const String &signature) const; 38 | virtual ImageDecoder newDecoder() const; 39 | 40 | protected: 41 | int m_width; // width of the image ( filled by readHeader ) 42 | int m_height; // height of the image ( filled by readHeader ) 43 | int m_type; 44 | int m_scale_denom; 45 | String m_filename; 46 | String m_signature; 47 | Mat m_buf; 48 | bool m_buf_supported; 49 | }; 50 | 51 | ///////////////////////////// base class for encoders //////////////////////////// 52 | class BaseImageEncoder 53 | { 54 | public: 55 | BaseImageEncoder(); 56 | virtual ~BaseImageEncoder() {} 57 | virtual bool isFormatSupported(int depth) const; 58 | 59 | virtual bool setDestination(const String &filename); 60 | virtual bool setDestination(std::vector &buf); 61 | virtual bool write(const Mat &img, const std::vector ¶ms) = 0; 62 | 63 | virtual String getDescription() const; 64 | virtual ImageEncoder newEncoder() const; 65 | 66 | virtual void throwOnEror() const; 67 | 68 | protected: 69 | String m_description; 70 | 71 | String m_filename; 72 | std::vector *m_buf; 73 | bool m_buf_supported; 74 | 75 | String m_last_error; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /cmake/LocatePythonLibs.cmake: -------------------------------------------------------------------------------- 1 | # Python executable 2 | if (NOT DEFINED ${PYTHON_BIN}) 3 | find_program(PYTHON_BIN python) 4 | endif() 5 | message(STATUS "Python binary: ${PYTHON_BIN}") 6 | 7 | # Python include path 8 | if (NOT DEFINED ${PYTHON_INCLUDE_DIR}) 9 | execute_process(COMMAND ${PYTHON_BIN} 10 | -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())" 11 | OUTPUT_VARIABLE PYTHON_INCLUDE_DIR 12 | OUTPUT_STRIP_TRAILING_WHITESPACE) 13 | endif() 14 | message(STATUS "Python include path: ${PYTHON_INCLUDE_DIR}") 15 | 16 | # Python library path 17 | if (NOT DEFINED ${PYTHON_LIB_PATH}) 18 | # Find the Python lib dir 19 | execute_process(COMMAND ${PYTHON_BIN} 20 | -c "from distutils.sysconfig import get_config_var; print(get_config_var('LIBDIR'))" 21 | OUTPUT_VARIABLE PYTHON_LIB_DIR 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | message(STATUS "Python library path: ${PYTHON_LIB_DIR}") 24 | 25 | # Get the Python version 26 | execute_process(COMMAND ${PYTHON_BIN} -c "from distutils.sysconfig import get_python_version; print(get_python_version())" 27 | OUTPUT_VARIABLE PYTHON_VERSION 28 | OUTPUT_STRIP_TRAILING_WHITESPACE) 29 | message(STATUS "Python version: ${PYTHON_VERSION}") 30 | 31 | # Get the full Python lib path 32 | # First search in the precise location indicated by Python 33 | # The following Python lib suffixes are known and supported: 34 | # * m (configured --with-pymalloc) 35 | # * dm (configured --with-pydebug and --with-pymalloc) 36 | set (PYTHON_LIB_PREFIX python${PYTHON_VERSION}) 37 | find_library(PYTHON_LIB_PATH 38 | NAMES ${PYTHON_LIB_PREFIX} ${PYTHON_LIB_PREFIX}m ${PYTHON_LIB_PREFIX}dm 39 | PATHS ${PYTHON_LIB_DIR} 40 | NO_DEFAULT_PATH) 41 | 42 | # If the targeted search fails, look in cmake default locations 43 | if (NOT PYTHON_LIB_PATH) 44 | message(STATUS "Expanding search for libpython") 45 | find_library(PYTHON_LIB_PATH 46 | NAMES ${PYTHON_LIB_PREFIX} ${PYTHON_LIB_PREFIX}m ${PYTHON_LIB_PREFIX}dm 47 | PATHS ${PYTHON_LIB_DIR}) 48 | endif() 49 | endif() 50 | message(STATUS "Python library path: ${PYTHON_LIB_PATH}") 51 | 52 | # NumPy include path 53 | if (NOT DEFINED ${NUMPY_INCLUDE_DIR}) 54 | execute_process(COMMAND ${PYTHON_BIN} 55 | -c "import numpy; print(numpy.get_include())" 56 | OUTPUT_VARIABLE NUMPY_INCLUDE_DIR 57 | OUTPUT_STRIP_TRAILING_WHITESPACE) 58 | endif() 59 | message(STATUS "NumPy include path: ${NUMPY_INCLUDE_DIR}") 60 | -------------------------------------------------------------------------------- /src/lycon/python/interop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "lycon/mat/allocator.h" 9 | #include "lycon/mat/umat_data.h" 10 | #include "lycon/python/compat.h" 11 | #include "lycon/python/macros.h" 12 | #include "lycon/types.h" 13 | 14 | namespace lycon 15 | { 16 | class NumpyAllocator : public MatAllocator 17 | { 18 | public: 19 | NumpyAllocator(); 20 | ~NumpyAllocator(); 21 | 22 | UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const; 23 | 24 | UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags, 25 | UMatUsageFlags usageFlags) const; 26 | 27 | bool allocate(UMatData* u, int accessFlags, UMatUsageFlags usageFlags) const; 28 | 29 | void deallocate(UMatData* u) const; 30 | 31 | const MatAllocator* stdAllocator; 32 | 33 | static NumpyAllocator& getNumpyAllocator(); 34 | }; 35 | 36 | bool mat_from_ndarray(PyObject* py_obj, Mat& mat, bool allow_copy); 37 | 38 | PyObject* ndarray_from_mat(const Mat& mat); 39 | 40 | std::string string_from_pyobject(PyObject* obj); 41 | 42 | Size size_from_pyobject(PyObject* obj); 43 | 44 | template std::vector<_Tp> vector_from_pyobject(PyObject* obj) 45 | { 46 | std::vector<_Tp> output_vec; 47 | PYCON_ASSERT_NOT_NONE(obj); 48 | LYCON_ASSERT(PySequence_Check(obj)) 49 | PyObject* seq = PySequence_Fast(obj, "seq_extract"); 50 | PYCON_ASSERT_NOT_NONE(seq) 51 | int num_elems = (int)PySequence_Fast_GET_SIZE(seq); 52 | output_vec.reserve(num_elems); 53 | PyObject** items = PySequence_Fast_ITEMS(seq); 54 | for (int i = 0; i < num_elems; i++) 55 | { 56 | PyObject* item = items[i]; 57 | if (PyInt_Check(item)) 58 | { 59 | int v = (int)PyInt_AsLong(item); 60 | if (v == -1 && PyErr_Occurred()) 61 | break; 62 | output_vec.push_back(static_cast<_Tp>(v)); 63 | } 64 | else if (PyLong_Check(item)) 65 | { 66 | int v = (int)PyLong_AsLong(item); 67 | if (v == -1 && PyErr_Occurred()) 68 | break; 69 | output_vec.push_back(static_cast<_Tp>(v)); 70 | } 71 | else if (PyFloat_Check(item)) 72 | { 73 | double v = PyFloat_AsDouble(item); 74 | if (PyErr_Occurred()) 75 | break; 76 | output_vec.push_back(static_cast<_Tp>(v)); 77 | } 78 | else 79 | { 80 | break; 81 | } 82 | } 83 | Py_DECREF(seq); 84 | LYCON_ASSERT(output_vec.size() == num_elems); 85 | return output_vec; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/lycon/mat/umat_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/util/error.h" 5 | #include "lycon/util/macros.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | class MatAllocator; 11 | 12 | struct LYCON_EXPORTS UMatData 13 | { 14 | enum 15 | { 16 | COPY_ON_MAP = 1, 17 | HOST_COPY_OBSOLETE = 2, 18 | DEVICE_COPY_OBSOLETE = 4, 19 | TEMP_UMAT = 8, 20 | TEMP_COPIED_UMAT = 24, 21 | USER_ALLOCATED = 32, 22 | DEVICE_MEM_MAPPED = 64 23 | }; 24 | UMatData(const MatAllocator *allocator); 25 | ~UMatData(); 26 | 27 | // provide atomic access to the structure 28 | void lock(); 29 | void unlock(); 30 | 31 | bool hostCopyObsolete() const; 32 | bool deviceCopyObsolete() const; 33 | bool deviceMemMapped() const; 34 | bool copyOnMap() const; 35 | bool tempUMat() const; 36 | bool tempCopiedUMat() const; 37 | void markHostCopyObsolete(bool flag); 38 | void markDeviceCopyObsolete(bool flag); 39 | void markDeviceMemMapped(bool flag); 40 | 41 | const MatAllocator *prevAllocator; 42 | const MatAllocator *currAllocator; 43 | int urefcount; 44 | int refcount; 45 | uchar *data; 46 | uchar *origdata; 47 | size_t size; 48 | 49 | int flags; 50 | void *handle; 51 | void *userdata; 52 | int allocatorFlags_; 53 | int mapcount; 54 | UMatData *originalUMatData; 55 | }; 56 | 57 | inline bool UMatData::hostCopyObsolete() const 58 | { 59 | return (flags & HOST_COPY_OBSOLETE) != 0; 60 | } 61 | inline bool UMatData::deviceCopyObsolete() const 62 | { 63 | return (flags & DEVICE_COPY_OBSOLETE) != 0; 64 | } 65 | inline bool UMatData::deviceMemMapped() const 66 | { 67 | return (flags & DEVICE_MEM_MAPPED) != 0; 68 | } 69 | inline bool UMatData::copyOnMap() const 70 | { 71 | return (flags & COPY_ON_MAP) != 0; 72 | } 73 | inline bool UMatData::tempUMat() const 74 | { 75 | return (flags & TEMP_UMAT) != 0; 76 | } 77 | inline bool UMatData::tempCopiedUMat() const 78 | { 79 | return (flags & TEMP_COPIED_UMAT) == TEMP_COPIED_UMAT; 80 | } 81 | 82 | inline void UMatData::markDeviceMemMapped(bool flag) 83 | { 84 | if (flag) 85 | flags |= DEVICE_MEM_MAPPED; 86 | else 87 | flags &= ~DEVICE_MEM_MAPPED; 88 | } 89 | 90 | inline void UMatData::markHostCopyObsolete(bool flag) 91 | { 92 | if (flag) 93 | flags |= HOST_COPY_OBSOLETE; 94 | else 95 | flags &= ~HOST_COPY_OBSOLETE; 96 | } 97 | inline void UMatData::markDeviceCopyObsolete(bool flag) 98 | { 99 | if (flag) 100 | flags |= DEVICE_COPY_OBSOLETE; 101 | else 102 | flags &= ~DEVICE_COPY_OBSOLETE; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/lycon/mat/umat_data.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/mat/umat_data.h" 2 | 3 | #include 4 | 5 | #include "lycon/mat/mat.h" 6 | 7 | namespace lycon 8 | { 9 | enum 10 | { 11 | UMAT_NLOCKS = 31 12 | }; 13 | 14 | static std::mutex umatLocks[UMAT_NLOCKS]; 15 | 16 | UMatData::UMatData(const MatAllocator* allocator) 17 | { 18 | prevAllocator = currAllocator = allocator; 19 | urefcount = refcount = mapcount = 0; 20 | data = origdata = 0; 21 | size = 0; 22 | flags = 0; 23 | handle = 0; 24 | userdata = 0; 25 | allocatorFlags_ = 0; 26 | originalUMatData = NULL; 27 | } 28 | 29 | UMatData::~UMatData() 30 | { 31 | prevAllocator = currAllocator = 0; 32 | urefcount = refcount = 0; 33 | LYCON_ASSERT(mapcount == 0); 34 | data = origdata = 0; 35 | size = 0; 36 | flags = 0; 37 | handle = 0; 38 | userdata = 0; 39 | allocatorFlags_ = 0; 40 | if (originalUMatData) 41 | { 42 | UMatData* u = originalUMatData; 43 | LYCON_XADD(&(u->urefcount), -1); 44 | LYCON_XADD(&(u->refcount), -1); 45 | bool showWarn = false; 46 | if (u->refcount == 0) 47 | { 48 | if (u->urefcount > 0) 49 | showWarn = true; 50 | // simulate Mat::deallocate 51 | if (u->mapcount != 0) 52 | { 53 | (u->currAllocator ? u->currAllocator : /* TODO allocator ? allocator :*/ Mat::getDefaultAllocator()) 54 | ->unmap(u); 55 | } 56 | else 57 | { 58 | // we don't do "map", so we can't do "unmap" 59 | } 60 | } 61 | if (u->refcount == 0 && u->urefcount == 0) // oops, we need to free resources 62 | { 63 | showWarn = true; 64 | // simulate UMat::deallocate 65 | u->currAllocator->deallocate(u); 66 | } 67 | #ifndef NDEBUG 68 | if (showWarn) 69 | { 70 | static int warn_message_showed = 0; 71 | if (warn_message_showed++ < 100) 72 | { 73 | fflush(stdout); 74 | fprintf(stderr, "\n! getUMat()/getMat() call chain possible problem." 75 | "\n! Base object is dead, while nested/derived object is still alive or processed." 76 | "\n! Please check lifetime of UMat/Mat objects!\n"); 77 | fflush(stderr); 78 | } 79 | } 80 | #else 81 | (void)showWarn; 82 | #endif 83 | originalUMatData = NULL; 84 | } 85 | } 86 | 87 | void UMatData::lock() 88 | { 89 | umatLocks[(size_t)(void*)this % UMAT_NLOCKS].lock(); 90 | } 91 | 92 | void UMatData::unlock() 93 | { 94 | umatLocks[(size_t)(void*)this % UMAT_NLOCKS].unlock(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lycon/enum.py: -------------------------------------------------------------------------------- 1 | try: 2 | from enum import IntEnum 3 | except ImportError: 4 | class IntEnumMeta(type): 5 | def __iter__(cls): 6 | return cls.values() 7 | 8 | def __contains__(cls, value): 9 | return value in cls.values() 10 | 11 | class IntEnum: 12 | """ 13 | A rudimentary Python 3 style IntEnum Implementation that supports 14 | iteration and membership testing. 15 | """ 16 | __metaclass__ = IntEnumMeta 17 | 18 | @classmethod 19 | def values(cls): 20 | return (getattr(cls, elem) for elem in cls.__dict__ if elem.upper() == elem) 21 | 22 | class Decode(IntEnum): 23 | """ 24 | Modes for the load function. 25 | """ 26 | 27 | # Load either a grayscale or color image (including alpha channel), 8-bit format 28 | UNCHANGED = -1 29 | 30 | # Load as a grayscale 8-bit image. 31 | # Color images will be converted to grayscale. 32 | GRAYSCALE = 0 33 | 34 | # Load as a three-channeled 8-bit image. 35 | # Grayscale images will be converted. 36 | # Any alpha channels will be discarded. 37 | COLOR = 1 38 | 39 | # If set, 16-bit and 32-bit images are returned as such. 40 | # Otherwise, an 8-bit image is returned. 41 | ANY_DEPTH = 2 42 | 43 | class Encode(IntEnum): 44 | """ 45 | Options for the save function. 46 | """ 47 | 48 | # An integer from 0 to 100 (the higher is the better). 49 | # The default value is 95. 50 | JPEG_QUALITY = 1 51 | 52 | JPEG_PROGRESSIVE = 2 53 | 54 | JPEG_OPTIMIZE = 3 55 | 56 | JPEG_RST_INTERVAL = 4 57 | 58 | JPEG_LUMA_QUALITY = 5 59 | 60 | JPEG_CHROMA_QUALITY = 6 61 | 62 | # An integer from 0 to 9. 63 | # A higher value means a smaller size and longer compression time. 64 | # Default value is 3. 65 | PNG_COMPRESSION = 16 66 | 67 | PNG_STRATEGY = 17 68 | 69 | PNG_BILEVEL = 18 70 | 71 | PNG_STRATEGY_DEFAULT = 0 72 | 73 | PNG_STRATEGY_FILTERED = 1 74 | 75 | PNG_STRATEGY_HUFFMAN_ONLY = 2 76 | 77 | PNG_STRATEGY_RLE = 3 78 | 79 | PNG_STRATEGY_FIXED = 4 80 | 81 | 82 | class Interpolation(IntEnum): 83 | """ 84 | Interpolation methods for the resize function. 85 | """ 86 | # Nearest Neighbor interpolation 87 | NEAREST = 0 88 | 89 | # Bilinear interpolation 90 | LINEAR = 1 91 | 92 | # Bicubic interpolation 93 | CUBIC = 2 94 | 95 | # Resampling using pixel area relation. 96 | # It may be a preferred method for image decimation, as it gives moire free results. 97 | # When the image is zoomed, it is similar to nearest neighborhood interpolation. 98 | AREA = 3 99 | 100 | # Lanczos interpolation over 8x8 neighborhood 101 | LANCZOS = 4 102 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.11) 2 | 3 | project(lycon) 4 | 5 | include(cmake/LyconUtils.cmake) 6 | 7 | set(LYCON_SOURCES 8 | src/lycon/io/base.cc 9 | src/lycon/io/bitstream.cc 10 | src/lycon/io/exif.cc 11 | src/lycon/io/io.cc 12 | src/lycon/io/jpeg.cc 13 | src/lycon/io/png.cc 14 | 15 | src/lycon/mat/allocator.cc 16 | src/lycon/mat/convert.cc 17 | src/lycon/mat/copy.cc 18 | src/lycon/mat/io_array.cc 19 | src/lycon/mat/iterator.cc 20 | src/lycon/mat/mat.cc 21 | src/lycon/mat/umat_data.cc 22 | 23 | src/lycon/transform/resize.cc 24 | src/lycon/transform/rotate.cc 25 | 26 | src/lycon/util/alloc.cc 27 | src/lycon/util/color.cc 28 | src/lycon/util/file.cc 29 | src/lycon/util/hardware.cc 30 | src/lycon/util/parallel_pthreads.cc 31 | src/lycon/util/parallel.cc 32 | src/lycon/util/singleton.cc 33 | src/lycon/util/string.cc 34 | src/lycon/util/tls.cc 35 | ) 36 | 37 | set(LYCON_PYTHON_SOURCES 38 | src/lycon/python/interop.cc 39 | src/lycon/python/module.cc 40 | ) 41 | 42 | set(CMAKE_MACOSX_RPATH TRUE) 43 | 44 | # Build options 45 | lycon_option(LYCON_BUILD_STATIC "Build Lycon as a static library" ON) 46 | lycon_option(LYCON_BUILD_PYTHON "Build the Python native extension" ON) 47 | lycon_option(LYCON_NUMPY_ALLOCATOR_BY_DEFAULT "Use the NumPy allocator by default" ${LYCON_BUILD_PYTHON}) 48 | # Enabling this can avoid libstdc++ compatibility issues under environments like Conda 49 | lycon_option(LYCON_STATIC_LIBSTDCPP "Statically link against libstdc++" ON IF NOT APPLE) 50 | 51 | include_directories(src) 52 | 53 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -march=native -O3 -fPIC -DNDEBUG -pthread") 54 | if(LYCON_STATIC_LIBSTDCPP) 55 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++") 56 | endif() 57 | 58 | # If enabled, use the NumPy allocator as the default Mat allocator 59 | if(LYCON_NUMPY_ALLOCATOR_BY_DEFAULT) 60 | add_definitions(-DLYCON_USE_NUMPY_ALLOCATOR_BY_DEFAULT) 61 | endif() 62 | 63 | # The main library 64 | if(LYCON_BUILD_STATIC) 65 | add_library(lycon STATIC ${LYCON_SOURCES}) 66 | else() 67 | add_library(lycon SHARED ${LYCON_SOURCES}) 68 | endif() 69 | 70 | # LibPNG 71 | find_package(PNG REQUIRED) 72 | include_directories(${PNG_INCLUDE_DIR}) 73 | target_link_libraries(lycon ${PNG_LIBRARY}) 74 | 75 | # LibJPEG 76 | find_package(JPEG REQUIRED) 77 | include_directories(${JPEG_INCLUDE_DIR}) 78 | target_link_libraries(lycon ${JPEG_LIBRARY}) 79 | 80 | # The Python extension 81 | if (LYCON_BUILD_PYTHON) 82 | include(cmake/LocatePythonLibs.cmake) 83 | 84 | include_directories(${PYTHON_INCLUDE_DIR} ${NUMPY_INCLUDE_DIR}) 85 | 86 | add_library(pycon SHARED ${LYCON_PYTHON_SOURCES}) 87 | target_link_libraries(pycon lycon ${PYTHON_LIB_PATH}) 88 | # NOTE(saumitro): Even on macOS, Python expects the ".so" suffix rather than ".dylib" 89 | set_target_properties(pycon PROPERTIES PREFIX "_" SUFFIX ".so" OUTPUT_NAME "lycon") 90 | endif() 91 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import lycon 3 | 4 | import hashlib 5 | import numpy as np 6 | import os 7 | import shutil 8 | import tempfile 9 | import unittest 10 | 11 | def random_rgb_image(): 12 | return (255*np.random.rand(128, 42, 3)).astype(np.uint8) 13 | 14 | def rgb_bgr(img): 15 | return img[:, :, (2, 1, 0)] 16 | 17 | def filehash(path): 18 | buffer_size = 65536 19 | md5 = hashlib.md5() 20 | with open(path, 'rb') as infile: 21 | while True: 22 | data = infile.read(buffer_size) 23 | if not data: 24 | break 25 | md5.update(data) 26 | return md5.hexdigest() 27 | 28 | class TestAgainstOpenCV(unittest.TestCase): 29 | 30 | def setUp(self): 31 | self.temp_path = tempfile.mkdtemp(prefix='lycon_test_') 32 | 33 | def tearDown(self): 34 | shutil.rmtree(self.temp_path) 35 | 36 | def get_path(self, filename): 37 | return os.path.join(self.temp_path, filename) 38 | 39 | def test_save(self): 40 | img = random_rgb_image() 41 | for extension in lycon.get_supported_extensions(): 42 | mkpath = lambda name : self.get_path('{}.{}'.format(name, extension)) 43 | # Write using Lycon 44 | lycon.save(mkpath('opencv'), img) 45 | # Write using OpenCV 46 | cv2.imwrite(mkpath('lycon'), rgb_bgr(img)) 47 | self.assertEqual(filehash(mkpath('opencv')), filehash(mkpath('lycon'))) 48 | 49 | def test_load(self): 50 | img = random_rgb_image() 51 | for extension in lycon.get_supported_extensions(): 52 | mkpath = lambda name : self.get_path('{}.{}'.format(name, extension)) 53 | # Write using OpenCV 54 | cv2.imwrite(mkpath('opencv'), img) 55 | # Read using OpenCV 56 | cv_img = cv2.imread(mkpath('opencv')) 57 | # Read using Lycon 58 | lycon_img = rgb_bgr(lycon.load(mkpath('opencv'))) 59 | np.testing.assert_array_equal(cv_img, lycon_img) 60 | 61 | def test_resize(self): 62 | src_img = random_rgb_image() 63 | images = [src_img, 64 | src_img.astype(np.float32), 65 | src_img.astype(np.float64), 66 | src_img.astype(np.int16)] 67 | new_shapes = [ 68 | # No change 69 | src_img.shape[:2], 70 | # Upsample 71 | tuple(map(int, np.array(src_img.shape[:2]) * 3)), 72 | # Downsample 73 | tuple(map(int, np.array(src_img.shape[:2]) / 2)) 74 | ] 75 | for img in images: 76 | for (h, w) in new_shapes: 77 | for interp in lycon.Interpolation: 78 | cv_resized = cv2.resize(img, (w, h), interpolation=interp) 79 | lycon_resized = lycon.resize(img, width=w, height=h, interpolation=interp) 80 | np.testing.assert_array_equal( 81 | cv_resized, 82 | lycon_resized, 83 | err_msg='Mismatch for dtype={}, interp={}, size=({}, {})'.format( 84 | img.dtype, interp, w, h 85 | ) 86 | ) 87 | 88 | 89 | if __name__ == '__main__': 90 | unittest.main() 91 | -------------------------------------------------------------------------------- /src/lycon/util/fast_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/defs.h" 6 | 7 | namespace lycon 8 | { 9 | /** @brief Rounds floating-point number to the nearest integer 10 | 11 | @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the 12 | result is not defined. 13 | */ 14 | static inline int fast_round(double value) 15 | { 16 | #if LYCON_SSE2 17 | __m128d t = _mm_set_sd(value); 18 | return _mm_cvtsd_si32(t); 19 | #else 20 | return (int)(value + (value >= 0 ? 0.5 : -0.5)); 21 | #endif 22 | } 23 | 24 | /** @brief Rounds floating-point number to the nearest integer not larger than the original. 25 | 26 | The function computes an integer i such that: 27 | \f[i \le \texttt{value} < i+1\f] 28 | @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the 29 | result is not defined. 30 | */ 31 | static inline int fast_floor(double value) 32 | { 33 | #if LYCON_SSE2 34 | __m128d t = _mm_set_sd(value); 35 | int i = _mm_cvtsd_si32(t); 36 | return i - _mm_movemask_pd(_mm_cmplt_sd(t, _mm_cvtsi32_sd(t, i))); 37 | #else 38 | int i = fast_round(value); 39 | float diff = (float)(value - i); 40 | return i - (diff < 0); 41 | #endif 42 | } 43 | 44 | /** @brief Rounds floating-point number to the nearest integer not smaller than the original. 45 | 46 | The function computes an integer i such that: 47 | \f[i \le \texttt{value} < i+1\f] 48 | @param value floating-point number. If the value is outside of INT_MIN ... INT_MAX range, the 49 | result is not defined. 50 | */ 51 | static inline int fast_ceil(double value) 52 | { 53 | #if LYCON_SSE2 54 | __m128d t = _mm_set_sd(value); 55 | int i = _mm_cvtsd_si32(t); 56 | return i + _mm_movemask_pd(_mm_cmplt_sd(_mm_cvtsi32_sd(t, i), t)); 57 | #else 58 | int i = fast_round(value); 59 | float diff = (float)(i - value); 60 | return i + (diff < 0); 61 | #endif 62 | } 63 | 64 | /** @overload */ 65 | static inline int fast_round(float value) 66 | { 67 | #if LYCON_SSE2 68 | __m128 t = _mm_set_ss(value); 69 | return _mm_cvtss_si32(t); 70 | #else 71 | /* it's ok if round does not comply with IEEE754 standard; 72 | the tests should allow +/-1 difference when the tested functions use round */ 73 | return (int)(value + (value >= 0 ? 0.5f : -0.5f)); 74 | #endif 75 | } 76 | 77 | /** @overload */ 78 | static inline int fast_round(int value) { return value; } 79 | 80 | /** @overload */ 81 | static inline int fast_floor(float value) 82 | { 83 | #if LYCON_SSE2 84 | __m128 t = _mm_set_ss(value); 85 | int i = _mm_cvtss_si32(t); 86 | return i - _mm_movemask_ps(_mm_cmplt_ss(t, _mm_cvtsi32_ss(t, i))); 87 | #else 88 | int i = fast_round(value); 89 | float diff = (float)(value - i); 90 | return i - (diff < 0); 91 | #endif 92 | } 93 | 94 | /** @overload */ 95 | static inline int fast_floor(int value) { return value; } 96 | 97 | /** @overload */ 98 | static inline int fast_ceil(float value) 99 | { 100 | #if LYCON_SSE2 101 | __m128 t = _mm_set_ss(value); 102 | int i = _mm_cvtss_si32(t); 103 | return i + _mm_movemask_ps(_mm_cmplt_ss(_mm_cvtsi32_ss(t, i), t)); 104 | #else 105 | int i = fast_round(value); 106 | float diff = (float)(i - value); 107 | return i + (diff < 0); 108 | #endif 109 | } 110 | 111 | /** @overload */ 112 | static inline int fast_ceil(int value) { return value; } 113 | } 114 | -------------------------------------------------------------------------------- /src/lycon/types/size.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lycon 4 | { 5 | 6 | template class Size_ 7 | { 8 | public: 9 | typedef _Tp value_type; 10 | 11 | //! various constructors 12 | Size_(); 13 | Size_(_Tp _width, _Tp _height); 14 | Size_(const Size_ &sz); 15 | 16 | Size_ &operator=(const Size_ &sz); 17 | //! the area (width*height) 18 | _Tp area() const; 19 | 20 | //! conversion of another data type. 21 | template operator Size_<_Tp2>() const; 22 | 23 | _Tp width, height; // the width and the height 24 | }; 25 | 26 | typedef Size_ Size2i; 27 | typedef Size_ Size2l; 28 | typedef Size_ Size2f; 29 | typedef Size_ Size2d; 30 | typedef Size2i Size; 31 | 32 | template inline Size_<_Tp>::Size_() : width(0), height(0) 33 | { 34 | } 35 | 36 | template inline Size_<_Tp>::Size_(_Tp _width, _Tp _height) : width(_width), height(_height) 37 | { 38 | } 39 | 40 | template inline Size_<_Tp>::Size_(const Size_ &sz) : width(sz.width), height(sz.height) 41 | { 42 | } 43 | 44 | template template inline Size_<_Tp>::operator Size_<_Tp2>() const 45 | { 46 | return Size_<_Tp2>(saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); 47 | } 48 | 49 | template inline Size_<_Tp> &Size_<_Tp>::operator=(const Size_<_Tp> &sz) 50 | { 51 | width = sz.width; 52 | height = sz.height; 53 | return *this; 54 | } 55 | 56 | template inline _Tp Size_<_Tp>::area() const 57 | { 58 | return width * height; 59 | } 60 | 61 | template static inline Size_<_Tp> &operator*=(Size_<_Tp> &a, _Tp b) 62 | { 63 | a.width *= b; 64 | a.height *= b; 65 | return a; 66 | } 67 | 68 | template static inline Size_<_Tp> operator*(const Size_<_Tp> &a, _Tp b) 69 | { 70 | Size_<_Tp> tmp(a); 71 | tmp *= b; 72 | return tmp; 73 | } 74 | 75 | template static inline Size_<_Tp> &operator/=(Size_<_Tp> &a, _Tp b) 76 | { 77 | a.width /= b; 78 | a.height /= b; 79 | return a; 80 | } 81 | 82 | template static inline Size_<_Tp> operator/(const Size_<_Tp> &a, _Tp b) 83 | { 84 | Size_<_Tp> tmp(a); 85 | tmp /= b; 86 | return tmp; 87 | } 88 | 89 | template static inline Size_<_Tp> &operator+=(Size_<_Tp> &a, const Size_<_Tp> &b) 90 | { 91 | a.width += b.width; 92 | a.height += b.height; 93 | return a; 94 | } 95 | 96 | template static inline Size_<_Tp> operator+(const Size_<_Tp> &a, const Size_<_Tp> &b) 97 | { 98 | Size_<_Tp> tmp(a); 99 | tmp += b; 100 | return tmp; 101 | } 102 | 103 | template static inline Size_<_Tp> &operator-=(Size_<_Tp> &a, const Size_<_Tp> &b) 104 | { 105 | a.width -= b.width; 106 | a.height -= b.height; 107 | return a; 108 | } 109 | 110 | template static inline Size_<_Tp> operator-(const Size_<_Tp> &a, const Size_<_Tp> &b) 111 | { 112 | Size_<_Tp> tmp(a); 113 | tmp -= b; 114 | return tmp; 115 | } 116 | 117 | template static inline bool operator==(const Size_<_Tp> &a, const Size_<_Tp> &b) 118 | { 119 | return a.width == b.width && a.height == b.height; 120 | } 121 | 122 | template static inline bool operator!=(const Size_<_Tp> &a, const Size_<_Tp> &b) 123 | { 124 | return !(a == b); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/lycon/util/color.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/types.h" 5 | 6 | namespace lycon 7 | { 8 | 9 | struct PaletteEntry 10 | { 11 | unsigned char b, g, r, a; 12 | }; 13 | 14 | void convert_BGR2Gray_8u_C3C1R(const uchar *bgr, int bgr_step, uchar *gray, int gray_step, Size size, int swap_rb = 0); 15 | void convert_BGRA2Gray_8u_C4C1R(const uchar *bgra, int bgra_step, uchar *gray, int gray_step, Size size, 16 | int swap_rb = 0); 17 | void convert_BGRA2Gray_16u_CnC1R(const ushort *bgra, int bgra_step, ushort *gray, int gray_step, Size size, int ncn, 18 | int swap_rb = 0); 19 | 20 | void convert_Gray2BGR_8u_C1C3R(const uchar *gray, int gray_step, uchar *bgr, int bgr_step, Size size); 21 | void convert_Gray2BGR_16u_C1C3R(const ushort *gray, int gray_step, ushort *bgr, int bgr_step, Size size); 22 | 23 | void convert_RGBA2RGB_8u_C4C3R(const uchar *rgba, int rgba_step, uchar *rgb, int rgb_step, Size size, int _swap_rb = 0); 24 | void convert_BGRA2BGR_16u_C4C3R(const ushort *bgra, int bgra_step, ushort *bgr, int bgr_step, Size size, int _swap_rb); 25 | 26 | void convert_BGR2RGB_8u_C3R(const uchar *bgr, int bgr_step, uchar *rgb, int rgb_step, Size size); 27 | #define convert_RGB2BGR_8u_C3R convert_BGR2RGB_8u_C3R 28 | 29 | void convert_BGR2RGB_16u_C3R(const ushort *bgr, int bgr_step, ushort *rgb, int rgb_step, Size size); 30 | #define convert_RGB2BGR_16u_C3R convert_BGR2RGB_16u_C3R 31 | 32 | void convert_BGRA2RGBA_8u_C4R(const uchar *bgra, int bgra_step, uchar *rgba, int rgba_step, Size size); 33 | #define convert_RGBA2BGRA_8u_C4R convert_BGRA2RGBA_8u_C4R 34 | 35 | void convert_BGRA2RGBA_16u_C4R(const ushort *bgra, int bgra_step, ushort *rgba, int rgba_step, Size size); 36 | #define convert_RGBA2BGRA_16u_C4R convert_BGRA2RGBA_16u_C4R 37 | 38 | void convert_BGR5552Gray_8u_C2C1R(const uchar *bgr555, int bgr555_step, uchar *gray, int gray_step, Size size); 39 | void convert_BGR5652Gray_8u_C2C1R(const uchar *bgr565, int bgr565_step, uchar *gray, int gray_step, Size size); 40 | void convert_BGR5552BGR_8u_C2C3R(const uchar *bgr555, int bgr555_step, uchar *bgr, int bgr_step, Size size); 41 | void convert_BGR5652BGR_8u_C2C3R(const uchar *bgr565, int bgr565_step, uchar *bgr, int bgr_step, Size size); 42 | void convert_CMYK2BGR_8u_C4C3R(const uchar *cmyk, int cmyk_step, uchar *bgr, int bgr_step, Size size); 43 | void convert_CMYK2RGB_8u_C4C3R(const uchar *cmyk, int cmyk_step, uchar *rgb, int rgb_step, Size size); 44 | void convert_CMYK2Gray_8u_C4C1R(const uchar *ycck, int ycck_step, uchar *gray, int gray_step, Size size); 45 | 46 | void FillGrayPalette(PaletteEntry *palette, int bpp, bool negative = false); 47 | bool IsColorPalette(PaletteEntry *palette, int bpp); 48 | void CvtPaletteToGray(const PaletteEntry *palette, uchar *grayPalette, int entries); 49 | uchar *FillUniColor(uchar *data, uchar *&line_end, int step, int width3, int &y, int height, int count3, 50 | PaletteEntry clr); 51 | uchar *FillUniGray(uchar *data, uchar *&line_end, int step, int width3, int &y, int height, int count3, uchar clr); 52 | 53 | uchar *FillColorRow8(uchar *data, uchar *indices, int len, PaletteEntry *palette); 54 | uchar *FillGrayRow8(uchar *data, uchar *indices, int len, uchar *palette); 55 | uchar *FillColorRow4(uchar *data, uchar *indices, int len, PaletteEntry *palette); 56 | uchar *FillGrayRow4(uchar *data, uchar *indices, int len, uchar *palette); 57 | uchar *FillColorRow1(uchar *data, uchar *indices, int len, PaletteEntry *palette); 58 | uchar *FillGrayRow1(uchar *data, uchar *indices, int len, uchar *palette); 59 | } 60 | -------------------------------------------------------------------------------- /src/lycon/io/bitstream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lycon/defs.h" 7 | #include "lycon/util/string.h" 8 | 9 | namespace lycon 10 | { 11 | enum 12 | { 13 | RBS_THROW_EOS = -123, // exception code 14 | RBS_THROW_FORB = -124, // exception code 15 | RBS_HUFF_FORB = 2047, // forrbidden huffman code "value" 16 | RBS_BAD_HEADER = -125 // invalid header 17 | }; 18 | 19 | typedef unsigned long ulong; 20 | 21 | // class RBaseStream - base class for other reading streams. 22 | class RBaseStream 23 | { 24 | public: 25 | // methods 26 | RBaseStream(); 27 | virtual ~RBaseStream(); 28 | 29 | virtual bool open(const String &filename); 30 | virtual void close(); 31 | bool isOpened(); 32 | void setPos(int pos); 33 | int getPos(); 34 | void skip(int bytes); 35 | 36 | protected: 37 | bool m_allocated; 38 | uchar *m_start; 39 | uchar *m_end; 40 | uchar *m_current; 41 | FILE *m_file; 42 | int m_block_size; 43 | int m_block_pos; 44 | bool m_is_opened; 45 | 46 | virtual void readBlock(); 47 | virtual void release(); 48 | virtual void allocate(); 49 | }; 50 | 51 | // class RLByteStream - uchar-oriented stream. 52 | // l in prefix means that the least significant uchar of a multi-uchar value goes first 53 | class RLByteStream : public RBaseStream 54 | { 55 | public: 56 | virtual ~RLByteStream(); 57 | 58 | int getByte(); 59 | int getBytes(void *buffer, int count); 60 | int getWord(); 61 | int getDWord(); 62 | }; 63 | 64 | // class RMBitStream - uchar-oriented stream. 65 | // m in prefix means that the most significant uchar of a multi-uchar value go first 66 | class RMByteStream : public RLByteStream 67 | { 68 | public: 69 | virtual ~RMByteStream(); 70 | 71 | int getWord(); 72 | int getDWord(); 73 | }; 74 | 75 | // WBaseStream - base class for output streams 76 | class WBaseStream 77 | { 78 | public: 79 | // methods 80 | WBaseStream(); 81 | virtual ~WBaseStream(); 82 | 83 | virtual bool open(const String &filename); 84 | virtual bool open(std::vector &buf); 85 | virtual void close(); 86 | bool isOpened(); 87 | int getPos(); 88 | 89 | protected: 90 | uchar *m_start; 91 | uchar *m_end; 92 | uchar *m_current; 93 | int m_block_size; 94 | int m_block_pos; 95 | FILE *m_file; 96 | bool m_is_opened; 97 | std::vector *m_buf; 98 | 99 | virtual void writeBlock(); 100 | virtual void release(); 101 | virtual void allocate(); 102 | }; 103 | 104 | // class WLByteStream - uchar-oriented stream. 105 | // l in prefix means that the least significant uchar of a multi-byte value goes first 106 | class WLByteStream : public WBaseStream 107 | { 108 | public: 109 | virtual ~WLByteStream(); 110 | 111 | void putByte(int val); 112 | void putBytes(const void *buffer, int count); 113 | void putWord(int val); 114 | void putDWord(int val); 115 | }; 116 | 117 | // class WLByteStream - uchar-oriented stream. 118 | // m in prefix means that the least significant uchar of a multi-byte value goes last 119 | class WMByteStream : public WLByteStream 120 | { 121 | public: 122 | virtual ~WMByteStream(); 123 | void putWord(int val); 124 | void putDWord(int val); 125 | }; 126 | 127 | inline unsigned BSWAP(unsigned v) 128 | { 129 | return (v << 24) | ((v & 0xff00) << 8) | ((v >> 8) & 0xff00) | ((unsigned)v >> 24); 130 | } 131 | 132 | bool bsIsBigEndian(void); 133 | } 134 | -------------------------------------------------------------------------------- /src/lycon/arch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined __SSE2__ || defined _M_X64 || (defined _M_IX86_FP && _M_IX86_FP >= 2) 4 | #include 5 | #define LYCON_MMX 1 6 | #define LYCON_SSE 1 7 | #define LYCON_SSE2 1 8 | #if defined __SSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 9 | #include 10 | #define LYCON_SSE3 1 11 | #endif 12 | #if defined __SSSE3__ || (defined _MSC_VER && _MSC_VER >= 1500) 13 | #include 14 | #define LYCON_SSSE3 1 15 | #endif 16 | #if defined __SSE4_1__ || (defined _MSC_VER && _MSC_VER >= 1500) 17 | #include 18 | #define LYCON_SSE4_1 1 19 | #endif 20 | #if defined __SSE4_2__ || (defined _MSC_VER && _MSC_VER >= 1500) 21 | #include 22 | #define LYCON_SSE4_2 1 23 | #endif 24 | #if defined __POPCNT__ || (defined _MSC_VER && _MSC_VER >= 1500) 25 | #ifdef _MSC_VER 26 | #include 27 | #else 28 | #include 29 | #endif 30 | #define LYCON_POPCNT 1 31 | #endif 32 | #if defined __AVX__ || (defined _MSC_VER && _MSC_VER >= 1600 && 0) 33 | // MS Visual Studio 2010 (2012?) has no macro pre-defined to identify the use of /arch:AVX 34 | // See: 35 | // http://connect.microsoft.com/VisualStudio/feedback/details/605858/arch-avx-should-define-a-predefined-macro-in-x64-and-set-a-unique-value-for-m-ix86-fp-in-win32 36 | #include 37 | #define LYCON_AVX 1 38 | #if defined(_XCR_XFEATURE_ENABLED_MASK) 39 | #define __xgetbv() _xgetbv(_XCR_XFEATURE_ENABLED_MASK) 40 | #else 41 | #define __xgetbv() 0 42 | #endif 43 | #endif 44 | #if defined __AVX2__ || (defined _MSC_VER && _MSC_VER >= 1800 && 0) 45 | #include 46 | #define LYCON_AVX2 1 47 | #if defined __FMA__ 48 | #define LYCON_FMA3 1 49 | #endif 50 | #endif 51 | #endif 52 | 53 | #if (defined WIN32 || defined _WIN32) && defined(_M_ARM) 54 | #include 55 | #include 56 | #define LYCON_NEON 1 57 | #define CPU_HAS_NEON_FEATURE (true) 58 | #elif defined(__ARM_NEON__) || (defined(__ARM_NEON) && defined(__aarch64__)) 59 | #include 60 | #define LYCON_NEON 1 61 | #endif 62 | 63 | #if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__ || defined __ARM_NEON__) && \ 64 | !defined __SOFTFP__ 65 | #define LYCON_VFP 1 66 | #endif 67 | 68 | #ifndef LYCON_POPCNT 69 | #define LYCON_POPCNT 0 70 | #endif 71 | #ifndef LYCON_MMX 72 | #define LYCON_MMX 0 73 | #endif 74 | #ifndef LYCON_SSE 75 | #define LYCON_SSE 0 76 | #endif 77 | #ifndef LYCON_SSE2 78 | #define LYCON_SSE2 0 79 | #endif 80 | #ifndef LYCON_SSE3 81 | #define LYCON_SSE3 0 82 | #endif 83 | #ifndef LYCON_SSSE3 84 | #define LYCON_SSSE3 0 85 | #endif 86 | #ifndef LYCON_SSE4_1 87 | #define LYCON_SSE4_1 0 88 | #endif 89 | #ifndef LYCON_SSE4_2 90 | #define LYCON_SSE4_2 0 91 | #endif 92 | #ifndef LYCON_AVX 93 | #define LYCON_AVX 0 94 | #endif 95 | #ifndef LYCON_AVX2 96 | #define LYCON_AVX2 0 97 | #endif 98 | #ifndef LYCON_FMA3 99 | #define LYCON_FMA3 0 100 | #endif 101 | #ifndef LYCON_AVX_512F 102 | #define LYCON_AVX_512F 0 103 | #endif 104 | #ifndef LYCON_AVX_512BW 105 | #define LYCON_AVX_512BW 0 106 | #endif 107 | #ifndef LYCON_AVX_512CD 108 | #define LYCON_AVX_512CD 0 109 | #endif 110 | #ifndef LYCON_AVX_512DQ 111 | #define LYCON_AVX_512DQ 0 112 | #endif 113 | #ifndef LYCON_AVX_512ER 114 | #define LYCON_AVX_512ER 0 115 | #endif 116 | #ifndef LYCON_AVX_512IFMA512 117 | #define LYCON_AVX_512IFMA512 0 118 | #endif 119 | #ifndef LYCON_AVX_512PF 120 | #define LYCON_AVX_512PF 0 121 | #endif 122 | #ifndef LYCON_AVX_512VBMI 123 | #define LYCON_AVX_512VBMI 0 124 | #endif 125 | #ifndef LYCON_AVX_512VL 126 | #define LYCON_AVX_512VL 0 127 | #endif 128 | 129 | #ifndef LYCON_NEON 130 | #define LYCON_NEON 0 131 | #endif 132 | 133 | #ifndef LYCON_VFP 134 | #define LYCON_VFP 0 135 | #endif 136 | -------------------------------------------------------------------------------- /perf/benchmark.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import lycon 3 | import PIL 4 | import skimage.io 5 | import skimage.transform 6 | 7 | import numpy as np 8 | import os 9 | from timeit import default_timer as timer 10 | 11 | DATA_PATH = os.path.join(os.path.dirname(__file__), 'data') 12 | 13 | def get_path(name): 14 | return os.path.join(DATA_PATH, name) 15 | 16 | def time(func, count=10): 17 | times = [] 18 | # Perform an extra iteration and discard the first run to account for one-time initializations. 19 | count += 1 20 | for idx in xrange(count): 21 | start = timer() 22 | func() 23 | times.append(timer() - start) 24 | return np.mean(times[1:]) # [seconds] 25 | 26 | def benchmark(*ops): 27 | results = [(tag, time(func)) for tag, func in ops] 28 | results.sort(key=lambda pair: pair[1]) 29 | min_time = results[0][1] 30 | for tag, mean_time in results: 31 | print('{:50}: {:6.4f} | {:6.3f}x'.format(tag, mean_time, mean_time/min_time)) 32 | print('-'*80) 33 | 34 | def benchmark_read(path): 35 | # Read once to account for disk-caching effects 36 | with open(path) as infile: 37 | infile.read() 38 | msg = lambda tag: '[READ ({})] {}'.format(path.split('.')[-1], tag) 39 | benchmark( 40 | (msg('Lycon'), lambda: lycon.load(path)), 41 | (msg('OpenCV'), lambda: cv2.imread(path)), 42 | (msg('PIL'), lambda: np.asarray(PIL.Image.open(path))), 43 | (msg('SKImage'), lambda: skimage.io.imread(path)), 44 | ) 45 | 46 | def benchmark_write(img): 47 | for ext in ('png', 'jpg'): 48 | output = '/tmp/lycon_test.' + ext 49 | msg = lambda tag : '[WRITE ({})] {}'.format(ext, tag) 50 | benchmark( 51 | (msg('Lycon'), lambda: lycon.save(output, img)), 52 | (msg('OpenCV'), lambda: cv2.imwrite(output, img)), 53 | (msg('PIL'), lambda: PIL.Image.fromarray(img).save(output)), 54 | (msg('SKImage'), lambda: skimage.io.imsave(output, img)), 55 | ) 56 | 57 | def benchmark_resize(img): 58 | h, w = img.shape[:2] 59 | new_sizes = [(2*w, 2*h), (int(w/2), int(h/2))] 60 | interpolations = { 61 | 'nearest':{ 62 | 'Lycon': lycon.Interpolation.NEAREST, 63 | 'OpenCV': cv2.INTER_NEAREST, 64 | 'PIL': PIL.Image.NEAREST, 65 | 'SKImage': 0 66 | }, 67 | 'bilinear':{ 68 | 'Lycon': lycon.Interpolation.LINEAR, 69 | 'OpenCV': cv2.INTER_LINEAR, 70 | 'PIL': PIL.Image.BILINEAR, 71 | 'SKImage': 1 72 | }, 73 | 'bicubic':{ 74 | 'Lycon': lycon.Interpolation.CUBIC, 75 | 'OpenCV': cv2.INTER_CUBIC, 76 | 'PIL': PIL.Image.BICUBIC, 77 | 'SKImage': 3 78 | }, 79 | 'lanczos':{ 80 | 'Lycon': lycon.Interpolation.LANCZOS, 81 | 'OpenCV': cv2.INTER_LANCZOS4, 82 | 'PIL': PIL.Image.LANCZOS, 83 | }, 84 | 'area':{ 85 | 'Lycon': lycon.Interpolation.AREA, 86 | 'OpenCV': cv2.INTER_AREA, 87 | } 88 | } 89 | for w, h in new_sizes: 90 | for interp in interpolations: 91 | msg = lambda tag : '[RESIZE ({} - {} x {})] {}'.format(interp, w, h, tag) 92 | modes = interpolations[interp] 93 | op = lambda tag, func: (msg(tag), lambda: func(modes[tag])) if tag in modes else None 94 | benchmark(*filter(None,[ 95 | op('Lycon', lambda i: lycon.resize(img, width=w, height=h, interpolation=i)), 96 | op('OpenCV', lambda i: cv2.resize(img, (w, h), interpolation=i)), 97 | op('PIL', lambda i: np.asarray(PIL.Image.fromarray(img).resize((w, h), i))), 98 | op('SKImage', lambda i: skimage.transform.resize(img, (h, w), order=i)) 99 | ])) 100 | 101 | 102 | benchmark_read(get_path('16k.png')) 103 | benchmark_read(get_path('16k.jpg')) 104 | benchmark_write(lycon.load(get_path('16k.jpg'))) 105 | benchmark_resize(lycon.load(get_path('16k.jpg'))) 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Lycon is provided under a split license: 2 | 3 | * A significant portion of Lycon is derived directly from OpenCV, which is 4 | provided under the 3-clause BSD license. 5 | 6 | * All Lycon-specific modifications are provided under the MIT license. 7 | 8 | Both licenses are provided below, in the order specified above. 9 | 10 | ---------------------------------------------------------------------------------------------------- 11 | 12 | By downloading, copying, installing or using the software you agree to this license. 13 | If you do not agree to this license, do not download, install, 14 | copy or use the software. 15 | 16 | 17 | License Agreement 18 | For Open Source Computer Vision Library 19 | (3-clause BSD License) 20 | 21 | Copyright (C) 2000-2016, Intel Corporation, all rights reserved. 22 | Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. 23 | Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. 24 | Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. 25 | Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. 26 | Copyright (C) 2015-2016, Itseez Inc., all rights reserved. 27 | Third party copyrights are property of their respective owners. 28 | 29 | Redistribution and use in source and binary forms, with or without modification, 30 | are permitted provided that the following conditions are met: 31 | 32 | * Redistributions of source code must retain the above copyright notice, 33 | this list of conditions and the following disclaimer. 34 | 35 | * Redistributions in binary form must reproduce the above copyright notice, 36 | this list of conditions and the following disclaimer in the documentation 37 | and/or other materials provided with the distribution. 38 | 39 | * Neither the names of the copyright holders nor the names of the contributors 40 | may be used to endorse or promote products derived from this software 41 | without specific prior written permission. 42 | 43 | This software is provided by the copyright holders and contributors "as is" and 44 | any express or implied warranties, including, but not limited to, the implied 45 | warranties of merchantability and fitness for a particular purpose are disclaimed. 46 | In no event shall copyright holders or contributors be liable for any direct, 47 | indirect, incidental, special, exemplary, or consequential damages 48 | (including, but not limited to, procurement of substitute goods or services; 49 | loss of use, data, or profits; or business interruption) however caused 50 | and on any theory of liability, whether in contract, strict liability, 51 | or tort (including negligence or otherwise) arising in any way out of 52 | the use of this software, even if advised of the possibility of such damage. 53 | 54 | ---------------------------------------------------------------------------------------------------- 55 | 56 | (The MIT License) 57 | 58 | Copyright 2017 Saumitro Dasgupta 59 | 60 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 61 | associated documentation files (the "Software"), to deal in the Software without restriction, 62 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 63 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 64 | furnished to do so, subject to the following conditions: 65 | 66 | The above copyright notice and this permission notice shall be included in all copies or 67 | substantial portions of the Software. 68 | 69 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 70 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 71 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 72 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 73 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 74 | 75 | ---------------------------------------------------------------------------------------------------- 76 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import shutil 4 | import multiprocessing 5 | import subprocess as sp 6 | 7 | from distutils.spawn import find_executable 8 | from distutils.command.build_ext import build_ext 9 | 10 | from setuptools import Extension, setup, find_packages 11 | 12 | class BuilderError(Exception): pass 13 | 14 | class LyconBuilder(build_ext): 15 | """ 16 | Builds the C++ Lycon extension using CMake. 17 | """ 18 | 19 | LYCON_NATIVE_EXETENSION_NAME = '_lycon.so' 20 | 21 | def locate(self, name): 22 | """ 23 | Locate the executable with the given name. 24 | """ 25 | exec_path = find_executable(name) 26 | if exec_path is None: 27 | raise BuilderError('{} not found. Please install it first.'.format(name)) 28 | return exec_path 29 | 30 | def execute(self, args): 31 | """ 32 | Execute the given command in the temporary build directory. 33 | """ 34 | proc = sp.Popen(args, cwd=self.build_temp) 35 | if proc.wait() != 0: 36 | raise BuilderError('Failed to exceute: {}'.format(' '.join(args))) 37 | 38 | def prepare(self): 39 | """ 40 | Prepare to build (check everything required exists). 41 | """ 42 | self.make_path = self.locate('make') 43 | self.cmake_path = self.locate('cmake') 44 | # Make sure CMakeLists.txt exists 45 | if not os.path.exists(os.path.join(self.source_path, 'CMakeLists.txt')): 46 | raise BuilderError('Could not locate CMakeLists.txt') 47 | 48 | def cmake(self): 49 | """ 50 | Run cmake. 51 | """ 52 | print('Source path is {}'.format(self.source_path)) 53 | python_bin = '-DPYTHON_BIN={}'.format(sys.executable) 54 | self.execute([self.cmake_path, self.source_path, python_bin]) 55 | 56 | def make(self, parallel=True): 57 | """ 58 | Run make. 59 | """ 60 | num_jobs = multiprocessing.cpu_count() if parallel else 1 61 | print('Starting build with {} jobs'.format(num_jobs)) 62 | self.execute([self.make_path, '-j', str(num_jobs)]) 63 | 64 | def move(self): 65 | """ 66 | Move the built library to the libs directory. 67 | """ 68 | if not os.path.exists(self.build_lib): 69 | os.makedirs(self.build_lib) 70 | src_path = os.path.join(self.build_temp, self.LYCON_NATIVE_EXETENSION_NAME) 71 | dst_path = os.path.join(self.build_lib, self.LYCON_NATIVE_EXETENSION_NAME) 72 | shutil.move(src_path, dst_path) 73 | 74 | def build_extensions(self): 75 | """ 76 | Build the native extension. [overriden] 77 | """ 78 | # Setup paths 79 | self.source_path = os.path.realpath(os.path.dirname(__file__)) 80 | if not os.path.exists(self.build_temp): 81 | os.makedirs(self.build_temp) 82 | 83 | # Build lycon 84 | try: 85 | self.prepare() 86 | self.cmake() 87 | self.make() 88 | self.move() 89 | except BuilderError as err: 90 | print('\t* Failed to build the Lycon native extension.') 91 | print('\t* [Error] {}'.format(err)) 92 | exit(-1) 93 | 94 | setup(name='lycon', 95 | version='0.2.0', 96 | description='A minimal and fast image library', 97 | author='Saumitro Dasgupta', 98 | author_email='sd@cs.stanford.edu', 99 | url='https://github.com/ethereon/lycon', 100 | classifiers=[ 101 | 'Development Status :: 4 - Beta', 102 | 'Topic :: Multimedia :: Graphics', 103 | 'Programming Language :: Python :: 2', 104 | 'Programming Language :: Python :: 2.7', 105 | 'Programming Language :: Python :: 3', 106 | 'Programming Language :: Python :: 3.3', 107 | 'Programming Language :: Python :: 3.4', 108 | 'Programming Language :: Python :: 3.5', 109 | 'Programming Language :: Python :: 3.6', 110 | 'Programming Language :: Python :: Implementation :: CPython', 111 | ], 112 | cmdclass={'build_ext': LyconBuilder}, 113 | ext_modules=[Extension('_lycon', ['lycon.placeholder.c'])], 114 | packages=find_packages(), 115 | install_requires=['numpy'], 116 | include_package_data=True, 117 | keywords=['Imaging',], 118 | zip_safe=True, 119 | license='MIT + 3-clause BSD') 120 | -------------------------------------------------------------------------------- /src/lycon/transform/resize/nearest.h: -------------------------------------------------------------------------------- 1 | class resizeNNInvoker : public ParallelLoopBody 2 | { 3 | public: 4 | resizeNNInvoker(const Mat& _src, Mat& _dst, int* _x_ofs, int _pix_size4, double _ify) 5 | : ParallelLoopBody(), src(_src), dst(_dst), x_ofs(_x_ofs), pix_size4(_pix_size4), ify(_ify) 6 | { 7 | } 8 | 9 | virtual void operator()(const Range& range) const 10 | { 11 | Size ssize = src.size(), dsize = dst.size(); 12 | int y, x, pix_size = (int)src.elemSize(); 13 | 14 | for (y = range.start; y < range.end; y++) 15 | { 16 | uchar* D = dst.data + dst.step * y; 17 | int sy = std::min(fast_floor(y * ify), ssize.height - 1); 18 | const uchar* S = src.ptr(sy); 19 | 20 | switch (pix_size) 21 | { 22 | case 1: 23 | for (x = 0; x <= dsize.width - 2; x += 2) 24 | { 25 | uchar t0 = S[x_ofs[x]]; 26 | uchar t1 = S[x_ofs[x + 1]]; 27 | D[x] = t0; 28 | D[x + 1] = t1; 29 | } 30 | 31 | for (; x < dsize.width; x++) D[x] = S[x_ofs[x]]; 32 | break; 33 | case 2: 34 | for (x = 0; x < dsize.width; x++) *(ushort*)(D + x * 2) = *(ushort*)(S + x_ofs[x]); 35 | break; 36 | case 3: 37 | for (x = 0; x < dsize.width; x++, D += 3) 38 | { 39 | const uchar* _tS = S + x_ofs[x]; 40 | D[0] = _tS[0]; 41 | D[1] = _tS[1]; 42 | D[2] = _tS[2]; 43 | } 44 | break; 45 | case 4: 46 | for (x = 0; x < dsize.width; x++) *(int*)(D + x * 4) = *(int*)(S + x_ofs[x]); 47 | break; 48 | case 6: 49 | for (x = 0; x < dsize.width; x++, D += 6) 50 | { 51 | const ushort* _tS = (const ushort*)(S + x_ofs[x]); 52 | ushort* _tD = (ushort*)D; 53 | _tD[0] = _tS[0]; 54 | _tD[1] = _tS[1]; 55 | _tD[2] = _tS[2]; 56 | } 57 | break; 58 | case 8: 59 | for (x = 0; x < dsize.width; x++, D += 8) 60 | { 61 | const int* _tS = (const int*)(S + x_ofs[x]); 62 | int* _tD = (int*)D; 63 | _tD[0] = _tS[0]; 64 | _tD[1] = _tS[1]; 65 | } 66 | break; 67 | case 12: 68 | for (x = 0; x < dsize.width; x++, D += 12) 69 | { 70 | const int* _tS = (const int*)(S + x_ofs[x]); 71 | int* _tD = (int*)D; 72 | _tD[0] = _tS[0]; 73 | _tD[1] = _tS[1]; 74 | _tD[2] = _tS[2]; 75 | } 76 | break; 77 | default: 78 | for (x = 0; x < dsize.width; x++, D += pix_size) 79 | { 80 | const int* _tS = (const int*)(S + x_ofs[x]); 81 | int* _tD = (int*)D; 82 | for (int k = 0; k < pix_size4; k++) _tD[k] = _tS[k]; 83 | } 84 | } 85 | } 86 | } 87 | 88 | private: 89 | const Mat src; 90 | Mat dst; 91 | int *x_ofs, pix_size4; 92 | double ify; 93 | 94 | resizeNNInvoker(const resizeNNInvoker&); 95 | resizeNNInvoker& operator=(const resizeNNInvoker&); 96 | }; 97 | 98 | static void resizeNN(const Mat& src, Mat& dst, double fx, double fy) 99 | { 100 | Size ssize = src.size(), dsize = dst.size(); 101 | AutoBuffer _x_ofs(dsize.width); 102 | int* x_ofs = _x_ofs; 103 | int pix_size = (int)src.elemSize(); 104 | int pix_size4 = (int)(pix_size / sizeof(int)); 105 | double ifx = 1. / fx, ify = 1. / fy; 106 | int x; 107 | 108 | for (x = 0; x < dsize.width; x++) 109 | { 110 | int sx = fast_floor(x * ifx); 111 | x_ofs[x] = std::min(sx, ssize.width - 1) * pix_size; 112 | } 113 | 114 | Range range(0, dsize.height); 115 | resizeNNInvoker invoker(src, dst, x_ofs, pix_size4, ify); 116 | parallel_for_(range, invoker, dst.total() / (double)(1 << 16)); 117 | } 118 | -------------------------------------------------------------------------------- /src/lycon/defs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lycon/arch.h" 7 | 8 | namespace lycon 9 | { 10 | #define LYCON_VERSION_STRING "0.2.0" 11 | 12 | // Type aliases 13 | using uchar = unsigned char; 14 | using schar = signed char; 15 | using ushort = unsigned short; 16 | using int64 = int64_t; 17 | using uint64 = uint64_t; 18 | 19 | // LYCON_EXPORTS 20 | #if (defined WIN32 || defined _WIN32 || defined WINCE || defined __CYGWIN__) && defined LYCONAPI_EXPORTS 21 | #define LYCON_EXPORTS __declspec(dllexport) 22 | #elif defined __GNUC__ && __GNUC__ >= 4 23 | #define LYCON_EXPORTS __attribute__((visibility("default"))) 24 | #else 25 | #define LYCON_EXPORTS 26 | #endif 27 | 28 | #define LYCON_CN_MAX 512 29 | #define LYCON_CN_SHIFT 3 30 | #define LYCON_DEPTH_MAX (1 << LYCON_CN_SHIFT) 31 | 32 | #define LYCON_8U 0 33 | #define LYCON_8S 1 34 | #define LYCON_16U 2 35 | #define LYCON_16S 3 36 | #define LYCON_32S 4 37 | #define LYCON_32F 5 38 | #define LYCON_64F 6 39 | #define LYCON_USRTYPE1 7 40 | 41 | #define LYCON_MAT_DEPTH_MASK (LYCON_DEPTH_MAX - 1) 42 | #define LYCON_MAT_DEPTH(flags) ((flags)&LYCON_MAT_DEPTH_MASK) 43 | 44 | #define LYCON_MAKETYPE(depth, cn) (LYCON_MAT_DEPTH(depth) + (((cn)-1) << LYCON_CN_SHIFT)) 45 | #define LYCON_MAKE_TYPE LYCON_MAKETYPE 46 | 47 | #define LYCON_8UC1 LYCON_MAKETYPE(LYCON_8U, 1) 48 | #define LYCON_8UC2 LYCON_MAKETYPE(LYCON_8U, 2) 49 | #define LYCON_8UC3 LYCON_MAKETYPE(LYCON_8U, 3) 50 | #define LYCON_8UC4 LYCON_MAKETYPE(LYCON_8U, 4) 51 | #define LYCON_8UC(n) LYCON_MAKETYPE(LYCON_8U, (n)) 52 | 53 | #define LYCON_8SC1 LYCON_MAKETYPE(LYCON_8S, 1) 54 | #define LYCON_8SC2 LYCON_MAKETYPE(LYCON_8S, 2) 55 | #define LYCON_8SC3 LYCON_MAKETYPE(LYCON_8S, 3) 56 | #define LYCON_8SC4 LYCON_MAKETYPE(LYCON_8S, 4) 57 | #define LYCON_8SC(n) LYCON_MAKETYPE(LYCON_8S, (n)) 58 | 59 | #define LYCON_16UC1 LYCON_MAKETYPE(LYCON_16U, 1) 60 | #define LYCON_16UC2 LYCON_MAKETYPE(LYCON_16U, 2) 61 | #define LYCON_16UC3 LYCON_MAKETYPE(LYCON_16U, 3) 62 | #define LYCON_16UC4 LYCON_MAKETYPE(LYCON_16U, 4) 63 | #define LYCON_16UC(n) LYCON_MAKETYPE(LYCON_16U, (n)) 64 | 65 | #define LYCON_16SC1 LYCON_MAKETYPE(LYCON_16S, 1) 66 | #define LYCON_16SC2 LYCON_MAKETYPE(LYCON_16S, 2) 67 | #define LYCON_16SC3 LYCON_MAKETYPE(LYCON_16S, 3) 68 | #define LYCON_16SC4 LYCON_MAKETYPE(LYCON_16S, 4) 69 | #define LYCON_16SC(n) LYCON_MAKETYPE(LYCON_16S, (n)) 70 | 71 | #define LYCON_32SC1 LYCON_MAKETYPE(LYCON_32S, 1) 72 | #define LYCON_32SC2 LYCON_MAKETYPE(LYCON_32S, 2) 73 | #define LYCON_32SC3 LYCON_MAKETYPE(LYCON_32S, 3) 74 | #define LYCON_32SC4 LYCON_MAKETYPE(LYCON_32S, 4) 75 | #define LYCON_32SC(n) LYCON_MAKETYPE(LYCON_32S, (n)) 76 | 77 | #define LYCON_32FC1 LYCON_MAKETYPE(LYCON_32F, 1) 78 | #define LYCON_32FC2 LYCON_MAKETYPE(LYCON_32F, 2) 79 | #define LYCON_32FC3 LYCON_MAKETYPE(LYCON_32F, 3) 80 | #define LYCON_32FC4 LYCON_MAKETYPE(LYCON_32F, 4) 81 | #define LYCON_32FC(n) LYCON_MAKETYPE(LYCON_32F, (n)) 82 | 83 | #define LYCON_64FC1 LYCON_MAKETYPE(LYCON_64F, 1) 84 | #define LYCON_64FC2 LYCON_MAKETYPE(LYCON_64F, 2) 85 | #define LYCON_64FC3 LYCON_MAKETYPE(LYCON_64F, 3) 86 | #define LYCON_64FC4 LYCON_MAKETYPE(LYCON_64F, 4) 87 | #define LYCON_64FC(n) LYCON_MAKETYPE(LYCON_64F, (n)) 88 | 89 | #define LYCON_MAT_CN_MASK ((LYCON_CN_MAX - 1) << LYCON_CN_SHIFT) 90 | #define LYCON_MAT_CN(flags) ((((flags)&LYCON_MAT_CN_MASK) >> LYCON_CN_SHIFT) + 1) 91 | #define LYCON_MAT_TYPE_MASK (LYCON_DEPTH_MAX * LYCON_CN_MAX - 1) 92 | #define LYCON_MAT_TYPE(flags) ((flags)&LYCON_MAT_TYPE_MASK) 93 | #define LYCON_MAT_CONT_FLAG_SHIFT 14 94 | #define LYCON_MAT_CONT_FLAG (1 << LYCON_MAT_CONT_FLAG_SHIFT) 95 | #define LYCON_IS_MAT_CONT(flags) ((flags)&LYCON_MAT_CONT_FLAG) 96 | #define LYCON_IS_CONT_MAT LYCON_IS_MAT_CONT 97 | #define LYCON_SUBMAT_FLAG_SHIFT 15 98 | #define LYCON_SUBMAT_FLAG (1 << LYCON_SUBMAT_FLAG_SHIFT) 99 | 100 | /** Size of each channel item, 101 | 0x124489 = 1000 0100 0100 0010 0010 0001 0001 ~ array of sizeof(arr_type_elem) */ 102 | #define LYCON_ELEM_SIZE1(type) ((((sizeof(size_t) << 28) | 0x8442211) >> LYCON_MAT_DEPTH(type) * 4) & 15) 103 | 104 | /** 0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) */ 105 | #define LYCON_ELEM_SIZE(type) \ 106 | (LYCON_MAT_CN(type) << ((((sizeof(size_t) / 4 + 1) * 16384 | 0x3a50) >> LYCON_MAT_DEPTH(type) * 2) & 3)) 107 | 108 | #define LYCON_MAX_DIM 32 109 | #define LYCON_MAX_DIM_HEAP 1024 110 | 111 | #define HAVE_PTHREADS 112 | 113 | /* parallel_for with pthreads */ 114 | #define HAVE_PTHREADS_PF 115 | 116 | // Mat forward declarations 117 | class LYCON_EXPORTS Mat; 118 | typedef Mat MatND; 119 | template class Mat_; 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lycon 2 | 3 | A minimal and fast image library for Python and C++. 4 | 5 | Lycon is a small subset of optimized image operations derived from [OpenCV](http://opencv.org/). 6 | 7 | Current set of features include: 8 | 9 | - Reading and writing JPEG and PNG images 10 | - Fast SIMD optimized image resizing 11 | - Zero-copy interop with [NumPy](http://www.numpy.org/) whenever possible 12 | 13 | Tested on: 14 | 15 | - Linux (Ubuntu 14.04) with Python`2.7.6` and `3.5.2`. 16 | - macOS (Sierra, 10.12) with Python `2.7.11` and `3.5.1`. 17 | 18 | ## Install 19 | 20 | ``` 21 | pip install lycon 22 | ``` 23 | 24 | Native extension dependencies: 25 | 26 | - CMake 2.8 or newer 27 | - C++ toolchain 28 | - LibJPEG 29 | - LibPNG 30 | 31 | ### Ubuntu 32 | 33 | Single-line command for installing all dependencies: 34 | 35 | ``` 36 | sudo apt-get install cmake build-essential libjpeg-dev libpng-dev 37 | ``` 38 | 39 | ### Anaconda 40 | 41 | When working within an Anaconda Python distribution, it is recommended to use the latest `cmake` version (`3.6` or newer). Older versions can lead to a mismatch between the `libpng` and `libjpeg` headers used to build Lycon (usually the system headers), and the linked library (which may be preempted by the Anaconda-scoped version). To install the latest `cmake` version: 42 | 43 | ``` 44 | conda install cmake 45 | ``` 46 | 47 | ## Example 48 | 49 | ```python 50 | import lycon 51 | 52 | # Load an image as a numpy array 53 | img = lycon.load('mittens.jpg') 54 | # Resize the image using bicubic interpolation 55 | resized = lycon.resize(img, width=256, height=512, interpolation=lycon.Interpolation.CUBIC) 56 | # Crop the image (like any regular numpy array) 57 | cropped = resized[:100, :200] 58 | # Save the image 59 | lycon.save('cropped-mittens.png', cropped) 60 | ``` 61 | 62 | ## Limitations 63 | 64 | Compared to other image processing libraries ([OpenCV](http://opencv.org/), [pillow](https://python-pillow.org/), [scikit-image](http://scikit-image.org/)), Lycon offers a very limited set of operations. Intended usages include data loaders for deep learning, mass image resizing, etc. 65 | 66 | ## Advantages over OpenCV 67 | 68 | - Drastically smaller (at the cost of drastically fewer features) 69 | - Python module installable via `pip` 70 | - Images use the more common `RGB` ordering (vs OpenCV's `BGR`) 71 | 72 | However, if you already have OpenCV installed, Lycon's advantages are minimal. 73 | 74 | ## Advantages over PIL(low) 75 | 76 | - Faster 77 | - First-class NumPy support 78 | - Full support for floating point images 79 | 80 | ## Advantages over Scikit-Image 81 | 82 | - Drastically faster 83 | 84 | ## Benchmarks 85 | 86 | - The table below lists execution time (in seconds), averaged across 10 runs 87 | - The multiplier next to the time is the relative slowdown compared to Lycon 88 | 89 | | Operation | Lycon | OpenCV | PIL | Scikit-Image | 90 | |----------------------|-------:|--------------:|----------------:|------------------:| 91 | | Upsample: Nearest | 0.1944 | 0.1948 (1x) | 2.1342 (11x) | 30.8982 (158.9x) | 92 | | Upsample: Bilinear | 0.4852 | 0.4940 (1x) | 7.2940 (15x) | 45.9095 (94.6x) | 93 | | Upsample: Bicubic | 1.8162 | 1.8182 (1x) | 8.9589 (4.9x) | 120.1645 (66.1x) | 94 | | Upsample: Lanczos | 4.5641 | 4.5714 (1x) | 10.7517 (2.3x) | | 95 | | Upsample: Area | 0.4801 | 0.4931 (1x) | | | 96 | | Downsample: Nearest | 0.0183 | 0.0181 (1x) | 0.4379 (24.2x) | 3.6101 (199.9x) | 97 | | Downsample: Bilinear | 0.0258 | 0.0257 (1x) | 1.3122 (51x) | 4.8487 (188.4x) | 98 | | Downsample: Bicubic | 0.1324 | 0.1329 (1x) | 1.8153 (13.7x) | 9.4905 (71.6x) | 99 | | Downsample: Lanczos | 0.3317 | 0.3328 (1x) | 2.4058 (7.2x) | | 100 | | Downsample: Area | 0.0258 | 0.0259 (1x) | | | 101 | | Read: JPG | 0.3409 | 0.5085 (1.5x) | 1.4081 (4.1x) | 1.4628 (4.3x) | 102 | | Read: PNG | 1.2114 | 1.3245 (1.1x) | 1.8274 (1.5x) | 1.8674 (1.5x) | 103 | | Write: JPG | 0.4760 | 0.6046 (1.3x) | 2.3823 (5x) | 5.0159 (10.5x) | 104 | | Write: PNG | 2.1421 | 2.2370 (1x) | 9.0580 (4.2x) | 11.6060 (5.4x) | 105 | 106 | - Blank cells indicate that the operation is not supported by the library 107 | - All operations performed on a 16k (15360 x 8640) RGB image 108 | - Tests performed on Ubuntu 14.04 running on an Intel Core i7 (Skylake) 109 | - OpenCV `3.2+ (master: a85b4b5)`, Pillow `4.0.0`, skimage `0.12.3`, Python `2.7.3` 110 | - OpenCV can potentially achieve better performance with GPU implementations and proprietary libraries like Intel IPP 111 | 112 | ## License 113 | 114 | - All code derived from the OpenCV project is licensed under the 3-clause BSD License. 115 | - All Lycon-specific modifications are licensed under the MIT license. 116 | 117 | See `LICENSE` for further details. 118 | -------------------------------------------------------------------------------- /src/lycon/mat/iterator.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/mat/mat.h" 2 | 3 | namespace lycon 4 | { 5 | NAryMatIterator::NAryMatIterator() 6 | : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) 7 | { 8 | } 9 | 10 | NAryMatIterator::NAryMatIterator(const Mat** _arrays, Mat* _planes, int _narrays) 11 | : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) 12 | { 13 | init(_arrays, _planes, 0, _narrays); 14 | } 15 | 16 | NAryMatIterator::NAryMatIterator(const Mat** _arrays, uchar** _ptrs, int _narrays) 17 | : arrays(0), planes(0), ptrs(0), narrays(0), nplanes(0), size(0), iterdepth(0), idx(0) 18 | { 19 | init(_arrays, 0, _ptrs, _narrays); 20 | } 21 | 22 | void NAryMatIterator::init(const Mat** _arrays, Mat* _planes, uchar** _ptrs, int _narrays) 23 | { 24 | LYCON_ASSERT(_arrays && (_ptrs || _planes)); 25 | int i, j, d1 = 0, i0 = -1, d = -1; 26 | 27 | arrays = _arrays; 28 | ptrs = _ptrs; 29 | planes = _planes; 30 | narrays = _narrays; 31 | nplanes = 0; 32 | size = 0; 33 | 34 | if (narrays < 0) 35 | { 36 | for (i = 0; _arrays[i] != 0; i++) 37 | ; 38 | narrays = i; 39 | LYCON_ASSERT(narrays <= 1000); 40 | } 41 | 42 | iterdepth = 0; 43 | 44 | for (i = 0; i < narrays; i++) 45 | { 46 | LYCON_ASSERT(arrays[i] != 0); 47 | const Mat& A = *arrays[i]; 48 | if (ptrs) 49 | ptrs[i] = A.data; 50 | 51 | if (!A.data) 52 | continue; 53 | 54 | if (i0 < 0) 55 | { 56 | i0 = i; 57 | d = A.dims; 58 | 59 | // find the first dimensionality which is different from 1; 60 | // in any of the arrays the first "d1" step do not affect the continuity 61 | for (d1 = 0; d1 < d; d1++) 62 | if (A.size[d1] > 1) 63 | break; 64 | } 65 | else 66 | LYCON_ASSERT(A.size == arrays[i0]->size); 67 | 68 | if (!A.isContinuous()) 69 | { 70 | LYCON_ASSERT(A.step[d - 1] == A.elemSize()); 71 | for (j = d - 1; j > d1; j--) 72 | if (A.step[j] * A.size[j] < A.step[j - 1]) 73 | break; 74 | iterdepth = std::max(iterdepth, j); 75 | } 76 | } 77 | 78 | if (i0 >= 0) 79 | { 80 | size = arrays[i0]->size[d - 1]; 81 | for (j = d - 1; j > iterdepth; j--) 82 | { 83 | int64 total1 = (int64)size * arrays[i0]->size[j - 1]; 84 | if (total1 != (int)total1) 85 | break; 86 | size = (int)total1; 87 | } 88 | 89 | iterdepth = j; 90 | if (iterdepth == d1) 91 | iterdepth = 0; 92 | 93 | nplanes = 1; 94 | for (j = iterdepth - 1; j >= 0; j--) 95 | nplanes *= arrays[i0]->size[j]; 96 | } 97 | else 98 | iterdepth = 0; 99 | 100 | idx = 0; 101 | 102 | if (!planes) 103 | return; 104 | 105 | for (i = 0; i < narrays; i++) 106 | { 107 | LYCON_ASSERT(arrays[i] != 0); 108 | const Mat& A = *arrays[i]; 109 | 110 | if (!A.data) 111 | { 112 | planes[i] = Mat(); 113 | continue; 114 | } 115 | 116 | planes[i] = Mat(1, (int)size, A.type(), A.data); 117 | } 118 | } 119 | 120 | NAryMatIterator& NAryMatIterator::operator++() 121 | { 122 | if (idx >= nplanes - 1) 123 | return *this; 124 | ++idx; 125 | 126 | if (iterdepth == 1) 127 | { 128 | if (ptrs) 129 | { 130 | for (int i = 0; i < narrays; i++) 131 | { 132 | if (!ptrs[i]) 133 | continue; 134 | ptrs[i] = arrays[i]->data + arrays[i]->step[0] * idx; 135 | } 136 | } 137 | if (planes) 138 | { 139 | for (int i = 0; i < narrays; i++) 140 | { 141 | if (!planes[i].data) 142 | continue; 143 | planes[i].data = arrays[i]->data + arrays[i]->step[0] * idx; 144 | } 145 | } 146 | } 147 | else 148 | { 149 | for (int i = 0; i < narrays; i++) 150 | { 151 | const Mat& A = *arrays[i]; 152 | if (!A.data) 153 | continue; 154 | int _idx = (int)idx; 155 | uchar* data = A.data; 156 | for (int j = iterdepth - 1; j >= 0 && _idx > 0; j--) 157 | { 158 | int szi = A.size[j], t = _idx / szi; 159 | data += (_idx - t * szi) * A.step[j]; 160 | _idx = t; 161 | } 162 | if (ptrs) 163 | ptrs[i] = data; 164 | if (planes) 165 | planes[i].data = data; 166 | } 167 | } 168 | 169 | return *this; 170 | } 171 | 172 | NAryMatIterator NAryMatIterator::operator++(int) 173 | { 174 | NAryMatIterator it = *this; 175 | ++*this; 176 | return it; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/lycon/util/auto_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace lycon 7 | { 8 | 9 | /* 10 | Automatically Allocated Buffer Class 11 | 12 | The class is used for temporary buffers in functions and methods. 13 | If a temporary buffer is usually small (a few K's of memory), 14 | but its size depends on the parameters, it makes sense to create a small 15 | fixed-size array on stack and use it if it's large enough. If the required buffer size 16 | is larger than the fixed size, another buffer of sufficient size is allocated dynamically 17 | and released after the processing. Therefore, in typical cases, when the buffer size is small, 18 | there is no overhead associated with malloc()/free(). 19 | At the same time, there is no limit on the size of processed data. 20 | 21 | This is what AutoBuffer does. The template takes 2 parameters - type of the buffer elements and 22 | the number of stack-allocated elements. Here is how the class is used: 23 | 24 | cv::AutoBuffer buf; // create automatic buffer containing 1000 floats 25 | buf.allocate(rows); // if rows <= 1000, the pre-allocated buffer is used, 26 | // otherwise the buffer of "rows" floats will be allocated 27 | // dynamically and deallocated in cv::AutoBuffer destructor 28 | */ 29 | 30 | template class AutoBuffer 31 | { 32 | public: 33 | typedef _Tp value_type; 34 | 35 | //! the default constructor 36 | AutoBuffer(); 37 | //! constructor taking the real buffer size 38 | AutoBuffer(size_t _size); 39 | 40 | //! the copy constructor 41 | AutoBuffer(const AutoBuffer<_Tp, fixed_size> &buf); 42 | //! the assignment operator 43 | AutoBuffer<_Tp, fixed_size> &operator=(const AutoBuffer<_Tp, fixed_size> &buf); 44 | 45 | //! destructor. calls deallocate() 46 | ~AutoBuffer(); 47 | 48 | //! allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used 49 | void allocate(size_t _size); 50 | //! deallocates the buffer if it was dynamically allocated 51 | void deallocate(); 52 | //! resizes the buffer and preserves the content 53 | void resize(size_t _size); 54 | //! returns the current buffer size 55 | size_t size() const; 56 | //! returns pointer to the real buffer, stack-allocated or head-allocated 57 | operator _Tp *(); 58 | //! returns read-only pointer to the real buffer, stack-allocated or head-allocated 59 | operator const _Tp *() const; 60 | 61 | protected: 62 | //! pointer to the real buffer, can point to buf if the buffer is small enough 63 | _Tp *ptr; 64 | //! size of the real buffer 65 | size_t sz; 66 | //! pre-allocated buffer. At least 1 element to confirm C++ standard reqirements 67 | _Tp buf[(fixed_size > 0) ? fixed_size : 1]; 68 | }; 69 | 70 | template inline AutoBuffer<_Tp, fixed_size>::AutoBuffer() 71 | { 72 | ptr = buf; 73 | sz = fixed_size; 74 | } 75 | 76 | template inline AutoBuffer<_Tp, fixed_size>::AutoBuffer(size_t _size) 77 | { 78 | ptr = buf; 79 | sz = fixed_size; 80 | allocate(_size); 81 | } 82 | 83 | template 84 | inline AutoBuffer<_Tp, fixed_size>::AutoBuffer(const AutoBuffer<_Tp, fixed_size> &abuf) 85 | { 86 | ptr = buf; 87 | sz = fixed_size; 88 | allocate(abuf.size()); 89 | for (size_t i = 0; i < sz; i++) 90 | ptr[i] = abuf.ptr[i]; 91 | } 92 | 93 | template 94 | inline AutoBuffer<_Tp, fixed_size> &AutoBuffer<_Tp, fixed_size>::operator=(const AutoBuffer<_Tp, fixed_size> &abuf) 95 | { 96 | if (this != &abuf) 97 | { 98 | deallocate(); 99 | allocate(abuf.size()); 100 | for (size_t i = 0; i < sz; i++) 101 | ptr[i] = abuf.ptr[i]; 102 | } 103 | return *this; 104 | } 105 | 106 | template inline AutoBuffer<_Tp, fixed_size>::~AutoBuffer() 107 | { 108 | deallocate(); 109 | } 110 | 111 | template inline void AutoBuffer<_Tp, fixed_size>::allocate(size_t _size) 112 | { 113 | if (_size <= sz) 114 | { 115 | sz = _size; 116 | return; 117 | } 118 | deallocate(); 119 | sz = _size; 120 | if (_size > fixed_size) 121 | { 122 | ptr = new _Tp[_size]; 123 | } 124 | } 125 | 126 | template inline void AutoBuffer<_Tp, fixed_size>::deallocate() 127 | { 128 | if (ptr != buf) 129 | { 130 | delete[] ptr; 131 | ptr = buf; 132 | sz = fixed_size; 133 | } 134 | } 135 | 136 | template inline void AutoBuffer<_Tp, fixed_size>::resize(size_t _size) 137 | { 138 | if (_size <= sz) 139 | { 140 | sz = _size; 141 | return; 142 | } 143 | size_t i, prevsize = sz, minsize = std::min(prevsize, _size); 144 | _Tp *prevptr = ptr; 145 | 146 | ptr = _size > fixed_size ? new _Tp[_size] : buf; 147 | sz = _size; 148 | 149 | if (ptr != prevptr) 150 | for (i = 0; i < minsize; i++) 151 | ptr[i] = prevptr[i]; 152 | for (i = prevsize; i < _size; i++) 153 | ptr[i] = _Tp(); 154 | 155 | if (prevptr != buf) 156 | delete[] prevptr; 157 | } 158 | 159 | template inline size_t AutoBuffer<_Tp, fixed_size>::size() const 160 | { 161 | return sz; 162 | } 163 | 164 | template inline AutoBuffer<_Tp, fixed_size>::operator _Tp *() 165 | { 166 | return ptr; 167 | } 168 | 169 | template inline AutoBuffer<_Tp, fixed_size>::operator const _Tp *() const 170 | { 171 | return ptr; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/lycon/types/traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | 5 | namespace lycon 6 | { 7 | 8 | template class DataType 9 | { 10 | public: 11 | typedef _Tp value_type; 12 | typedef value_type work_type; 13 | typedef value_type channel_type; 14 | typedef value_type vec_type; 15 | enum 16 | { 17 | generic_type = 1, 18 | depth = -1, 19 | channels = 1, 20 | fmt = 0, 21 | type = LYCON_MAKETYPE(depth, channels) 22 | }; 23 | }; 24 | 25 | template <> class DataType 26 | { 27 | public: 28 | typedef bool value_type; 29 | typedef int work_type; 30 | typedef value_type channel_type; 31 | typedef value_type vec_type; 32 | enum 33 | { 34 | generic_type = 0, 35 | depth = LYCON_8U, 36 | channels = 1, 37 | fmt = (int)'u', 38 | type = LYCON_MAKETYPE(depth, channels) 39 | }; 40 | }; 41 | 42 | template <> class DataType 43 | { 44 | public: 45 | typedef uchar value_type; 46 | typedef int work_type; 47 | typedef value_type channel_type; 48 | typedef value_type vec_type; 49 | enum 50 | { 51 | generic_type = 0, 52 | depth = LYCON_8U, 53 | channels = 1, 54 | fmt = (int)'u', 55 | type = LYCON_MAKETYPE(depth, channels) 56 | }; 57 | }; 58 | 59 | template <> class DataType 60 | { 61 | public: 62 | typedef schar value_type; 63 | typedef int work_type; 64 | typedef value_type channel_type; 65 | typedef value_type vec_type; 66 | enum 67 | { 68 | generic_type = 0, 69 | depth = LYCON_8S, 70 | channels = 1, 71 | fmt = (int)'c', 72 | type = LYCON_MAKETYPE(depth, channels) 73 | }; 74 | }; 75 | 76 | template <> class DataType 77 | { 78 | public: 79 | typedef schar value_type; 80 | typedef int work_type; 81 | typedef value_type channel_type; 82 | typedef value_type vec_type; 83 | enum 84 | { 85 | generic_type = 0, 86 | depth = LYCON_8S, 87 | channels = 1, 88 | fmt = (int)'c', 89 | type = LYCON_MAKETYPE(depth, channels) 90 | }; 91 | }; 92 | 93 | template <> class DataType 94 | { 95 | public: 96 | typedef ushort value_type; 97 | typedef int work_type; 98 | typedef value_type channel_type; 99 | typedef value_type vec_type; 100 | enum 101 | { 102 | generic_type = 0, 103 | depth = LYCON_16U, 104 | channels = 1, 105 | fmt = (int)'w', 106 | type = LYCON_MAKETYPE(depth, channels) 107 | }; 108 | }; 109 | 110 | template <> class DataType 111 | { 112 | public: 113 | typedef short value_type; 114 | typedef int work_type; 115 | typedef value_type channel_type; 116 | typedef value_type vec_type; 117 | enum 118 | { 119 | generic_type = 0, 120 | depth = LYCON_16S, 121 | channels = 1, 122 | fmt = (int)'s', 123 | type = LYCON_MAKETYPE(depth, channels) 124 | }; 125 | }; 126 | 127 | template <> class DataType 128 | { 129 | public: 130 | typedef int value_type; 131 | typedef value_type work_type; 132 | typedef value_type channel_type; 133 | typedef value_type vec_type; 134 | enum 135 | { 136 | generic_type = 0, 137 | depth = LYCON_32S, 138 | channels = 1, 139 | fmt = (int)'i', 140 | type = LYCON_MAKETYPE(depth, channels) 141 | }; 142 | }; 143 | 144 | template <> class DataType 145 | { 146 | public: 147 | typedef float value_type; 148 | typedef value_type work_type; 149 | typedef value_type channel_type; 150 | typedef value_type vec_type; 151 | enum 152 | { 153 | generic_type = 0, 154 | depth = LYCON_32F, 155 | channels = 1, 156 | fmt = (int)'f', 157 | type = LYCON_MAKETYPE(depth, channels) 158 | }; 159 | }; 160 | 161 | template <> class DataType 162 | { 163 | public: 164 | typedef double value_type; 165 | typedef value_type work_type; 166 | typedef value_type channel_type; 167 | typedef value_type vec_type; 168 | enum 169 | { 170 | generic_type = 0, 171 | depth = LYCON_64F, 172 | channels = 1, 173 | fmt = (int)'d', 174 | type = LYCON_MAKETYPE(depth, channels) 175 | }; 176 | }; 177 | 178 | template class DataDepth 179 | { 180 | public: 181 | enum 182 | { 183 | value = DataType<_Tp>::depth, 184 | fmt = DataType<_Tp>::fmt 185 | }; 186 | }; 187 | 188 | template class TypeDepth 189 | { 190 | enum 191 | { 192 | depth = LYCON_USRTYPE1 193 | }; 194 | typedef void value_type; 195 | }; 196 | 197 | template <> class TypeDepth 198 | { 199 | enum 200 | { 201 | depth = LYCON_8U 202 | }; 203 | typedef uchar value_type; 204 | }; 205 | 206 | template <> class TypeDepth 207 | { 208 | enum 209 | { 210 | depth = LYCON_8S 211 | }; 212 | typedef schar value_type; 213 | }; 214 | 215 | template <> class TypeDepth 216 | { 217 | enum 218 | { 219 | depth = LYCON_16U 220 | }; 221 | typedef ushort value_type; 222 | }; 223 | 224 | template <> class TypeDepth 225 | { 226 | enum 227 | { 228 | depth = LYCON_16S 229 | }; 230 | typedef short value_type; 231 | }; 232 | 233 | template <> class TypeDepth 234 | { 235 | enum 236 | { 237 | depth = LYCON_32S 238 | }; 239 | typedef int value_type; 240 | }; 241 | 242 | template <> class TypeDepth 243 | { 244 | enum 245 | { 246 | depth = LYCON_32F 247 | }; 248 | typedef float value_type; 249 | }; 250 | 251 | template <> class TypeDepth 252 | { 253 | enum 254 | { 255 | depth = LYCON_64F 256 | }; 257 | typedef double value_type; 258 | }; 259 | } 260 | -------------------------------------------------------------------------------- /src/lycon/util/hardware.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/hardware.h" 2 | 3 | #include 4 | 5 | #include "lycon/util/error.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | struct HWFeatures 11 | { 12 | enum 13 | { 14 | MAX_FEATURE = LYCON_HARDWARE_MAX_FEATURE 15 | }; 16 | 17 | HWFeatures(void) 18 | { 19 | memset(have, 0, sizeof(have)); 20 | x86_family = 0; 21 | } 22 | 23 | static HWFeatures initialize(void) 24 | { 25 | HWFeatures f; 26 | int cpuid_data[4] = {0, 0, 0, 0}; 27 | 28 | #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) 29 | __cpuid(cpuid_data, 1); 30 | #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) 31 | #ifdef __x86_64__ 32 | asm __volatile__("movl $1, %%eax\n\t" 33 | "cpuid\n\t" 34 | : [eax] "=a"(cpuid_data[0]), [ebx] "=b"(cpuid_data[1]), [ecx] "=c"(cpuid_data[2]), 35 | [edx] "=d"(cpuid_data[3]) 36 | : 37 | : "cc"); 38 | #else 39 | asm volatile("pushl %%ebx\n\t" 40 | "movl $1,%%eax\n\t" 41 | "cpuid\n\t" 42 | "popl %%ebx\n\t" 43 | : "=a"(cpuid_data[0]), "=c"(cpuid_data[2]), "=d"(cpuid_data[3]) 44 | : 45 | : "cc"); 46 | #endif 47 | #endif 48 | 49 | f.x86_family = (cpuid_data[0] >> 8) & 15; 50 | if (f.x86_family >= 6) 51 | { 52 | f.have[LYCON_CPU_MMX] = (cpuid_data[3] & (1 << 23)) != 0; 53 | f.have[LYCON_CPU_SSE] = (cpuid_data[3] & (1 << 25)) != 0; 54 | f.have[LYCON_CPU_SSE2] = (cpuid_data[3] & (1 << 26)) != 0; 55 | f.have[LYCON_CPU_SSE3] = (cpuid_data[2] & (1 << 0)) != 0; 56 | f.have[LYCON_CPU_SSSE3] = (cpuid_data[2] & (1 << 9)) != 0; 57 | f.have[LYCON_CPU_FMA3] = (cpuid_data[2] & (1 << 12)) != 0; 58 | f.have[LYCON_CPU_SSE4_1] = (cpuid_data[2] & (1 << 19)) != 0; 59 | f.have[LYCON_CPU_SSE4_2] = (cpuid_data[2] & (1 << 20)) != 0; 60 | f.have[LYCON_CPU_POPCNT] = (cpuid_data[2] & (1 << 23)) != 0; 61 | f.have[LYCON_CPU_AVX] = (((cpuid_data[2] & (1 << 28)) != 0) && 62 | ((cpuid_data[2] & (1 << 27)) != 0)); // OS uses XSAVE_XRSTORE and CPU support AVX 63 | f.have[LYCON_CPU_FP16] = (cpuid_data[2] & (1 << 29)) != 0; 64 | 65 | // make the second call to the cpuid command in order to get 66 | // information about extended features like AVX2 67 | #if defined _MSC_VER && (defined _M_IX86 || defined _M_X64) 68 | __cpuidex(cpuid_data, 7, 0); 69 | #elif defined __GNUC__ && (defined __i386__ || defined __x86_64__) 70 | #ifdef __x86_64__ 71 | asm __volatile__("movl $7, %%eax\n\t" 72 | "movl $0, %%ecx\n\t" 73 | "cpuid\n\t" 74 | : [eax] "=a"(cpuid_data[0]), [ebx] "=b"(cpuid_data[1]), [ecx] "=c"(cpuid_data[2]), 75 | [edx] "=d"(cpuid_data[3]) 76 | : 77 | : "cc"); 78 | #else 79 | asm volatile("pushl %%ebx\n\t" 80 | "movl $7,%%eax\n\t" 81 | "movl $0,%%ecx\n\t" 82 | "cpuid\n\t" 83 | "movl %%ebx, %0\n\t" 84 | "popl %%ebx\n\t" 85 | : "=r"(cpuid_data[1]), "=c"(cpuid_data[2]) 86 | : 87 | : "cc"); 88 | #endif 89 | #endif 90 | f.have[LYCON_CPU_AVX2] = (cpuid_data[1] & (1 << 5)) != 0; 91 | 92 | f.have[LYCON_CPU_AVX_512F] = (cpuid_data[1] & (1 << 16)) != 0; 93 | f.have[LYCON_CPU_AVX_512DQ] = (cpuid_data[1] & (1 << 17)) != 0; 94 | f.have[LYCON_CPU_AVX_512IFMA512] = (cpuid_data[1] & (1 << 21)) != 0; 95 | f.have[LYCON_CPU_AVX_512PF] = (cpuid_data[1] & (1 << 26)) != 0; 96 | f.have[LYCON_CPU_AVX_512ER] = (cpuid_data[1] & (1 << 27)) != 0; 97 | f.have[LYCON_CPU_AVX_512CD] = (cpuid_data[1] & (1 << 28)) != 0; 98 | f.have[LYCON_CPU_AVX_512BW] = (cpuid_data[1] & (1 << 30)) != 0; 99 | f.have[LYCON_CPU_AVX_512VL] = (cpuid_data[1] & (1 << 31)) != 0; 100 | f.have[LYCON_CPU_AVX_512VBMI] = (cpuid_data[2] & (1 << 1)) != 0; 101 | } 102 | 103 | #if defined ANDROID || defined __linux__ 104 | #ifdef __aarch64__ 105 | f.have[LYCON_CPU_NEON] = true; 106 | f.have[LYCON_CPU_FP16] = true; 107 | #elif defined __arm__ 108 | int cpufile = open("/proc/self/auxv", O_RDONLY); 109 | 110 | if (cpufile >= 0) 111 | { 112 | Elf32_auxv_t auxv; 113 | const size_t size_auxv_t = sizeof(auxv); 114 | 115 | while ((size_t)read(cpufile, &auxv, size_auxv_t) == size_auxv_t) 116 | { 117 | if (auxv.a_type == AT_HWCAP) 118 | { 119 | f.have[LYCON_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0; 120 | f.have[LYCON_CPU_FP16] = (auxv.a_un.a_val & 2) != 0; 121 | break; 122 | } 123 | } 124 | 125 | close(cpufile); 126 | } 127 | #endif 128 | #elif (defined __clang__ || defined __APPLE__) 129 | #if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__)) 130 | f.have[LYCON_CPU_NEON] = true; 131 | #endif 132 | #if (defined __ARM_FP && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__)) 133 | f.have[LYCON_CPU_FP16] = true; 134 | #endif 135 | #endif 136 | 137 | return f; 138 | } 139 | 140 | int x86_family; 141 | bool have[MAX_FEATURE + 1]; 142 | }; 143 | 144 | static HWFeatures featuresEnabled = HWFeatures::initialize(), featuresDisabled = HWFeatures(); 145 | static HWFeatures* currentFeatures = &featuresEnabled; 146 | 147 | bool checkHardwareSupport(int feature) 148 | { 149 | LYCON_DbgAssert(0 <= feature && feature <= LYCON_HARDWARE_MAX_FEATURE); 150 | return currentFeatures->have[feature]; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/lycon/io/options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace lycon 4 | { 5 | //! Imread flags 6 | enum ImreadModes 7 | { 8 | IMREAD_UNCHANGED = -1, //!< If set, return the loaded image as is (with alpha channel, otherwise it gets cropped). 9 | IMREAD_GRAYSCALE = 0, //!< If set, always convert image to the single channel grayscale image. 10 | IMREAD_COLOR = 1, //!< If set, always convert image to the 3 channel BGR color image. 11 | IMREAD_ANYDEPTH = 2, //!< If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise 12 | //! convert it to 8-bit. 13 | IMREAD_ANYCOLOR = 4, //!< If set, the image is read in any possible color format. 14 | IMREAD_LOAD_GDAL = 8, //!< If set, use the gdal driver for loading the image. 15 | IMREAD_REDUCED_GRAYSCALE_2 = 16 | 16, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/2. 17 | IMREAD_REDUCED_COLOR_2 = 18 | 17, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/2. 19 | IMREAD_REDUCED_GRAYSCALE_4 = 20 | 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4. 21 | IMREAD_REDUCED_COLOR_4 = 22 | 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4. 23 | IMREAD_REDUCED_GRAYSCALE_8 = 24 | 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8. 25 | IMREAD_REDUCED_COLOR_8 = 26 | 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8. 27 | IMREAD_IGNORE_ORIENTATION = 128 //!< If set, do not rotate the image according to EXIF's orientation flag. 28 | }; 29 | 30 | //! Imwrite flags 31 | enum ImwriteFlags 32 | { 33 | IMWRITE_JPEG_QUALITY = 34 | 1, //!< For JPEG, it can be a quality from 0 to 100 (the higher is the better). Default value is 95. 35 | IMWRITE_JPEG_PROGRESSIVE = 2, //!< Enable JPEG features, 0 or 1, default is False. 36 | IMWRITE_JPEG_OPTIMIZE = 3, //!< Enable JPEG features, 0 or 1, default is False. 37 | IMWRITE_JPEG_RST_INTERVAL = 4, //!< JPEG restart interval, 0 - 65535, default is 0 - no restart. 38 | IMWRITE_JPEG_LUMA_QUALITY = 5, //!< Separate luma quality level, 0 - 100, default is 0 - don't use. 39 | IMWRITE_JPEG_CHROMA_QUALITY = 6, //!< Separate chroma quality level, 0 - 100, default is 0 - don't use. 40 | IMWRITE_PNG_COMPRESSION = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a 41 | //! smaller size and longer compression time. Default value is 3. Also strategy is 42 | //! changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY). 43 | IMWRITE_PNG_STRATEGY = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT. 44 | IMWRITE_PNG_BILEVEL = 18, //!< Binary level PNG, 0 or 1, default is 0. 45 | IMWRITE_PXM_BINARY = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1. 46 | IMWRITE_WEBP_QUALITY = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default 47 | //!(without any parameter) and for quality above 100 the lossless compression is used. 48 | IMWRITE_PAM_TUPLETYPE = 49 | 128, //!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format 50 | }; 51 | 52 | //! Imwrite PNG specific flags used to tune the compression algorithm. 53 | /** These flags will be modify the way of PNG image compression and will be passed to the underlying zlib processing 54 | stage. 55 | 56 | - The effect of IMWRITE_PNG_STRATEGY_FILTERED is to force more Huffman coding and less string matching; it is somewhat 57 | intermediate between IMWRITE_PNG_STRATEGY_DEFAULT and IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY. 58 | - IMWRITE_PNG_STRATEGY_RLE is designed to be almost as fast as IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, but give better 59 | compression for PNG image data. 60 | - The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if 61 | it is not set appropriately. 62 | - IMWRITE_PNG_STRATEGY_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special 63 | applications. 64 | */ 65 | enum ImwritePNGFlags 66 | { 67 | IMWRITE_PNG_STRATEGY_DEFAULT = 0, //!< Use this value for normal data. 68 | IMWRITE_PNG_STRATEGY_FILTERED = 1, //!< Use this value for data produced by a filter (or predictor).Filtered data 69 | //! consists mostly of small values with a somewhat random distribution. In this 70 | //! case, the compression algorithm is tuned to compress them better. 71 | IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY = 2, //!< Use this value to force Huffman encoding only (no string match). 72 | IMWRITE_PNG_STRATEGY_RLE = 3, //!< Use this value to limit match distances to one (run-length encoding). 73 | IMWRITE_PNG_STRATEGY_FIXED = 4 //!< Using this value prevents the use of dynamic Huffman codes, allowing for a 74 | //! simpler decoder for special applications. 75 | }; 76 | 77 | //! Imwrite PAM specific tupletype flags used to define the 'TUPETYPE' field of a PAM file. 78 | enum ImwritePAMFlags 79 | { 80 | IMWRITE_PAM_FORMAT_NULL = 0, 81 | IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1, 82 | IMWRITE_PAM_FORMAT_GRAYSCALE = 2, 83 | IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3, 84 | IMWRITE_PAM_FORMAT_RGB = 4, 85 | IMWRITE_PAM_FORMAT_RGB_ALPHA = 5, 86 | }; 87 | 88 | enum 89 | { 90 | /* 8bit, color or not */ 91 | LYCON_LOAD_IMAGE_UNCHANGED = -1, 92 | /* 8bit, gray */ 93 | LYCON_LOAD_IMAGE_GRAYSCALE = 0, 94 | /* ?, color */ 95 | LYCON_LOAD_IMAGE_COLOR = 1, 96 | /* any depth, ? */ 97 | LYCON_LOAD_IMAGE_ANYDEPTH = 2, 98 | /* ?, any color */ 99 | LYCON_LOAD_IMAGE_ANYCOLOR = 4, 100 | /* ?, no rotate */ 101 | LYCON_LOAD_IMAGE_IGNORE_ORIENTATION = 128 102 | }; 103 | } 104 | -------------------------------------------------------------------------------- /src/lycon/mat/allocator.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/mat/allocator.h" 2 | 3 | #include 4 | 5 | #include "lycon/mat/iterator.h" 6 | #include "lycon/mat/mat.h" 7 | #include "lycon/mat/umat_data.h" 8 | #include "lycon/util/singleton.h" 9 | 10 | #ifdef LYCON_USE_NUMPY_ALLOCATOR_BY_DEFAULT 11 | #include "lycon/python/interop.h" 12 | #endif 13 | 14 | #define LYCON_AUTOSTEP 0x7fffffff 15 | 16 | namespace lycon 17 | { 18 | void MatAllocator::map(UMatData*, int) const 19 | { 20 | } 21 | 22 | void MatAllocator::unmap(UMatData* u) const 23 | { 24 | if (u->urefcount == 0 && u->refcount == 0) 25 | { 26 | deallocate(u); 27 | u = NULL; 28 | } 29 | } 30 | 31 | void MatAllocator::download(UMatData* u, void* dstptr, int dims, const size_t sz[], const size_t srcofs[], 32 | const size_t srcstep[], const size_t dststep[]) const 33 | { 34 | if (!u) 35 | return; 36 | int isz[LYCON_MAX_DIM]; 37 | uchar* srcptr = u->data; 38 | for (int i = 0; i < dims; i++) 39 | { 40 | LYCON_ASSERT(sz[i] <= (size_t)INT_MAX); 41 | if (sz[i] == 0) 42 | return; 43 | if (srcofs) 44 | srcptr += srcofs[i] * (i <= dims - 2 ? srcstep[i] : 1); 45 | isz[i] = (int)sz[i]; 46 | } 47 | 48 | Mat src(dims, isz, LYCON_8U, srcptr, srcstep); 49 | Mat dst(dims, isz, LYCON_8U, dstptr, dststep); 50 | 51 | const Mat* arrays[] = {&src, &dst}; 52 | uchar* ptrs[2]; 53 | NAryMatIterator it(arrays, ptrs, 2); 54 | size_t planesz = it.size; 55 | 56 | for (size_t j = 0; j < it.nplanes; j++, ++it) 57 | memcpy(ptrs[1], ptrs[0], planesz); 58 | } 59 | 60 | void MatAllocator::upload(UMatData* u, const void* srcptr, int dims, const size_t sz[], const size_t dstofs[], 61 | const size_t dststep[], const size_t srcstep[]) const 62 | { 63 | if (!u) 64 | return; 65 | int isz[LYCON_MAX_DIM]; 66 | uchar* dstptr = u->data; 67 | for (int i = 0; i < dims; i++) 68 | { 69 | LYCON_ASSERT(sz[i] <= (size_t)INT_MAX); 70 | if (sz[i] == 0) 71 | return; 72 | if (dstofs) 73 | dstptr += dstofs[i] * (i <= dims - 2 ? dststep[i] : 1); 74 | isz[i] = (int)sz[i]; 75 | } 76 | 77 | Mat src(dims, isz, LYCON_8U, (void*)srcptr, srcstep); 78 | Mat dst(dims, isz, LYCON_8U, dstptr, dststep); 79 | 80 | const Mat* arrays[] = {&src, &dst}; 81 | uchar* ptrs[2]; 82 | NAryMatIterator it(arrays, ptrs, 2); 83 | size_t planesz = it.size; 84 | 85 | for (size_t j = 0; j < it.nplanes; j++, ++it) 86 | memcpy(ptrs[1], ptrs[0], planesz); 87 | } 88 | 89 | void MatAllocator::copy(UMatData* usrc, UMatData* udst, int dims, const size_t sz[], const size_t srcofs[], 90 | const size_t srcstep[], const size_t dstofs[], const size_t dststep[], bool /*sync*/) const 91 | { 92 | if (!usrc || !udst) 93 | return; 94 | int isz[LYCON_MAX_DIM]; 95 | uchar* srcptr = usrc->data; 96 | uchar* dstptr = udst->data; 97 | for (int i = 0; i < dims; i++) 98 | { 99 | LYCON_ASSERT(sz[i] <= (size_t)INT_MAX); 100 | if (sz[i] == 0) 101 | return; 102 | if (srcofs) 103 | srcptr += srcofs[i] * (i <= dims - 2 ? srcstep[i] : 1); 104 | if (dstofs) 105 | dstptr += dstofs[i] * (i <= dims - 2 ? dststep[i] : 1); 106 | isz[i] = (int)sz[i]; 107 | } 108 | 109 | Mat src(dims, isz, LYCON_8U, srcptr, srcstep); 110 | Mat dst(dims, isz, LYCON_8U, dstptr, dststep); 111 | 112 | const Mat* arrays[] = {&src, &dst}; 113 | uchar* ptrs[2]; 114 | NAryMatIterator it(arrays, ptrs, 2); 115 | size_t planesz = it.size; 116 | 117 | for (size_t j = 0; j < it.nplanes; j++, ++it) 118 | memcpy(ptrs[1], ptrs[0], planesz); 119 | } 120 | 121 | BufferPoolController* MatAllocator::getBufferPoolController(const char* id) const 122 | { 123 | return nullptr; 124 | } 125 | 126 | class StdMatAllocator : public MatAllocator 127 | { 128 | public: 129 | UMatData* allocate(int dims, const int* sizes, int type, void* data0, size_t* step, int /*flags*/, 130 | UMatUsageFlags /*usageFlags*/) const 131 | { 132 | size_t total = LYCON_ELEM_SIZE(type); 133 | for (int i = dims - 1; i >= 0; i--) 134 | { 135 | if (step) 136 | { 137 | if (data0 && step[i] != LYCON_AUTOSTEP) 138 | { 139 | LYCON_ASSERT(total <= step[i]); 140 | total = step[i]; 141 | } 142 | else 143 | step[i] = total; 144 | } 145 | total *= sizes[i]; 146 | } 147 | uchar* data = data0 ? (uchar*)data0 : (uchar*)fastMalloc(total); 148 | UMatData* u = new UMatData(this); 149 | u->data = u->origdata = data; 150 | u->size = total; 151 | if (data0) 152 | u->flags |= UMatData::USER_ALLOCATED; 153 | 154 | return u; 155 | } 156 | 157 | bool allocate(UMatData* u, int /*accessFlags*/, UMatUsageFlags /*usageFlags*/) const 158 | { 159 | if (!u) 160 | return false; 161 | return true; 162 | } 163 | 164 | void deallocate(UMatData* u) const 165 | { 166 | if (!u) 167 | return; 168 | 169 | LYCON_ASSERT(u->urefcount == 0); 170 | LYCON_ASSERT(u->refcount == 0); 171 | if (!(u->flags & UMatData::USER_ALLOCATED)) 172 | { 173 | fastFree(u->origdata); 174 | u->origdata = 0; 175 | } 176 | delete u; 177 | } 178 | }; 179 | namespace 180 | { 181 | MatAllocator* g_matAllocator = NULL; 182 | } 183 | 184 | MatAllocator* Mat::getDefaultAllocator() 185 | { 186 | if (g_matAllocator == NULL) 187 | { 188 | #ifdef LYCON_USE_NUMPY_ALLOCATOR_BY_DEFAULT 189 | g_matAllocator = &(NumpyAllocator::getNumpyAllocator()); 190 | #else 191 | g_matAllocator = getStdAllocator(); 192 | #endif 193 | } 194 | return g_matAllocator; 195 | } 196 | void Mat::setDefaultAllocator(MatAllocator* allocator) 197 | { 198 | g_matAllocator = allocator; 199 | } 200 | MatAllocator* Mat::getStdAllocator() 201 | { 202 | LYCON_SINGLETON_LAZY_INIT(MatAllocator, new StdMatAllocator()) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/lycon/types/rect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/types/point.h" 4 | #include "lycon/types/size.h" 5 | #include "lycon/util/saturate_cast.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | template class Rect_ 11 | { 12 | public: 13 | typedef _Tp value_type; 14 | 15 | //! various constructors 16 | Rect_(); 17 | Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height); 18 | Rect_(const Rect_ &r); 19 | Rect_(const Point_<_Tp> &org, const Size_<_Tp> &sz); 20 | Rect_(const Point_<_Tp> &pt1, const Point_<_Tp> &pt2); 21 | 22 | Rect_ &operator=(const Rect_ &r); 23 | //! the top-left corner 24 | Point_<_Tp> tl() const; 25 | //! the bottom-right corner 26 | Point_<_Tp> br() const; 27 | 28 | //! size (width, height) of the rectangle 29 | Size_<_Tp> size() const; 30 | //! area (width*height) of the rectangle 31 | _Tp area() const; 32 | 33 | //! conversion to another data type 34 | template operator Rect_<_Tp2>() const; 35 | 36 | //! checks whether the rectangle contains the point 37 | bool contains(const Point_<_Tp> &pt) const; 38 | 39 | _Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle 40 | }; 41 | 42 | typedef Rect_ Rect2i; 43 | typedef Rect_ Rect2f; 44 | typedef Rect_ Rect2d; 45 | typedef Rect2i Rect; 46 | 47 | template inline Rect_<_Tp>::Rect_() : x(0), y(0), width(0), height(0) 48 | { 49 | } 50 | 51 | template inline Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height) : x(_x), y(_y), width(_width), height(_height) 52 | { 53 | } 54 | 55 | template inline Rect_<_Tp>::Rect_(const Rect_<_Tp> &r) : x(r.x), y(r.y), width(r.width), height(r.height) 56 | { 57 | } 58 | 59 | template inline Rect_<_Tp>::Rect_(const Point_<_Tp> &org, const Size_<_Tp> &sz) : x(org.x), y(org.y), width(sz.width), height(sz.height) 60 | { 61 | } 62 | 63 | template inline Rect_<_Tp>::Rect_(const Point_<_Tp> &pt1, const Point_<_Tp> &pt2) 64 | { 65 | x = std::min(pt1.x, pt2.x); 66 | y = std::min(pt1.y, pt2.y); 67 | width = std::max(pt1.x, pt2.x) - x; 68 | height = std::max(pt1.y, pt2.y) - y; 69 | } 70 | 71 | template inline Rect_<_Tp> &Rect_<_Tp>::operator=(const Rect_<_Tp> &r) 72 | { 73 | x = r.x; 74 | y = r.y; 75 | width = r.width; 76 | height = r.height; 77 | return *this; 78 | } 79 | 80 | template inline Point_<_Tp> Rect_<_Tp>::tl() const 81 | { 82 | return Point_<_Tp>(x, y); 83 | } 84 | 85 | template inline Point_<_Tp> Rect_<_Tp>::br() const 86 | { 87 | return Point_<_Tp>(x + width, y + height); 88 | } 89 | 90 | template inline Size_<_Tp> Rect_<_Tp>::size() const 91 | { 92 | return Size_<_Tp>(width, height); 93 | } 94 | 95 | template inline _Tp Rect_<_Tp>::area() const 96 | { 97 | return width * height; 98 | } 99 | 100 | template template inline Rect_<_Tp>::operator Rect_<_Tp2>() const 101 | { 102 | return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height)); 103 | } 104 | 105 | template inline bool Rect_<_Tp>::contains(const Point_<_Tp> &pt) const 106 | { 107 | return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height; 108 | } 109 | 110 | template static inline Rect_<_Tp> &operator+=(Rect_<_Tp> &a, const Point_<_Tp> &b) 111 | { 112 | a.x += b.x; 113 | a.y += b.y; 114 | return a; 115 | } 116 | 117 | template static inline Rect_<_Tp> &operator-=(Rect_<_Tp> &a, const Point_<_Tp> &b) 118 | { 119 | a.x -= b.x; 120 | a.y -= b.y; 121 | return a; 122 | } 123 | 124 | template static inline Rect_<_Tp> &operator+=(Rect_<_Tp> &a, const Size_<_Tp> &b) 125 | { 126 | a.width += b.width; 127 | a.height += b.height; 128 | return a; 129 | } 130 | 131 | template static inline Rect_<_Tp> &operator-=(Rect_<_Tp> &a, const Size_<_Tp> &b) 132 | { 133 | a.width -= b.width; 134 | a.height -= b.height; 135 | return a; 136 | } 137 | 138 | template static inline Rect_<_Tp> &operator&=(Rect_<_Tp> &a, const Rect_<_Tp> &b) 139 | { 140 | _Tp x1 = std::max(a.x, b.x); 141 | _Tp y1 = std::max(a.y, b.y); 142 | a.width = std::min(a.x + a.width, b.x + b.width) - x1; 143 | a.height = std::min(a.y + a.height, b.y + b.height) - y1; 144 | a.x = x1; 145 | a.y = y1; 146 | if (a.width <= 0 || a.height <= 0) 147 | a = Rect(); 148 | return a; 149 | } 150 | 151 | template static inline Rect_<_Tp> &operator|=(Rect_<_Tp> &a, const Rect_<_Tp> &b) 152 | { 153 | _Tp x1 = std::min(a.x, b.x); 154 | _Tp y1 = std::min(a.y, b.y); 155 | a.width = std::max(a.x + a.width, b.x + b.width) - x1; 156 | a.height = std::max(a.y + a.height, b.y + b.height) - y1; 157 | a.x = x1; 158 | a.y = y1; 159 | return a; 160 | } 161 | 162 | template static inline bool operator==(const Rect_<_Tp> &a, const Rect_<_Tp> &b) 163 | { 164 | return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height; 165 | } 166 | 167 | template static inline bool operator!=(const Rect_<_Tp> &a, const Rect_<_Tp> &b) 168 | { 169 | return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; 170 | } 171 | 172 | template static inline Rect_<_Tp> operator+(const Rect_<_Tp> &a, const Point_<_Tp> &b) 173 | { 174 | return Rect_<_Tp>(a.x + b.x, a.y + b.y, a.width, a.height); 175 | } 176 | 177 | template static inline Rect_<_Tp> operator-(const Rect_<_Tp> &a, const Point_<_Tp> &b) 178 | { 179 | return Rect_<_Tp>(a.x - b.x, a.y - b.y, a.width, a.height); 180 | } 181 | 182 | template static inline Rect_<_Tp> operator+(const Rect_<_Tp> &a, const Size_<_Tp> &b) 183 | { 184 | return Rect_<_Tp>(a.x, a.y, a.width + b.width, a.height + b.height); 185 | } 186 | 187 | template static inline Rect_<_Tp> operator&(const Rect_<_Tp> &a, const Rect_<_Tp> &b) 188 | { 189 | Rect_<_Tp> c = a; 190 | return c &= b; 191 | } 192 | 193 | template static inline Rect_<_Tp> operator|(const Rect_<_Tp> &a, const Rect_<_Tp> &b) 194 | { 195 | Rect_<_Tp> c = a; 196 | return c |= b; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/lycon/types/point.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/util/saturate_cast.h" 4 | 5 | namespace lycon 6 | { 7 | 8 | template class Point_ 9 | { 10 | public: 11 | typedef _Tp value_type; 12 | 13 | // various constructors 14 | Point_(); 15 | Point_(_Tp _x, _Tp _y); 16 | Point_(const Point_ &pt); 17 | 18 | Point_ &operator=(const Point_ &pt); 19 | //! conversion to another data type 20 | template operator Point_<_Tp2>() const; 21 | 22 | //! dot product 23 | _Tp dot(const Point_ &pt) const; 24 | //! dot product computed in double-precision arithmetics 25 | double ddot(const Point_ &pt) const; 26 | //! cross-product 27 | double cross(const Point_ &pt) const; 28 | 29 | _Tp x, y; //< the point coordinates 30 | }; 31 | 32 | typedef Point_ Point2i; 33 | typedef Point_ Point2l; 34 | typedef Point_ Point2f; 35 | typedef Point_ Point2d; 36 | typedef Point2i Point; 37 | 38 | template inline Point_<_Tp>::Point_() : x(0), y(0) 39 | { 40 | } 41 | 42 | template inline Point_<_Tp>::Point_(_Tp _x, _Tp _y) : x(_x), y(_y) 43 | { 44 | } 45 | 46 | template inline Point_<_Tp>::Point_(const Point_ &pt) : x(pt.x), y(pt.y) 47 | { 48 | } 49 | 50 | template inline Point_<_Tp> &Point_<_Tp>::operator=(const Point_ &pt) 51 | { 52 | x = pt.x; 53 | y = pt.y; 54 | return *this; 55 | } 56 | 57 | template template inline Point_<_Tp>::operator Point_<_Tp2>() const 58 | { 59 | return Point_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y)); 60 | } 61 | 62 | template inline _Tp Point_<_Tp>::dot(const Point_ &pt) const 63 | { 64 | return saturate_cast<_Tp>(x * pt.x + y * pt.y); 65 | } 66 | 67 | template inline double Point_<_Tp>::ddot(const Point_ &pt) const 68 | { 69 | return (double)x * pt.x + (double)y * pt.y; 70 | } 71 | 72 | template inline double Point_<_Tp>::cross(const Point_ &pt) const 73 | { 74 | return (double)x * pt.y - (double)y * pt.x; 75 | } 76 | 77 | template static inline Point_<_Tp> &operator+=(Point_<_Tp> &a, const Point_<_Tp> &b) 78 | { 79 | a.x += b.x; 80 | a.y += b.y; 81 | return a; 82 | } 83 | 84 | template static inline Point_<_Tp> &operator-=(Point_<_Tp> &a, const Point_<_Tp> &b) 85 | { 86 | a.x -= b.x; 87 | a.y -= b.y; 88 | return a; 89 | } 90 | 91 | template static inline Point_<_Tp> &operator*=(Point_<_Tp> &a, int b) 92 | { 93 | a.x = saturate_cast<_Tp>(a.x * b); 94 | a.y = saturate_cast<_Tp>(a.y * b); 95 | return a; 96 | } 97 | 98 | template static inline Point_<_Tp> &operator*=(Point_<_Tp> &a, float b) 99 | { 100 | a.x = saturate_cast<_Tp>(a.x * b); 101 | a.y = saturate_cast<_Tp>(a.y * b); 102 | return a; 103 | } 104 | 105 | template static inline Point_<_Tp> &operator*=(Point_<_Tp> &a, double b) 106 | { 107 | a.x = saturate_cast<_Tp>(a.x * b); 108 | a.y = saturate_cast<_Tp>(a.y * b); 109 | return a; 110 | } 111 | 112 | template static inline Point_<_Tp> &operator/=(Point_<_Tp> &a, int b) 113 | { 114 | a.x = saturate_cast<_Tp>(a.x / b); 115 | a.y = saturate_cast<_Tp>(a.y / b); 116 | return a; 117 | } 118 | 119 | template static inline Point_<_Tp> &operator/=(Point_<_Tp> &a, float b) 120 | { 121 | a.x = saturate_cast<_Tp>(a.x / b); 122 | a.y = saturate_cast<_Tp>(a.y / b); 123 | return a; 124 | } 125 | 126 | template static inline Point_<_Tp> &operator/=(Point_<_Tp> &a, double b) 127 | { 128 | a.x = saturate_cast<_Tp>(a.x / b); 129 | a.y = saturate_cast<_Tp>(a.y / b); 130 | return a; 131 | } 132 | 133 | template static inline double norm(const Point_<_Tp> &pt) 134 | { 135 | return std::sqrt((double)pt.x * pt.x + (double)pt.y * pt.y); 136 | } 137 | 138 | template static inline bool operator==(const Point_<_Tp> &a, const Point_<_Tp> &b) 139 | { 140 | return a.x == b.x && a.y == b.y; 141 | } 142 | 143 | template static inline bool operator!=(const Point_<_Tp> &a, const Point_<_Tp> &b) 144 | { 145 | return a.x != b.x || a.y != b.y; 146 | } 147 | 148 | template static inline Point_<_Tp> operator+(const Point_<_Tp> &a, const Point_<_Tp> &b) 149 | { 150 | return Point_<_Tp>(saturate_cast<_Tp>(a.x + b.x), saturate_cast<_Tp>(a.y + b.y)); 151 | } 152 | 153 | template static inline Point_<_Tp> operator-(const Point_<_Tp> &a, const Point_<_Tp> &b) 154 | { 155 | return Point_<_Tp>(saturate_cast<_Tp>(a.x - b.x), saturate_cast<_Tp>(a.y - b.y)); 156 | } 157 | 158 | template static inline Point_<_Tp> operator-(const Point_<_Tp> &a) 159 | { 160 | return Point_<_Tp>(saturate_cast<_Tp>(-a.x), saturate_cast<_Tp>(-a.y)); 161 | } 162 | 163 | template static inline Point_<_Tp> operator*(const Point_<_Tp> &a, int b) 164 | { 165 | return Point_<_Tp>(saturate_cast<_Tp>(a.x * b), saturate_cast<_Tp>(a.y * b)); 166 | } 167 | 168 | template static inline Point_<_Tp> operator*(int a, const Point_<_Tp> &b) 169 | { 170 | return Point_<_Tp>(saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a)); 171 | } 172 | 173 | template static inline Point_<_Tp> operator*(const Point_<_Tp> &a, float b) 174 | { 175 | return Point_<_Tp>(saturate_cast<_Tp>(a.x * b), saturate_cast<_Tp>(a.y * b)); 176 | } 177 | 178 | template static inline Point_<_Tp> operator*(float a, const Point_<_Tp> &b) 179 | { 180 | return Point_<_Tp>(saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a)); 181 | } 182 | 183 | template static inline Point_<_Tp> operator*(const Point_<_Tp> &a, double b) 184 | { 185 | return Point_<_Tp>(saturate_cast<_Tp>(a.x * b), saturate_cast<_Tp>(a.y * b)); 186 | } 187 | 188 | template static inline Point_<_Tp> operator*(double a, const Point_<_Tp> &b) 189 | { 190 | return Point_<_Tp>(saturate_cast<_Tp>(b.x * a), saturate_cast<_Tp>(b.y * a)); 191 | } 192 | 193 | template static inline Point_<_Tp> operator/(const Point_<_Tp> &a, int b) 194 | { 195 | Point_<_Tp> tmp(a); 196 | tmp /= b; 197 | return tmp; 198 | } 199 | 200 | template static inline Point_<_Tp> operator/(const Point_<_Tp> &a, float b) 201 | { 202 | Point_<_Tp> tmp(a); 203 | tmp /= b; 204 | return tmp; 205 | } 206 | 207 | template static inline Point_<_Tp> operator/(const Point_<_Tp> &a, double b) 208 | { 209 | Point_<_Tp> tmp(a); 210 | tmp /= b; 211 | return tmp; 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/lycon/transform/resize/interp.lut.h: -------------------------------------------------------------------------------- 1 | const int INTER_RESIZE_COEF_BITS = 11; 2 | const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS; 3 | 4 | const int INTER_REMAP_COEF_BITS = 15; 5 | const int INTER_REMAP_COEF_SCALE = 1 << INTER_REMAP_COEF_BITS; 6 | 7 | static uchar NNDeltaTab_i[INTER_TAB_SIZE2][2]; 8 | 9 | static float BilinearTab_f[INTER_TAB_SIZE2][2][2]; 10 | static short BilinearTab_i[INTER_TAB_SIZE2][2][2]; 11 | 12 | #if LYCON_SSE2 || LYCON_NEON 13 | static short BilinearTab_iC4_buf[INTER_TAB_SIZE2 + 2][2][8]; 14 | static short (*BilinearTab_iC4)[2][8] = (short (*)[2][8])alignPtr(BilinearTab_iC4_buf, 16); 15 | #endif 16 | 17 | static float BicubicTab_f[INTER_TAB_SIZE2][4][4]; 18 | static short BicubicTab_i[INTER_TAB_SIZE2][4][4]; 19 | 20 | static float Lanczos4Tab_f[INTER_TAB_SIZE2][8][8]; 21 | static short Lanczos4Tab_i[INTER_TAB_SIZE2][8][8]; 22 | 23 | static inline void interpolateLinear(float x, float* coeffs) 24 | { 25 | coeffs[0] = 1.f - x; 26 | coeffs[1] = x; 27 | } 28 | 29 | static inline void interpolateCubic(float x, float* coeffs) 30 | { 31 | const float A = -0.75f; 32 | 33 | coeffs[0] = ((A * (x + 1) - 5 * A) * (x + 1) + 8 * A) * (x + 1) - 4 * A; 34 | coeffs[1] = ((A + 2) * x - (A + 3)) * x * x + 1; 35 | coeffs[2] = ((A + 2) * (1 - x) - (A + 3)) * (1 - x) * (1 - x) + 1; 36 | coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2]; 37 | } 38 | 39 | static inline void interpolateLanczos4(float x, float* coeffs) 40 | { 41 | static const double s45 = 0.70710678118654752440084436210485; 42 | static const double cs[][2] = {{1, 0}, {-s45, -s45}, {0, 1}, {s45, -s45}, 43 | {-1, 0}, {s45, s45}, {0, -1}, {-s45, s45}}; 44 | 45 | if (x < FLT_EPSILON) 46 | { 47 | for (int i = 0; i < 8; i++) coeffs[i] = 0; 48 | coeffs[3] = 1; 49 | return; 50 | } 51 | 52 | float sum = 0; 53 | double y0 = -(x + 3) * M_PI * 0.25, s0 = sin(y0), c0 = cos(y0); 54 | for (int i = 0; i < 8; i++) 55 | { 56 | double y = -(x + 3 - i) * M_PI * 0.25; 57 | coeffs[i] = (float)((cs[i][0] * s0 + cs[i][1] * c0) / (y * y)); 58 | sum += coeffs[i]; 59 | } 60 | 61 | sum = 1.f / sum; 62 | for (int i = 0; i < 8; i++) coeffs[i] *= sum; 63 | } 64 | 65 | static void initInterTab1D(int method, float* tab, int tabsz) 66 | { 67 | float scale = 1.f / tabsz; 68 | if (method == INTER_LINEAR) 69 | { 70 | for (int i = 0; i < tabsz; i++, tab += 2) interpolateLinear(i * scale, tab); 71 | } 72 | else if (method == INTER_CUBIC) 73 | { 74 | for (int i = 0; i < tabsz; i++, tab += 4) interpolateCubic(i * scale, tab); 75 | } 76 | else if (method == INTER_LANCZOS4) 77 | { 78 | for (int i = 0; i < tabsz; i++, tab += 8) interpolateLanczos4(i * scale, tab); 79 | } 80 | else 81 | LYCON_ERROR("Unknown interpolation method"); 82 | } 83 | 84 | static const void* initInterTab2D(int method, bool fixpt) 85 | { 86 | static bool inittab[INTER_MAX + 1] = {false}; 87 | float* tab = 0; 88 | short* itab = 0; 89 | int ksize = 0; 90 | if (method == INTER_LINEAR) 91 | tab = BilinearTab_f[0][0], itab = BilinearTab_i[0][0], ksize = 2; 92 | else if (method == INTER_CUBIC) 93 | tab = BicubicTab_f[0][0], itab = BicubicTab_i[0][0], ksize = 4; 94 | else if (method == INTER_LANCZOS4) 95 | tab = Lanczos4Tab_f[0][0], itab = Lanczos4Tab_i[0][0], ksize = 8; 96 | else 97 | LYCON_ERROR("Unknown/unsupported interpolation type"); 98 | 99 | if (!inittab[method]) 100 | { 101 | AutoBuffer _tab(8 * INTER_TAB_SIZE); 102 | int i, j, k1, k2; 103 | initInterTab1D(method, _tab, INTER_TAB_SIZE); 104 | for (i = 0; i < INTER_TAB_SIZE; i++) 105 | for (j = 0; j < INTER_TAB_SIZE; j++, tab += ksize * ksize, itab += ksize * ksize) 106 | { 107 | int isum = 0; 108 | NNDeltaTab_i[i * INTER_TAB_SIZE + j][0] = j < INTER_TAB_SIZE / 2; 109 | NNDeltaTab_i[i * INTER_TAB_SIZE + j][1] = i < INTER_TAB_SIZE / 2; 110 | 111 | for (k1 = 0; k1 < ksize; k1++) 112 | { 113 | float vy = _tab[i * ksize + k1]; 114 | for (k2 = 0; k2 < ksize; k2++) 115 | { 116 | float v = vy * _tab[j * ksize + k2]; 117 | tab[k1 * ksize + k2] = v; 118 | isum += itab[k1 * ksize + k2] = saturate_cast(v * INTER_REMAP_COEF_SCALE); 119 | } 120 | } 121 | 122 | if (isum != INTER_REMAP_COEF_SCALE) 123 | { 124 | int diff = isum - INTER_REMAP_COEF_SCALE; 125 | int ksize2 = ksize / 2, Mk1 = ksize2, Mk2 = ksize2, mk1 = ksize2, mk2 = ksize2; 126 | for (k1 = ksize2; k1 < ksize2 + 2; k1++) 127 | for (k2 = ksize2; k2 < ksize2 + 2; k2++) 128 | { 129 | if (itab[k1 * ksize + k2] < itab[mk1 * ksize + mk2]) 130 | mk1 = k1, mk2 = k2; 131 | else if (itab[k1 * ksize + k2] > itab[Mk1 * ksize + Mk2]) 132 | Mk1 = k1, Mk2 = k2; 133 | } 134 | if (diff < 0) 135 | itab[Mk1 * ksize + Mk2] = (short)(itab[Mk1 * ksize + Mk2] - diff); 136 | else 137 | itab[mk1 * ksize + mk2] = (short)(itab[mk1 * ksize + mk2] - diff); 138 | } 139 | } 140 | tab -= INTER_TAB_SIZE2 * ksize * ksize; 141 | itab -= INTER_TAB_SIZE2 * ksize * ksize; 142 | #if LYCON_SSE2 || LYCON_NEON 143 | if (method == INTER_LINEAR) 144 | { 145 | for (i = 0; i < INTER_TAB_SIZE2; i++) 146 | for (j = 0; j < 4; j++) 147 | { 148 | BilinearTab_iC4[i][0][j * 2] = BilinearTab_i[i][0][0]; 149 | BilinearTab_iC4[i][0][j * 2 + 1] = BilinearTab_i[i][0][1]; 150 | BilinearTab_iC4[i][1][j * 2] = BilinearTab_i[i][1][0]; 151 | BilinearTab_iC4[i][1][j * 2 + 1] = BilinearTab_i[i][1][1]; 152 | } 153 | } 154 | #endif 155 | inittab[method] = true; 156 | } 157 | return fixpt ? (const void*)itab : (const void*)tab; 158 | } 159 | 160 | #ifndef __MINGW32__ 161 | static bool initAllInterTab2D() 162 | { 163 | return initInterTab2D(INTER_LINEAR, false) && initInterTab2D(INTER_LINEAR, true) && 164 | initInterTab2D(INTER_CUBIC, false) && initInterTab2D(INTER_CUBIC, true) && 165 | initInterTab2D(INTER_LANCZOS4, false) && initInterTab2D(INTER_LANCZOS4, true); 166 | } 167 | 168 | static volatile bool doInitAllInterTab2D = initAllInterTab2D(); 169 | #endif 170 | -------------------------------------------------------------------------------- /src/lycon/util/saturate_cast.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "lycon/util/fast_math.h" 7 | 8 | namespace lycon { 9 | 10 | /////////////// saturate_cast (used in image & signal processing) /////////////////// 11 | 12 | /** @brief Template function for accurate conversion from one primitive type to another. 13 | 14 | The functions saturate_cast resemble the standard C++ cast operations, such as static_cast\() 15 | and others. They perform an efficient and accurate conversion from one primitive type to another 16 | (see the introduction chapter). saturate in the name means that when the input value v is out of the 17 | range of the target type, the result is not formed just by taking low bits of the input, but instead 18 | the value is clipped. For example: 19 | @code 20 | uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN) 21 | short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX) 22 | @endcode 23 | Such clipping is done when the target type is unsigned char , signed char , unsigned short or 24 | signed short . For 32-bit integers, no clipping is done. 25 | 26 | When the parameter is a floating-point value and the target type is an integer (8-, 16- or 32-bit), 27 | the floating-point value is first rounded to the nearest integer and then clipped if needed (when 28 | the target type is 8- or 16-bit). 29 | 30 | This operation is used in the simplest or most complex image processing functions in OpenCV. 31 | 32 | @param v Function parameter. 33 | @sa add, subtract, multiply, divide, Mat::convertTo 34 | */ 35 | template static inline _Tp saturate_cast(uchar v) { return _Tp(v); } 36 | /** @overload */ 37 | template static inline _Tp saturate_cast(schar v) { return _Tp(v); } 38 | /** @overload */ 39 | template static inline _Tp saturate_cast(ushort v) { return _Tp(v); } 40 | /** @overload */ 41 | template static inline _Tp saturate_cast(short v) { return _Tp(v); } 42 | /** @overload */ 43 | template static inline _Tp saturate_cast(unsigned v) { return _Tp(v); } 44 | /** @overload */ 45 | template static inline _Tp saturate_cast(int v) { return _Tp(v); } 46 | /** @overload */ 47 | template static inline _Tp saturate_cast(float v) { return _Tp(v); } 48 | /** @overload */ 49 | template static inline _Tp saturate_cast(double v) { return _Tp(v); } 50 | /** @overload */ 51 | template static inline _Tp saturate_cast(int64 v) { return _Tp(v); } 52 | /** @overload */ 53 | template static inline _Tp saturate_cast(uint64 v) { return _Tp(v); } 54 | 55 | template <> inline uchar saturate_cast(schar v) { return (uchar)std::max((int)v, 0); } 56 | template <> inline uchar saturate_cast(ushort v) { return (uchar)std::min((unsigned)v, (unsigned)UCHAR_MAX); } 57 | template <> inline uchar saturate_cast(int v) { return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } 58 | template <> inline uchar saturate_cast(short v) { return saturate_cast((int)v); } 59 | template <> inline uchar saturate_cast(unsigned v) { return (uchar)std::min(v, (unsigned)UCHAR_MAX); } 60 | template <> inline uchar saturate_cast(float v) { 61 | int iv = fast_round(v); 62 | return saturate_cast(iv); 63 | } 64 | template <> inline uchar saturate_cast(double v) { 65 | int iv = fast_round(v); 66 | return saturate_cast(iv); 67 | } 68 | template <> inline uchar saturate_cast(int64 v) { return (uchar)((uint64)v <= (uint64)UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0); } 69 | template <> inline uchar saturate_cast(uint64 v) { return (uchar)std::min(v, (uint64)UCHAR_MAX); } 70 | 71 | template <> inline schar saturate_cast(uchar v) { return (schar)std::min((int)v, SCHAR_MAX); } 72 | template <> inline schar saturate_cast(ushort v) { return (schar)std::min((unsigned)v, (unsigned)SCHAR_MAX); } 73 | template <> inline schar saturate_cast(int v) { return (schar)((unsigned)(v - SCHAR_MIN) <= (unsigned)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } 74 | template <> inline schar saturate_cast(short v) { return saturate_cast((int)v); } 75 | template <> inline schar saturate_cast(unsigned v) { return (schar)std::min(v, (unsigned)SCHAR_MAX); } 76 | template <> inline schar saturate_cast(float v) { 77 | int iv = fast_round(v); 78 | return saturate_cast(iv); 79 | } 80 | template <> inline schar saturate_cast(double v) { 81 | int iv = fast_round(v); 82 | return saturate_cast(iv); 83 | } 84 | template <> inline schar saturate_cast(int64 v) { return (schar)((uint64)((int64)v - SCHAR_MIN) <= (uint64)UCHAR_MAX ? v : v > 0 ? SCHAR_MAX : SCHAR_MIN); } 85 | template <> inline schar saturate_cast(uint64 v) { return (schar)std::min(v, (uint64)SCHAR_MAX); } 86 | 87 | template <> inline ushort saturate_cast(schar v) { return (ushort)std::max((int)v, 0); } 88 | template <> inline ushort saturate_cast(short v) { return (ushort)std::max((int)v, 0); } 89 | template <> inline ushort saturate_cast(int v) { return (ushort)((unsigned)v <= (unsigned)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } 90 | template <> inline ushort saturate_cast(unsigned v) { return (ushort)std::min(v, (unsigned)USHRT_MAX); } 91 | template <> inline ushort saturate_cast(float v) { 92 | int iv = fast_round(v); 93 | return saturate_cast(iv); 94 | } 95 | template <> inline ushort saturate_cast(double v) { 96 | int iv = fast_round(v); 97 | return saturate_cast(iv); 98 | } 99 | template <> inline ushort saturate_cast(int64 v) { return (ushort)((uint64)v <= (uint64)USHRT_MAX ? v : v > 0 ? USHRT_MAX : 0); } 100 | template <> inline ushort saturate_cast(uint64 v) { return (ushort)std::min(v, (uint64)USHRT_MAX); } 101 | 102 | template <> inline short saturate_cast(ushort v) { return (short)std::min((int)v, SHRT_MAX); } 103 | template <> inline short saturate_cast(int v) { return (short)((unsigned)(v - SHRT_MIN) <= (unsigned)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } 104 | template <> inline short saturate_cast(unsigned v) { return (short)std::min(v, (unsigned)SHRT_MAX); } 105 | template <> inline short saturate_cast(float v) { 106 | int iv = fast_round(v); 107 | return saturate_cast(iv); 108 | } 109 | template <> inline short saturate_cast(double v) { 110 | int iv = fast_round(v); 111 | return saturate_cast(iv); 112 | } 113 | template <> inline short saturate_cast(int64 v) { return (short)((uint64)((int64)v - SHRT_MIN) <= (uint64)USHRT_MAX ? v : v > 0 ? SHRT_MAX : SHRT_MIN); } 114 | template <> inline short saturate_cast(uint64 v) { return (short)std::min(v, (uint64)SHRT_MAX); } 115 | 116 | template <> inline int saturate_cast(float v) { return fast_round(v); } 117 | template <> inline int saturate_cast(double v) { return fast_round(v); } 118 | 119 | // we intentionally do not clip negative numbers, to make -1 become 0xffffffff etc. 120 | template <> inline unsigned saturate_cast(float v) { return fast_round(v); } 121 | template <> inline unsigned saturate_cast(double v) { return fast_round(v); } 122 | } 123 | -------------------------------------------------------------------------------- /src/lycon/mat/iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/defs.h" 6 | #include "lycon/types.h" 7 | #include "lycon/util/error.h" 8 | 9 | namespace lycon 10 | { 11 | class LYCON_EXPORTS MatConstIterator 12 | { 13 | public: 14 | typedef uchar *value_type; 15 | typedef ptrdiff_t difference_type; 16 | typedef const uchar **pointer; 17 | typedef uchar *reference; 18 | 19 | typedef std::random_access_iterator_tag iterator_category; 20 | 21 | //! default constructor 22 | MatConstIterator(); 23 | //! constructor that sets the iterator to the beginning of the matrix 24 | MatConstIterator(const Mat *_m); 25 | //! constructor that sets the iterator to the specified element of the matrix 26 | MatConstIterator(const Mat *_m, int _row, int _col = 0); 27 | //! constructor that sets the iterator to the specified element of the matrix 28 | MatConstIterator(const Mat *_m, Point _pt); 29 | //! constructor that sets the iterator to the specified element of the matrix 30 | MatConstIterator(const Mat *_m, const int *_idx); 31 | //! copy constructor 32 | MatConstIterator(const MatConstIterator &it); 33 | 34 | //! copy operator 35 | MatConstIterator &operator=(const MatConstIterator &it); 36 | //! returns the current matrix element 37 | const uchar *operator*() const; 38 | //! returns the i-th matrix element, relative to the current 39 | const uchar *operator[](ptrdiff_t i) const; 40 | 41 | //! shifts the iterator forward by the specified number of elements 42 | MatConstIterator &operator+=(ptrdiff_t ofs); 43 | //! shifts the iterator backward by the specified number of elements 44 | MatConstIterator &operator-=(ptrdiff_t ofs); 45 | //! decrements the iterator 46 | MatConstIterator &operator--(); 47 | //! decrements the iterator 48 | MatConstIterator operator--(int); 49 | //! increments the iterator 50 | MatConstIterator &operator++(); 51 | //! increments the iterator 52 | MatConstIterator operator++(int); 53 | //! returns the current iterator position 54 | Point pos() const; 55 | //! returns the current iterator position 56 | void pos(int *_idx) const; 57 | 58 | ptrdiff_t lpos() const; 59 | void seek(ptrdiff_t ofs, bool relative = false); 60 | void seek(const int *_idx, bool relative = false); 61 | 62 | const Mat *m; 63 | size_t elemSize; 64 | const uchar *ptr; 65 | const uchar *sliceStart; 66 | const uchar *sliceEnd; 67 | }; 68 | 69 | template 70 | class MatConstIterator_ : public MatConstIterator 71 | { 72 | public: 73 | typedef _Tp value_type; 74 | typedef ptrdiff_t difference_type; 75 | typedef const _Tp *pointer; 76 | typedef const _Tp &reference; 77 | 78 | typedef std::random_access_iterator_tag iterator_category; 79 | 80 | //! default constructor 81 | MatConstIterator_(); 82 | //! constructor that sets the iterator to the beginning of the matrix 83 | MatConstIterator_(const Mat_<_Tp> *_m); 84 | //! constructor that sets the iterator to the specified element of the matrix 85 | MatConstIterator_(const Mat_<_Tp> *_m, int _row, int _col = 0); 86 | //! constructor that sets the iterator to the specified element of the matrix 87 | MatConstIterator_(const Mat_<_Tp> *_m, Point _pt); 88 | //! constructor that sets the iterator to the specified element of the matrix 89 | MatConstIterator_(const Mat_<_Tp> *_m, const int *_idx); 90 | //! copy constructor 91 | MatConstIterator_(const MatConstIterator_ &it); 92 | 93 | //! copy operator 94 | MatConstIterator_ &operator=(const MatConstIterator_ &it); 95 | //! returns the current matrix element 96 | const _Tp &operator*() const; 97 | //! returns the i-th matrix element, relative to the current 98 | const _Tp &operator[](ptrdiff_t i) const; 99 | 100 | //! shifts the iterator forward by the specified number of elements 101 | MatConstIterator_ &operator+=(ptrdiff_t ofs); 102 | //! shifts the iterator backward by the specified number of elements 103 | MatConstIterator_ &operator-=(ptrdiff_t ofs); 104 | //! decrements the iterator 105 | MatConstIterator_ &operator--(); 106 | //! decrements the iterator 107 | MatConstIterator_ operator--(int); 108 | //! increments the iterator 109 | MatConstIterator_ &operator++(); 110 | //! increments the iterator 111 | MatConstIterator_ operator++(int); 112 | //! returns the current iterator position 113 | Point pos() const; 114 | }; 115 | 116 | template 117 | class MatIterator_ : public MatConstIterator_<_Tp> 118 | { 119 | public: 120 | typedef _Tp *pointer; 121 | typedef _Tp &reference; 122 | 123 | typedef std::random_access_iterator_tag iterator_category; 124 | 125 | //! the default constructor 126 | MatIterator_(); 127 | //! constructor that sets the iterator to the beginning of the matrix 128 | MatIterator_(Mat_<_Tp> *_m); 129 | //! constructor that sets the iterator to the specified element of the matrix 130 | MatIterator_(Mat_<_Tp> *_m, int _row, int _col = 0); 131 | //! constructor that sets the iterator to the specified element of the matrix 132 | MatIterator_(Mat_<_Tp> *_m, Point _pt); 133 | //! constructor that sets the iterator to the specified element of the matrix 134 | MatIterator_(Mat_<_Tp> *_m, const int *_idx); 135 | //! copy constructor 136 | MatIterator_(const MatIterator_ &it); 137 | //! copy operator 138 | MatIterator_ &operator=(const MatIterator_<_Tp> &it); 139 | 140 | //! returns the current matrix element 141 | _Tp &operator*() const; 142 | //! returns the i-th matrix element, relative to the current 143 | _Tp &operator[](ptrdiff_t i) const; 144 | 145 | //! shifts the iterator forward by the specified number of elements 146 | MatIterator_ &operator+=(ptrdiff_t ofs); 147 | //! shifts the iterator backward by the specified number of elements 148 | MatIterator_ &operator-=(ptrdiff_t ofs); 149 | //! decrements the iterator 150 | MatIterator_ &operator--(); 151 | //! decrements the iterator 152 | MatIterator_ operator--(int); 153 | //! increments the iterator 154 | MatIterator_ &operator++(); 155 | //! increments the iterator 156 | MatIterator_ operator++(int); 157 | }; 158 | 159 | class LYCON_EXPORTS NAryMatIterator 160 | { 161 | public: 162 | //! the default constructor 163 | NAryMatIterator(); 164 | //! the full constructor taking arbitrary number of n-dim matrices 165 | NAryMatIterator(const Mat **arrays, uchar **ptrs, int narrays = -1); 166 | //! the full constructor taking arbitrary number of n-dim matrices 167 | NAryMatIterator(const Mat **arrays, Mat *planes, int narrays = -1); 168 | //! the separate iterator initialization method 169 | void init(const Mat **arrays, Mat *planes, uchar **ptrs, int narrays = -1); 170 | 171 | //! proceeds to the next plane of every iterated matrix 172 | NAryMatIterator &operator++(); 173 | //! proceeds to the next plane of every iterated matrix (postfix increment operator) 174 | NAryMatIterator operator++(int); 175 | 176 | //! the iterated arrays 177 | const Mat **arrays; 178 | //! the current planes 179 | Mat *planes; 180 | //! data pointers 181 | uchar **ptrs; 182 | //! the number of arrays 183 | int narrays; 184 | //! the number of hyper-planes that the iterator steps through 185 | size_t nplanes; 186 | //! the size of each segment (in elements) 187 | size_t size; 188 | 189 | protected: 190 | int iterdepth; 191 | size_t idx; 192 | }; 193 | } 194 | -------------------------------------------------------------------------------- /src/lycon/mat/io_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "lycon/defs.h" 6 | #include "lycon/types.h" 7 | 8 | namespace lycon 9 | { 10 | enum 11 | { 12 | ACCESS_READ = 1 << 24, 13 | ACCESS_WRITE = 1 << 25, 14 | ACCESS_RW = 3 << 24, 15 | ACCESS_MASK = ACCESS_RW, 16 | ACCESS_FAST = 1 << 26 17 | }; 18 | 19 | class LYCON_EXPORTS _OutputArray; 20 | 21 | class LYCON_EXPORTS _InputArray 22 | { 23 | public: 24 | enum 25 | { 26 | KIND_SHIFT = 16, 27 | FIXED_TYPE = 0x8000 << KIND_SHIFT, 28 | FIXED_SIZE = 0x4000 << KIND_SHIFT, 29 | KIND_MASK = 31 << KIND_SHIFT, 30 | 31 | NONE = 0 << KIND_SHIFT, 32 | MAT = 1 << KIND_SHIFT, 33 | MATX = 2 << KIND_SHIFT, 34 | STD_VECTOR = 3 << KIND_SHIFT, 35 | STD_VECTOR_VECTOR = 4 << KIND_SHIFT, 36 | STD_VECTOR_MAT = 5 << KIND_SHIFT, 37 | EXPR = 6 << KIND_SHIFT, 38 | STD_BOOL_VECTOR = 12 << KIND_SHIFT, 39 | }; 40 | 41 | _InputArray(); 42 | _InputArray(int _flags, void *_obj); 43 | _InputArray(const Mat &m); 44 | _InputArray(const std::vector &vec); 45 | template 46 | _InputArray(const Mat_<_Tp> &m); 47 | template 48 | _InputArray(const std::vector<_Tp> &vec); 49 | _InputArray(const std::vector &vec); 50 | template 51 | _InputArray(const std::vector> &vec); 52 | template 53 | _InputArray(const std::vector> &vec); 54 | template 55 | _InputArray(const _Tp *vec, int n); 56 | template 57 | _InputArray(const Matx<_Tp, m, n> &matx); 58 | _InputArray(const double &val); 59 | 60 | Mat getMat(int idx = -1) const; 61 | Mat getMat_(int idx = -1) const; 62 | void getMatVector(std::vector &mv) const; 63 | 64 | int getFlags() const; 65 | void *getObj() const; 66 | Size getSz() const; 67 | 68 | int kind() const; 69 | int dims(int i = -1) const; 70 | int cols(int i = -1) const; 71 | int rows(int i = -1) const; 72 | Size size(int i = -1) const; 73 | int sizend(int *sz, int i = -1) const; 74 | bool sameSize(const _InputArray &arr) const; 75 | size_t total(int i = -1) const; 76 | int type(int i = -1) const; 77 | int depth(int i = -1) const; 78 | int channels(int i = -1) const; 79 | bool isContinuous(int i = -1) const; 80 | bool isSubmatrix(int i = -1) const; 81 | bool empty() const; 82 | void copyTo(const _OutputArray &arr) const; 83 | void copyTo(const _OutputArray &arr, const _InputArray &mask) const; 84 | size_t offset(int i = -1) const; 85 | size_t step(int i = -1) const; 86 | bool isMat() const; 87 | bool isMatx() const; 88 | bool isMatVector() const; 89 | bool isVector() const; 90 | ~_InputArray(); 91 | 92 | protected: 93 | int flags; 94 | void *obj; 95 | Size sz; 96 | 97 | void init(int _flags, const void *_obj); 98 | void init(int _flags, const void *_obj, Size _sz); 99 | }; 100 | 101 | class LYCON_EXPORTS _OutputArray : public _InputArray 102 | { 103 | public: 104 | enum 105 | { 106 | DEPTH_MASK_8U = 1 << LYCON_8U, 107 | DEPTH_MASK_8S = 1 << LYCON_8S, 108 | DEPTH_MASK_16U = 1 << LYCON_16U, 109 | DEPTH_MASK_16S = 1 << LYCON_16S, 110 | DEPTH_MASK_32S = 1 << LYCON_32S, 111 | DEPTH_MASK_32F = 1 << LYCON_32F, 112 | DEPTH_MASK_64F = 1 << LYCON_64F, 113 | DEPTH_MASK_ALL = (DEPTH_MASK_64F << 1) - 1, 114 | DEPTH_MASK_ALL_BUT_8S = DEPTH_MASK_ALL & ~DEPTH_MASK_8S, 115 | DEPTH_MASK_FLT = DEPTH_MASK_32F + DEPTH_MASK_64F 116 | }; 117 | 118 | _OutputArray(); 119 | _OutputArray(int _flags, void *_obj); 120 | _OutputArray(Mat &m); 121 | _OutputArray(std::vector &vec); 122 | template 123 | _OutputArray(std::vector<_Tp> &vec); 124 | _OutputArray(std::vector &vec); 125 | template 126 | _OutputArray(std::vector> &vec); 127 | template 128 | _OutputArray(std::vector> &vec); 129 | template 130 | _OutputArray(Mat_<_Tp> &m); 131 | template 132 | _OutputArray(_Tp *vec, int n); 133 | template 134 | _OutputArray(Matx<_Tp, m, n> &matx); 135 | 136 | _OutputArray(const Mat &m); 137 | _OutputArray(const std::vector &vec); 138 | template 139 | _OutputArray(const std::vector<_Tp> &vec); 140 | template 141 | _OutputArray(const std::vector> &vec); 142 | template 143 | _OutputArray(const std::vector> &vec); 144 | template 145 | _OutputArray(const Mat_<_Tp> &m); 146 | template 147 | _OutputArray(const _Tp *vec, int n); 148 | template 149 | _OutputArray(const Matx<_Tp, m, n> &matx); 150 | 151 | bool fixedSize() const; 152 | bool fixedType() const; 153 | bool needed() const; 154 | Mat &getMatRef(int i = -1) const; 155 | void create(Size sz, int type, int i = -1, bool allowTransposed = false, int fixedDepthMask = 0) const; 156 | void create(int rows, int cols, int type, int i = -1, bool allowTransposed = false, int fixedDepthMask = 0) const; 157 | void create(int dims, const int *size, int type, int i = -1, bool allowTransposed = false, 158 | int fixedDepthMask = 0) const; 159 | void createSameSize(const _InputArray &arr, int mtype) const; 160 | void release() const; 161 | void clear() const; 162 | void setTo(const _InputArray &value, const _InputArray &mask = _InputArray()) const; 163 | 164 | void assign(const Mat &m) const; 165 | }; 166 | 167 | class LYCON_EXPORTS _InputOutputArray : public _OutputArray 168 | { 169 | public: 170 | _InputOutputArray(); 171 | _InputOutputArray(int _flags, void *_obj); 172 | _InputOutputArray(Mat &m); 173 | _InputOutputArray(std::vector &vec); 174 | template 175 | _InputOutputArray(std::vector<_Tp> &vec); 176 | _InputOutputArray(std::vector &vec); 177 | template 178 | _InputOutputArray(std::vector> &vec); 179 | template 180 | _InputOutputArray(std::vector> &vec); 181 | template 182 | _InputOutputArray(Mat_<_Tp> &m); 183 | template 184 | _InputOutputArray(_Tp *vec, int n); 185 | template 186 | _InputOutputArray(Matx<_Tp, m, n> &matx); 187 | 188 | _InputOutputArray(const Mat &m); 189 | _InputOutputArray(const std::vector &vec); 190 | template 191 | _InputOutputArray(const std::vector<_Tp> &vec); 192 | template 193 | _InputOutputArray(const std::vector> &vec); 194 | template 195 | _InputOutputArray(const std::vector> &vec); 196 | template 197 | _InputOutputArray(const Mat_<_Tp> &m); 198 | template 199 | _InputOutputArray(const _Tp *vec, int n); 200 | template 201 | _InputOutputArray(const Matx<_Tp, m, n> &matx); 202 | }; 203 | 204 | typedef const _InputArray &InputArray; 205 | typedef InputArray InputArrayOfArrays; 206 | typedef const _OutputArray &OutputArray; 207 | typedef OutputArray OutputArrayOfArrays; 208 | typedef const _InputOutputArray &InputOutputArray; 209 | typedef InputOutputArray InputOutputArrayOfArrays; 210 | 211 | LYCON_EXPORTS InputOutputArray noArray(); 212 | } 213 | -------------------------------------------------------------------------------- /src/lycon/io/exif.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace lycon 12 | { 13 | /** 14 | * @brief Jpeg markers that can encounter in Jpeg file 15 | */ 16 | enum AppMarkerTypes 17 | { 18 | SOI = 0xD8, 19 | SOF0 = 0xC0, 20 | SOF2 = 0xC2, 21 | DHT = 0xC4, 22 | DQT = 0xDB, 23 | DRI = 0xDD, 24 | SOS = 0xDA, 25 | 26 | RST0 = 0xD0, 27 | RST1 = 0xD1, 28 | RST2 = 0xD2, 29 | RST3 = 0xD3, 30 | RST4 = 0xD4, 31 | RST5 = 0xD5, 32 | RST6 = 0xD6, 33 | RST7 = 0xD7, 34 | 35 | APP0 = 0xE0, 36 | APP1 = 0xE1, 37 | APP2 = 0xE2, 38 | APP3 = 0xE3, 39 | APP4 = 0xE4, 40 | APP5 = 0xE5, 41 | APP6 = 0xE6, 42 | APP7 = 0xE7, 43 | APP8 = 0xE8, 44 | APP9 = 0xE9, 45 | APP10 = 0xEA, 46 | APP11 = 0xEB, 47 | APP12 = 0xEC, 48 | APP13 = 0xED, 49 | APP14 = 0xEE, 50 | APP15 = 0xEF, 51 | 52 | COM = 0xFE, 53 | EOI = 0xD9 54 | }; 55 | 56 | /** 57 | * @brief Base Exif tags used by IFD0 (main image) 58 | */ 59 | enum ExifTagName 60 | { 61 | IMAGE_DESCRIPTION = 0x010E, ///< Image Description: ASCII string 62 | MAKE = 0x010F, ///< Description of manufacturer: ASCII string 63 | MODEL = 0x0110, ///< Description of camera model: ASCII string 64 | ORIENTATION = 0x0112, ///< Orientation of the image: unsigned short 65 | XRESOLUTION = 0x011A, ///< Resolution of the image across X axis: unsigned rational 66 | YRESOLUTION = 0x011B, ///< Resolution of the image across Y axis: unsigned rational 67 | RESOLUTION_UNIT = 0x0128, ///< Resolution units. '1' no-unit, '2' inch, '3' centimeter 68 | SOFTWARE = 0x0131, ///< Shows firmware(internal software of digicam) version number 69 | DATE_TIME = 0x0132, ///< Date/Time of image was last modified 70 | WHITE_POINT = 0x013E, ///< Chromaticity of white point of the image 71 | PRIMARY_CHROMATICIES = 0x013F, ///< Chromaticity of the primaries of the image 72 | Y_CB_CR_COEFFICIENTS = 0x0211, ///< constant to translate an image from YCbCr to RGB format 73 | Y_CB_CR_POSITIONING = 0x0213, ///< Chroma sample point of subsampling pixel array 74 | REFERENCE_BLACK_WHITE = 0x0214, ///< Reference value of black point/white point 75 | COPYRIGHT = 0x8298, ///< Copyright information 76 | EXIF_OFFSET = 0x8769, ///< Offset to Exif Sub IFD 77 | INVALID_TAG = 0xFFFF ///< Shows that the tag was not recognized 78 | }; 79 | 80 | enum Endianess_t 81 | { 82 | INTEL = 0x49, 83 | MOTO = 0x4D, 84 | NONE = 0x00 85 | }; 86 | 87 | typedef std::pair u_rational_t; 88 | 89 | /** 90 | * @brief Entry which contains possible values for different exif tags 91 | */ 92 | struct ExifEntry_t 93 | { 94 | ExifEntry_t(); 95 | 96 | std::vector field_u_rational; ///< vector of rational fields 97 | std::string field_str; ///< any kind of textual information 98 | 99 | float field_float; ///< Currently is not used 100 | double field_double; ///< Currently is not used 101 | 102 | uint32_t field_u32; ///< Unsigned 32-bit value 103 | int32_t field_s32; ///< Signed 32-bit value 104 | 105 | uint16_t tag; ///< Tag number 106 | 107 | uint16_t field_u16; ///< Unsigned 16-bit value 108 | int16_t field_s16; ///< Signed 16-bit value 109 | uint8_t field_u8; ///< Unsigned 8-bit value 110 | int8_t field_s8; ///< Signed 8-bit value 111 | }; 112 | 113 | /** 114 | * @brief Picture orientation which may be taken from EXIF 115 | * Orientation usually matters when the picture is taken by 116 | * smartphone or other camera with orientation sensor support 117 | * Corresponds to EXIF 2.3 Specification 118 | */ 119 | enum ImageOrientation 120 | { 121 | IMAGE_ORIENTATION_TL = 1, ///< Horizontal (normal) 122 | IMAGE_ORIENTATION_TR = 2, ///< Mirrored horizontal 123 | IMAGE_ORIENTATION_BR = 3, ///< Rotate 180 124 | IMAGE_ORIENTATION_BL = 4, ///< Mirrored vertical 125 | IMAGE_ORIENTATION_LT = 5, ///< Mirrored horizontal & rotate 270 CW 126 | IMAGE_ORIENTATION_RT = 6, ///< Rotate 90 CW 127 | IMAGE_ORIENTATION_RB = 7, ///< Mirrored horizontal & rotate 90 CW 128 | IMAGE_ORIENTATION_LB = 8 ///< Rotate 270 CW 129 | }; 130 | 131 | /** 132 | * @brief Reading exif information from Jpeg file 133 | * 134 | * Usage example for getting the orientation of the image: 135 | * 136 | * @code 137 | * ExifReader reader(fileName); 138 | * if( reader.parse() ) 139 | * { 140 | * int orientation = reader.getTag(Orientation).field_u16; 141 | * } 142 | * @endcode 143 | * 144 | */ 145 | class ExifReader 146 | { 147 | public: 148 | /** 149 | * @brief ExifReader constructor. Constructs an object of exif reader 150 | * 151 | * @param [in]filename The name of file to look exif info in 152 | */ 153 | explicit ExifReader(std::string filename); 154 | ~ExifReader(); 155 | 156 | /** 157 | * @brief Parse the file with exif info 158 | * 159 | * @return true if parsing was successful and exif information exists in JpegReader object 160 | */ 161 | bool parse(); 162 | 163 | /** 164 | * @brief Get tag info by tag number 165 | * 166 | * @param [in] tag The tag number 167 | * @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the 168 | * structure ExifEntry_t 169 | */ 170 | ExifEntry_t getTag(const ExifTagName tag); 171 | 172 | private: 173 | std::string m_filename; 174 | std::vector m_data; 175 | std::map m_exif; 176 | Endianess_t m_format; 177 | 178 | void parseExif(); 179 | bool checkTagMark() const; 180 | 181 | size_t getFieldSize(FILE *f) const; 182 | size_t getNumDirEntry() const; 183 | uint32_t getStartOffset() const; 184 | uint16_t getExifTag(const size_t offset) const; 185 | uint16_t getU16(const size_t offset) const; 186 | uint32_t getU32(const size_t offset) const; 187 | uint16_t getOrientation(const size_t offset) const; 188 | uint16_t getResolutionUnit(const size_t offset) const; 189 | uint16_t getYCbCrPos(const size_t offset) const; 190 | 191 | Endianess_t getFormat() const; 192 | 193 | ExifEntry_t parseExifEntry(const size_t offset); 194 | 195 | u_rational_t getURational(const size_t offset) const; 196 | 197 | std::map getExif(); 198 | std::string getString(const size_t offset) const; 199 | std::vector getResolution(const size_t offset) const; 200 | std::vector getWhitePoint(const size_t offset) const; 201 | std::vector getPrimaryChromaticies(const size_t offset) const; 202 | std::vector getYCbCrCoeffs(const size_t offset) const; 203 | std::vector getRefBW(const size_t offset) const; 204 | 205 | private: 206 | static const uint16_t tagMarkRequired = 0x2A; 207 | 208 | // offset to the _number-of-directory-entry_ field 209 | static const size_t offsetNumDir = 8; 210 | 211 | // max size of data in tag. 212 | //'DDDDDDDD' contains the value of that Tag. If its size is over 4bytes, 213 | //'DDDDDDDD' contains the offset to data stored address. 214 | static const size_t maxDataSize = 4; 215 | 216 | // bytes per tag field 217 | static const size_t tiffFieldSize = 12; 218 | 219 | // number of primary chromaticies components 220 | static const size_t primaryChromaticiesComponents = 6; 221 | 222 | // number of YCbCr coefficients in field 223 | static const size_t ycbcrCoeffs = 3; 224 | 225 | // number of Reference Black&White components 226 | static const size_t refBWComponents = 6; 227 | }; 228 | } 229 | -------------------------------------------------------------------------------- /src/lycon/types/scalar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "lycon/defs.h" 4 | #include "lycon/mat/vec.h" 5 | #include "lycon/util/saturate_cast.h" 6 | 7 | namespace lycon 8 | { 9 | 10 | template class Scalar_ : public Vec<_Tp, 4> 11 | { 12 | public: 13 | //! various constructors 14 | Scalar_(); 15 | Scalar_(_Tp v0, _Tp v1, _Tp v2 = 0, _Tp v3 = 0); 16 | Scalar_(_Tp v0); 17 | 18 | template Scalar_(const Vec<_Tp2, cn> &v); 19 | 20 | //! returns a scalar with all elements set to v0 21 | static Scalar_<_Tp> all(_Tp v0); 22 | 23 | //! conversion to another data type 24 | template operator Scalar_() const; 25 | 26 | //! per-element product 27 | Scalar_<_Tp> mul(const Scalar_<_Tp> &a, double scale = 1) const; 28 | 29 | // returns (v0, -v1, -v2, -v3) 30 | Scalar_<_Tp> conj() const; 31 | 32 | // returns true iff v1 == v2 == v3 == 0 33 | bool isReal() const; 34 | }; 35 | 36 | typedef Scalar_ Scalar; 37 | 38 | template class DataType> 39 | { 40 | public: 41 | typedef Scalar_<_Tp> value_type; 42 | typedef Scalar_::work_type> work_type; 43 | typedef _Tp channel_type; 44 | 45 | enum 46 | { 47 | generic_type = 0, 48 | depth = DataType::depth, 49 | channels = 4, 50 | fmt = DataType::fmt + ((channels - 1) << 8), 51 | type = LYCON_MAKETYPE(depth, channels) 52 | }; 53 | 54 | typedef Vec vec_type; 55 | }; 56 | 57 | template inline Scalar_<_Tp>::Scalar_() 58 | { 59 | this->val[0] = this->val[1] = this->val[2] = this->val[3] = 0; 60 | } 61 | 62 | template inline Scalar_<_Tp>::Scalar_(_Tp v0, _Tp v1, _Tp v2, _Tp v3) 63 | { 64 | this->val[0] = v0; 65 | this->val[1] = v1; 66 | this->val[2] = v2; 67 | this->val[3] = v3; 68 | } 69 | 70 | template template inline Scalar_<_Tp>::Scalar_(const Vec<_Tp2, cn> &v) 71 | { 72 | int i; 73 | for (i = 0; i < (cn < 4 ? cn : 4); i++) 74 | this->val[i] = saturate_cast<_Tp>(v.val[i]); 75 | for (; i < 4; i++) 76 | this->val[i] = 0; 77 | } 78 | 79 | template inline Scalar_<_Tp>::Scalar_(_Tp v0) 80 | { 81 | this->val[0] = v0; 82 | this->val[1] = this->val[2] = this->val[3] = 0; 83 | } 84 | 85 | template inline Scalar_<_Tp> Scalar_<_Tp>::all(_Tp v0) 86 | { 87 | return Scalar_<_Tp>(v0, v0, v0, v0); 88 | } 89 | 90 | template inline Scalar_<_Tp> Scalar_<_Tp>::mul(const Scalar_<_Tp> &a, double scale) const 91 | { 92 | return Scalar_<_Tp>(saturate_cast<_Tp>(this->val[0] * a.val[0] * scale), saturate_cast<_Tp>(this->val[1] * a.val[1] * scale), saturate_cast<_Tp>(this->val[2] * a.val[2] * scale), 93 | saturate_cast<_Tp>(this->val[3] * a.val[3] * scale)); 94 | } 95 | 96 | template inline Scalar_<_Tp> Scalar_<_Tp>::conj() const 97 | { 98 | return Scalar_<_Tp>(saturate_cast<_Tp>(this->val[0]), saturate_cast<_Tp>(-this->val[1]), saturate_cast<_Tp>(-this->val[2]), saturate_cast<_Tp>(-this->val[3])); 99 | } 100 | 101 | template inline bool Scalar_<_Tp>::isReal() const 102 | { 103 | return this->val[1] == 0 && this->val[2] == 0 && this->val[3] == 0; 104 | } 105 | 106 | template template inline Scalar_<_Tp>::operator Scalar_() const 107 | { 108 | return Scalar_(saturate_cast(this->val[0]), saturate_cast(this->val[1]), saturate_cast(this->val[2]), saturate_cast(this->val[3])); 109 | } 110 | 111 | template static inline Scalar_<_Tp> &operator+=(Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 112 | { 113 | a.val[0] += b.val[0]; 114 | a.val[1] += b.val[1]; 115 | a.val[2] += b.val[2]; 116 | a.val[3] += b.val[3]; 117 | return a; 118 | } 119 | 120 | template static inline Scalar_<_Tp> &operator-=(Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 121 | { 122 | a.val[0] -= b.val[0]; 123 | a.val[1] -= b.val[1]; 124 | a.val[2] -= b.val[2]; 125 | a.val[3] -= b.val[3]; 126 | return a; 127 | } 128 | 129 | template static inline Scalar_<_Tp> &operator*=(Scalar_<_Tp> &a, _Tp v) 130 | { 131 | a.val[0] *= v; 132 | a.val[1] *= v; 133 | a.val[2] *= v; 134 | a.val[3] *= v; 135 | return a; 136 | } 137 | 138 | template static inline bool operator==(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 139 | { 140 | return a.val[0] == b.val[0] && a.val[1] == b.val[1] && a.val[2] == b.val[2] && a.val[3] == b.val[3]; 141 | } 142 | 143 | template static inline bool operator!=(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 144 | { 145 | return a.val[0] != b.val[0] || a.val[1] != b.val[1] || a.val[2] != b.val[2] || a.val[3] != b.val[3]; 146 | } 147 | 148 | template static inline Scalar_<_Tp> operator+(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 149 | { 150 | return Scalar_<_Tp>(a.val[0] + b.val[0], a.val[1] + b.val[1], a.val[2] + b.val[2], a.val[3] + b.val[3]); 151 | } 152 | 153 | template static inline Scalar_<_Tp> operator-(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 154 | { 155 | return Scalar_<_Tp>(saturate_cast<_Tp>(a.val[0] - b.val[0]), saturate_cast<_Tp>(a.val[1] - b.val[1]), saturate_cast<_Tp>(a.val[2] - b.val[2]), saturate_cast<_Tp>(a.val[3] - b.val[3])); 156 | } 157 | 158 | template static inline Scalar_<_Tp> operator*(const Scalar_<_Tp> &a, _Tp alpha) 159 | { 160 | return Scalar_<_Tp>(a.val[0] * alpha, a.val[1] * alpha, a.val[2] * alpha, a.val[3] * alpha); 161 | } 162 | 163 | template static inline Scalar_<_Tp> operator*(_Tp alpha, const Scalar_<_Tp> &a) 164 | { 165 | return a * alpha; 166 | } 167 | 168 | template static inline Scalar_<_Tp> operator-(const Scalar_<_Tp> &a) 169 | { 170 | return Scalar_<_Tp>(saturate_cast<_Tp>(-a.val[0]), saturate_cast<_Tp>(-a.val[1]), saturate_cast<_Tp>(-a.val[2]), saturate_cast<_Tp>(-a.val[3])); 171 | } 172 | 173 | template static inline Scalar_<_Tp> operator*(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 174 | { 175 | return Scalar_<_Tp>(saturate_cast<_Tp>(a[0] * b[0] - a[1] * b[1] - a[2] * b[2] - a[3] * b[3]), saturate_cast<_Tp>(a[0] * b[1] + a[1] * b[0] + a[2] * b[3] - a[3] * b[2]), 176 | saturate_cast<_Tp>(a[0] * b[2] - a[1] * b[3] + a[2] * b[0] + a[3] * b[1]), saturate_cast<_Tp>(a[0] * b[3] + a[1] * b[2] - a[2] * b[1] + a[3] * b[0])); 177 | } 178 | 179 | template static inline Scalar_<_Tp> &operator*=(Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 180 | { 181 | a = a * b; 182 | return a; 183 | } 184 | 185 | template static inline Scalar_<_Tp> operator/(const Scalar_<_Tp> &a, _Tp alpha) 186 | { 187 | return Scalar_<_Tp>(a.val[0] / alpha, a.val[1] / alpha, a.val[2] / alpha, a.val[3] / alpha); 188 | } 189 | 190 | template static inline Scalar_ operator/(const Scalar_ &a, float alpha) 191 | { 192 | float s = 1 / alpha; 193 | return Scalar_(a.val[0] * s, a.val[1] * s, a.val[2] * s, a.val[3] * s); 194 | } 195 | 196 | template static inline Scalar_ operator/(const Scalar_ &a, double alpha) 197 | { 198 | double s = 1 / alpha; 199 | return Scalar_(a.val[0] * s, a.val[1] * s, a.val[2] * s, a.val[3] * s); 200 | } 201 | 202 | template static inline Scalar_<_Tp> &operator/=(Scalar_<_Tp> &a, _Tp alpha) 203 | { 204 | a = a / alpha; 205 | return a; 206 | } 207 | 208 | template static inline Scalar_<_Tp> operator/(_Tp a, const Scalar_<_Tp> &b) 209 | { 210 | _Tp s = a / (b[0] * b[0] + b[1] * b[1] + b[2] * b[2] + b[3] * b[3]); 211 | return b.conj() * s; 212 | } 213 | 214 | template static inline Scalar_<_Tp> operator/(const Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 215 | { 216 | return a * ((_Tp)1 / b); 217 | } 218 | 219 | template static inline Scalar_<_Tp> &operator/=(Scalar_<_Tp> &a, const Scalar_<_Tp> &b) 220 | { 221 | a = a / b; 222 | return a; 223 | } 224 | 225 | template static inline Scalar operator*(const Matx<_Tp, 4, 4> &a, const Scalar &b) 226 | { 227 | Matx c((Matx)a, b, Matx_MatMulOp()); 228 | return reinterpret_cast(c); 229 | } 230 | 231 | template <> inline Scalar operator*(const Matx &a, const Scalar &b) 232 | { 233 | Matx c(a, b, Matx_MatMulOp()); 234 | return reinterpret_cast(c); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /src/lycon/util/tls.cc: -------------------------------------------------------------------------------- 1 | #include "lycon/util/tls.h" 2 | 3 | #include 4 | 5 | #include "lycon/util/error.h" 6 | #include "lycon/util/singleton.h" 7 | 8 | namespace lycon 9 | { 10 | #ifdef WIN32 11 | #ifdef _MSC_VER 12 | #pragma warning(disable : 4505) // unreferenced local function has been removed 13 | #endif 14 | #ifndef TLS_OUT_OF_INDEXES 15 | #define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF) 16 | #endif 17 | #endif 18 | 19 | // TLS platform abstraction layer 20 | class TlsAbstraction 21 | { 22 | public: 23 | TlsAbstraction(); 24 | ~TlsAbstraction(); 25 | void* GetData() const; 26 | void SetData(void* pData); 27 | 28 | private: 29 | #ifdef WIN32 30 | #ifndef WINRT 31 | DWORD tlsKey; 32 | #endif 33 | #else // WIN32 34 | pthread_key_t tlsKey; 35 | #endif 36 | }; 37 | 38 | #ifdef WIN32 39 | #ifdef WINRT 40 | static __declspec(thread) void* tlsData = NULL; // using C++11 thread attribute for local thread data 41 | TlsAbstraction::TlsAbstraction() 42 | { 43 | } 44 | TlsAbstraction::~TlsAbstraction() 45 | { 46 | } 47 | void* TlsAbstraction::GetData() const 48 | { 49 | return tlsData; 50 | } 51 | void TlsAbstraction::SetData(void* pData) 52 | { 53 | tlsData = pData; 54 | } 55 | #else // WINRT 56 | TlsAbstraction::TlsAbstraction() 57 | { 58 | tlsKey = TlsAlloc(); 59 | LYCON_ASSERT(tlsKey != TLS_OUT_OF_INDEXES); 60 | } 61 | TlsAbstraction::~TlsAbstraction() 62 | { 63 | TlsFree(tlsKey); 64 | } 65 | void* TlsAbstraction::GetData() const 66 | { 67 | return TlsGetValue(tlsKey); 68 | } 69 | void TlsAbstraction::SetData(void* pData) 70 | { 71 | LYCON_ASSERT(TlsSetValue(tlsKey, pData) == TRUE); 72 | } 73 | #endif 74 | #else // WIN32 75 | TlsAbstraction::TlsAbstraction() 76 | { 77 | LYCON_ASSERT(pthread_key_create(&tlsKey, NULL) == 0); 78 | } 79 | TlsAbstraction::~TlsAbstraction() 80 | { 81 | LYCON_ASSERT(pthread_key_delete(tlsKey) == 0); 82 | } 83 | void* TlsAbstraction::GetData() const 84 | { 85 | return pthread_getspecific(tlsKey); 86 | } 87 | void TlsAbstraction::SetData(void* pData) 88 | { 89 | LYCON_ASSERT(pthread_setspecific(tlsKey, pData) == 0); 90 | } 91 | #endif 92 | 93 | // Per-thread data structure 94 | struct ThreadData 95 | { 96 | ThreadData() 97 | { 98 | idx = 0; 99 | slots.reserve(32); 100 | } 101 | 102 | std::vector slots; // Data array for a thread 103 | size_t idx; // Thread index in TLS storage. This is not OS thread ID! 104 | }; 105 | 106 | // Main TLS storage class 107 | class TlsStorage 108 | { 109 | public: 110 | TlsStorage() 111 | { 112 | tlsSlots.reserve(32); 113 | threads.reserve(32); 114 | } 115 | ~TlsStorage() 116 | { 117 | for (size_t i = 0; i < threads.size(); i++) 118 | { 119 | if (threads[i]) 120 | { 121 | /* Current architecture doesn't allow proper global objects relase, so this check can cause crashes 122 | 123 | // Check if all slots were properly cleared 124 | for(size_t j = 0; j < threads[i]->slots.size(); j++) 125 | { 126 | LYCON_ASSERT(threads[i]->slots[j] == 0); 127 | } 128 | */ 129 | delete threads[i]; 130 | } 131 | } 132 | threads.clear(); 133 | } 134 | 135 | void releaseThread() 136 | { 137 | // std::lock_guard guard(mtxGlobalAccess); 138 | ThreadData* pTD = (ThreadData*)tls.GetData(); 139 | for (size_t i = 0; i < threads.size(); i++) 140 | { 141 | if (pTD == threads[i]) 142 | { 143 | threads[i] = 0; 144 | break; 145 | } 146 | } 147 | tls.SetData(0); 148 | delete pTD; 149 | } 150 | 151 | // Reserve TLS storage index 152 | size_t reserveSlot() 153 | { 154 | // std::lock_guard guard(mtxGlobalAccess); 155 | 156 | // Find unused slots 157 | for (size_t slot = 0; slot < tlsSlots.size(); slot++) 158 | { 159 | if (!tlsSlots[slot]) 160 | { 161 | tlsSlots[slot] = 1; 162 | return slot; 163 | } 164 | } 165 | 166 | // Create new slot 167 | tlsSlots.push_back(1); 168 | return (tlsSlots.size() - 1); 169 | } 170 | 171 | // Release TLS storage index and pass assosiated data to caller 172 | void releaseSlot(size_t slotIdx, std::vector& dataVec) 173 | { 174 | // std::lock_guard guard(mtxGlobalAccess); 175 | LYCON_ASSERT(tlsSlots.size() > slotIdx); 176 | 177 | for (size_t i = 0; i < threads.size(); i++) 178 | { 179 | if (threads[i]) 180 | { 181 | std::vector& thread_slots = threads[i]->slots; 182 | if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) 183 | { 184 | dataVec.push_back(thread_slots[slotIdx]); 185 | threads[i]->slots[slotIdx] = 0; 186 | } 187 | } 188 | } 189 | 190 | tlsSlots[slotIdx] = 0; 191 | } 192 | 193 | // Get data by TLS storage index 194 | void* getData(size_t slotIdx) const 195 | { 196 | LYCON_ASSERT(tlsSlots.size() > slotIdx); 197 | 198 | ThreadData* threadData = (ThreadData*)tls.GetData(); 199 | if (threadData && threadData->slots.size() > slotIdx) 200 | return threadData->slots[slotIdx]; 201 | 202 | return NULL; 203 | } 204 | 205 | // Gather data from threads by TLS storage index 206 | void gather(size_t slotIdx, std::vector& dataVec) 207 | { 208 | // std::lock_guard guard(mtxGlobalAccess); 209 | LYCON_ASSERT(tlsSlots.size() > slotIdx); 210 | 211 | for (size_t i = 0; i < threads.size(); i++) 212 | { 213 | if (threads[i]) 214 | { 215 | std::vector& thread_slots = threads[i]->slots; 216 | if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) 217 | dataVec.push_back(thread_slots[slotIdx]); 218 | } 219 | } 220 | } 221 | 222 | // Set data to storage index 223 | void setData(size_t slotIdx, void* pData) 224 | { 225 | LYCON_ASSERT(tlsSlots.size() > slotIdx && pData != NULL); 226 | 227 | ThreadData* threadData = (ThreadData*)tls.GetData(); 228 | if (!threadData) 229 | { 230 | threadData = new ThreadData; 231 | tls.SetData((void*)threadData); 232 | { 233 | // std::lock_guard guard(mtxGlobalAccess); 234 | threadData->idx = threads.size(); 235 | threads.push_back(threadData); 236 | } 237 | } 238 | 239 | if (slotIdx >= threadData->slots.size()) 240 | { 241 | // std::lock_guard guard(mtxGlobalAccess); 242 | while (slotIdx >= threadData->slots.size()) 243 | threadData->slots.push_back(NULL); 244 | } 245 | threadData->slots[slotIdx] = pData; 246 | } 247 | 248 | private: 249 | // TLS abstraction layer instance 250 | TlsAbstraction tls; 251 | 252 | // Shared objects operation guard 253 | std::mutex mtxGlobalAccess; 254 | 255 | // TLS keys state 256 | std::vector tlsSlots; 257 | 258 | // Array for all allocated data. Thread data pointers are placed here to allow data cleanup 259 | std::vector threads; 260 | }; 261 | 262 | // Create global TLS storage object 263 | static TlsStorage& getTlsStorage() 264 | { 265 | LYCON_SINGLETON_LAZY_INIT_REF(TlsStorage, new TlsStorage()) 266 | } 267 | 268 | TLSDataContainer::TLSDataContainer() 269 | { 270 | key_ = (int)getTlsStorage().reserveSlot(); // Reserve key from TLS storage 271 | } 272 | 273 | TLSDataContainer::~TLSDataContainer() 274 | { 275 | LYCON_ASSERT(key_ == -1); // Key must be released in child object 276 | } 277 | 278 | void TLSDataContainer::gatherData(std::vector& data) const 279 | { 280 | getTlsStorage().gather(key_, data); 281 | } 282 | 283 | void TLSDataContainer::release() 284 | { 285 | std::vector data; 286 | data.reserve(32); 287 | getTlsStorage().releaseSlot(key_, data); // Release key and get stored data for proper destruction 288 | for (size_t i = 0; i < data.size(); i++) // Delete all assosiated data 289 | deleteDataInstance(data[i]); 290 | key_ = -1; 291 | } 292 | 293 | void* TLSDataContainer::getData() const 294 | { 295 | void* pData = getTlsStorage().getData(key_); // Check if data was already allocated 296 | if (!pData) 297 | { 298 | // Create new data instance and save it to TLS storage 299 | pData = createDataInstance(); 300 | getTlsStorage().setData(key_, pData); 301 | } 302 | return pData; 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /src/lycon/mat/io_array_impl.h: -------------------------------------------------------------------------------- 1 | inline void _InputArray::init(int _flags, const void *_obj) 2 | { 3 | flags = _flags; 4 | obj = (void *)_obj; 5 | } 6 | 7 | inline void _InputArray::init(int _flags, const void *_obj, Size _sz) 8 | { 9 | flags = _flags; 10 | obj = (void *)_obj; 11 | sz = _sz; 12 | } 13 | 14 | inline void *_InputArray::getObj() const { return obj; } 15 | inline int _InputArray::getFlags() const { return flags; } 16 | inline Size _InputArray::getSz() const { return sz; } 17 | 18 | inline _InputArray::_InputArray() { init(NONE, 0); } 19 | inline _InputArray::_InputArray(int _flags, void *_obj) { init(_flags, _obj); } 20 | inline _InputArray::_InputArray(const Mat &m) { init(MAT + ACCESS_READ, &m); } 21 | inline _InputArray::_InputArray(const std::vector &vec) { init(STD_VECTOR_MAT + ACCESS_READ, &vec); } 22 | 23 | template 24 | inline _InputArray::_InputArray(const std::vector<_Tp> &vec) 25 | { 26 | init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); 27 | } 28 | 29 | inline _InputArray::_InputArray(const std::vector &vec) 30 | { 31 | init(FIXED_TYPE + STD_BOOL_VECTOR + DataType::type + ACCESS_READ, &vec); 32 | } 33 | 34 | template 35 | inline _InputArray::_InputArray(const std::vector> &vec) 36 | { 37 | init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_READ, &vec); 38 | } 39 | 40 | template 41 | inline _InputArray::_InputArray(const std::vector> &vec) 42 | { 43 | init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_READ, &vec); 44 | } 45 | 46 | template 47 | inline _InputArray::_InputArray(const Matx<_Tp, m, n> &mtx) 48 | { 49 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, &mtx, Size(n, m)); 50 | } 51 | 52 | template 53 | inline _InputArray::_InputArray(const _Tp *vec, int n) 54 | { 55 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_READ, vec, Size(n, 1)); 56 | } 57 | 58 | template 59 | inline _InputArray::_InputArray(const Mat_<_Tp> &m) 60 | { 61 | init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_READ, &m); 62 | } 63 | 64 | inline _InputArray::_InputArray(const double &val) 65 | { 66 | init(FIXED_TYPE + FIXED_SIZE + MATX + LYCON_64F + ACCESS_READ, &val, Size(1, 1)); 67 | } 68 | 69 | inline _InputArray::~_InputArray() {} 70 | 71 | inline Mat _InputArray::getMat(int i) const 72 | { 73 | if (kind() == MAT && i < 0) return *(const Mat *)obj; 74 | return getMat_(i); 75 | } 76 | 77 | inline bool _InputArray::isMat() const { return kind() == _InputArray::MAT; } 78 | 79 | inline bool _InputArray::isMatVector() const { return kind() == _InputArray::STD_VECTOR_MAT; } 80 | 81 | inline bool _InputArray::isMatx() const { return kind() == _InputArray::MATX; } 82 | inline bool _InputArray::isVector() const 83 | { 84 | return kind() == _InputArray::STD_VECTOR || kind() == _InputArray::STD_BOOL_VECTOR; 85 | } 86 | 87 | //////////////////////////////////////////////////////////////////////////////////////// 88 | 89 | inline _OutputArray::_OutputArray() { init(ACCESS_WRITE, 0); } 90 | inline _OutputArray::_OutputArray(int _flags, void *_obj) { init(_flags | ACCESS_WRITE, _obj); } 91 | inline _OutputArray::_OutputArray(Mat &m) { init(MAT + ACCESS_WRITE, &m); } 92 | inline _OutputArray::_OutputArray(std::vector &vec) { init(STD_VECTOR_MAT + ACCESS_WRITE, &vec); } 93 | 94 | template 95 | inline _OutputArray::_OutputArray(std::vector<_Tp> &vec) 96 | { 97 | init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); 98 | } 99 | 100 | inline _OutputArray::_OutputArray(std::vector &) { LYCON_ERROR("std::vector cannot be an output array\n"); } 101 | 102 | template 103 | inline _OutputArray::_OutputArray(std::vector> &vec) 104 | { 105 | init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); 106 | } 107 | 108 | template 109 | inline _OutputArray::_OutputArray(std::vector> &vec) 110 | { 111 | init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); 112 | } 113 | 114 | template 115 | inline _OutputArray::_OutputArray(Mat_<_Tp> &m) 116 | { 117 | init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); 118 | } 119 | 120 | template 121 | inline _OutputArray::_OutputArray(Matx<_Tp, m, n> &mtx) 122 | { 123 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); 124 | } 125 | 126 | template 127 | inline _OutputArray::_OutputArray(_Tp *vec, int n) 128 | { 129 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); 130 | } 131 | 132 | template 133 | inline _OutputArray::_OutputArray(const std::vector<_Tp> &vec) 134 | { 135 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); 136 | } 137 | 138 | template 139 | inline _OutputArray::_OutputArray(const std::vector> &vec) 140 | { 141 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_WRITE, &vec); 142 | } 143 | 144 | template 145 | inline _OutputArray::_OutputArray(const std::vector> &vec) 146 | { 147 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_WRITE, &vec); 148 | } 149 | 150 | template 151 | inline _OutputArray::_OutputArray(const Mat_<_Tp> &m) 152 | { 153 | init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_WRITE, &m); 154 | } 155 | 156 | template 157 | inline _OutputArray::_OutputArray(const Matx<_Tp, m, n> &mtx) 158 | { 159 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, &mtx, Size(n, m)); 160 | } 161 | 162 | template 163 | inline _OutputArray::_OutputArray(const _Tp *vec, int n) 164 | { 165 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_WRITE, vec, Size(n, 1)); 166 | } 167 | 168 | inline _OutputArray::_OutputArray(const Mat &m) { init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_WRITE, &m); } 169 | 170 | inline _OutputArray::_OutputArray(const std::vector &vec) 171 | { 172 | init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_WRITE, &vec); 173 | } 174 | 175 | /////////////////////////////////////////////////////////////////////////////////////////// 176 | 177 | inline _InputOutputArray::_InputOutputArray() { init(ACCESS_RW, 0); } 178 | inline _InputOutputArray::_InputOutputArray(int _flags, void *_obj) { init(_flags | ACCESS_RW, _obj); } 179 | inline _InputOutputArray::_InputOutputArray(Mat &m) { init(MAT + ACCESS_RW, &m); } 180 | inline _InputOutputArray::_InputOutputArray(std::vector &vec) { init(STD_VECTOR_MAT + ACCESS_RW, &vec); } 181 | template 182 | inline _InputOutputArray::_InputOutputArray(std::vector<_Tp> &vec) 183 | { 184 | init(FIXED_TYPE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); 185 | } 186 | 187 | inline _InputOutputArray::_InputOutputArray(std::vector &) 188 | { 189 | LYCON_ERROR("std::vector cannot be an input/output array\n"); 190 | } 191 | 192 | template 193 | inline _InputOutputArray::_InputOutputArray(std::vector> &vec) 194 | { 195 | init(FIXED_TYPE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); 196 | } 197 | 198 | template 199 | inline _InputOutputArray::_InputOutputArray(std::vector> &vec) 200 | { 201 | init(FIXED_TYPE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); 202 | } 203 | 204 | template 205 | inline _InputOutputArray::_InputOutputArray(Mat_<_Tp> &m) 206 | { 207 | init(FIXED_TYPE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); 208 | } 209 | 210 | template 211 | inline _InputOutputArray::_InputOutputArray(Matx<_Tp, m, n> &mtx) 212 | { 213 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); 214 | } 215 | 216 | template 217 | inline _InputOutputArray::_InputOutputArray(_Tp *vec, int n) 218 | { 219 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); 220 | } 221 | 222 | template 223 | inline _InputOutputArray::_InputOutputArray(const std::vector<_Tp> &vec) 224 | { 225 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); 226 | } 227 | 228 | template 229 | inline _InputOutputArray::_InputOutputArray(const std::vector> &vec) 230 | { 231 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_VECTOR + DataType<_Tp>::type + ACCESS_RW, &vec); 232 | } 233 | 234 | template 235 | inline _InputOutputArray::_InputOutputArray(const std::vector> &vec) 236 | { 237 | init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_MAT + DataType<_Tp>::type + ACCESS_RW, &vec); 238 | } 239 | 240 | template 241 | inline _InputOutputArray::_InputOutputArray(const Mat_<_Tp> &m) 242 | { 243 | init(FIXED_TYPE + FIXED_SIZE + MAT + DataType<_Tp>::type + ACCESS_RW, &m); 244 | } 245 | 246 | template 247 | inline _InputOutputArray::_InputOutputArray(const Matx<_Tp, m, n> &mtx) 248 | { 249 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, &mtx, Size(n, m)); 250 | } 251 | 252 | template 253 | inline _InputOutputArray::_InputOutputArray(const _Tp *vec, int n) 254 | { 255 | init(FIXED_TYPE + FIXED_SIZE + MATX + DataType<_Tp>::type + ACCESS_RW, vec, Size(n, 1)); 256 | } 257 | 258 | inline _InputOutputArray::_InputOutputArray(const Mat &m) { init(FIXED_TYPE + FIXED_SIZE + MAT + ACCESS_RW, &m); } 259 | 260 | inline _InputOutputArray::_InputOutputArray(const std::vector &vec) 261 | { 262 | init(FIXED_SIZE + STD_VECTOR_MAT + ACCESS_RW, &vec); 263 | } 264 | --------------------------------------------------------------------------------