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