diff --git a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/canny.cc b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/canny.cc index eb5b9419f9..e03136c228 100644 --- a/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/canny.cc +++ b/mindspore/ccsrc/minddata/dataset/kernels/image/lite_cv/canny.cc @@ -32,7 +32,7 @@ namespace mindspore { namespace dataset { -static void GetSobelKernel(float *kernel, int flag, int ksize) { +static void GetSobelKernel(float *kernel, int flag, int ksize, double scale) { std::vector buffer(ksize + 1); float *ptr = kernel; @@ -70,12 +70,14 @@ static void GetSobelKernel(float *kernel, int flag, int ksize) { } } + scale = flag == 0 ? scale : 1.0; for (int i = 0; i < ksize; i++) { - ptr[i] = buffer[i]; + ptr[i] = buffer[i] * scale; } } -bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize, PaddBorderType pad_type) { // NOLINT +bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize, double scale, // NOLINT + PaddBorderType pad_type) { if (src.IsEmpty() || src.data_type_ != LDataType::UINT8) { return false; } @@ -92,8 +94,8 @@ bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize, kx.Init(ksize, 1, 1, LDataType::FLOAT32); ky.Init(1, ksize, 1, LDataType::FLOAT32); - GetSobelKernel(kx, flag_x, ksize); - GetSobelKernel(ky, flag_y, ksize); + GetSobelKernel(kx, flag_x, ksize, scale); + GetSobelKernel(ky, flag_y, ksize, scale); return ConvRowCol(src, kx, ky, dst, LDataType::FLOAT32, pad_type); } @@ -106,6 +108,24 @@ static float GetEdge(const std::vector &temp, int width, int height, int } } +static float Round(float value) { + // rounding if the result is even + // eg. 1.5 -> 2, 2.5 -> 2 + float rnd = round(value); + float rnd_l = floor(value); + float rnd_h = ceil(value); + if (value - rnd_l == 0.5) { + if (fmod(rnd, 2) == 0) { + return rnd; + } else if (value > 0) { + return rnd_l; + } else { + return rnd_h; + } + } + return rnd; +} + static void NonMaximumSuppression(const LiteMat &gx, const LiteMat &gy, LiteMat &edges, bool L2gradient) { // NOLINT edges.Init(gx.width_, gx.height_, gx.channel_, gx.data_type_); @@ -116,8 +136,8 @@ static void NonMaximumSuppression(const LiteMat &gx, const LiteMat &gy, LiteMat int size = gx.height_ * gx.width_; std::vector temp(size); for (int i = 0; i < size; i++) { - float gx_value = gx_ptr[i]; - float gy_value = gy_ptr[i]; + float gx_value = Round(gx_ptr[i]); + float gy_value = Round(gy_ptr[i]); if (L2gradient) { temp[i] = sqrt(gx_value * gx_value + gy_value * gy_value); } else { @@ -127,8 +147,8 @@ static void NonMaximumSuppression(const LiteMat &gx, const LiteMat &gy, LiteMat for (int y = 0; y < gx.height_; y++) { for (int x = 0; x < gx.width_; x++) { - float gx_value = gx_ptr[y * gx.width_ + x]; - float gy_value = gy_ptr[y * gx.width_ + x]; + float gx_value = Round(gx_ptr[y * gx.width_ + x]); + float gy_value = Round(gy_ptr[y * gx.width_ + x]); float gx_value_abs = std::abs(gx_value); float gy_value_abs = std::abs(gy_value); @@ -242,9 +262,13 @@ bool Canny(const LiteMat &src, LiteMat &dst, double low_thresh, double high_thre dst.Init(src.width_, src.height_, src.channel_, src.data_type_); } + double scale = ksize == 7 ? 1 / 16.0 : 1.0; + low_thresh *= scale; + high_thresh *= scale; + LiteMat gx, gy; - Sobel(src, gx, 1, 0, ksize, PaddBorderType::PADD_BORDER_REPLICATE); - Sobel(src, gy, 0, 1, ksize, PaddBorderType::PADD_BORDER_REPLICATE); + Sobel(src, gx, 1, 0, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE); + Sobel(src, gy, 0, 1, ksize, scale, PaddBorderType::PADD_BORDER_REPLICATE); LiteMat edges; NonMaximumSuppression(gx, gy, edges, L2gradient); 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 08f4820d4c..8526c282a7 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 @@ -148,7 +148,8 @@ bool ConvRowCol(const LiteMat &src, const LiteMat &kx, const LiteMat &ky, LiteMa PaddBorderType pad_type = PaddBorderType::PADD_BORDER_DEFAULT); /// \brief Filter the image by a Sobel kernel -bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize, PaddBorderType pad_type); +bool Sobel(const LiteMat &src, LiteMat &dst, int flag_x, int flag_y, int ksize = 3, double scale = 1.0, + PaddBorderType pad_type = PaddBorderType::PADD_BORDER_DEFAULT); /// \brief Convert RGB image or color image to grayscale image bool ConvertRgbToGray(const LiteMat &src, LDataType data_type, int w, int h, LiteMat &mat); diff --git a/tests/ut/cpp/dataset/image_process_test.cc b/tests/ut/cpp/dataset/image_process_test.cc index 5e024fdb04..0539f66cac 100644 --- a/tests/ut/cpp/dataset/image_process_test.cc +++ b/tests/ut/cpp/dataset/image_process_test.cc @@ -1595,6 +1595,35 @@ TEST_F(MindDataImageProcess, TestCannySize5) { EXPECT_EQ(distance, 0.0f); } +TEST_F(MindDataImageProcess, TestCannySize7) { + 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 dst_image; + cv::Canny(gray_image, dst_image, 110, 220, 7); + + 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); + ASSERT_TRUE(ret == true); + + LiteMat lite_mat_dst; + ret = Canny(lite_mat_gray, lite_mat_dst, 110, 220, 7); + ASSERT_TRUE(ret == true); + + int total_size = lite_mat_dst.height_ * lite_mat_dst.width_ * lite_mat_dst.channel_; + double distance = 0.0f; + for (int i = 0; i < total_size; i++) { + distance += pow((uint8_t)dst_image.data[i] - ((uint8_t *)lite_mat_dst)[i], 2); + } + distance = sqrt(distance / total_size); + EXPECT_EQ(distance, 0.0f); +} + TEST_F(MindDataImageProcess, TestCannyL2) { std::string filename = "data/dataset/apple.jpg"; cv::Mat src_image = cv::imread(filename, cv::ImreadModes::IMREAD_COLOR); @@ -1689,8 +1718,8 @@ TEST_F(MindDataImageProcess, TestSobel) { ASSERT_TRUE(ret == true); LiteMat lite_mat_x; LiteMat lite_mat_y; - Sobel(lite_mat_gray, lite_mat_x, 1, 0, 3, PaddBorderType::PADD_BORDER_REPLICATE); - Sobel(lite_mat_gray, lite_mat_y, 0, 1, 3, PaddBorderType::PADD_BORDER_REPLICATE); + Sobel(lite_mat_gray, lite_mat_x, 1, 0, 3, 1, PaddBorderType::PADD_BORDER_REPLICATE); + Sobel(lite_mat_gray, lite_mat_y, 0, 1, 3, 1, PaddBorderType::PADD_BORDER_REPLICATE); ASSERT_TRUE(ret == true); cv::Mat dst_imageX(lite_mat_x.height_, lite_mat_x.width_, CV_32FC1, lite_mat_x.data_ptr_); @@ -1731,7 +1760,7 @@ TEST_F(MindDataImageProcess, TestSobelFlag) { InitFromPixel(rgba_mat.data, LPixelType::RGBA2GRAY, LDataType::UINT8, rgba_mat.cols, rgba_mat.rows, lite_mat_gray); ASSERT_TRUE(ret == true); LiteMat lite_mat_x; - Sobel(lite_mat_gray, lite_mat_x, 3, 1, 5, PaddBorderType::PADD_BORDER_REPLICATE); + Sobel(lite_mat_gray, lite_mat_x, 3, 1, 5, 1, PaddBorderType::PADD_BORDER_REPLICATE); ASSERT_TRUE(ret == true); cv::Mat dst_imageX(lite_mat_x.height_, lite_mat_x.width_, CV_32FC1, lite_mat_x.data_ptr_);