1 /** 2 * Copyright 2021 Huawei Technologies Co., Ltd 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "common/cvop_common.h" 17 #include "minddata/dataset/core/cv_tensor.h" 18 #include "minddata/dataset/kernels/image/affine_op.h" 19 #include "minddata/dataset/kernels/image/math_utils.h" 20 #include <opencv2/opencv.hpp> 21 #include <opencv2/imgproc/types_c.h> 22 #include "lite_cv/lite_mat.h" 23 #include "lite_cv/image_process.h" 24 25 using namespace mindspore::dataset; 26 using mindspore::dataset::InterpolationMode; 27 28 class MindDataTestAffineOp : public UT::CVOP::CVOpCommon { 29 public: 30 MindDataTestAffineOp() : CVOpCommon() {} 31 }; 32 33 // Helper function, consider moving this to helper class for UT 34 double Mse(cv::Mat img1, cv::Mat img2) { 35 // clone to get around open cv optimization 36 cv::Mat output1 = img1.clone(); 37 cv::Mat output2 = img2.clone(); 38 39 // input check 40 if (output1.rows < 0 || output1.rows != output2.rows || output1.cols < 0 || output1.cols != output2.cols) { 41 return 10000.0; 42 } 43 return cv::norm(output1, output2, cv::NORM_L1); 44 } 45 46 // helper function to generate corresponding affine matrix 47 std::vector<double> GenerateMatrix(const std::shared_ptr<Tensor> &input, float_t degrees, 48 const std::vector<float_t> &translation, float_t scale, 49 const std::vector<float_t> &shear) { 50 float_t translation_x = translation[0]; 51 float_t translation_y = translation[1]; 52 DegreesToRadians(degrees, °rees); 53 float_t shear_x = shear[0]; 54 float_t shear_y = shear[1]; 55 DegreesToRadians(shear_x, &shear_x); 56 DegreesToRadians(-1 * shear_y, &shear_y); 57 float_t cx = ((input->shape()[1] - 1) / 2.0); 58 float_t cy = ((input->shape()[0] - 1) / 2.0); 59 // Calculate RSS 60 std::vector<double> matrix{ 61 static_cast<double>(scale * cos(degrees + shear_y) / cos(shear_y)), 62 static_cast<double>(scale * (-1 * cos(degrees + shear_y) * tan(shear_x) / cos(shear_y) - sin(degrees))), 63 0, 64 static_cast<double>(scale * sin(degrees + shear_y) / cos(shear_y)), 65 static_cast<double>(scale * (-1 * sin(degrees + shear_y) * tan(shear_x) / cos(shear_y) + cos(degrees))), 66 0}; 67 // Compute T * C * RSS * C^-1 68 matrix[2] = (1 - matrix[0]) * cx - matrix[1] * cy + translation_x; 69 matrix[5] = (1 - matrix[4]) * cy - matrix[3] * cx + translation_y; 70 return matrix; 71 } 72 73 TEST_F(MindDataTestAffineOp, TestAffineLite) { 74 MS_LOG(INFO) << "Doing MindDataTestAffine-TestAffineLite."; 75 76 // create input tensor and 77 float degree = 0.0; 78 std::vector<float> translation = {0.0, 0.0}; 79 float scale = 0.0; 80 std::vector<float> shear = {0.0, 0.0}; 81 82 // Create affine object with default values 83 std::shared_ptr<AffineOp> op(new AffineOp(degree, translation, scale, shear, InterpolationMode::kLinear)); 84 // output tensor 85 std::shared_ptr<Tensor> output_tensor; 86 87 // output 88 LiteMat dst; 89 LiteMat lite_mat_rgb(input_tensor_->shape()[1], input_tensor_->shape()[0], input_tensor_->shape()[2], 90 const_cast<void *>(reinterpret_cast<const void *>(input_tensor_->GetBuffer())), 91 LDataType::UINT8); 92 93 std::vector<double> matrix = GenerateMatrix(input_tensor_, degree, translation, scale, shear); 94 95 int height = lite_mat_rgb.height_; 96 int width = lite_mat_rgb.width_; 97 std::vector<size_t> dsize; 98 dsize.push_back(width); 99 dsize.push_back(height); 100 double M[6] = {}; 101 for (int i = 0; i < matrix.size(); i++) { 102 M[i] = static_cast<double>(matrix[i]); 103 } 104 105 EXPECT_TRUE(Affine(lite_mat_rgb, dst, M, dsize, UINT8_C3(0, 0, 0))); 106 Status s = op->Compute(input_tensor_, &output_tensor); 107 EXPECT_TRUE(s.IsOk()); 108 // output tensor is a cv tenosr, we can compare mat values 109 cv::Mat lite_cv_out(dst.height_, dst.width_, CV_8UC3, dst.data_ptr_); 110 double mse = Mse(lite_cv_out, CVTensor(output_tensor).mat()); 111 MS_LOG(INFO) << "mse: " << std::to_string(mse) << std::endl; 112 EXPECT_LT(mse, 1); // predetermined magic number 113 } 114