From de6356ebfa159a320e48b49f8b7d7d773904330b Mon Sep 17 00:00:00 2001 From: xulei2020 Date: Tue, 5 Jan 2021 10:48:44 +0800 Subject: [PATCH] add warp affine --- .../kernels/image/lite_cv/CMakeLists.txt | 1 + .../kernels/image/lite_cv/image_process.cc | 104 +++- .../kernels/image/lite_cv/image_process.h | 24 +- .../dataset/kernels/image/lite_cv/lite_mat.cc | 54 +- .../dataset/kernels/image/lite_cv/lite_mat.h | 18 + .../kernels/image/lite_cv/warp_affine.cc | 522 ++++++++++++++++++ tests/ut/cpp/dataset/image_process_test.cc | 327 ++++++++++- 7 files changed, 1030 insertions(+), 20 deletions(-) create mode 100644 mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/warp_affine.cc diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/CMakeLists.txt b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/CMakeLists.txt index 3b3170702a8..71adc49cd5f 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/CMakeLists.txt +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/CMakeLists.txt @@ -2,4 +2,5 @@ file(GLOB_RECURSE _CURRENT_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc" set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD) add_library(lite-cv OBJECT image_process.cc + warp_affine.cc lite_mat.cc) \ No newline at end of file diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.cc b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.cc index db7142b4791..f6779d2f84b 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.cc +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.cc @@ -28,11 +28,34 @@ #endif #endif +#ifdef PLATFORM_ARM64 +#define R2GRAY 9798 +#define G2GRAY 19235 +#define B2GRAY 3735 +#define GRAYSHIFT 15 +#define GRAYSHIFT_DELTA (1 << (GRAYSHIFT - 1)) +#else +#define R2GRAY 77 +#define G2GRAY 150 +#define B2GRAY 29 +#define GRAYSHIFT 8 +#endif + +#define YSCALE 0x0101 +#define UTOB (-128) +#define UTOG 25 +#define VTOR (-102) +#define VTOG 52 +#define YTOG 18997 +#define YTOGB (-1160) +#define BTOB (UTOB * 128 + YTOGB) +#define BTOG (UTOG * 128 + VTOG * 128 + YTOGB) +#define BTOR (VTOR * 128 + YTOGB) +#define Equ(a, b) ((std::fabs((a) - (b)) < 1e-6)) + namespace mindspore { namespace dataset { -#define Equ(a, b) ((std::fabs((a) - (b)) < 1e-6)) - static inline void InitBilinearWeight(int *data_ptr, int16_t *weight_ptr, double scale, int dst_length, int src_length, int a) { const int RESIZE_SCALE = 1 << 11; @@ -374,6 +397,79 @@ static bool ConvertYUV420SPToBGR(const uint8_t *data, LDataType data_type, bool return true; } +#ifdef PLATFORM_ARM64 +static uint8x8_t RGBToGray(const uint16x8_t &r_value, const uint16x8_t &g_value, const uint16x8_t &b_value, + const uint16x4_t &r2y_value, const uint16x4_t &g2y_value, const uint16x4_t &b2y_value) { + uint32x4_t dst0_value = vmull_u16(vget_low_u16(g_value), g2y_value); + uint32x4_t dst1_value = vmull_u16(vget_high_u16(g_value), g2y_value); + + dst0_value = vmlal_u16(dst0_value, vget_low_u16(r_value), r2y_value); + dst1_value = vmlal_u16(dst1_value, vget_high_u16(r_value), r2y_value); + + dst0_value = vmlal_u16(dst0_value, vget_low_u16(b_value), b2y_value); + dst1_value = vmlal_u16(dst1_value, vget_high_u16(b_value), b2y_value); + + uint8x8_t v_gray = vqmovn_u16(vcombine_u16(vrshrn_n_u32(dst0_value, GRAYSHIFT), vrshrn_n_u32(dst1_value, GRAYSHIFT))); + + return v_gray; +} + +static bool ConvertRGBAToGRAY_Neon(const uint8_t *srcBase, uint8_t *dstBase, int w, int h) { + const uint32_t r_to_gray = R2GRAY; + const uint32_t g_to_gray = G2GRAY; + const uint32_t b_to_gray = B2GRAY; + + uint16x4_t r2y_value = vdup_n_u16(R2GRAY); + uint16x4_t g2y_value = vdup_n_u16(G2GRAY); + uint16x4_t b2y_value = vdup_n_u16(B2GRAY); + + size_t w16b = w >= 15 ? w - 15 : 0; + size_t w8b = w >= 7 ? w - 7 : 0; + + for (size_t i = 0; i < h; ++i) { + const uint8_t *src_ptr = srcBase + w * i * 4; + uint8_t *dst_ptr = dstBase + w * i * 4; + size_t src_j = 0u; + size_t dst_j = 0u; + + for (; dst_j < w16b; src_j += 64, dst_j += 16) { + uint8x16x4_t src_value0 = vld4q_u8(src_ptr + src_j); + + // 0 + uint16x8_t r_value = vmovl_u8(vget_low_u8(src_value0.val[0])); + uint16x8_t g_value = vmovl_u8(vget_low_u8(src_value0.val[1])); + uint16x8_t b_value = vmovl_u8(vget_low_u8(src_value0.val[2])); + uint8x8_t gray_value0 = RGBToGray(r_value, g_value, b_value, r2y_value, g2y_value, b2y_value); + + r_value = vmovl_u8(vget_high_u8(src_value0.val[0])); + g_value = vmovl_u8(vget_high_u8(src_value0.val[1])); + b_value = vmovl_u8(vget_high_u8(src_value0.val[2])); + uint8x8_t gray_value1 = RGBToGray(r_value, g_value, b_value, r2y_value, g2y_value, b2y_value); + + vst1q_u8(dst_ptr + dst_j, vcombine_u8(gray_value0, gray_value1)); + } + + if (dst_j < w8b) { + uint8x8x4_t v_src = vld4_u8(src_ptr + src_j); + uint16x8_t r_value = vmovl_u8(v_src.val[0]); + uint16x8_t g_value = vmovl_u8(v_src.val[1]); + uint16x8_t b_value = vmovl_u8(v_src.val[2]); + uint8x8_t gray_value = RGBToGray(r_value, g_value, b_value, r2y_value, g2y_value, b2y_value); + + vst1_u8(dst_ptr + dst_j, gray_value); + src_j += 32; + dst_j += 8; + } + + for (; dst_j < w; src_j += 4, dst_j++) { + uint32_t val = src_ptr[src_j] * r_to_gray + src_ptr[src_j + 1] * g_to_gray + src_ptr[src_j + 2] * b_to_gray; + dst_ptr[dst_j] = U32TOU8CAST((val + GRAYSHIFT_DELTA) >> GRAYSHIFT); + } + } + return true; +} +#endif + static bool ConvertRGBAToGRAY(const unsigned char *data, LDataType data_type, int w, int h, LiteMat &mat) { if (data_type == LDataType::UINT8) { mat.Init(w, h, 1, LDataType::UINT8); @@ -382,6 +478,9 @@ static bool ConvertRGBAToGRAY(const unsigned char *data, LDataType data_type, in } unsigned char *ptr = mat; const unsigned char *data_ptr = data; +#ifdef PLATFORM_ARM64 + ConvertRGBAToGRAY_Neon(data_ptr, ptr, w, h); +#else for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { *ptr = (data_ptr[2] * B2GRAY + data_ptr[1] * G2GRAY + data_ptr[0] * R2GRAY) >> GRAYSHIFT; @@ -389,6 +488,7 @@ static bool ConvertRGBAToGRAY(const unsigned char *data, LDataType data_type, in data_ptr += 4; } } +#endif } else { return false; } diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.h b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.h index 69a3e39d71b..c16ccbbfae2 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.h +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/image_process.h @@ -30,22 +30,6 @@ namespace dataset { #define INT16_CAST(X) \ static_cast(::std::min(::std::max(static_cast(X + (X >= 0.f ? 0.5f : -0.5f)), -32768), 32767)); -#define R2GRAY 77 -#define G2GRAY 150 -#define B2GRAY 29 -#define GRAYSHIFT 8 - -#define YSCALE 0x0101 -#define UTOB (-128) -#define UTOG 25 -#define VTOR (-102) -#define VTOG 52 -#define YTOG 18997 -#define YTOGB (-1160) -#define BTOB (UTOB * 128 + YTOGB) -#define BTOG (UTOG * 128 + VTOG * 128 + YTOGB) -#define BTOR (VTOR * 128 + YTOGB) - enum PaddBorderType { PADD_BORDER_CONSTANT = 0, PADD_BORDER_REPLICATE = 1 }; struct BoxesConfig { @@ -107,6 +91,14 @@ void ConvertBoxes(std::vector> &boxes, const std::vector ApplyNms(const std::vector> &all_boxes, std::vector &all_scores, float thres, int max_boxes); +/// \brief affine image by linear +bool WarpAffineBilinear(const LiteMat &src, LiteMat &dst, const LiteMat &M, int dst_w, int dst_h, + PaddBorderType borderType, std::vector &borderValue); + +/// \brief perspective image by linear +bool WarpPerspectiveBilinear(const LiteMat &src, LiteMat &dst, const LiteMat &M, int dst_w, int dst_h, + PaddBorderType borderType, std::vector &borderValue); + } // namespace dataset } // namespace mindspore #endif // IMAGE_PROCESS_H_ diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.cc b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.cc index a1e42ce9b29..c587f9ad358 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.cc +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.cc @@ -39,6 +39,7 @@ LiteMat::LiteMat() { size_ = 0; data_type_ = LDataType::UINT8; ref_count_ = nullptr; + setSteps(0, 0, 0); } LiteMat::LiteMat(int width, LDataType data_type) { @@ -52,6 +53,7 @@ LiteMat::LiteMat(int width, LDataType data_type) { data_type_ = LDataType::UINT8; ref_count_ = nullptr; size_ = 0; + setSteps(0, 0, 0); Init(width, data_type); } @@ -66,6 +68,7 @@ LiteMat::LiteMat(int width, int height, LDataType data_type) { data_type_ = LDataType::UINT8; ref_count_ = nullptr; size_ = 0; + setSteps(0, 0, 0); Init(width, height, data_type); } @@ -80,6 +83,7 @@ LiteMat::LiteMat(int width, int height, void *p_data, LDataType data_type) { data_type_ = LDataType::UINT8; ref_count_ = nullptr; size_ = 0; + setSteps(0, 0, 0); Init(width, height, p_data, data_type); } @@ -94,6 +98,7 @@ LiteMat::LiteMat(int width, int height, int channel, LDataType data_type) { data_type_ = LDataType::UINT8; ref_count_ = nullptr; size_ = 0; + setSteps(0, 0, 0); Init(width, height, channel, data_type); } @@ -108,6 +113,7 @@ LiteMat::LiteMat(int width, int height, int channel, void *p_data, LDataType dat data_type_ = LDataType::UINT8; ref_count_ = nullptr; size_ = 0; + setSteps(0, 0, 0); Init(width, height, channel, p_data, data_type); } @@ -130,11 +136,18 @@ LiteMat::LiteMat(const LiteMat &m) { data_type_ = m.data_type_; ref_count_ = m.ref_count_; size_ = 0; + setSteps(m.steps_[0], m.steps_[1], m.steps_[2]); if (ref_count_) { addRef(ref_count_, 1); } } +void LiteMat::setSteps(int c0, int c1, int c2) { + steps_[0] = c0; + steps_[1] = c1; + steps_[2] = c2; +} + LiteMat &LiteMat::operator=(const LiteMat &m) { if (this == &m) { return *this; @@ -154,7 +167,8 @@ LiteMat &LiteMat::operator=(const LiteMat &m) { dims_ = m.dims_; data_type_ = m.data_type_; ref_count_ = m.ref_count_; - size_ = 0; + setSteps(m.steps_[0], m.steps_[1], m.steps_[2]); + size_ = m.size_; return *this; } @@ -171,6 +185,7 @@ void LiteMat::Init(int width, LDataType data_type) { data_ptr_ = AlignMalloc(size_); ref_count_ = new int[1]; *ref_count_ = 1; + steps_[0] = elem_size_; } void LiteMat::Init(int width, int height, LDataType data_type) { @@ -186,6 +201,8 @@ void LiteMat::Init(int width, int height, LDataType data_type) { data_ptr_ = AlignMalloc(size_); ref_count_ = new int[1]; *ref_count_ = 1; + steps_[1] = elem_size_; + steps_[0] = width_ * steps_[1]; } void LiteMat::Init(int width, int height, void *p_data, LDataType data_type) { @@ -199,6 +216,8 @@ void LiteMat::Init(int width, int height, void *p_data, LDataType data_type) { size_ = c_step_ * channel_ * elem_size_; data_ptr_ = p_data; ref_count_ = nullptr; + steps_[1] = elem_size_; + steps_[0] = width_ * steps_[1]; } void LiteMat::Init(int width, int height, int channel, LDataType data_type) { @@ -214,6 +233,10 @@ void LiteMat::Init(int width, int height, int channel, LDataType data_type) { data_ptr_ = AlignMalloc(size_); ref_count_ = new int[1]; *ref_count_ = 1; + + steps_[2] = elem_size_; + steps_[1] = channel * steps_[2]; + steps_[0] = width_ * steps_[1]; } void LiteMat::Init(int width, int height, int channel, void *p_data, LDataType data_type) { @@ -227,6 +250,9 @@ void LiteMat::Init(int width, int height, int channel, void *p_data, LDataType d size_ = c_step_ * channel_ * elem_size_; data_ptr_ = p_data; ref_count_ = nullptr; + steps_[2] = elem_size_; + steps_[1] = channel * steps_[2]; + steps_[0] = width_ * steps_[1]; } bool LiteMat::IsEmpty() const { return data_ptr_ == nullptr || c_step_ * channel_ == 0; } @@ -248,6 +274,7 @@ void LiteMat::Release() { c_step_ = 0; ref_count_ = 0; size_ = 0; + setSteps(0, 0, 0); } void *LiteMat::AlignMalloc(unsigned int size) { @@ -271,6 +298,31 @@ void LiteMat::AlignFree(void *ptr) { inline void LiteMat::InitElemSize(LDataType data_type) { elem_size_ = data_type.SizeInBytes(); } +bool LiteMat::GetROI(int x, int y, int w, int h, LiteMat &m) { + if (x < 0 || y < 0 || x + w > width_ || h + y > height_) { + return false; + } + if (!m.IsEmpty()) { + m.Release(); + } + + if (ref_count_) { + addRef(ref_count_, 1); + } + + m.height_ = h; + m.width_ = w; + m.dims_ = dims_; + m.elem_size_ = elem_size_; + m.data_ptr_ = reinterpret_cast(data_ptr_) + y * steps_[0] + x * elem_size_ * channel_; + m.channel_ = channel_; + m.c_step_ = c_step_; + m.data_type_ = data_type_; + m.ref_count_ = ref_count_; + m.setSteps(steps_[0], steps_[1], steps_[2]); + return true; +} + template inline void SubtractImpl(const T *src0, const T *src1, T *dst, int64_t total_size) { for (int64_t i = 0; i < total_size; i++) { diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.h b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.h index 53024292ed2..94f1abdeb2c 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.h +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/lite_mat.h @@ -24,6 +24,7 @@ namespace mindspore { namespace dataset { #define ALIGN 16 +#define MAX_DIMS 3 template struct Chn1 { @@ -121,6 +122,8 @@ enum LPixelType { NV122BGR = 7, }; +enum WARP_BORDER_MODE { WARP_BORDER_MODE_CONSTANT }; + class LDataType { public: enum Type : uint8_t { @@ -137,6 +140,7 @@ class LDataType { FLOAT16, FLOAT32, FLOAT64, + DOUBLE, NUM_OF_TYPES }; @@ -179,6 +183,7 @@ class LDataType { 2, // FLOAT16 4, // FLOAT32 8, // FLOAT64 + 8, // DOUBLE }; Type type_; @@ -213,6 +218,8 @@ class LiteMat { void Init(int width, int height, int channel, void *p_data, LDataType data_type = LDataType::UINT8); + bool GetROI(int x, int y, int w, int h, LiteMat &dst); // NOLINT + bool IsEmpty() const; void Release(); @@ -229,6 +236,14 @@ class LiteMat { return reinterpret_cast(data_ptr_); } + template + inline T *ptr(int w) const { + if (IsEmpty()) { + return nullptr; + } + return reinterpret_cast(reinterpret_cast(data_ptr_) + steps_[0] * w); + } + private: /// \brief apply for memory alignment void *AlignMalloc(unsigned int size); @@ -241,6 +256,8 @@ class LiteMat { /// \brief add reference int addRef(int *p, int value); + void setSteps(int c0, int c1, int c2); + public: void *data_ptr_ = nullptr; int elem_size_; @@ -252,6 +269,7 @@ class LiteMat { size_t size_; LDataType data_type_; int *ref_count_; + size_t steps_[MAX_DIMS]; }; /// \brief Calculates the difference between the two images for each element diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/warp_affine.cc b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/warp_affine.cc new file mode 100644 index 00000000000..9467327971e --- /dev/null +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/warp_affine.cc @@ -0,0 +1,522 @@ +/** + * Copyright 2021 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include "lite_cv/lite_mat.h" +#include "lite_cv/image_process.h" + +#ifdef ENABLE_ANDROID +#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARM64) +#define USE_NEON +#include +#endif +#endif + +#define BITS 5 +#define BITS1 15 +#define TAB_SZ (1 << BITS) +#define TAB_SZ2 (TAB_SZ * TAB_SZ) +#define U32TOU8CAST(value) ((uint8_t)std::min(value, (uint32_t)UCHAR_MAX)) +#define FLOATTOSHORT(value) (IntCastShort(round(value))) +#define REMAP_SCALE (1 << 15) +#define INTTOUCHAR(v) ((uint8_t)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0)) +#define SrcValue(y, x) (reinterpret_cast(src + y * 3))[x] +#define DstValue(y, x) (reinterpret_cast(dst + y * 3))[x] + +namespace mindspore { +namespace dataset { +static int16_t BWBlock_i[TAB_SZ2][2][2]; + +static double GetDet3(double *src) { + double a1 = SrcValue(0, 0) * (SrcValue(1, 1) * SrcValue(2, 2) - SrcValue(1, 2) * SrcValue(2, 1)); + double a2 = SrcValue(0, 1) * (SrcValue(1, 0) * SrcValue(2, 2) - SrcValue(1, 2) * SrcValue(2, 0)); + double a3 = SrcValue(0, 2) * (SrcValue(1, 0) * SrcValue(2, 1) - SrcValue(1, 1) * SrcValue(2, 0)); + return a1 - a2 + a3; +} + +static int16_t IntCastShort(int value) { + return (int16_t)((unsigned)(value - SHRT_MIN) <= (unsigned)USHRT_MAX ? value : value > 0 ? SHRT_MAX : SHRT_MIN); +} + +static void InitWBlockInter(float *wBlock, int wBlockSz) { + float scale = 1.f / wBlockSz; + for (int i = 0; i < wBlockSz; i++, wBlock += 2) { + float value = (i * scale); + wBlock[0] = 1.f - value; + wBlock[1] = value; + } +} + +static const void *InitWBlock() { + static bool initWB = false; + int16_t *iWBlock = 0; + int ks = 2; + + iWBlock = BWBlock_i[0][0]; + + if (!initWB) { + float *_wblock = new float[8 * TAB_SZ]; + int i, j, h1, h2; + InitWBlockInter(_wblock, TAB_SZ); + for (i = 0; i < TAB_SZ; i++) { + for (j = 0; j < TAB_SZ; j++, iWBlock += ks * ks) { + int sum_i = 0; + for (h1 = 0; h1 < ks; h1++) { + float vy = _wblock[i * ks + h1]; + for (h2 = 0; h2 < ks; h2++) { + float v = vy * _wblock[j * ks + h2]; + sum_i += iWBlock[h1 * ks + h2] = FLOATTOSHORT(v * REMAP_SCALE); + } + } + if (sum_i != REMAP_SCALE) { + int df = sum_i - REMAP_SCALE; + int ks2 = 1; + int tk1 = ks2; + int tk2 = ks2; + int mtk1 = ks2; + int mtk2 = ks2; + for (h1 = ks2; h1 < ks2 + 2; h1++) { + for (h2 = ks2; h2 < ks2 + 2; h2++) { + if (iWBlock[h1 * ks + h2] < iWBlock[mtk1 * ks + mtk2]) { + mtk1 = h1, mtk2 = h2; + } else if (iWBlock[h1 * ks + h2] > iWBlock[tk1 * ks + tk2]) { + tk1 = h1, tk2 = h2; + } + } + } + if (df < 0) { + iWBlock[tk1 * ks + tk2] = (int16_t)(iWBlock[tk1 * ks + tk2] - df); + } else { + iWBlock[mtk1 * ks + mtk2] = (int16_t)(iWBlock[mtk1 * ks + mtk2] - df); + } + } + } + } + iWBlock -= TAB_SZ2 * ks * ks; + delete[] _wblock; + initWB = true; + } + return (const void *)iWBlock; +} + +static uint8_t CastToFixed(int v) { return INTTOUCHAR(((v + (1 << (BITS1 - 1))) >> BITS1)); } + +static int BorderPolate(int value, int length, PaddBorderType borderType) { + if ((unsigned)value < (unsigned)length) { + return value; + } else if (borderType == 0) { + value = -1; + } + return value; +} + +static void RemapBilinear(const LiteMat &_src, LiteMat &_dst, const LiteMat &_hw, const LiteMat &_fhw, // NOLINT + const void *_wblock, const PaddBorderType borderType, + const std::vector &borderValue) { + const int cn = _src.channel_; + const int16_t *wblock = (const int16_t *)_wblock; + const uint8_t *src_ptr = _src.ptr(0); + size_t src_step = _src.steps_[0]; + unsigned src_width = std::max(_src.width_ - 1, 0); + unsigned src_height = std::max(_src.height_ - 1, 0); + + for (int dy = 0; dy < _dst.height_; dy++) { + uint8_t *dst_ptr = _dst.ptr(dy); + const int16_t *HW = _hw.ptr(dy); + const uint16_t *FHW = _fhw.ptr(dy); + int tt = 0; + bool prevLine = false; + + for (int dx = 0; dx <= _dst.width_; dx++) { + bool curLine = + dx < _dst.width_ ? (unsigned)HW[dx * 2] < src_width && (unsigned)HW[dx * 2 + 1] < src_height : !prevLine; + if (curLine == prevLine) continue; + + int H1 = dx; + dx = tt; + tt = H1; + prevLine = curLine; + + if (!curLine) { + int length = 0; + dst_ptr += length * cn; + dx += length; + + if (cn == 1) { + for (; dx < H1; dx++, dst_ptr++) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + const uint8_t *t_src_ptr = src_ptr + shy * src_step + shx; + *dst_ptr = + CastToFixed(reinterpret_cast(t_src_ptr[0] * w_ptr[0] + t_src_ptr[1] * w_ptr[1] + + t_src_ptr[src_step] * w_ptr[2] + t_src_ptr[src_step + 1] * w_ptr[3])); + } + } else if (cn == 2) { + for (; dx < H1; dx++, dst_ptr += 2) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + const uint8_t *t_src_ptr = src_ptr + shy * src_step + shx * 2; + int v0 = t_src_ptr[0] * w_ptr[0] + t_src_ptr[2] * w_ptr[1] + t_src_ptr[src_step] * w_ptr[2] + + t_src_ptr[src_step + 2] * w_ptr[3]; + int v1 = t_src_ptr[1] * w_ptr[0] + t_src_ptr[3] * w_ptr[1] + t_src_ptr[src_step + 1] * w_ptr[2] + + t_src_ptr[src_step + 3] * w_ptr[3]; + dst_ptr[0] = CastToFixed(v0); + dst_ptr[1] = CastToFixed(v1); + } + } else if (cn == 3) { + for (; dx < H1; dx++, dst_ptr += 3) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + const uint8_t *t_src_ptr = src_ptr + shy * src_step + shx * 3; + int v0 = t_src_ptr[0] * w_ptr[0] + t_src_ptr[3] * w_ptr[1] + t_src_ptr[src_step] * w_ptr[2] + + t_src_ptr[src_step + 3] * w_ptr[3]; + int v1 = t_src_ptr[1] * w_ptr[0] + t_src_ptr[4] * w_ptr[1] + t_src_ptr[src_step + 1] * w_ptr[2] + + t_src_ptr[src_step + 4] * w_ptr[3]; + int v2 = t_src_ptr[2] * w_ptr[0] + t_src_ptr[5] * w_ptr[1] + t_src_ptr[src_step + 2] * w_ptr[2] + + t_src_ptr[src_step + 5] * w_ptr[3]; + dst_ptr[0] = CastToFixed(v0); + dst_ptr[1] = CastToFixed(v1); + dst_ptr[2] = CastToFixed(v2); + } + } else if (cn == 4) { + for (; dx < H1; dx++, dst_ptr += 4) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + const uint8_t *t_src_ptr = src_ptr + shy * src_step + shx * 4; + int v0 = t_src_ptr[0] * w_ptr[0] + t_src_ptr[4] * w_ptr[1] + t_src_ptr[src_step] * w_ptr[2] + + t_src_ptr[src_step + 4] * w_ptr[3]; + int v1 = t_src_ptr[1] * w_ptr[0] + t_src_ptr[5] * w_ptr[1] + t_src_ptr[src_step + 1] * w_ptr[2] + + t_src_ptr[src_step + 5] * w_ptr[3]; + dst_ptr[0] = CastToFixed(v0); + dst_ptr[1] = CastToFixed(v1); + v0 = t_src_ptr[2] * w_ptr[0] + t_src_ptr[6] * w_ptr[1] + t_src_ptr[src_step + 2] * w_ptr[2] + + t_src_ptr[src_step + 6] * w_ptr[3]; + v1 = t_src_ptr[3] * w_ptr[0] + t_src_ptr[7] * w_ptr[1] + t_src_ptr[src_step + 3] * w_ptr[2] + + t_src_ptr[src_step + 7] * w_ptr[3]; + dst_ptr[2] = CastToFixed(v0); + dst_ptr[3] = CastToFixed(v1); + } + } else { + for (; dx < H1; dx++, dst_ptr += cn) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + const uint8_t *t_src_ptr = src_ptr + shy * src_step + shx * cn; + for (int k = 0; k < cn; k++) { + int v0 = t_src_ptr[k] * w_ptr[0] + t_src_ptr[k + cn] * w_ptr[1] + t_src_ptr[src_step + k] * w_ptr[2] + + t_src_ptr[src_step + k + cn] * w_ptr[3]; + dst_ptr[k] = CastToFixed(v0); + } + } + } + } else { + if (cn == 1) { + for (; dx < H1; dx++, dst_ptr++) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + if (borderType == PADD_BORDER_CONSTANT && + (shx >= _src.width_ || shx + 1 < 0 || shy >= _src.height_ || shy + 1 < 0)) { + dst_ptr[0] = borderValue[0]; + } else { + int sv0; + int sv1; + int su0; + int su1; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + + sv0 = BorderPolate(shx, _src.width_, borderType); + sv1 = BorderPolate(shx + 1, _src.width_, borderType); + su0 = BorderPolate(shy, _src.height_, borderType); + su1 = BorderPolate(shy + 1, _src.height_, borderType); + uint8_t v0 = sv0 >= 0 && su0 >= 0 ? src_ptr[su0 * src_step + sv0] : borderValue[0]; + uint8_t v1 = sv1 >= 0 && su0 >= 0 ? src_ptr[su0 * src_step + sv1] : borderValue[0]; + uint8_t v2 = sv0 >= 0 && su1 >= 0 ? src_ptr[su1 * src_step + sv0] : borderValue[0]; + uint8_t v3 = sv1 >= 0 && su1 >= 0 ? src_ptr[su1 * src_step + sv1] : borderValue[0]; + dst_ptr[0] = + CastToFixed(reinterpret_cast(v0 * w_ptr[0] + v1 * w_ptr[1] + v2 * w_ptr[2] + v3 * w_ptr[3])); + } + } + } else { + for (; dx < H1; dx++, dst_ptr += cn) { + int shx = HW[dx * 2]; + int shy = HW[dx * 2 + 1]; + if (borderType == PADD_BORDER_CONSTANT && + (shx >= _src.width_ || shx + 1 < 0 || shy >= _src.height_ || shy + 1 < 0)) { + for (int k = 0; k < cn; k++) dst_ptr[k] = borderValue[k]; + } else { + int sv0; + int sv1; + int su0; + int su1; + const int16_t *w_ptr = wblock + FHW[dx] * 4; + sv0 = BorderPolate(shx, _src.width_, borderType); + sv1 = BorderPolate(shx + 1, _src.width_, borderType); + su0 = BorderPolate(shy, _src.height_, borderType); + su1 = BorderPolate(shy + 1, _src.height_, borderType); + const uint8_t *v0 = sv0 >= 0 && su0 >= 0 ? src_ptr + su0 * src_step + sv0 * cn : &borderValue[0]; + const uint8_t *v1 = sv1 >= 0 && su0 >= 0 ? src_ptr + su0 * src_step + sv1 * cn : &borderValue[0]; + const uint8_t *v2 = sv0 >= 0 && su1 >= 0 ? src_ptr + su1 * src_step + sv0 * cn : &borderValue[0]; + const uint8_t *v3 = sv1 >= 0 && su1 >= 0 ? src_ptr + su1 * src_step + sv1 * cn : &borderValue[0]; + + for (int k = 0; k < cn; k++) + dst_ptr[k] = CastToFixed( + reinterpret_cast(v0[k] * w_ptr[0] + v1[k] * w_ptr[1] + v2[k] * w_ptr[2] + v3[k] * w_ptr[3])); + } + } + } + } + } + } +} + +static void Remap(const LiteMat &src, LiteMat &dst, LiteMat &map1, const LiteMat &map2, // NOLINT + const PaddBorderType borderType, const std::vector &borderValue) { + int x, y, x1, y1; + const int buf_size = 1 << 14; + int dst_height = std::min(128, dst.height_); + int dst_width = std::min(buf_size / dst_height, dst.width_); + dst_height = std::min(buf_size / dst_width, dst.height_); + + const void *wblock = InitWBlock(); + + LiteMat _xyblock(dst_width, dst_height, 2, LDataType::INT16); + LiteMat _ablock(dst_width, dst_height, 1, LDataType::UINT16); + for (y = 0; y < dst.height_; y += dst_height) { + for (x = 0; x < dst.width_; x += dst_width) { + int bheight = std::min(dst_height, dst.height_ - y); + int bwidth = std::min(dst_width, dst.width_ - x); + LiteMat lite_part; + dst.GetROI(x, y, bwidth, bheight, lite_part); + + LiteMat xy_ptr; + _xyblock.GetROI(0, 0, bwidth, bheight, xy_ptr); + LiteMat a_ptr; + _ablock.GetROI(0, 0, bwidth, bheight, a_ptr); + + for (y1 = 0; y1 < bheight; y1++) { + uint16_t *t_a_ptr = a_ptr.ptr(y1); + + map1.GetROI(x, y, bwidth, bheight, xy_ptr); + + const uint16_t *sa_ptr = map2.ptr(y + y1) + x; + x1 = 0; + for (; x1 < bwidth; x1++) { + t_a_ptr[x1] = (uint16_t)(sa_ptr[x1] & (TAB_SZ2 - 1)); + } + } + RemapBilinear(src, lite_part, xy_ptr, a_ptr, wblock, borderType, borderValue); + } + } +} + +bool WarpAffineBilinear(const LiteMat &src, LiteMat &dst, const LiteMat &M, int dst_w, int dst_h, // NOLINT + PaddBorderType borderType, std::vector &borderValue) { // NOLINT + if (!(M.height_ == 2 && M.width_ == 3)) { + return false; + } + if (borderType != PADD_BORDER_CONSTANT) { + return false; + } + if (borderValue.size() != src.channel_) { + return false; + } + if (dst.IsEmpty()) { + (void)dst.Init(dst_w, dst_h, src.channel_, LDataType::UINT8); + } else if (dst.height_ != dst_h || dst.width_ != dst_w || dst.channel_ != src.channel_) { + return false; + } else if (dst.data_type_ != LDataType::UINT8) { + return false; + } else { + } + + double IM[6]; + const double *M_Ptr = M; + for (int i = 0; i < 6; i++) { + IM[i] = M_Ptr[i]; + } + + double D = IM[0] * IM[4] - IM[1] * IM[3]; + D = D != 0 ? 1.0f / D : 0; + double A11 = IM[4] * D, A22 = IM[0] * D; + IM[0] = A11; + IM[1] *= -D; + IM[3] *= -D; + IM[4] = A22; + double b1 = -IM[0] * IM[2] - IM[1] * IM[5]; + double b2 = -IM[3] * IM[2] - IM[4] * IM[5]; + IM[2] = b1; + IM[5] = b2; + + int *_a = new int[dst.width_ * 2]; + int *a = &_a[0], *b = a + dst.width_; + const int SCALE = 1 << 10; + const int B_SIZE = 64; + int16_t WH[B_SIZE * B_SIZE * 2]; + int16_t A_Ptr[B_SIZE * B_SIZE]; + int r_delta = SCALE / TAB_SZ / 2; + int x, y, x1, y1; + for (x = 0; x < dst.width_; x++) { + a[x] = round(IM[0] * x * SCALE); + b[x] = round(IM[3] * x * SCALE); + } + int t_bh0 = std::min(B_SIZE / 2, dst.height_); + int t_bw0 = std::min(B_SIZE * B_SIZE / t_bh0, dst.width_); + t_bh0 = std::min(B_SIZE * B_SIZE / t_bw0, dst.height_); + + for (y = 0; y < dst.height_; y += t_bh0) { + for (x = 0; x < dst.width_; x += t_bw0) { + int t_bw = std::min(t_bw0, dst.width_ - x); + int t_bh = std::min(t_bh0, dst.height_ - y); + LiteMat _HW(t_bw, t_bh, 2, WH, LDataType::INT16); + LiteMat lite_part; + dst.GetROI(x, y, t_bw, t_bh, lite_part); + + for (y1 = 0; y1 < t_bh; y1++) { + int16_t *t_xy = WH + y1 * t_bw * 2; + int X0 = round((IM[1] * (y + y1) + IM[2]) * SCALE) + r_delta; + int Y0 = round((IM[4] * (y + y1) + IM[5]) * SCALE) + r_delta; + int16_t *t_a = A_Ptr + y1 * t_bw; + x1 = 0; + for (; x1 < t_bw; x1++) { + int X = (X0 + a[x + x1]) >> (10 - BITS); + int Y = (Y0 + b[x + x1]) >> (10 - BITS); + t_xy[x1 * 2] = IntCastShort(X >> BITS); + t_xy[x1 * 2 + 1] = IntCastShort(Y >> BITS); + t_a[x1] = (int16_t)((Y & (TAB_SZ - 1)) * TAB_SZ + (X & (TAB_SZ - 1))); + } + } + + LiteMat _matA(t_bw, t_bh, 1, A_Ptr, LDataType::UINT16); + Remap(src, lite_part, _HW, _matA, borderType, borderValue); + } + } + + delete[] _a; + return true; +} + +static void PerspectiveInvert(double *src, double *dst) { + double value = GetDet3(src); + if (value != 0.) { + value = 1. / value; + double v[9]; + + v[0] = (SrcValue(1, 1) * SrcValue(2, 2) - SrcValue(1, 2) * SrcValue(2, 1)) * value; + v[1] = (SrcValue(0, 2) * SrcValue(2, 1) - SrcValue(0, 1) * SrcValue(2, 2)) * value; + v[2] = (SrcValue(0, 1) * SrcValue(1, 2) - SrcValue(0, 2) * SrcValue(1, 1)) * value; + + v[3] = (SrcValue(1, 2) * SrcValue(2, 0) - SrcValue(1, 0) * SrcValue(2, 2)) * value; + v[4] = (SrcValue(0, 0) * SrcValue(2, 2) - SrcValue(0, 2) * SrcValue(2, 0)) * value; + v[5] = (SrcValue(0, 2) * SrcValue(1, 0) - SrcValue(0, 0) * SrcValue(1, 2)) * value; + + v[6] = (SrcValue(1, 0) * SrcValue(2, 1) - SrcValue(1, 1) * SrcValue(2, 0)) * value; + v[7] = (SrcValue(0, 1) * SrcValue(2, 0) - SrcValue(0, 0) * SrcValue(2, 1)) * value; + v[8] = (SrcValue(0, 0) * SrcValue(1, 1) - SrcValue(0, 1) * SrcValue(1, 0)) * value; + + DstValue(0, 0) = v[0]; + DstValue(0, 1) = v[1]; + DstValue(0, 2) = v[2]; + DstValue(1, 0) = v[3]; + DstValue(1, 1) = v[4]; + DstValue(1, 2) = v[5]; + DstValue(2, 0) = v[6]; + DstValue(2, 1) = v[7]; + DstValue(2, 2) = v[8]; + } +} + +bool WarpPerspectiveBilinear(const LiteMat &src, LiteMat &dst, const LiteMat &M, int dst_w, int dst_h, // NOLINT + PaddBorderType borderType, std::vector &borderValue) { // NOLINT + if (!(M.height_ == 3 && M.width_ == 3)) { + return false; + } + if (borderType != PADD_BORDER_CONSTANT) { + return false; + } + if (borderValue.size() != src.channel_) { + return false; + } + if (dst.IsEmpty()) { + (void)dst.Init(dst_w, dst_h, src.channel_, LDataType::UINT8); + } else if (dst.height_ != dst_h || dst.width_ != dst_w || dst.channel_ != src.channel_) { + return false; + } else if (dst.data_type_ != LDataType::UINT8) { + return false; + } else { + } + + double IM[9]; + const double *M_Ptr = M; + for (int i = 0; i < 9; i++) { + IM[i] = M_Ptr[i]; + } + PerspectiveInvert(IM, IM); + const int B_SZ = 32; + int16_t HW[B_SZ * B_SZ * 2]; + int16_t TA[B_SZ * B_SZ]; + int x; + int y; + int y1; + int width = dst.width_; + int height = dst.height_; + + int bheight = std::min(B_SZ / 2, height); + int bwidth = std::min(B_SZ * B_SZ / bheight, width); + bheight = std::min(B_SZ * B_SZ / bwidth, height); + for (y = 0; y < dst.height_; y += bheight) { + for (x = 0; x < width; x += bwidth) { + int tw = std::min(bwidth, width - x); + int th = std::min(bheight, dst.height_ - y); + + LiteMat _HW(tw, th, 2, HW, LDataType::INT16); + LiteMat lite_part; + dst.GetROI(x, y, tw, th, lite_part); + + for (y1 = 0; y1 < th; y1++) { + int16_t *xy = HW + y1 * tw * 2; + double XV = IM[0] * x + IM[1] * (y + y1) + IM[2]; + double YV = IM[3] * x + IM[4] * (y + y1) + IM[5]; + double WV = IM[6] * x + IM[7] * (y + y1) + IM[8]; + + int16_t *t_a = TA + y1 * tw; + for (int x1 = 0; x1 < tw; x1++) { + double W = WV + IM[6] * x1; + W = W ? TAB_SZ / W : 0; + double fX = std::max((double)INT_MIN, std::min((double)INT_MAX, (XV + IM[0] * x1) * W)); // NOLINT + double fY = std::max((double)INT_MIN, std::min((double)INT_MAX, (YV + IM[3] * x1) * W)); // NOLINT + int X = round(fX); + int Y = round(fY); + + xy[x1 * 2] = IntCastShort(X >> BITS); + xy[x1 * 2 + 1] = IntCastShort(Y >> BITS); + t_a[x1] = (int16_t)((Y & (TAB_SZ - 1)) * TAB_SZ + (X & (TAB_SZ - 1))); + } + } + LiteMat _matA(tw, th, 1, TA, LDataType::UINT16); + Remap(src, lite_part, _HW, _matA, borderType, borderValue); + } + } + return true; +} + +} // namespace dataset +} // namespace mindspore diff --git a/tests/ut/cpp/dataset/image_process_test.cc b/tests/ut/cpp/dataset/image_process_test.cc index a86a9e6bf84..01a1eecb88e 100644 --- a/tests/ut/cpp/dataset/image_process_test.cc +++ b/tests/ut/cpp/dataset/image_process_test.cc @@ -886,4 +886,329 @@ TEST_F(MindDataImageProcess, TestExtractChannel) { EXPECT_FALSE(ExtractChannel(lite_mat, lite_single, 0)); EXPECT_TRUE(lite_single.IsEmpty()); -} \ No newline at end of file +} +TEST_F(MindDataImageProcess, testROI3C) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + + cv::Mat cv_roi = cv::Mat(src_image, cv::Rect(500, 500, 3000, 1500)); + + cv::imwrite("./cv_roi.jpg", cv_roi); + + bool ret = false; + LiteMat lite_mat_bgr; + ret = InitFromPixel(src_image.data, LPixelType::BGR, LDataType::UINT8, src_image.cols, src_image.rows, lite_mat_bgr); + EXPECT_TRUE(ret); + LiteMat lite_roi; + + ret = lite_mat_bgr.GetROI(500, 500, 3000, 1500, lite_roi); + EXPECT_TRUE(ret); + + LiteMat lite_roi_save(3000, 1500, lite_roi.channel_, LDataType::UINT8); + + for (size_t i = 0; i < lite_roi.height_; i++) { + const unsigned char *ptr = lite_roi.ptr(i); + size_t image_size = lite_roi.width_ * lite_roi.channel_ * sizeof(unsigned char); + unsigned char *dst_ptr = (unsigned char *)lite_roi_save.data_ptr_ + image_size * i; + (void)memcpy(dst_ptr, ptr, image_size); + } + + cv::Mat dst_imageR(lite_roi_save.height_, lite_roi_save.width_, CV_8UC3, lite_roi_save.data_ptr_); + cv::imwrite("./lite_roi.jpg", dst_imageR); +} + +TEST_F(MindDataImageProcess, testROI1C) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + + cv::Mat gray_image; + cv::cvtColor(src_image, gray_image, CV_BGR2GRAY); + cv::Mat cv_roi_gray = cv::Mat(gray_image, cv::Rect(500, 500, 3000, 1500)); + + cv::imwrite("./cv_roi_gray.jpg", cv_roi_gray); + + cv::Mat rgba_mat; + cv::cvtColor(src_image, rgba_mat, CV_BGR2RGBA); + bool ret = false; + LiteMat lite_mat_gray; + ret = + InitFromPixel(rgba_mat.data, LPixelType::RGBA2GRAY, LDataType::UINT8, rgba_mat.cols, rgba_mat.rows, lite_mat_gray); + EXPECT_TRUE(ret); + LiteMat lite_roi_gray; + + ret = lite_mat_gray.GetROI(500, 500, 3000, 1500, lite_roi_gray); + EXPECT_TRUE(ret); + + LiteMat lite_roi_gray_save(3000, 1500, lite_roi_gray.channel_, LDataType::UINT8); + + for (size_t i = 0; i < lite_roi_gray.height_; i++) { + const unsigned char *ptr = lite_roi_gray.ptr(i); + size_t image_size = lite_roi_gray.width_ * lite_roi_gray.channel_ * sizeof(unsigned char); + unsigned char *dst_ptr = (unsigned char *)lite_roi_gray_save.data_ptr_ + image_size * i; + (void)memcpy(dst_ptr, ptr, image_size); + } + + cv::Mat dst_imageR(lite_roi_gray_save.height_, lite_roi_gray_save.width_, CV_8UC1, lite_roi_gray_save.data_ptr_); + cv::imwrite("./lite_roi.jpg", dst_imageR); +} + + + +//warp +TEST_F(MindDataImageProcess, testWarpAffineBGR) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + cv::Point2f srcTri[3]; + cv::Point2f dstTri[3]; + srcTri[0] = cv::Point2f(0, 0); + srcTri[1] = cv::Point2f(src_image.cols - 1, 0); + srcTri[2] = cv::Point2f(0, src_image.rows - 1); + + dstTri[0] = cv::Point2f(src_image.cols * 0.0, src_image.rows * 0.33); + dstTri[1] = cv::Point2f(src_image.cols * 0.85, src_image.rows * 0.25); + dstTri[2] = cv::Point2f(src_image.cols * 0.15, src_image.rows * 0.7); + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + ; + cv::Mat warp_dstImage; + cv::warpAffine(src_image, warp_dstImage, warp_mat, warp_dstImage.size()); + cv::imwrite("./warpAffine_cv_bgr.png", warp_dstImage); + + bool ret = false; + LiteMat lite_mat_bgr; + ret = InitFromPixel(src_image.data, LPixelType::BGR, LDataType::UINT8, src_image.cols, src_image.rows, lite_mat_bgr); + EXPECT_TRUE(ret); + double *mat_ptr = warp_mat.ptr(0); + LiteMat lite_M(3, 2, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + borderValues.push_back(0); + borderValues.push_back(0); + ret = WarpAffineBilinear(lite_mat_bgr, lite_warp, lite_M, lite_mat_bgr.width_, lite_mat_bgr.height_, PADD_BORDER_CONSTANT, borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC3, lite_warp.data_ptr_); + cv::imwrite("./warpAffine_lite_bgr.png", dst_imageR); +} + +TEST_F(MindDataImageProcess, testWarpAffineBGRScale) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + cv::Point2f srcTri[3]; + cv::Point2f dstTri[3]; + srcTri[0] = cv::Point2f(10, 20); + srcTri[1] = cv::Point2f(src_image.cols - 1 - 100, 0); + srcTri[2] = cv::Point2f(0, src_image.rows - 1 - 300); + + dstTri[0] = cv::Point2f(src_image.cols * 0.22, src_image.rows * 0.33); + dstTri[1] = cv::Point2f(src_image.cols * 0.87, src_image.rows * 0.75); + dstTri[2] = cv::Point2f(src_image.cols * 0.35, src_image.rows * 0.37); + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + ; + cv::Mat warp_dstImage; + cv::warpAffine(src_image, warp_dstImage, warp_mat, warp_dstImage.size()); + cv::imwrite("./warpAffine_cv_bgr_scale.png", warp_dstImage); + + bool ret = false; + LiteMat lite_mat_bgr; + ret = InitFromPixel(src_image.data, LPixelType::BGR, LDataType::UINT8, src_image.cols, src_image.rows, lite_mat_bgr); + EXPECT_TRUE(ret); + double *mat_ptr = warp_mat.ptr(0); + LiteMat lite_M(3, 2, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + borderValues.push_back(0); + borderValues.push_back(0); + ret = WarpAffineBilinear(lite_mat_bgr, lite_warp, lite_M, lite_mat_bgr.width_, lite_mat_bgr.height_, PADD_BORDER_CONSTANT, borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC3, lite_warp.data_ptr_); + cv::imwrite("./warpAffine_lite_bgr_scale.png", dst_imageR); +} + +TEST_F(MindDataImageProcess, testWarpAffineBGRResize) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + cv::Point2f srcTri[3]; + cv::Point2f dstTri[3]; + srcTri[0] = cv::Point2f(10, 20); + srcTri[1] = cv::Point2f(src_image.cols - 1 - 100, 0); + srcTri[2] = cv::Point2f(0, src_image.rows - 1 - 300); + + dstTri[0] = cv::Point2f(src_image.cols * 0.22, src_image.rows * 0.33); + dstTri[1] = cv::Point2f(src_image.cols * 0.87, src_image.rows * 0.75); + dstTri[2] = cv::Point2f(src_image.cols * 0.35, src_image.rows * 0.37); + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + ; + cv::Mat warp_dstImage; + cv::warpAffine(src_image, warp_dstImage, warp_mat, cv::Size(src_image.cols + 200, src_image.rows - 300)); + cv::imwrite("./warpAffine_cv_bgr_resize.png", warp_dstImage); + + bool ret = false; + LiteMat lite_mat_bgr; + ret = InitFromPixel(src_image.data, LPixelType::BGR, LDataType::UINT8, src_image.cols, src_image.rows, lite_mat_bgr); + EXPECT_TRUE(ret); + double *mat_ptr = warp_mat.ptr(0); + LiteMat lite_M(3, 2, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + borderValues.push_back(0); + borderValues.push_back(0); + ret = WarpAffineBilinear(lite_mat_bgr, lite_warp, lite_M, lite_mat_bgr.width_ + 200, lite_mat_bgr.height_ - 300, PADD_BORDER_CONSTANT, + borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC3, lite_warp.data_ptr_); + cv::imwrite("./warpAffine_lite_bgr_resize.png", dst_imageR); +} + +TEST_F(MindDataImageProcess, testWarpAffineGray) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + + cv::Mat gray_image; + cv::cvtColor(src_image, gray_image, CV_BGR2GRAY); + + cv::Point2f srcTri[3]; + cv::Point2f dstTri[3]; + srcTri[0] = cv::Point2f(0, 0); + srcTri[1] = cv::Point2f(src_image.cols - 1, 0); + srcTri[2] = cv::Point2f(0, src_image.rows - 1); + + dstTri[0] = cv::Point2f(src_image.cols * 0.0, src_image.rows * 0.33); + dstTri[1] = cv::Point2f(src_image.cols * 0.85, src_image.rows * 0.25); + dstTri[2] = cv::Point2f(src_image.cols * 0.15, src_image.rows * 0.7); + + cv::Mat warp_mat = cv::getAffineTransform(srcTri, dstTri); + ; + cv::Mat warp_gray_dstImage; + cv::warpAffine(gray_image, warp_gray_dstImage, warp_mat, cv::Size(src_image.cols + 200, src_image.rows - 300)); + cv::imwrite("./warpAffine_cv_gray.png", warp_gray_dstImage); + + cv::Mat rgba_mat; + cv::cvtColor(src_image, rgba_mat, CV_BGR2RGBA); + bool ret = false; + LiteMat lite_mat_gray; + ret = + InitFromPixel(rgba_mat.data, LPixelType::RGBA2GRAY, LDataType::UINT8, rgba_mat.cols, rgba_mat.rows, lite_mat_gray); + EXPECT_TRUE(ret); + double *mat_ptr = warp_mat.ptr(0); + LiteMat lite_M(3, 2, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + ret = WarpAffineBilinear(lite_mat_gray, lite_warp, lite_M, lite_mat_gray.width_ + 200, lite_mat_gray.height_ - 300, PADD_BORDER_CONSTANT, + borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC1, lite_warp.data_ptr_); + cv::imwrite("./warpAffine_lite_gray.png", dst_imageR); +} + +TEST_F(MindDataImageProcess, testWarpPerspectiveBGRResize) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + cv::Point2f srcQuad[4], dstQuad[4]; + srcQuad[0].x = 0; + srcQuad[0].y = 0; + srcQuad[1].x = src_image.cols - 1.; + srcQuad[1].y = 0; + srcQuad[2].x = 0; + srcQuad[2].y = src_image.rows - 1; + srcQuad[3].x = src_image.cols - 1; + srcQuad[3].y = src_image.rows - 1; + + dstQuad[0].x = src_image.cols * 0.05; + dstQuad[0].y = src_image.rows * 0.33; + dstQuad[1].x = src_image.cols * 0.9; + dstQuad[1].y = src_image.rows * 0.25; + dstQuad[2].x = src_image.cols * 0.2; + dstQuad[2].y = src_image.rows * 0.7; + dstQuad[3].x = src_image.cols * 0.8; + dstQuad[3].y = src_image.rows * 0.9; + + cv::Mat ptran = cv::getPerspectiveTransform(srcQuad, dstQuad, cv::DECOMP_SVD); + cv::Mat warp_dstImage; + cv::warpPerspective(src_image, warp_dstImage, ptran, cv::Size(src_image.cols + 200, src_image.rows - 300)); + cv::imwrite("./warpPerspective_cv_bgr.png", warp_dstImage); + + bool ret = false; + LiteMat lite_mat_bgr; + ret = InitFromPixel(src_image.data, LPixelType::BGR, LDataType::UINT8, src_image.cols, src_image.rows, lite_mat_bgr); + EXPECT_TRUE(ret); + double *mat_ptr = ptran.ptr(0); + LiteMat lite_M(3, 3, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + borderValues.push_back(0); + borderValues.push_back(0); + ret = WarpPerspectiveBilinear(lite_mat_bgr, lite_warp, lite_M, lite_mat_bgr.width_ + 200, lite_mat_bgr.height_ - 300, PADD_BORDER_CONSTANT, + borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC3, lite_warp.data_ptr_); + cv::imwrite("./warpPerspective_lite_bgr.png", dst_imageR); +} + +TEST_F(MindDataImageProcess, testWarpPerspectiveGrayResize) { + std::string filename = "data/dataset/apple.jpg"; + cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); + + cv::Mat gray_image; + cv::cvtColor(src_image, gray_image, CV_BGR2GRAY); + + cv::Point2f srcQuad[4], dstQuad[4]; + srcQuad[0].x = 0; + srcQuad[0].y = 0; + srcQuad[1].x = src_image.cols - 1.; + srcQuad[1].y = 0; + srcQuad[2].x = 0; + srcQuad[2].y = src_image.rows - 1; + srcQuad[3].x = src_image.cols - 1; + srcQuad[3].y = src_image.rows - 1; + + dstQuad[0].x = src_image.cols * 0.05; + dstQuad[0].y = src_image.rows * 0.33; + dstQuad[1].x = src_image.cols * 0.9; + dstQuad[1].y = src_image.rows * 0.25; + dstQuad[2].x = src_image.cols * 0.2; + dstQuad[2].y = src_image.rows * 0.7; + dstQuad[3].x = src_image.cols * 0.8; + dstQuad[3].y = src_image.rows * 0.9; + + cv::Mat ptran = cv::getPerspectiveTransform(srcQuad, dstQuad, cv::DECOMP_SVD); + cv::Mat warp_dstImage; + cv::warpPerspective(gray_image, warp_dstImage, ptran, cv::Size(gray_image.cols + 200, gray_image.rows - 300)); + cv::imwrite("./warpPerspective_cv_gray.png", warp_dstImage); + + cv::Mat rgba_mat; + cv::cvtColor(src_image, rgba_mat, CV_BGR2RGBA); + bool ret = false; + LiteMat lite_mat_gray; + ret = + InitFromPixel(rgba_mat.data, LPixelType::RGBA2GRAY, LDataType::UINT8, rgba_mat.cols, rgba_mat.rows, lite_mat_gray); + EXPECT_TRUE(ret); + double *mat_ptr = ptran.ptr(0); + LiteMat lite_M(3, 3, 1, mat_ptr, LDataType::DOUBLE); + + LiteMat lite_warp; + std::vector borderValues; + borderValues.push_back(0); + ret = WarpPerspectiveBilinear(lite_mat_gray, lite_warp, lite_M, lite_mat_gray.width_ + 200, lite_mat_gray.height_ - 300, PADD_BORDER_CONSTANT, + borderValues); + EXPECT_TRUE(ret); + + cv::Mat dst_imageR(lite_warp.height_, lite_warp.width_, CV_8UC1, lite_warp.data_ptr_); + cv::imwrite("./warpPerspective_lite_gray.png", dst_imageR); +}