1 /**
2 * Copyright 2019 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 "minddata/dataset/core/cv_tensor.h"
17
18 #include <memory>
19 #include <vector>
20
21 #include "minddata/dataset/include/dataset/constants.h"
22 #include "minddata/dataset/core/tensor.h"
23
24 namespace mindspore {
25 namespace dataset {
26
CVTensor(std::shared_ptr<Tensor> tensor)27 CVTensor::CVTensor(std::shared_ptr<Tensor> tensor) : Tensor(std::move(*tensor)) {
28 (void)this->MatInit(GetMutableBuffer(), shape_, type_, &mat_);
29 }
30
CreateEmpty(const TensorShape & shape,DataType type,CVTensorPtr * out)31 Status CVTensor::CreateEmpty(const TensorShape &shape, DataType type, CVTensorPtr *out) {
32 RETURN_UNEXPECTED_IF_NULL(out);
33 const CVTensorAlloc *alloc = GlobalContext::Instance()->cv_tensor_allocator();
34 *out = std::allocate_shared<CVTensor>(*alloc, shape, type);
35 RETURN_UNEXPECTED_IF_NULL(out);
36 int64_t byte_size = (*out)->SizeInBytes();
37 // Don't allocate if we have a tensor with no elements.
38 if (byte_size != 0) {
39 RETURN_IF_NOT_OK((*out)->AllocateBuffer(byte_size));
40 }
41
42 return (*out)->MatInit((*out)->GetMutableBuffer(), (*out)->shape_, (*out)->type_, &(*out)->mat_);
43 }
44
CreateFromMat(const cv::Mat & mat,const dsize_t rank,CVTensorPtr * out)45 Status CVTensor::CreateFromMat(const cv::Mat &mat, const dsize_t rank, CVTensorPtr *out) {
46 RETURN_UNEXPECTED_IF_NULL(out);
47 TensorPtr out_tensor;
48 cv::Mat mat_local = mat;
49 // if the input Mat's memory is not continuous, copy it to one block of memory
50 if (!mat.isContinuous()) {
51 mat_local = mat.clone();
52 }
53 TensorShape shape({});
54 if (mat.dims == 2 && rank == 2) {
55 shape = TensorShape({mat.rows, mat.cols});
56 } else if (mat.dims == 2 && rank == 3) {
57 shape = TensorShape({mat.rows, mat.cols, mat.channels()});
58 } else {
59 // the info of <C, H, W> tensor is: dims = 3, size = (C, H, W), channels = 1
60 RETURN_STATUS_UNEXPECTED("CreateFromMat: tensor should be in shape of <H,W,C> or <H,W>.");
61 }
62 DataType type = DataType::FromCVType(mat_local.type());
63 RETURN_IF_NOT_OK(CreateFromMemory(shape, type, mat_local.data, &out_tensor));
64 *out = AsCVTensor(out_tensor);
65 return Status::OK();
66 }
67
IsValidImage(const TensorShape & shape,const DataType & type)68 std::pair<std::array<int, 2>, int> CVTensor::IsValidImage(const TensorShape &shape, const DataType &type) {
69 std::array<int, 2> size = {1, 1};
70 if (shape.Rank() <= 2 || (shape.Rank() == 3 && shape[2] <= CV_CN_MAX)) {
71 uint16_t ch = 1;
72 if (shape.Rank() == 3) {
73 ch = static_cast<uint16_t>(shape[2]);
74 }
75 if (shape.Rank() > 0) size[0] = static_cast<int>(shape[0]);
76 if (shape.Rank() > 1) size[1] = static_cast<int>(shape[1]);
77 if (type.AsCVType() == kCVInvalidType) return std::make_pair(size, -1);
78 int cv_type = CV_MAKETYPE(type.AsCVType(), ch);
79 return std::make_pair(size, cv_type);
80 }
81 return std::make_pair(size, -1);
82 }
83
AsCVTensor(std::shared_ptr<Tensor> t)84 std::shared_ptr<CVTensor> CVTensor::AsCVTensor(std::shared_ptr<Tensor> t) {
85 if (t == nullptr) {
86 return nullptr;
87 }
88 std::shared_ptr<CVTensor> cv_t = std::dynamic_pointer_cast<CVTensor>(t);
89 if (cv_t != nullptr) {
90 return cv_t;
91 } else {
92 const CVTensorAlloc *alloc = GlobalContext::Instance()->cv_tensor_allocator();
93 return std::allocate_shared<CVTensor>(*alloc, t);
94 }
95 }
96
MatInit(uchar * data,const TensorShape & shape,const DataType & type,cv::Mat * mat)97 Status CVTensor::MatInit(uchar *data, const TensorShape &shape, const DataType &type, cv::Mat *mat) {
98 RETURN_UNEXPECTED_IF_NULL(data);
99 RETURN_UNEXPECTED_IF_NULL(mat);
100 const int kShapeAsDefault = 2;
101 std::pair<std::array<int, kShapeAsDefault>, int> cv_shape_type = IsValidImage(shape, type);
102 if (cv_shape_type.second == -1) {
103 std::vector<dsize_t> sizes = shape.AsVector();
104 std::vector<int> sizes32(sizes.begin(), sizes.end()); // convert long to int for usage with OpenCV
105
106 uint8_t cv_type = type.AsCVType();
107 if (cv_type == kCVInvalidType) {
108 RETURN_STATUS_UNEXPECTED("Error in creating CV mat. Invalid type.");
109 }
110 *mat = cv::Mat(static_cast<int>(shape.Rank()), &sizes32[0], cv_type, data);
111 } else {
112 *mat = cv::Mat(kShapeAsDefault, &(cv_shape_type.first[0]), cv_shape_type.second, data);
113 }
114 return Status::OK();
115 }
116
Reshape(const TensorShape & shape)117 Status CVTensor::Reshape(const TensorShape &shape) {
118 RETURN_IF_NOT_OK(Tensor::Reshape(shape));
119 RETURN_IF_NOT_OK(this->MatInit(GetMutableBuffer(), shape_, type_, &mat_));
120 return Status::OK();
121 }
122
ExpandDim(const dsize_t & axis)123 Status CVTensor::ExpandDim(const dsize_t &axis) {
124 RETURN_IF_NOT_OK(Tensor::ExpandDim(axis));
125 RETURN_IF_NOT_OK(this->MatInit(GetMutableBuffer(), shape_, type_, &mat_));
126 return Status::OK();
127 }
128
Squeeze()129 void CVTensor::Squeeze() {
130 Tensor::Squeeze();
131 Status rc = this->MatInit(GetMutableBuffer(), shape_, type_, &mat_);
132 if (rc.IsError()) {
133 MS_LOG(ERROR) << "Squeeze failed, error details is " << rc;
134 }
135 }
136
MatAtIndex(const std::vector<dsize_t> & index,cv::Mat * mat)137 Status CVTensor::MatAtIndex(const std::vector<dsize_t> &index, cv::Mat *mat) {
138 RETURN_UNEXPECTED_IF_NULL(mat);
139 uchar *start = nullptr;
140 TensorShape remaining({-1});
141 RETURN_IF_NOT_OK(this->StartAddrOfIndex(index, &start, &remaining));
142 RETURN_IF_NOT_OK(this->MatInit(start, remaining, type_, mat));
143 return Status::OK();
144 }
145 } // namespace dataset
146 } // namespace mindspore
147