Merge pull request !6009 from jiangzhiwen/lite/affine_uttags/v1.0.0
| @@ -516,18 +516,10 @@ void ConvertBoxes(std::vector<std::vector<float>> &boxes, const std::vector<std: | |||||
| std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std::vector<float> &all_scores, float thres, | std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std::vector<float> &all_scores, float thres, | ||||
| int max_boxes) { | int max_boxes) { | ||||
| int boxes_num = all_boxes.size(); | int boxes_num = all_boxes.size(); | ||||
| std::vector<float> y1(boxes_num); | |||||
| std::vector<float> x1(boxes_num); | |||||
| std::vector<float> y2(boxes_num); | |||||
| std::vector<float> x2(boxes_num); | |||||
| std::vector<float> areas(boxes_num); | std::vector<float> areas(boxes_num); | ||||
| std::vector<int> order(boxes_num); | std::vector<int> order(boxes_num); | ||||
| for (int i = 0; i < boxes_num; i++) { | for (int i = 0; i < boxes_num; i++) { | ||||
| y1[i] = all_boxes[i][0]; | |||||
| x1[i] = all_boxes[i][1]; | |||||
| y2[i] = all_boxes[i][2]; | |||||
| x2[i] = all_boxes[i][3]; | |||||
| areas[i] = (x2[i] - x1[i] + 1) * (y2[i] - y1[i] + 1); | |||||
| areas[i] = (all_boxes[i][3] - all_boxes[i][1] + 1) * (all_boxes[i][2] - all_boxes[i][0] + 1); | |||||
| order[i] = i; | order[i] = i; | ||||
| } | } | ||||
| @@ -543,10 +535,10 @@ std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std: | |||||
| int len = order.size() - 1; | int len = order.size() - 1; | ||||
| std::vector<float> ovr(len); | std::vector<float> ovr(len); | ||||
| for (int j = 0; j < len; j++) { | for (int j = 0; j < len; j++) { | ||||
| float xx1 = std::max(x1[i], x1[order[j + 1]]); | |||||
| float yy1 = std::max(y1[i], y1[order[j + 1]]); | |||||
| float xx2 = std::min(x2[i], x2[order[j + 1]]); | |||||
| float yy2 = std::min(y2[i], y2[order[j + 1]]); | |||||
| float xx1 = std::max(all_boxes[i][1], all_boxes[order[j + 1]][1]); | |||||
| float yy1 = std::max(all_boxes[i][0], all_boxes[order[j + 1]][0]); | |||||
| float xx2 = std::min(all_boxes[i][3], all_boxes[order[j + 1]][3]); | |||||
| float yy2 = std::min(all_boxes[i][2], all_boxes[order[j + 1]][2]); | |||||
| float w = std::max(0.0f, xx2 - xx1 + 1); | float w = std::max(0.0f, xx2 - xx1 + 1); | ||||
| float h = std::max(0.0f, yy2 - yy1 + 1); | float h = std::max(0.0f, yy2 - yy1 + 1); | ||||
| @@ -568,14 +560,15 @@ std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std: | |||||
| return keep; | return keep; | ||||
| } | } | ||||
| void WarpAffine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, UINT8_C3 borderValue) { | |||||
| template <typename Pixel_Type> | |||||
| void ImplementAffine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> &dsize, Pixel_Type borderValue) { | |||||
| double IM[6]; | double IM[6]; | ||||
| for (int i = 0; i < 6; i++) { | for (int i = 0; i < 6; i++) { | ||||
| IM[i] = M[i]; | IM[i] = M[i]; | ||||
| } | } | ||||
| double D = IM[0] * IM[4] - IM[1] * IM[3]; | double D = IM[0] * IM[4] - IM[1] * IM[3]; | ||||
| D = D != 0 ? 1. / D : 0; | |||||
| D = D != 0 ? 1.0f / D : 0; | |||||
| double A11 = IM[4] * D, A22 = IM[0] * D; | double A11 = IM[4] * D, A22 = IM[0] * D; | ||||
| IM[0] = A11; | IM[0] = A11; | ||||
| IM[1] *= -D; | IM[1] *= -D; | ||||
| @@ -592,13 +585,22 @@ void WarpAffine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> | |||||
| int src_x = IM[0] * x + IM[1] * y + IM[2]; | int src_x = IM[0] * x + IM[1] * y + IM[2]; | ||||
| int src_y = IM[3] * x + IM[4] * y + IM[5]; | int src_y = IM[3] * x + IM[4] * y + IM[5]; | ||||
| if (src_x >= 0 && src_y >= 0 && src_x < src.width_ && src_y < src.height_) { | if (src_x >= 0 && src_y >= 0 && src_x < src.width_ && src_y < src.height_) { | ||||
| UINT8_C3 src_pixel = static_cast<UINT8_C3 *>(src.data_ptr_)[src_y * src.width_ + src_x]; | |||||
| static_cast<UINT8_C3 *>(out_img.data_ptr_)[y * src.width_ + x] = src_pixel; | |||||
| Pixel_Type src_pixel = static_cast<Pixel_Type *>(src.data_ptr_)[src_y * src.width_ + src_x]; | |||||
| static_cast<Pixel_Type *>(out_img.data_ptr_)[y * src.width_ + x] = src_pixel; | |||||
| } else { | } else { | ||||
| static_cast<UINT8_C3 *>(out_img.data_ptr_)[y * src.width_ + x] = borderValue; | |||||
| static_cast<Pixel_Type *>(out_img.data_ptr_)[y * src.width_ + x] = borderValue; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void Affine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, UINT8_C1 borderValue) { | |||||
| ImplementAffine(src, out_img, M, dsize, borderValue); | |||||
| } | |||||
| void Affine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, UINT8_C3 borderValue) { | |||||
| ImplementAffine(src, out_img, M, dsize, borderValue); | |||||
| } | |||||
| } // namespace dataset | } // namespace dataset | ||||
| } // namespace mindspore | } // namespace mindspore | ||||
| @@ -20,6 +20,7 @@ | |||||
| #include <math.h> | #include <math.h> | ||||
| #include <vector> | #include <vector> | ||||
| #include <algorithm> | #include <algorithm> | ||||
| #include <iostream> | |||||
| #include "lite_cv/lite_mat.h" | #include "lite_cv/lite_mat.h" | ||||
| @@ -68,13 +69,20 @@ bool SubStractMeanNormalize(const LiteMat &src, LiteMat &dst, float *mean, float | |||||
| bool Padd(const LiteMat &src, LiteMat &dst, int top, int bottom, int left, int right, PaddBorderType pad_type, | bool Padd(const LiteMat &src, LiteMat &dst, int top, int bottom, int left, int right, PaddBorderType pad_type, | ||||
| uint8_t fill_b_or_gray, uint8_t fill_g, uint8_t fill_r); | uint8_t fill_b_or_gray, uint8_t fill_g, uint8_t fill_r); | ||||
| void WarpAffine(const LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, uint8_t borderValue[3]); | |||||
| /// \brief Apply affine transformation for 1 channel image | |||||
| void Affine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, UINT8_C1 borderValue); | |||||
| /// \brief Apply affine transformation for 3 channel image | |||||
| void Affine(LiteMat &src, LiteMat &out_img, double M[6], std::vector<size_t> dsize, UINT8_C3 borderValue); | |||||
| /// \brief Get default anchor boxes for Faster R-CNN, SSD, YOLO etc | |||||
| std::vector<std::vector<float>> GetDefaultBoxes(const BoxesConfig config); | std::vector<std::vector<float>> GetDefaultBoxes(const BoxesConfig config); | ||||
| /// \brief Convert the prediction boxes to the actual boxes of (y, x, h, w) | |||||
| void ConvertBoxes(std::vector<std::vector<float>> &boxes, const std::vector<std::vector<float>> &default_boxes, | void ConvertBoxes(std::vector<std::vector<float>> &boxes, const std::vector<std::vector<float>> &default_boxes, | ||||
| const BoxesConfig config); | const BoxesConfig config); | ||||
| /// \brief Apply Non-Maximum Suppression | |||||
| std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std::vector<float> &all_scores, float thres, | std::vector<int> ApplyNms(const std::vector<std::vector<float>> &all_boxes, std::vector<float> &all_scores, float thres, | ||||
| int max_boxes); | int max_boxes); | ||||
| @@ -27,17 +27,20 @@ namespace dataset { | |||||
| template <typename T> | template <typename T> | ||||
| struct Chn1 { | struct Chn1 { | ||||
| Chn1(T c1) : c1(c1) {} | |||||
| T c1; | T c1; | ||||
| }; | }; | ||||
| template <typename T> | template <typename T> | ||||
| struct Chn2 { | struct Chn2 { | ||||
| Chn2(T c1, T c2) : c1(c1), c2(c2) {} | |||||
| T c1; | T c1; | ||||
| T c2; | T c2; | ||||
| }; | }; | ||||
| template <typename T> | template <typename T> | ||||
| struct Chn3 { | struct Chn3 { | ||||
| Chn3(T c1, T c2, T c3) : c1(c1), c2(c2), c3(c3) {} | |||||
| T c1; | T c1; | ||||
| T c2; | T c2; | ||||
| T c3; | T c3; | ||||
| @@ -45,6 +48,7 @@ struct Chn3 { | |||||
| template <typename T> | template <typename T> | ||||
| struct Chn4 { | struct Chn4 { | ||||
| Chn4(T c1, T c2, T c3, T c4) : c1(c1), c2(c2), c3(c3), c4(c4) {} | |||||
| T c1; | T c1; | ||||
| T c2; | T c2; | ||||
| T c3; | T c3; | ||||
| @@ -21,6 +21,8 @@ | |||||
| #include <opencv2/imgproc/types_c.h> | #include <opencv2/imgproc/types_c.h> | ||||
| #include "utils/log_adapter.h" | #include "utils/log_adapter.h" | ||||
| #include <fstream> | |||||
| using namespace mindspore::dataset; | using namespace mindspore::dataset; | ||||
| class MindDataImageProcess : public UT::Common { | class MindDataImageProcess : public UT::Common { | ||||
| public: | public: | ||||
| @@ -228,6 +230,7 @@ TEST_F(MindDataImageProcess, TestPadd) { | |||||
| } | } | ||||
| TEST_F(MindDataImageProcess, TestGetDefaultBoxes) { | TEST_F(MindDataImageProcess, TestGetDefaultBoxes) { | ||||
| std::string benchmark = "data/dataset/testLite/default_boxes.bin"; | |||||
| BoxesConfig config; | BoxesConfig config; | ||||
| config.img_shape = {300, 300}; | config.img_shape = {300, 300}; | ||||
| config.num_default = {3, 6, 6, 6, 6, 6}; | config.num_default = {3, 6, 6, 6, 6, 6}; | ||||
| @@ -238,8 +241,25 @@ TEST_F(MindDataImageProcess, TestGetDefaultBoxes) { | |||||
| config.steps = {16, 32, 64, 100, 150, 300}; | config.steps = {16, 32, 64, 100, 150, 300}; | ||||
| config.prior_scaling = {0.1, 0.2}; | config.prior_scaling = {0.1, 0.2}; | ||||
| int rows = 1917; | |||||
| int cols = 4; | |||||
| std::vector<double> benchmark_boxes(rows * cols); | |||||
| std::ifstream in(benchmark, std::ios::in | std::ios::binary); | |||||
| in.read(reinterpret_cast<char*>(benchmark_boxes.data()), benchmark_boxes.size() * sizeof(double)); | |||||
| in.close(); | |||||
| std::vector<std::vector<float>> default_boxes = GetDefaultBoxes(config); | std::vector<std::vector<float>> default_boxes = GetDefaultBoxes(config); | ||||
| ASSERT_TRUE(default_boxes.size() == 1917); | |||||
| EXPECT_EQ(default_boxes.size(), rows); | |||||
| EXPECT_EQ(default_boxes[0].size(), cols); | |||||
| double distance = 0.0f; | |||||
| for (int i = 0; i < rows; i++) { | |||||
| for (int j = 0; j < cols; j++) { | |||||
| distance += pow(default_boxes[i][j] - benchmark_boxes[i * cols + j], 2); | |||||
| } | |||||
| } | |||||
| distance = sqrt(distance); | |||||
| EXPECT_LT(distance, 1e-5); | |||||
| } | } | ||||
| TEST_F(MindDataImageProcess, TestApplyNms) { | TEST_F(MindDataImageProcess, TestApplyNms) { | ||||
| @@ -250,3 +270,67 @@ TEST_F(MindDataImageProcess, TestApplyNms) { | |||||
| ASSERT_TRUE(keep[1] == 0); | ASSERT_TRUE(keep[1] == 0); | ||||
| ASSERT_TRUE(keep[2] == 1); | ASSERT_TRUE(keep[2] == 1); | ||||
| } | } | ||||
| TEST_F(MindDataImageProcess, TestAffine) { | |||||
| // The input matrix | |||||
| // 0 0 1 0 0 | |||||
| // 0 0 1 0 0 | |||||
| // 2 2 3 2 2 | |||||
| // 0 0 1 0 0 | |||||
| // 0 0 1 0 0 | |||||
| size_t rows = 5; | |||||
| size_t cols = 5; | |||||
| LiteMat src(rows, cols); | |||||
| for (size_t i = 0; i < rows; i++) { | |||||
| for (size_t j = 0; j < cols; j++) { | |||||
| if (i == 2 && j == 2) { | |||||
| static_cast<UINT8_C1*>(src.data_ptr_)[i * cols + j] = 3; | |||||
| } else if (i == 2) { | |||||
| static_cast<UINT8_C1*>(src.data_ptr_)[i * cols + j] = 2; | |||||
| } else if (j == 2) { | |||||
| static_cast<UINT8_C1*>(src.data_ptr_)[i * cols + j] = 1; | |||||
| } else { | |||||
| static_cast<UINT8_C1*>(src.data_ptr_)[i * cols + j] = 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| // Expect output matrix | |||||
| // 0 0 2 0 0 | |||||
| // 0 0 2 0 0 | |||||
| // 1 1 3 1 1 | |||||
| // 0 0 2 0 0 | |||||
| // 0 0 2 0 0 | |||||
| LiteMat expect(rows, cols); | |||||
| for (size_t i = 0; i < rows; i++) { | |||||
| for (size_t j = 0; j < cols; j++) { | |||||
| if (i == 2 && j == 2) { | |||||
| static_cast<UINT8_C1*>(expect.data_ptr_)[i * cols + j] = 3; | |||||
| } else if (i == 2) { | |||||
| static_cast<UINT8_C1*>(expect.data_ptr_)[i * cols + j] = 1; | |||||
| } else if (j == 2) { | |||||
| static_cast<UINT8_C1*>(expect.data_ptr_)[i * cols + j] = 2; | |||||
| } else { | |||||
| static_cast<UINT8_C1*>(expect.data_ptr_)[i * cols + j] = 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| double angle = 90.0f; | |||||
| cv::Point2f center(rows / 2, cols / 2); | |||||
| cv::Mat rotate_matrix = cv::getRotationMatrix2D(center, angle, 1.0); | |||||
| double M[6]; | |||||
| for (size_t i = 0; i < 6; i++) { | |||||
| M[i] = rotate_matrix.at<double>(i); | |||||
| } | |||||
| std::cout << std::endl; | |||||
| LiteMat dst; | |||||
| Affine(src, dst, M, {rows, cols}, UINT8_C1(0)); | |||||
| for (size_t i = 0; i < rows; i++) { | |||||
| for (size_t j = 0; j < cols; j++) { | |||||
| EXPECT_EQ(static_cast<UINT8_C1*>(expect.data_ptr_)[i * cols + j].c1, | |||||
| static_cast<UINT8_C1*>(dst.data_ptr_)[i * cols + j].c1); | |||||
| } | |||||
| } | |||||
| } | |||||