1 /**
2 * Copyright 2021 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
17 #include "tools/converter/config_parser/preprocess_parser.h"
18 #include <dirent.h>
19 #include <sys/stat.h>
20 #include <map>
21 #include <vector>
22 #include "tools/converter/preprocess/opencv_utils.h"
23 #include "src/common/log_adapter.h"
24 #include "mindspore/lite/tools/common/string_util.h"
25 #include "src/common/file_utils.h"
26 #include "include/errorcode.h"
27
28 namespace mindspore {
29 namespace lite {
30 namespace {
31 constexpr int kMinSize = 0;
32 constexpr int kMaxSize = 65535;
33 } // namespace
ParseInputType(const std::string & input_type_str,preprocess::InputType * input_type)34 int PreprocessParser::ParseInputType(const std::string &input_type_str, preprocess::InputType *input_type) {
35 if (input_type_str == "IMAGE") {
36 (*input_type) = preprocess::IMAGE;
37 } else if (input_type_str == "BIN") {
38 (*input_type) = preprocess::BIN;
39 } else {
40 (*input_type) = preprocess::INPUT_TYPE_MAX;
41 MS_LOG(ERROR) << "INPUT ILLEGAL: input_type must be IMAGE|BIN.";
42 return RET_INPUT_PARAM_INVALID;
43 }
44 return RET_OK;
45 }
46
ParsePreprocess(const DataPreProcessString & data_pre_process_str,preprocess::DataPreProcessParam * data_pre_process)47 int PreprocessParser::ParsePreprocess(const DataPreProcessString &data_pre_process_str,
48 preprocess::DataPreProcessParam *data_pre_process) {
49 int ret;
50 if (!data_pre_process_str.calibrate_path.empty()) {
51 ret = ParseCalibratePath(data_pre_process_str.calibrate_path, &data_pre_process->calibrate_path);
52 if (ret != RET_OK) {
53 MS_LOG(ERROR) << "Parse calibrate path failed.";
54 return ret;
55 }
56 }
57
58 if (!data_pre_process_str.calibrate_size.empty()) {
59 if (!ConvertIntNum(data_pre_process_str.calibrate_size, &data_pre_process->calibrate_size)) {
60 MS_LOG(ERROR) << "calibrate_size should be a valid number.";
61 return RET_INPUT_PARAM_INVALID;
62 }
63 if (data_pre_process->calibrate_size < kMinSize) {
64 MS_LOG(ERROR) << "calibrate_size must larger 0.";
65 return RET_INPUT_PARAM_INVALID;
66 }
67 }
68
69 if (!data_pre_process_str.input_type.empty()) {
70 ret = ParseInputType(data_pre_process_str.input_type, &data_pre_process->input_type);
71 if (ret != RET_OK) {
72 MS_LOG(ERROR) << "input_type parse failed.";
73 return ret;
74 }
75 }
76 if (!data_pre_process_str.image_to_format.empty()) {
77 ret =
78 ParseImageToFormat(data_pre_process_str.image_to_format, &data_pre_process->image_pre_process.image_to_format);
79 if (ret != RET_OK) {
80 MS_LOG(ERROR) << "image preprocess parse failed.";
81 return ret;
82 }
83 if (data_pre_process->image_pre_process.image_to_format == preprocess::RGB ||
84 data_pre_process->image_pre_process.image_to_format == preprocess::GRAY) {
85 data_pre_process->image_pre_process.image_to_format_code =
86 preprocess::ConvertColorConversionCodes(data_pre_process->image_pre_process.image_to_format);
87 }
88 }
89 ret = ParseImagePreProcess(data_pre_process_str, &data_pre_process->image_pre_process);
90 if (ret != RET_OK) {
91 MS_LOG(ERROR) << "image preprocess parse failed.";
92 return ret;
93 }
94
95 ret = CollectCalibInputs(data_pre_process->calibrate_path, data_pre_process->calibrate_size,
96 &data_pre_process->calibrate_path_vector);
97 if (ret != RET_OK) {
98 MS_LOG(ERROR) << "collect calibrate inputs failed.";
99 return ret;
100 }
101 return RET_OK;
102 }
103
ParseCalibratePath(const std::string & str,std::map<std::string,std::string> * value)104 int PreprocessParser::ParseCalibratePath(const std::string &str, std::map<std::string, std::string> *value) {
105 if (value == nullptr) {
106 MS_LOG(ERROR) << "value is nullptr.";
107 return RET_ERROR;
108 }
109 auto key_values = SplitStringToVector(str, ',');
110 for (const auto &key_value : key_values) {
111 auto tmp = SplitStringToVector(key_value, ':');
112 if (tmp.size() != 2) {
113 MS_LOG(ERROR) << "vector need size = 2, size is " << tmp.size();
114 return RET_INPUT_PARAM_INVALID;
115 }
116 auto data_path = RealPath(tmp.at(1).c_str());
117 if (data_path.empty()) {
118 MS_LOG(ERROR) << "path is invalid.";
119 return RET_INPUT_PARAM_INVALID;
120 }
121 (*value)[tmp.at(0)] = data_path;
122 }
123 return RET_OK;
124 }
125
ParseImagePreProcess(const DataPreProcessString & data_pre_process_str,preprocess::ImagePreProcessParam * image_pre_process)126 int PreprocessParser::ParseImagePreProcess(const DataPreProcessString &data_pre_process_str,
127 preprocess::ImagePreProcessParam *image_pre_process) {
128 auto ret = ParseImageNormalize(data_pre_process_str, image_pre_process);
129 if (ret != RET_OK) {
130 MS_LOG(ERROR) << "Parse image normalize failed.";
131 return ret;
132 }
133 ret = ParseImageCenterCrop(data_pre_process_str, image_pre_process);
134 if (ret != RET_OK) {
135 MS_LOG(ERROR) << "Parse image center crop failed.";
136 return ret;
137 }
138 ret = ParseImageResize(data_pre_process_str, image_pre_process);
139 if (ret != RET_OK) {
140 MS_LOG(ERROR) << "Parse image resize failed.";
141 return ret;
142 }
143 return RET_OK;
144 }
145
ParseImageToFormat(const std::string & image_to_format_str,preprocess::ImageToFormat * image_to_format)146 int PreprocessParser::ParseImageToFormat(const std::string &image_to_format_str,
147 preprocess::ImageToFormat *image_to_format) {
148 if (image_to_format_str == "RGB") {
149 (*image_to_format) = preprocess::RGB;
150 } else if (image_to_format_str == "GRAY") {
151 (*image_to_format) = preprocess::GRAY;
152 } else if (image_to_format_str == "BGR") {
153 (*image_to_format) = preprocess::BGR;
154 } else {
155 (*image_to_format) = preprocess::IMAGE_TO_FORMAT_MAX;
156 MS_LOG(ERROR) << "INPUT ILLEGAL: image_to_format must be RGB|GRAY|BGR.";
157 return RET_INPUT_PARAM_INVALID;
158 }
159 return RET_OK;
160 }
161
CollectCalibInputs(const std::map<std::string,std::string> & calibrate_data_path,size_t limited_count,std::map<std::string,std::vector<std::string>> * inputs)162 int PreprocessParser::CollectCalibInputs(const std::map<std::string, std::string> &calibrate_data_path,
163 size_t limited_count,
164 std::map<std::string, std::vector<std::string>> *inputs) {
165 if (inputs == nullptr) {
166 MS_LOG(ERROR) << "inputs is null";
167 return RET_ERROR;
168 }
169
170 auto AddImage = [&inputs](const std::string &file, const std::string &input_name) {
171 struct stat buf {};
172 if (stat(file.c_str(), &buf) == 0) {
173 (*inputs)[input_name].push_back(file);
174 } else {
175 MS_LOG(WARNING) << "invalid image file path: " << file;
176 }
177 };
178
179 for (const auto &image_path : calibrate_data_path) {
180 DIR *root = opendir(image_path.second.c_str());
181 if (root == nullptr) {
182 MS_LOG(ERROR) << "invalid data path: " << image_path;
183 return RET_PARAM_INVALID;
184 }
185 struct dirent *image_dir = readdir(root);
186 size_t count = 0;
187 while (image_dir != nullptr && count < limited_count) {
188 std::string file_name(image_dir->d_name);
189 if (file_name != "." && file_name != "..") {
190 const std::string file_path = image_path.second + "/" + file_name;
191 AddImage(file_path, image_path.first);
192 count++;
193 }
194 image_dir = readdir(root);
195 }
196 auto ret = closedir(root);
197 if (ret != 0) {
198 MS_LOG(ERROR) << " close dir failed.";
199 return RET_ERROR;
200 }
201 auto &cur_inputs = inputs->at(image_path.first);
202 std::sort(cur_inputs.begin(), cur_inputs.end());
203 if (count != limited_count) {
204 MS_LOG(ERROR) << " data path: " << image_path.second << " data count:" << count
205 << " < limited_count:" << limited_count;
206 return RET_ERROR;
207 }
208 }
209 return RET_OK;
210 }
ParseImageNormalize(const DataPreProcessString & data_pre_process_str,preprocess::ImagePreProcessParam * image_pre_process)211 int PreprocessParser::ParseImageNormalize(const DataPreProcessString &data_pre_process_str,
212 preprocess::ImagePreProcessParam *image_pre_process) {
213 if (!data_pre_process_str.normalize_mean.empty() &&
214 !ConvertDoubleVector(data_pre_process_str.normalize_mean, &image_pre_process->normalize_mean)) {
215 MS_LOG(ERROR) << "Convert normalize_mean failed.";
216 return RET_INPUT_PARAM_INVALID;
217 }
218
219 if (!data_pre_process_str.normalize_std.empty() &&
220 !ConvertDoubleVector(data_pre_process_str.normalize_std, &image_pre_process->normalize_std)) {
221 MS_LOG(ERROR) << "Convert normalize_std failed.";
222 return RET_INPUT_PARAM_INVALID;
223 }
224
225 return RET_OK;
226 }
ParseImageResize(const DataPreProcessString & data_pre_process_str,preprocess::ImagePreProcessParam * image_pre_process)227 int PreprocessParser::ParseImageResize(const DataPreProcessString &data_pre_process_str,
228 preprocess::ImagePreProcessParam *image_pre_process) {
229 if (!data_pre_process_str.resize_width.empty()) {
230 if (!ConvertIntNum(data_pre_process_str.resize_width, &image_pre_process->resize_width)) {
231 MS_LOG(ERROR) << "resize_width should be a valid number.";
232 return RET_INPUT_PARAM_INVALID;
233 }
234 if (image_pre_process->resize_width <= kMinSize || image_pre_process->resize_width > kMaxSize) {
235 MS_LOG(ERROR) << "resize_width must be in [1, 65535].";
236 return RET_INPUT_PARAM_INVALID;
237 }
238 }
239 if (!data_pre_process_str.resize_height.empty()) {
240 if (!ConvertIntNum(data_pre_process_str.resize_height, &image_pre_process->resize_height)) {
241 MS_LOG(ERROR) << "resize_width should be a valid number.";
242 return RET_INPUT_PARAM_INVALID;
243 }
244 if (image_pre_process->resize_height <= kMinSize || image_pre_process->resize_height > kMaxSize) {
245 MS_LOG(ERROR) << "resize_height must be in [1, 65535].";
246 return RET_INPUT_PARAM_INVALID;
247 }
248 }
249
250 if (!data_pre_process_str.resize_method.empty()) {
251 image_pre_process->resize_method = preprocess::ConvertResizeMethod(data_pre_process_str.resize_method);
252 if (image_pre_process->resize_method == cv::INTER_MAX) {
253 MS_LOG(ERROR) << "INPUT ILLEGAL: resize_method must be NEAREST|LINEAR|CUBIC.";
254 return RET_INPUT_PARAM_INVALID;
255 }
256 }
257 return RET_OK;
258 }
ParseImageCenterCrop(const DataPreProcessString & data_pre_process_str,preprocess::ImagePreProcessParam * image_pre_process)259 int PreprocessParser::ParseImageCenterCrop(const DataPreProcessString &data_pre_process_str,
260 preprocess::ImagePreProcessParam *image_pre_process) {
261 if (!data_pre_process_str.center_crop_width.empty()) {
262 if (!ConvertIntNum(data_pre_process_str.center_crop_width, &image_pre_process->center_crop_width)) {
263 MS_LOG(ERROR) << "center_crop_width should be a valid number.";
264 return RET_INPUT_PARAM_INVALID;
265 }
266 if (image_pre_process->center_crop_width <= kMinSize || image_pre_process->center_crop_width > kMaxSize) {
267 MS_LOG(ERROR) << "center_crop_width must be in [1, 65535].";
268 return RET_INPUT_PARAM_INVALID;
269 }
270 }
271 if (!data_pre_process_str.center_crop_height.empty()) {
272 if (!ConvertIntNum(data_pre_process_str.center_crop_height, &image_pre_process->center_crop_height)) {
273 MS_LOG(ERROR) << "center_crop_height should be a valid number.";
274 return RET_INPUT_PARAM_INVALID;
275 }
276 if (image_pre_process->center_crop_height <= kMinSize || image_pre_process->center_crop_height > kMaxSize) {
277 MS_LOG(ERROR) << "center_crop_height must be in [1, 65535].";
278 return RET_INPUT_PARAM_INVALID;
279 }
280 }
281 return RET_OK;
282 }
283 } // namespace lite
284 } // namespace mindspore
285