Skip to content

Commit

Permalink
Merge pull request #1 from MengqingCao/npu_support
Browse files Browse the repository at this point in the history
Add reisze and crop operations support for NPU
  • Loading branch information
MengqingCao authored Oct 20, 2023
2 parents 2820b30 + afdd121 commit 26650b0
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 11 deletions.
71 changes: 60 additions & 11 deletions modules/cannops/include/opencv2/cann_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ namespace cann
{

/**
@addtogroup cann
@{
@defgroup cannops Operations for Ascend Backend.
@addtogroup cann
@{
@defgroup cannops_elem Per-element Operations
@defgroup cannops_core Core Operations on Matrices
@defgroup cannimgproc Image Processing
@defgroup cannops Operations for Ascend Backend.
@{
@defgroup cannops_elem Per-element Operations
@defgroup cannops_core Core Operations on Matrices
@defgroup cannimgproc Image Processing
@}
@}
@}
*/

//! @addtogroup cannops_elem
Expand Down Expand Up @@ -106,10 +106,10 @@ CV_EXPORTS_W void multiply(Scalar src1, InputArray src2, OutputArray dst, float
CV_EXPORTS_W void divide(InputArray src1, InputArray src2, OutputArray dst, float scale = 1,
int dtype = -1, AscendStream& stream = AscendStream::Null());
#ifdef NEVER_DEFINED
CV_EXPORTS_W void divide(InputArray src1, Scalar src2, OutputArray dst, float scale = 1, int dtype = -1,
AscendStream& stream = AscendStream::Null());
CV_EXPORTS_W void divide(Scalar src1, InputArray src2, OutputArray dst, float scale = 1, int dtype = -1,
AscendStream& stream = AscendStream::Null());
CV_EXPORTS_W void divide(InputArray src1, Scalar src2, OutputArray dst, float scale = 1,
int dtype = -1, AscendStream& stream = AscendStream::Null());
CV_EXPORTS_W void divide(Scalar src1, InputArray src2, OutputArray dst, float scale = 1,
int dtype = -1, AscendStream& stream = AscendStream::Null());
#endif

/** @brief Performs a per-element bitwise conjunction of two matrices (or of matrix and scalar).
Expand Down Expand Up @@ -306,6 +306,55 @@ and the rows and cols are switched for ROTATE_90_CLOCKWISE and ROTATE_90_COUNTER
*/
CV_EXPORTS_W void rotate(InputArray src, OutputArray dst, int rotateCode,
AscendStream& stream = AscendStream::Null());

/** @brief Resizes an image src down to or up to the specified size.
@param src input image
@param dst output image; it has the size dsize (when it is non-zero) or the size computed from
src.size(), fx, and fy; the type of dst is the same as of src.
@param dsize output image size; if it equals zero, it is computed as:
\f[𝚍𝚜𝚒𝚣𝚎 = 𝚂𝚒𝚣𝚎(𝚛𝚘𝚞𝚗𝚍(𝚏𝚡*𝚜𝚛𝚌.𝚌𝚘𝚕𝚜), 𝚛𝚘𝚞𝚗𝚍(𝚏𝚢*𝚜𝚛𝚌.𝚛𝚘𝚠𝚜))\f]
Either dsize or both fx and fy must be non-zero.
@param fx scale factor along the horizontal axis; when it equals 0, it is computed as
\f[(𝚍𝚘𝚞𝚋𝚕𝚎)𝚍𝚜𝚒𝚣𝚎.𝚠𝚒𝚍𝚝𝚑/𝚜𝚛𝚌.𝚌𝚘𝚕𝚜\f]
@param fy scale factor along the vertical axis; when it equals 0, it is computed as
\f[(𝚍𝚘𝚞𝚋𝚕𝚎)𝚍𝚜𝚒𝚣𝚎.𝚑𝚎𝚒𝚐𝚑𝚝/𝚜𝚛𝚌.𝚛𝚘𝚠𝚜\f]
@param interpolation interpolation method(see **cv.cann.InterpolationFlags**)
@sa cv::resize
*/

//! interpolation algorithm
enum InterpolationFlags
{
/** nearest neighbor interpolation */
INTER_NEAREST = 0,
/** bilinear interpolation */
INTER_LINEAR = 1,
/** bicubic interpolation */
INTER_CUBIC = 2,
/** resampling using pixel area relation. It may be a preferred method for image decimation, as
it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST
method. */
INTER_AREA = 3,
/** mask for interpolation codes */
INTER_MAX = 7,
};

CV_EXPORTS_W void resize(InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x,
double inv_scale_y, int interpolation,
AscendStream& stream = AscendStream::Null());

/** @brief crop a 2D array.
The function crops the matrix by given cv::Rect.
Output matrix must be of the same depth as input one, size is specified by given rect size.
@param src input array.
@param rect a rect to crop a array to
@sa cv::gapi::crop
*/
CV_EXPORTS_W AscendMat crop(InputArray _src, const Rect& rect,
AscendStream& stream = AscendStream::Null());
//! @} cannops_core

//! @addtogroup cannimgproc
Expand Down
2 changes: 2 additions & 0 deletions modules/cannops/include/opencv2/cann_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ void transpose(const AscendMat& src, int64_t* perm, AscendMat& dst, AscendStream
void flip(const AscendMat& src, std::vector<int32_t>& asixs, AscendMat& dst, AscendStream& stream);
void merge(const AscendMat* src, size_t n, AscendMat& dst, AscendStream& stream);
void split(const AscendMat& src, AscendMat* dst, AscendStream& stream);
void resize(AscendMat& src, AscendMat& dst, const int32_t* dstSize, int interpolation,
AscendStream& stream);

double threshold(AscendMat& src, AscendMat& dst, double thresh, double maxval, int type,
AscendStream& stream);
Expand Down
11 changes: 11 additions & 0 deletions modules/cannops/perf/perf_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,16 @@ PERF_TEST_P(CPU, CROP, TYPICAL_ASCEND_MAT_SIZES)
SANITY_CHECK_NOTHING();
}

PERF_TEST_P(NPU, CROP_OVERLOAD, TYPICAL_ASCEND_MAT_SIZES)
{
Mat mat(GET_PARAM(0), CV_8UC3);
Mat dst;
declare.in(mat, WARMUP_RNG);
Rect b(1, 2, 4, 4);
cv::cann::setDevice(DEVICE_ID);
TEST_CYCLE() { cv::cann::crop(mat, b); }
cv::cann::resetDevice();
SANITY_CHECK_NOTHING();
}
} // namespace
} // namespace opencv_test
85 changes: 85 additions & 0 deletions modules/cannops/src/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,90 @@ void rotate(InputArray _src, OutputArray _dst, int rotateMode, AscendStream& str
syncOutput(dst, _dst, stream);
}

AscendMat crop(InputArray _src, const Rect& rect, AscendStream& stream)
{
AscendMat src = getInputMat(_src, stream);
AscendMat dst, sizeSrcNpu;

// left-up conner
int x = rect.x, y = rect.y, width = rect.width, height = rect.height;
int64_t offset[] = {y, x, 0};

CV_Assert(x + width <= src.cols && y + height <= src.rows);
int16_t size1[] = {1, src.channels(), height, width};
dst.create(height, width, src.type());

Mat sizeSrc(height, width, src.type(), size1);
sizeSrcNpu.upload(sizeSrc);

OperatorRunner runner;
runner.setOp("Crop")
.addInput(src, "x")
.addInput(sizeSrcNpu, "size")
.addAttr(1, "axis")
.addAttr(offset, 3, "offsets")
.addOutput(dst, "y")
.run(stream);
return dst;
}

void resize(AscendMat& src, AscendMat& dst, const int32_t* dstSize, int interpolation,
AscendStream& stream)
{
OperatorRunner runner;
int64_t dims[] = {2};
char const* mode;
switch (interpolation)
{
case INTER_CUBIC:
mode = "ResizeBicubic";
break;
case INTER_AREA:
mode = "ResizeArea";
break;
default:
break;
}

runner.setOp(mode)
.addInput(src, "images")
.addInput<int32_t>(dstSize, dims, 1, ACL_INT32, "size")
.addAttr(true, "half_pixel_centers")
.addOutput(dst, "y")
.run(stream);
}

void resize(InputArray _src, OutputArray _dst, Size dsize, double inv_scale_x, double inv_scale_y,
int interpolation, AscendStream& stream)
{
AscendMat src = getInputMat(_src, stream);
Size ssize = _src.size();
CV_Assert(!ssize.empty());
float_t scaleX = (float_t)inv_scale_x;
float_t scaleY = (float_t)inv_scale_y;
CV_Assert(interpolation == INTER_CUBIC || interpolation == INTER_AREA);

if (dsize.empty())
{
CV_Assert(scaleX > 0);
CV_Assert(scaleY > 0);
dsize = Size(saturate_cast<int>(ssize.width * inv_scale_x),
saturate_cast<int>(ssize.height * inv_scale_y));
CV_Assert(!dsize.empty());
}
else
{
scaleX = (float_t)dsize.width / ssize.width;
scaleY = (float_t)dsize.height / ssize.height;
CV_Assert(scaleX > 0);
CV_Assert(scaleY > 0);
}
AscendMat dst = getOutputMat(_dst, dsize.height, dsize.width, src.type(), stream);
int32_t dstSize[] = {dsize.width, dsize.height};

resize(src, dst, dstSize, interpolation, stream);
syncOutput(dst, _dst, stream);
}

} // namespace cann
} // namespace cv
28 changes: 28 additions & 0 deletions modules/cannops/test/test_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,33 @@ TEST(CORE, CROP)
EXPECT_MAT_NEAR(cropped_cv, checker, 1e-10);
}

TEST(CORE, CROP_OVERLOAD)
{
Mat cpuOpRet, checker, cpuMat = randomMat(6, 6, CV_16SC3, 0.0, 255.0);
const Rect b(1, 2, 4, 4);
Mat cropped_cv = cpuMat(b);
AscendMat cropped_cann = cv::cann::crop(cpuMat, b);
cropped_cann.download(checker);
EXPECT_MAT_NEAR(cropped_cv, checker, 1e-10);
}

TEST(CORE, RESIZE)
{
Mat resized_cv, checker, cpuMat = randomMat(10, 10, CV_32F, 100.0, 255.0);
Size dsize = Size(6, 6);
// only support {2 INTER_CUBIC} and {3 INTER_AREA}
// only the resize result of INTER_AREA is close to CV's.
int flags = 3;
cv::cann::setDevice(0);
cv::resize(cpuMat, resized_cv, dsize, 0, 0, flags);
cv::cann::resize(cpuMat, checker, dsize, 0, 0, flags);
EXPECT_MAT_NEAR(resized_cv, checker, 1e-4);

cv::resize(cpuMat, resized_cv, Size(), 0.6, 0.6, flags);
cv::cann::resize(cpuMat, checker, Size(), 0.6, 0.6, flags);
EXPECT_MAT_NEAR(resized_cv, checker, 1e-4);
cv::cann::resetDevice();
}

} // namespace
} // namespace opencv_test

0 comments on commit 26650b0

Please sign in to comment.