Skip to content

Commit

Permalink
Decoupled from the opencv main repository
Browse files Browse the repository at this point in the history
Co-authored-by: CaoMengqing <[email protected]>
  • Loading branch information
hipudding and MengqingCao committed Nov 3, 2023
1 parent 2820b30 commit 7ab8521
Show file tree
Hide file tree
Showing 19 changed files with 1,641 additions and 382 deletions.
15 changes: 13 additions & 2 deletions modules/cannops/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# libacl_op_compiler.so
set(lib_acl_op_compiler "${CANN_INSTALL_DIR}/lib64")
find_library(found_lib_acl_op_compiler NAMES acl_op_compiler PATHS ${lib_acl_op_compiler} NO_DEFAULT_PATH)
if(found_lib_acl_op_compiler)
set(lib_acl_op_compiler ${found_lib_acl_op_compiler})
message(STATUS "CANN: libacl_op_compiler.so is found at ${lib_acl_op_compiler}")
else()
message(STATUS "CANN: Missing libacl_op_compiler.so. Turning off HAVE_CANN")
set(HAVE_CANN OFF)
return()
endif()
if(IOS OR WINRT OR ANDROID OR APPLE OR WIN32 OR (NOT HAVE_CANN))
ocv_module_disable(cannops)
endif()
Expand All @@ -7,8 +18,8 @@ set(the_description "Ascend-accelerated Operations on Matrices")
ocv_add_module(cannops opencv_core WRAP python)
ocv_module_include_directories(${CANN_INCLUDE_DIRS})
ocv_glob_module_sources()
ocv_install_used_external_targets(${CANN_LIBRARIES})
ocv_create_module(${CANN_LIBRARIES})
ocv_install_used_external_targets(${CANN_LIBRARIES} ${lib_acl_op_compiler})
ocv_create_module(${CANN_LIBRARIES} ${lib_acl_op_compiler})

ocv_include_directories(${CMAKE_SOURCE_DIR}/modules/ts/include)

Expand Down
2 changes: 2 additions & 0 deletions modules/cannops/include/opencv2/cann.inl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ inline AscendMat::AscendMat(AscendMat::Allocator* allocator_)
: flags(0), rows(0), cols(0), step(0), datastart(0), dataend(0),
allocator(allocator_)
{
// Empty mat is also continuous.
flags |= Mat::CONTINUOUS_FLAG;
}

inline AscendMat::AscendMat(int rows_, int cols_, int type_, AscendMat::Allocator* allocator_)
Expand Down
24 changes: 23 additions & 1 deletion modules/cannops/include/opencv2/cann_call.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace cv
{
namespace cann
{
// Warpper for functions in CANN, callers should not call CANN's api directly, but should call the
// function provided in cann_call.
void aclrtMallocWarpper(void** data, size_t size);
void aclrtFreeWarpper(void* data);
void aclrtMemcpyWarpper(std::shared_ptr<uchar>& dst, size_t offset, const void* src, size_t size,
Expand All @@ -34,21 +36,35 @@ void aclrtMemcpy2dWarpper(void* dst, size_t dpitch, const std::shared_ptr<uchar>
AscendStream& stream);
void aclrtMemsetWarpper(std::shared_ptr<uchar>& ptr, int32_t value, size_t count,
AscendStream& stream);
//! Type mapping between opencv and cann.
aclDataType getACLType(int opencvdepth);
//! Malloc and upload raw data to devices.
std::shared_ptr<uchar> mallocAndUpload(const void* data, size_t size, AscendStream& stream,
AscendMat::Allocator* allocator);

/**
* @brief Warpper of CANN streams.
*/
class AscendStream::Impl
{
public:
aclrtStream stream;
bool ownStream;
/**
* @brief Ascend and CANN use stream to implement asynchronous calls. Which means when function
* returns, operator may not finish, even not start. If caller free any tensors that participate
* in this operatation, it have a chance to access invalid memory.
* All tensors should add to holder, holder will be cleaned by waitForCompletion function, or when
* the stream is destructing.
*/
std::set<std::shared_ptr<uchar>> tensorHolders;
Impl();
explicit Impl(aclrtStream stream);
void AddTensorHolder(const std::shared_ptr<uchar>& tensorData);
};

/**
* @brief Warpper of CANN event.
*/
class AscendEvent::Impl
{
public:
Expand All @@ -60,6 +76,9 @@ class AscendEvent::Impl
~Impl();
};

/**
* @brief Parameter type for call_call interfaces.
*/
struct AscendTensor
{
const char* name;
Expand All @@ -79,6 +98,9 @@ struct AscendTensor
aclFormat format = ACL_FORMAT_ND);
};

/**
* @brief Interface to call operators in CANN package.
*/
class OperatorRunner
{
private:
Expand Down
283 changes: 232 additions & 51 deletions modules/cannops/include/opencv2/cann_interface.hpp

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions modules/cannops/include/opencv2/cann_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ void arithm_op(const Scalar& sc, const AscendMat& src, AscendMat& dst, const cha
void arithm_op(const AscendMat& src, AscendMat& dst, const char* op, AscendStream& stream);
void arithm_op(const AscendMat& src, float scalar, AscendMat& dst, const char* op,
AscendStream& stream);
void transData(const AscendMat& src, AscendMat& dst, const char* from, const char* to,
AscendStream& stream);
void transpose(const AscendMat& src, int64_t* perm, AscendMat& dst, AscendStream& stream);
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);

double threshold(AscendMat& src, AscendMat& dst, double thresh, double maxval, int type,
AscendStream& stream);
void crop(const AscendMat& src, AscendMat& dst, const AscendMat& sizeSrcNpu, int64_t* offset,
AscendStream& stream);
void transData(const AscendMat& src, AscendMat& dst, const char* from, const char* to,
AscendStream& stream);
void resize(const AscendMat& src, AscendMat& dst, int32_t* dstSize, int interpolation,
AscendStream& stream);
} // namespace cann
} // namespace cv

Expand Down
137 changes: 132 additions & 5 deletions modules/cannops/misc/python/test/test_cannops.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
# It is subject to the license terms in the LICENSE file found in the top-level directory
# of this distribution and at http://opencv.org/license.html.

from tests_common import NewOpenCVTests
import cv2 as cv
from tests_common import NewOpenCVTests
import numpy as np


def genMask(mask, listx, listy):
for row in range(mask.shape[0]):
for col in range(mask.shape[1]):
Expand All @@ -32,10 +31,21 @@ def test_ascend(self):
cv.cann.resetDevice()

def test_arithmetic(self):
# input data
npMat1 = np.random.random((5, 5, 3)).astype(int)
npMat2 = np.random.random((5, 5, 3)).astype(int)
cv.cann.setDevice(0)

# ACLMat input data
aclMat1 = cv.cann.AscendMat()
aclMat1.upload(npMat1)
aclMat2 = cv.cann.AscendMat()
aclMat2.upload(npMat2)
aclMask = cv.cann.AscendMat()
aclMask.upload(mask)
aclMatDst = cv.cann.AscendMat(aclMat1.size(), aclMat1.type())

# InputArray interface test
self.assertTrue(np.allclose(cv.cann.add(
npMat1, npMat2), cv.add(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.subtract(
Expand All @@ -45,6 +55,16 @@ def test_arithmetic(self):
self.assertTrue(np.allclose(cv.cann.divide(
npMat1, npMat2, scale=2), cv.divide(npMat1, npMat2, scale=2)))

# AscendMat interface test
self.assertTrue(np.allclose(cv.cann.add(aclMat1, aclMat2).download(),
cv.add(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.subtract(aclMat1, aclMat2).download(),
cv.subtract(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.multiply(aclMat1, aclMat2, scale=2).download(),
cv.multiply(npMat1, npMat2, scale=2)))
self.assertTrue(np.allclose(cv.cann.divide(aclMat1, aclMat2, scale=2).download(),
cv.divide(npMat1, npMat2, scale=2)))

# mask
self.assertTrue(np.allclose(cv.cann.add(
npMat1, npMat2, mask=mask), cv.add(npMat1, npMat2, mask=mask)))
Expand All @@ -57,6 +77,17 @@ def test_arithmetic(self):
self.assertTrue(np.allclose(cv.cann.addWeighted(npMat1, 2, npMat2, 4, 3),
cv.addWeighted(npMat1, 2, npMat2, 4, 3)))

self.assertTrue(np.allclose(cv.cann.add(aclMat1, aclMat2, mask=aclMask).download(),
cv.add(npMat1, npMat2, mask=mask)))
self.assertTrue(np.allclose(cv.cann.subtract(aclMat1, aclMat2, mask=aclMask).download(),
cv.subtract(npMat1, npMat2, mask=mask)))
self.assertTrue(np.allclose(cv.cann.multiply(aclMat1, aclMat2, scale=2).download(),
cv.multiply(npMat1, npMat2, scale=2)))
self.assertTrue(np.allclose(cv.cann.divide(aclMat1, aclMat2, scale=2).download(),
cv.divide(npMat1, npMat2, scale=2)))
self.assertTrue(np.allclose(cv.cann.addWeighted(aclMat1, 2, aclMat2, 4, 3).download(),
cv.addWeighted(npMat1, 2, npMat2, 4, 3)))

# stream
stream = cv.cann.AscendStream()
matDst = cv.cann.add(npMat1, npMat2, stream=stream)
Expand All @@ -70,13 +101,37 @@ def test_arithmetic(self):
self.assertTrue(np.allclose(
matDst, cv.subtract(npMat1, npMat2, mask=mask)))

# stream AsceendMat
aclMatDst = cv.cann.add(aclMat1, aclMat2, stream=stream)
stream.waitForCompletion()
self.assertTrue(np.allclose(aclMatDst.download(),
cv.add(npMat1, npMat2)))

aclMatDst = cv.cann.add(aclMat1, aclMat2, mask=aclMask, stream=stream)
stream.waitForCompletion()
self.assertTrue(np.allclose(aclMatDst.download(),
cv.add(npMat1, npMat2, mask=mask)))

aclMatDst = cv.cann.subtract(aclMat1, aclMat2, mask=aclMask, stream=stream)
stream.waitForCompletion()
self.assertTrue(np.allclose(aclMatDst.download(),
cv.subtract(npMat1, npMat2, mask=mask)))

cv.cann.resetDevice()

def test_logical(self):
npMat1 = np.random.random((5, 5, 3)).astype(np.uint16)
npMat2 = np.random.random((5, 5, 3)).astype(np.uint16)
cv.cann.setDevice(0)

# ACLMat input data
aclMat1 = cv.cann.AscendMat()
aclMat1.upload(npMat1)
aclMat2 = cv.cann.AscendMat()
aclMat2.upload(npMat2)
aclMask = cv.cann.AscendMat()
aclMask.upload(mask)

self.assertTrue(np.allclose(cv.cann.bitwise_or(npMat1, npMat2),
cv.bitwise_or(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_or(
Expand All @@ -101,28 +156,87 @@ def test_logical(self):
cv.bitwise_not(npMat1, mask=mask)))
self.assertTrue(np.allclose(cv.cann.bitwise_xor(npMat1, npMat2, mask=mask),
cv.bitwise_xor(npMat1, npMat2, mask=mask)))

# AscendMat interface
self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2).download(),
cv.bitwise_or(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2).download(),
cv.bitwise_or(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_and(aclMat1, aclMat2).download(),
cv.bitwise_and(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_and(
aclMat1, aclMat2).download(), cv.bitwise_and(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_xor(aclMat1, aclMat2).download(),
cv.bitwise_xor(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_xor(
aclMat1, aclMat2).download(), cv.bitwise_xor(npMat1, npMat2)))
self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1).download(),
cv.bitwise_not(npMat1)))
self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1).download(),
cv.bitwise_not(npMat1)))
self.assertTrue(np.allclose(cv.cann.bitwise_and(aclMat1, aclMat2, mask=aclMask).download(),
cv.bitwise_and(npMat1, npMat2, mask=mask)))
self.assertTrue(np.allclose(cv.cann.bitwise_or(aclMat1, aclMat2, mask=aclMask).download(),
cv.bitwise_or(npMat1, npMat2, mask=mask)))
self.assertTrue(np.allclose(cv.cann.bitwise_not(aclMat1, mask=aclMask).download(),
cv.bitwise_not(npMat1, mask=mask)))
self.assertTrue(np.allclose(cv.cann.bitwise_xor(aclMat1, aclMat2, mask=aclMask).download(),
cv.bitwise_xor(npMat1, npMat2, mask=mask)))
cv.cann.resetDevice()

def test_imgproc(self):
npMat = (np.random.random((128, 128, 3)) * 255).astype(np.uint8)
cv.cann.setDevice(0)

aclMat = cv.cann.AscendMat()
aclMatDst = aclMat
aclMat.upload(npMat)

# TODO try pass out param, not use return value.
# merge & split
self.assertTrue(np.allclose(
cv.cann.merge(cv.cann.split(npMat)), npMat))
cv.cann.merge(cv.cann.split(npMat)).download(), npMat))
self.assertTrue(np.allclose(
cv.cann.merge(cv.cann.split(aclMat)).download(), npMat))

# transpose
self.assertTrue(np.allclose(
cv.cann.transpose(npMat), cv.transpose(npMat)))
self.assertTrue(np.allclose(
cv.cann.transpose(aclMat).download(), cv.transpose(npMat)))

# crop
w_off, h_off, crop_w, crop_h = 0, 0, 64, 64
roi = [w_off, h_off, crop_w, crop_h]
self.assertTrue(np.allclose(
cv.cann.crop(npMat, roi).download(), npMat[w_off:crop_w, h_off:crop_h]))
self.assertTrue(np.allclose(
cv.cann.crop(aclMat, roi).download(), npMat[w_off:crop_w, h_off:crop_h]))

# resize
dstSize = np.array([crop_w, crop_h])
aclMat32F = cv.cann.AscendMat()
aclMat32F.upload(npMat.astype(np.float32))
self.assertTrue(np.allclose(cv.cann.resize(npMat.astype(np.float32), dstSize, 0, 0, 3),
cv.resize(npMat.astype(np.float32), dstSize, 0, 0, 3)))
self.assertTrue(np.allclose(cv.cann.resize(aclMat32F, dstSize, 0, 0, 3).download(),
cv.resize(npMat.astype(np.float32), dstSize, 0, 0, 3)))
# flip
flipMode = [0, 1, -1]
for fMode in flipMode:
self.assertTrue(np.allclose(cv.cann.flip(
npMat, fMode), cv.flip(npMat, fMode)))
self.assertTrue(np.allclose(cv.cann.flip(
aclMat, fMode).download(), cv.flip(npMat, fMode)))

# rotate
rotateMode = [0, 1, 2]
for rMode in rotateMode:
self.assertTrue(np.allclose(cv.cann.rotate(
npMat, rMode), cv.rotate(npMat, rMode)))
self.assertTrue(np.allclose(cv.cann.rotate(
aclMat, rMode).download(), cv.rotate(npMat, rMode)))

# cvtColcor
cvtModeC1 = [cv.COLOR_GRAY2BGR, cv.COLOR_GRAY2BGRA]
cvtModeC3 = [cv.COLOR_BGR2GRAY, cv.COLOR_BGRA2BGR, cv.COLOR_BGR2RGBA, cv.COLOR_RGBA2BGR,
cv.COLOR_BGR2RGB, cv.COLOR_BGRA2RGBA, cv.COLOR_RGB2GRAY, cv.COLOR_BGRA2GRAY,
Expand All @@ -133,11 +247,19 @@ def test_imgproc(self):
for cvtM in cvtModeC3:
self.assertTrue(np.allclose(cv.cann.cvtColor(
npMat, cvtM), cv.cvtColor(npMat, cvtM), 1))
self.assertTrue(np.allclose(cv.cann.cvtColor(
aclMat, cvtM).download(), cv.cvtColor(npMat, cvtM), 1))

npMatC1 = (np.random.random((128, 128, 1)) * 255).astype(np.uint8)
aclMatC1 = cv.cann.AscendMat()
aclMatC1.upload(npMatC1)
for cvtM in cvtModeC1:
self.assertTrue(np.allclose(cv.cann.cvtColor(
npMatC1, cvtM), cv.cvtColor(npMatC1, cvtM), 1))
self.assertTrue(np.allclose(cv.cann.cvtColor(
aclMatC1, cvtM).download(), cv.cvtColor(npMatC1, cvtM), 1))

# threshold
threshType = [cv.THRESH_BINARY, cv.THRESH_BINARY_INV,
cv.THRESH_TRUNC, cv.THRESH_TOZERO, cv.THRESH_TOZERO_INV]
for tType in threshType:
Expand All @@ -147,8 +269,13 @@ def test_imgproc(self):
npMat.astype(np.float32), 127, 255, tType)
self.assertTrue(np.allclose(cvThresh, cannThresh))
self.assertTrue(np.allclose(cvRet, cannRet))
cv.cann.resetDevice()

aclMat.upload(npMat.astype(np.float32))
cannRet, cannThresh = cv.cann.threshold(
aclMat, 127, 255, tType)
self.assertTrue(np.allclose(cvThresh, cannThresh.download()))
self.assertTrue(np.allclose(cvRet, cannRet))
cv.cann.resetDevice()

if __name__ == '__main__':
NewOpenCVTests.bootstrap()
2 changes: 1 addition & 1 deletion modules/cannops/perf/perf_cvtcolor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace
COLOR_YUV2RGB)
#define CVT_COLORS_1 Values(COLOR_GRAY2BGR, COLOR_GRAY2BGRA)
#define TYPICAL_ASCEND_MAT_SIZES \
Values(::perf::sz1080p, ::perf::sz2K, ::perf::sz2160p, ::perf::sz4320p)
Values(::perf::sz1080p, ::perf::sz2K)
#define DEF_PARAM_TEST(name, ...) \
typedef ::perf::TestBaseWithParam<testing::tuple<__VA_ARGS__>> name

Expand Down
Loading

0 comments on commit 7ab8521

Please sign in to comment.