Merge pull request !3874 from qianlong21st/soft_dvpptags/v0.7.0-beta
| @@ -8,11 +8,12 @@ endif() | |||
| set(jpeg_turbo_LDFLAGS "-Wl,-z,relro,-z,now,-z,noexecstack") | |||
| mindspore_add_pkg(jpeg_turbo | |||
| VER 2.0.4 | |||
| LIBS jpeg | |||
| LIBS jpeg turbojpeg | |||
| URL https://github.com/libjpeg-turbo/libjpeg-turbo/archive/2.0.4.tar.gz | |||
| MD5 44c43e4a9fb352f47090804529317c88 | |||
| CMAKE_OPTION -DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=TRUE | |||
| CMAKE_OPTION -DCMAKE_BUILD_TYPE=Release -DCMAKE_SKIP_RPATH=TRUE -DWITH_SIMD=ON | |||
| PATCHES ${CMAKE_SOURCE_DIR}/third_party/patch/jpeg_turbo/jpeg_turbo.patch001 | |||
| ) | |||
| include_directories(${jpeg_turbo_INC}) | |||
| add_library(mindspore::jpeg_turbo ALIAS jpeg_turbo::jpeg) | |||
| add_library(mindspore::turbojpeg ALIAS jpeg_turbo::turbojpeg) | |||
| @@ -62,6 +62,7 @@ add_subdirectory(text) | |||
| add_dependencies(utils core) | |||
| add_dependencies(kernels-image core) | |||
| add_dependencies(kernels-data core) | |||
| add_dependencies(kernels-soft-dvpp-image core soft-dvpp-utils) | |||
| add_dependencies(kernels core) | |||
| add_dependencies(engine-datasetops-source core) | |||
| add_dependencies(engine-datasetops-source-sampler core) | |||
| @@ -88,6 +89,8 @@ set(submodules | |||
| $<TARGET_OBJECTS:kernels-image> | |||
| $<TARGET_OBJECTS:kernels-data> | |||
| $<TARGET_OBJECTS:cpp-API> | |||
| $<TARGET_OBJECTS:kernels-soft-dvpp-image> | |||
| $<TARGET_OBJECTS:soft-dvpp-utils> | |||
| $<TARGET_OBJECTS:engine-datasetops-source> | |||
| $<TARGET_OBJECTS:engine-datasetops-source-sampler> | |||
| $<TARGET_OBJECTS:engine-datasetops-mapop> | |||
| @@ -141,7 +144,7 @@ else() | |||
| target_link_libraries(_c_dataengine PRIVATE -ldl mindspore::protobuf ${SECUREC_LIBRARY}) | |||
| endif() | |||
| endif() | |||
| target_link_libraries(_c_dataengine PUBLIC mindspore::jpeg_turbo mindspore::opencv_core mindspore::opencv_imgcodecs | |||
| target_link_libraries(_c_dataengine PUBLIC mindspore::jpeg_turbo mindspore::turbojpeg mindspore::opencv_core mindspore::opencv_imgcodecs | |||
| mindspore::opencv_imgproc mindspore::tinyxml2 mindspore::sentencepiece mindspore::sentencepiece_train ${ICU_LIB}) | |||
| if (ENABLE_GPUQUE) | |||
| target_link_libraries(_c_dataengine PRIVATE gpu_queue | |||
| @@ -50,6 +50,8 @@ | |||
| #include "minddata/dataset/kernels/image/resize_bilinear_op.h" | |||
| #include "minddata/dataset/kernels/image/resize_op.h" | |||
| #include "minddata/dataset/kernels/image/resize_with_bbox_op.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/soft_dvpp_decode_random_crop_resize_jpeg_op.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/soft_dvpp_decode_resize_jpeg_op.h" | |||
| #include "minddata/dataset/kernels/image/uniform_aug_op.h" | |||
| namespace mindspore { | |||
| @@ -362,6 +364,24 @@ PYBIND_REGISTER(RandomSelectSubpolicyOp, 1, ([](const py::module *m) { | |||
| return std::make_shared<RandomSelectSubpolicyOp>(cpp_policy); | |||
| })); | |||
| })); | |||
| PYBIND_REGISTER(SoftDvppDecodeResizeJpegOp, 1, ([](const py::module *m) { | |||
| (void)py::class_<SoftDvppDecodeResizeJpegOp, TensorOp, std::shared_ptr<SoftDvppDecodeResizeJpegOp>>( | |||
| *m, "SoftDvppDecodeResizeJpegOp", "TensorOp to use soft dvpp decode and resize jpeg image.") | |||
| .def(py::init<int32_t, int32_t>(), py::arg("targetHeight"), py::arg("targetWidth")); | |||
| })); | |||
| PYBIND_REGISTER( | |||
| SoftDvppDecodeRandomCropResizeJpegOp, 1, ([](const py::module *m) { | |||
| (void) | |||
| py::class_<SoftDvppDecodeRandomCropResizeJpegOp, TensorOp, std::shared_ptr<SoftDvppDecodeRandomCropResizeJpegOp>>( | |||
| *m, "SoftDvppDecodeRandomCropResizeJpegOp", | |||
| "TensorOp to use soft dvpp decode, random crop and resize jepg image.") | |||
| .def(py::init<int32_t, int32_t, float, float, float, float, int32_t>(), py::arg("targetHeight"), | |||
| py::arg("targetWidth"), py::arg("scaleLb") = RandomCropDecodeResizeOp::kDefScaleLb, | |||
| py::arg("scaleUb") = RandomCropDecodeResizeOp::kDefScaleUb, | |||
| py::arg("aspectLb") = RandomCropDecodeResizeOp::kDefAspectLb, | |||
| py::arg("aspectUb") = RandomCropDecodeResizeOp::kDefAspectUb, | |||
| py::arg("maxIter") = RandomCropDecodeResizeOp::kDefMaxIter); | |||
| })); | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -1,5 +1,6 @@ | |||
| file(GLOB_RECURSE _CURRENT_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc") | |||
| set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD) | |||
| add_subdirectory(soft_dvpp) | |||
| add_library(kernels-image OBJECT | |||
| affine_op.cc | |||
| auto_contrast_op.cc | |||
| @@ -38,3 +39,4 @@ add_library(kernels-image OBJECT | |||
| resize_with_bbox_op.cc | |||
| random_resize_with_bbox_op.cc | |||
| ) | |||
| add_dependencies(kernels-image kernels-soft-dvpp-image) | |||
| @@ -956,5 +956,24 @@ Status UpdateBBoxesForResize(const std::shared_ptr<Tensor> &bboxList, const size | |||
| return Status::OK(); | |||
| } | |||
| Status GetJpegImageInfo(const std::shared_ptr<Tensor> &input, int *img_width, int *img_height) { | |||
| struct jpeg_decompress_struct cinfo {}; | |||
| struct JpegErrorManagerCustom jerr {}; | |||
| cinfo.err = jpeg_std_error(&jerr.pub); | |||
| jerr.pub.error_exit = JpegErrorExitCustom; | |||
| try { | |||
| jpeg_create_decompress(&cinfo); | |||
| JpegSetSource(&cinfo, input->GetBuffer(), input->SizeInBytes()); | |||
| (void)jpeg_read_header(&cinfo, TRUE); | |||
| jpeg_calc_output_dimensions(&cinfo); | |||
| } catch (std::runtime_error &e) { | |||
| jpeg_destroy_decompress(&cinfo); | |||
| RETURN_STATUS_UNEXPECTED(e.what()); | |||
| } | |||
| *img_height = cinfo.output_height; | |||
| *img_width = cinfo.output_width; | |||
| jpeg_destroy_decompress(&cinfo); | |||
| return Status::OK(); | |||
| } | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -268,6 +268,12 @@ Status PadBBoxes(const std::shared_ptr<Tensor> *bboxList, const size_t &bboxCoun | |||
| Status UpdateBBoxesForResize(const std::shared_ptr<Tensor> &bboxList, const size_t &bboxCount, int32_t target_width_, | |||
| int32_t target_height_, int orig_width, int orig_height); | |||
| // Get jpeg image width and height | |||
| // @param input: CVTensor containing the not decoded image 1D bytes | |||
| // @param img_width: the jpeg image width | |||
| // @param img_height: the jpeg image height | |||
| Status GetJpegImageInfo(const std::shared_ptr<Tensor> &input, int *img_width, int *img_height); | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_CCSRC_MINDDATA_DATASET_KERNELS_IMAGE_IMAGE_UTILS_H_ | |||
| @@ -37,22 +37,9 @@ Status RandomCropDecodeResizeOp::Compute(const std::shared_ptr<Tensor> &input, s | |||
| RETURN_IF_NOT_OK(op.Compute(input, &decoded)); | |||
| return RandomCropAndResizeOp::Compute(decoded, output); | |||
| } else { | |||
| struct jpeg_decompress_struct cinfo {}; | |||
| struct JpegErrorManagerCustom jerr {}; | |||
| cinfo.err = jpeg_std_error(&jerr.pub); | |||
| jerr.pub.error_exit = JpegErrorExitCustom; | |||
| try { | |||
| jpeg_create_decompress(&cinfo); | |||
| JpegSetSource(&cinfo, input->GetBuffer(), input->SizeInBytes()); | |||
| (void)jpeg_read_header(&cinfo, TRUE); | |||
| jpeg_calc_output_dimensions(&cinfo); | |||
| } catch (std::runtime_error &e) { | |||
| jpeg_destroy_decompress(&cinfo); | |||
| RETURN_STATUS_UNEXPECTED(e.what()); | |||
| } | |||
| int h_in = cinfo.output_height; | |||
| int w_in = cinfo.output_width; | |||
| jpeg_destroy_decompress(&cinfo); | |||
| int h_in = 0; | |||
| int w_in = 0; | |||
| RETURN_IF_NOT_OK(GetJpegImageInfo(input, &w_in, &h_in)); | |||
| int x = 0; | |||
| int y = 0; | |||
| @@ -0,0 +1,6 @@ | |||
| file(GLOB_RECURSE _CURRENT_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cc") | |||
| set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD) | |||
| add_subdirectory(utils) | |||
| add_library(kernels-soft-dvpp-image OBJECT | |||
| soft_dvpp_decode_resize_jpeg_op.cc | |||
| soft_dvpp_decode_random_crop_resize_jpeg_op.cc) | |||
| @@ -0,0 +1,84 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/soft_dvpp_decode_random_crop_resize_jpeg_op.h" | |||
| #include <string> | |||
| #include "opencv2/opencv.hpp" | |||
| #include "minddata/dataset/core/cv_tensor.h" | |||
| #include "minddata/dataset/kernels/image/image_utils.h" | |||
| #include "minddata/dataset/util/random.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| SoftDvppDecodeRandomCropResizeJpegOp::SoftDvppDecodeRandomCropResizeJpegOp(int32_t target_height, int32_t target_width, | |||
| float scale_lb, float scale_ub, | |||
| float aspect_lb, float aspect_ub, | |||
| int32_t max_iter) | |||
| : RandomCropAndResizeOp(target_height, target_width, scale_lb, scale_ub, aspect_lb, aspect_ub, | |||
| InterpolationMode::kLinear, max_iter) {} | |||
| Status SoftDvppDecodeRandomCropResizeJpegOp::GetCropInfo(const std::shared_ptr<Tensor> &input, | |||
| SoftDpCropInfo *crop_info) { | |||
| int img_width = 0; | |||
| int img_height = 0; | |||
| RETURN_IF_NOT_OK(GetJpegImageInfo(input, &img_width, &img_height)); | |||
| int x = 0; | |||
| int y = 0; | |||
| int crop_heigh = 0; | |||
| int crop_widht = 0; | |||
| RETURN_IF_NOT_OK(GetCropBox(img_height, img_width, &x, &y, &crop_heigh, &crop_widht)); | |||
| crop_info->left = x; | |||
| crop_info->up = y; | |||
| crop_info->right = crop_info->left + crop_widht; | |||
| crop_info->down = crop_info->up + crop_heigh; | |||
| return Status::OK(); | |||
| } | |||
| Status SoftDvppDecodeRandomCropResizeJpegOp::Compute(const std::shared_ptr<Tensor> &input, | |||
| std::shared_ptr<Tensor> *output) { | |||
| IO_CHECK(input, output); | |||
| if (!IsNonEmptyJPEG(input)) { | |||
| RETURN_STATUS_UNEXPECTED("SoftDvppDecodeRandomCropResizeJpeg only support process jpeg image."); | |||
| } | |||
| SoftDpCropInfo crop_info; | |||
| RETURN_IF_NOT_OK(GetCropInfo(input, &crop_info)); | |||
| try { | |||
| unsigned char *buffer = const_cast<unsigned char *>(input->GetBuffer()); | |||
| CHECK_FAIL_RETURN_UNEXPECTED(buffer != nullptr, "The input image buffer is empty."); | |||
| SoftDpProcsessInfo info; | |||
| info.input_buffer = static_cast<uint8_t *>(buffer); | |||
| info.input_buffer_size = input->SizeInBytes(); | |||
| info.output_width = target_width_; | |||
| info.output_height = target_height_; | |||
| cv::Mat out_rgb_img(target_height_, target_width_, CV_8UC3); | |||
| info.output_buffer = out_rgb_img.data; | |||
| info.output_buffer_size = target_width_ * target_height_ * 3; | |||
| info.is_v_before_u = true; | |||
| int ret = DecodeAndCropAndResizeJpeg(&info, crop_info); | |||
| std::string error_info("Soft dvpp DecodeAndResizeJpeg failed with return code: "); | |||
| error_info += std::to_string(ret); | |||
| CHECK_FAIL_RETURN_UNEXPECTED(ret == 0, error_info); | |||
| std::shared_ptr<CVTensor> cv_tensor = nullptr; | |||
| RETURN_IF_NOT_OK(CVTensor::CreateFromMat(out_rgb_img, &cv_tensor)); | |||
| *output = std::static_pointer_cast<Tensor>(cv_tensor); | |||
| } catch (const cv::Exception &e) { | |||
| RETURN_STATUS_UNEXPECTED("Error in soft dvpp image decode and resize."); | |||
| } | |||
| return Status::OK(); | |||
| } | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,47 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RANDOM_CROP_RESIZE_JPEG_OP_H_ | |||
| #define DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RANDOM_CROP_RESIZE_JPEG_OP_H_ | |||
| #include <memory> | |||
| #include <random> | |||
| #include <string> | |||
| #include "./utils/external_soft_dp.h" | |||
| #include "minddata/dataset/core/tensor.h" | |||
| #include "minddata/dataset/kernels/image/random_crop_and_resize_op.h" | |||
| #include "minddata/dataset/util/status.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| class SoftDvppDecodeRandomCropResizeJpegOp : public RandomCropAndResizeOp { | |||
| public: | |||
| SoftDvppDecodeRandomCropResizeJpegOp(int32_t target_height, int32_t target_width, float scale_lb = kDefScaleLb, | |||
| float scale_ub = kDefScaleUb, float aspect_lb = kDefAspectLb, | |||
| float aspect_ub = kDefAspectUb, int32_t max_iter = kDefMaxIter); | |||
| Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override; | |||
| std::string Name() const override { return kSoftDvppDecodeRandomCropResizeJpegOp; } | |||
| protected: | |||
| Status GetCropInfo(const std::shared_ptr<Tensor> &input, SoftDpCropInfo *crop_info); | |||
| }; | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| #endif // DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RANDOM_CROP_RESIZE_JPEG_OP_H_ | |||
| @@ -0,0 +1,60 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/soft_dvpp_decode_resize_jpeg_op.h" | |||
| #include <string> | |||
| #include "./utils/external_soft_dp.h" | |||
| #include "opencv2/opencv.hpp" | |||
| #include "minddata/dataset/core/cv_tensor.h" | |||
| #include "minddata/dataset/kernels/image/image_utils.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| Status SoftDvppDecodeResizeJpegOp::Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) { | |||
| IO_CHECK(input, output); | |||
| if (!IsNonEmptyJPEG(input)) { | |||
| RETURN_STATUS_UNEXPECTED("SoftDvppDecodeReiszeJpegOp only support process jpeg image."); | |||
| } | |||
| try { | |||
| unsigned char *buffer = const_cast<unsigned char *>(input->GetBuffer()); | |||
| CHECK_FAIL_RETURN_UNEXPECTED(buffer != nullptr, "The input image buffer is empty."); | |||
| SoftDpProcsessInfo info; | |||
| info.input_buffer = static_cast<uint8_t *>(buffer); | |||
| info.input_buffer_size = input->SizeInBytes(); | |||
| info.output_width = target_width_; | |||
| info.output_height = target_height_; | |||
| SoftDpCropInfo crop_info{0, 0, 0, 0}; | |||
| cv::Mat out_rgb_img(target_height_, target_width_, CV_8UC3); | |||
| info.output_buffer = out_rgb_img.data; | |||
| info.output_buffer_size = target_width_ * target_height_ * 3; | |||
| info.is_v_before_u = true; | |||
| int ret = DecodeAndResizeJpeg(&info); | |||
| std::string error_info("Soft dvpp DecodeAndResizeJpeg failed with return code: "); | |||
| error_info += std::to_string(ret); | |||
| CHECK_FAIL_RETURN_UNEXPECTED(ret == 0, error_info); | |||
| std::shared_ptr<CVTensor> cv_tensor = nullptr; | |||
| RETURN_IF_NOT_OK(CVTensor::CreateFromMat(out_rgb_img, &cv_tensor)); | |||
| *output = std::static_pointer_cast<Tensor>(cv_tensor); | |||
| } catch (const cv::Exception &e) { | |||
| RETURN_STATUS_UNEXPECTED("Error in soft dvpp image decode and resize."); | |||
| } | |||
| return Status::OK(); | |||
| } | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,44 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RESIZE_JPEG_OP_H_ | |||
| #define DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RESIZE_JPEG_OP_H_ | |||
| #include <memory> | |||
| #include <string> | |||
| #include "minddata/dataset/core/tensor.h" | |||
| #include "minddata/dataset/kernels/tensor_op.h" | |||
| #include "minddata/dataset/util/status.h" | |||
| namespace mindspore { | |||
| namespace dataset { | |||
| class SoftDvppDecodeResizeJpegOp : public TensorOp { | |||
| public: | |||
| SoftDvppDecodeResizeJpegOp(int32_t target_height, int32_t target_width) | |||
| : target_height_(target_height), target_width_(target_width) {} | |||
| Status Compute(const std::shared_ptr<Tensor> &input, std::shared_ptr<Tensor> *output) override; | |||
| std::string Name() const override { return kSoftDvppDecodeReiszeJpegOp; } | |||
| private: | |||
| int32_t target_height_; | |||
| int32_t target_width_; | |||
| }; | |||
| } // namespace dataset | |||
| } // namespace mindspore | |||
| #endif // DATASET_KERNELS_IMAGE_SOFT_DVPP_DECODE_RESIZE_JPEG_OP_H_ | |||
| @@ -0,0 +1,13 @@ | |||
| file(GLOB_RECURSE _CURRENT_SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cpp") | |||
| set_property(SOURCE ${_CURRENT_SRC_FILES} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_MD) | |||
| add_library(soft-dvpp-utils OBJECT | |||
| soft_dp.cc | |||
| soft_dp_tools.cc | |||
| soft_jpegd.cc | |||
| soft_vpc.cc | |||
| yuv_scaler_para_set.cc) | |||
| if (USE_GLOG) | |||
| message("Soft dvpp use glog to print message.") | |||
| else() | |||
| add_compile_definitions(DVPP_UTST) | |||
| endif() | |||
| @@ -0,0 +1,57 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef EXTERNAL_SOFTDP_H | |||
| #define EXTERNAL_SOFTDP_H | |||
| #include <stdint.h> | |||
| struct SoftDpProcsessInfo { | |||
| uint8_t *input_buffer; // input buffer | |||
| uint32_t input_buffer_size; // input buffer size | |||
| uint8_t *output_buffer; // output buffer | |||
| uint32_t output_buffer_size; // output buffer size | |||
| uint32_t output_width; // output width | |||
| uint32_t output_height; // output height | |||
| bool is_v_before_u; // uv : true, uv : false | |||
| }; | |||
| struct SoftDpCropInfo { | |||
| uint32_t left; // crop left boundry | |||
| uint32_t right; // crop right boundry | |||
| uint32_t up; // crop up boundry | |||
| uint32_t down; // crop down boundry | |||
| }; | |||
| /* | |||
| * @brief decode and resize image | |||
| * @param [in] SoftDpProcsessInfo& soft_dp_process_info: soft decode process struct | |||
| * @return success: return 0, fail: return error number | |||
| */ | |||
| uint32_t DecodeAndResizeJpeg(SoftDpProcsessInfo *soft_dp_process_info); | |||
| /* | |||
| * @brief decode and crop and resize image | |||
| * @param [in] SoftDpProcsessInfo& soft_dp_process_info: soft decode process struct | |||
| * @param [in] SoftDpCropInfo& crop_info: user crop info | |||
| * @return success: return 0, fail: return error number | |||
| */ | |||
| uint32_t DecodeAndCropAndResizeJpeg(SoftDpProcsessInfo *soft_dp_process_info, const SoftDpCropInfo &crop_info); | |||
| #endif // EXTERNAL_SOFTDP_H | |||
| @@ -0,0 +1,69 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_check.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_jpegd.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_vpc.h" | |||
| const int32_t decodeSucc = 0; | |||
| uint32_t DecodeAndResizeJpeg(SoftDpProcsessInfo *soft_dp_process_info) { | |||
| VpcInfo vpc_input_info; | |||
| SoftJpegd soft_handler; | |||
| int32_t ret = soft_handler.JpegdSoftwareDecodeProcess(&vpc_input_info, soft_dp_process_info); | |||
| if (ret != decodeSucc) { | |||
| API_LOGE("Jpegd decode fail in resize interface."); | |||
| return ret; | |||
| } | |||
| // use vpc interface to resize and convert RGB, give user output buf and output size. | |||
| SoftDpCropInfo crop; | |||
| crop.left = 0; | |||
| crop.right = vpc_input_info.real_width - 1; | |||
| crop.up = 0; | |||
| crop.down = vpc_input_info.real_height - 1; | |||
| VpcInfo output; | |||
| output.addr = soft_dp_process_info->output_buffer; | |||
| output.width = soft_dp_process_info->output_width; | |||
| output.height = soft_dp_process_info->output_height; | |||
| SoftVpc soft_vpc; | |||
| ret = soft_vpc.Process(vpc_input_info, crop, output); | |||
| return ret; | |||
| } | |||
| uint32_t DecodeAndCropAndResizeJpeg(SoftDpProcsessInfo *soft_dp_process_info, const SoftDpCropInfo &crop_info) { | |||
| VpcInfo vpc_input_info; | |||
| SoftJpegd soft_handler; | |||
| int32_t ret = soft_handler.JpegdSoftwareDecodeProcess(&vpc_input_info, soft_dp_process_info); | |||
| if (ret != decodeSucc) { | |||
| API_LOGE("Jpegd decode fail in crop and resize interface."); | |||
| return ret; | |||
| } | |||
| // use vpc interface to resize and crop and convert RGB, give user output buf and output size. | |||
| VpcInfo output; | |||
| output.addr = soft_dp_process_info->output_buffer; | |||
| output.width = soft_dp_process_info->output_width; | |||
| output.height = soft_dp_process_info->output_height; | |||
| SoftDpCropInfo crop = crop_info; | |||
| SoftVpc soft_vpc; | |||
| ret = soft_vpc.Process(vpc_input_info, crop, output); | |||
| return ret; | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_DP_H | |||
| #define SOFT_DP_H | |||
| #include <stdint.h> | |||
| #include "./external_soft_dp.h" | |||
| enum JpegdToVpcFormat { | |||
| INPUT_VPC_UNKNOWN = -1, | |||
| INPUT_YUV420_PLANNER = 1, // 1 | |||
| INPUT_YUV422_PLANNER, // 2 | |||
| INPUT_YUV444_PLANNER, // 3 | |||
| INPUT_YUV400_PLANNER, // 4 | |||
| }; | |||
| struct VpcInfo { | |||
| uint8_t *addr; | |||
| int32_t width; | |||
| int32_t height; | |||
| int32_t real_width; | |||
| int32_t real_height; | |||
| enum JpegdToVpcFormat format; | |||
| bool is_v_before_u; | |||
| bool is_fake420; | |||
| VpcInfo() | |||
| : addr(nullptr), | |||
| width(0), | |||
| height(0), | |||
| real_width(0), | |||
| real_height(0), | |||
| format(INPUT_VPC_UNKNOWN), | |||
| is_v_before_u(false), | |||
| is_fake420(false) {} | |||
| }; | |||
| #endif // SOFT_DP_H | |||
| @@ -0,0 +1,46 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_DP_CHECK_H | |||
| #define SOFT_DP_CHECK_H | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_log.h" | |||
| #define CHECK_COND_FAIL_RETURN(model, cond, ...) \ | |||
| do { \ | |||
| if (!(cond)) { \ | |||
| DP_LOG(model, DP_ERR, "check condition: %s fail", #cond); \ | |||
| return __VA_ARGS__; \ | |||
| } \ | |||
| } while (0) | |||
| #define VPC_CHECK_COND_FAIL_RETURN(cond, ret) CHECK_COND_FAIL_RETURN("VPC", cond, ret) | |||
| #define CHECK_COND_FAIL_PRINT_RETURN(module, cond, ret, format, argv...) \ | |||
| do { \ | |||
| if (!(cond)) { \ | |||
| DP_LOG(module, DP_ERR, format, ##argv); \ | |||
| return ret; \ | |||
| } \ | |||
| } while (0) | |||
| #define VPC_CHECK_COND_FAIL_PRINT_RETURN(cond, ret, format, argv...) \ | |||
| CHECK_COND_FAIL_PRINT_RETURN("VPC", cond, ret, format, ##argv) | |||
| #define JPEGD_CHECK_COND_FAIL_PRINT_RETURN(cond, ret, format, argv...) \ | |||
| CHECK_COND_FAIL_PRINT_RETURN("JPEGD", cond, ret, format, ##argv) | |||
| #endif // SOFT_DP_CHECK_H | |||
| @@ -0,0 +1,152 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_DP_LOG_H | |||
| #define SOFT_DP_LOG_H | |||
| #define VERSION_INFO 0x0 | |||
| #define DP_DEBUG 0x1 | |||
| #define DP_INFO 0x10 | |||
| #define DP_WARNING 0x100 | |||
| #define DP_ERR 0x1000 | |||
| #define DP_EVENT 0x10000 | |||
| #define DP_DEBUG_LEVEL (DP_EVENT | DP_ERR | DP_WARNING | DP_INFO | DP_DEBUG) | |||
| #include <vector> | |||
| #include <string> | |||
| #if defined(DVPP_UTST) || defined(DEBUG) | |||
| #include <stdio.h> | |||
| #define DP_LOG(model, level, format, ...) \ | |||
| do { \ | |||
| if (DP_DEBUG_LEVEL & level) { \ | |||
| if (DP_DEBUG & level) { \ | |||
| printf( \ | |||
| "[SOFT_DP-%s] [%s %d] [DEBUG:] " \ | |||
| "[T%d] " format "\n", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_INFO & level) { \ | |||
| printf( \ | |||
| "[SOFT_DP-%s] [%s %d] [INFO:] " \ | |||
| "[T%d] " format "\n", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_WARNING & level) { \ | |||
| printf( \ | |||
| "[SOFT_DP-%s] [%s %d] [WARNING] " \ | |||
| "[T%d] " format "\n", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_ERR & level) { \ | |||
| printf( \ | |||
| "[SOFT_DP-%s] [%s %d] [ERROR:] " \ | |||
| "[T%d] " format "\n", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else { \ | |||
| printf( \ | |||
| "[SOFT_DP-%s] [%s %d] [EVENT:] " \ | |||
| "[T%d] " format "\n", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| #elif defined(USE_GLOG) | |||
| #include <cstdio> | |||
| #include "glog/logging.h" | |||
| template <typename... Args> | |||
| inline std::string GetFormatString(const char *format, Args... args) { | |||
| char buf[BUFSIZ]; | |||
| int new_len = snprintf(&buf[0], BUFSIZ, format, args...); | |||
| new_len++; | |||
| if (new_len > BUFSIZ) { | |||
| std::vector<char> buf2(new_len); | |||
| snprintf(buf2.data(), new_len, format, args...); | |||
| return std::string(buf2.data()); | |||
| } | |||
| return buf; | |||
| } | |||
| #define DP_LOG(model, level, format, ...) \ | |||
| do { \ | |||
| std::string info = GetFormatString( \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| if (DP_WARNING & level) { \ | |||
| LOG(WARNING) << info; \ | |||
| } else if (DP_ERR & level) { \ | |||
| LOG(ERROR) << info; \ | |||
| } else { \ | |||
| LOG(INFO) << info; \ | |||
| } \ | |||
| } while (0) | |||
| #else // #if defined(DVPP_UTST) || defined(DEBUG) | |||
| #include "./slog.h" | |||
| #define DP_LOG(model, level, format, ...) \ | |||
| do { \ | |||
| if (DP_DEBUG_LEVEL & level) { \ | |||
| if (DP_DEBUG & level) { \ | |||
| dlog_debug(SOFT_DP, \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_INFO & level) { \ | |||
| dlog_info(SOFT_DP, \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_WARNING & level) { \ | |||
| dlog_warn(SOFT_DP, \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else if (DP_ERR & level) { \ | |||
| dlog_error(SOFT_DP, \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } else { \ | |||
| dlog_event(SOFT_DP, \ | |||
| "[%s] [%s:%d] " \ | |||
| "[T%d] " format "", \ | |||
| model, __FUNCTION__, __LINE__, VERSION_INFO, ##__VA_ARGS__); \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| #endif // #if defined(DVPP_UTST) || defined(DEBUG) | |||
| #define VPC_LOG(level, format, argv...) DP_LOG("VPC", level, format, ##argv) | |||
| #define VPC_LOGD(format, argv...) DP_LOG("VPC", DP_DEBUG, format, ##argv) | |||
| #define VPC_LOGW(format, argv...) DP_LOG("VPC", DP_WARNING, format, ##argv) | |||
| #define VPC_LOGE(format, argv...) DP_LOG("VPC", DP_ERR, format, ##argv) | |||
| #define JPEGD_LOG(level, format, argv...) DP_LOG("JPEGD", level, format, ##argv) | |||
| #define JPEGD_LOGD(format, argv...) DP_LOG("JPEGD", DP_DEBUG, format, ##argv) | |||
| #define JPEGD_LOGW(format, argv...) DP_LOG("JPEGD", DP_WARNING, format, ##argv) | |||
| #define JPEGD_LOGE(format, argv...) DP_LOG("JPEGD", DP_ERR, format, ##argv) | |||
| #define API_LOG(level, format, argv...) DP_LOG("API", level, format, ##argv) | |||
| #define API_LOGD(format, argv...) DP_LOG("API", DP_DEBUG, format, ##argv) | |||
| #define API_LOGW(format, argv...) DP_LOG("API", DP_WARNING, format, ##argv) | |||
| #define API_LOGE(format, argv...) DP_LOG("API", DP_ERR, format, ##argv) | |||
| #endif // SOFT_DP_LOG_H | |||
| @@ -0,0 +1,56 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_tools.h" | |||
| #include <sys/stat.h> | |||
| #include <cstring> | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_check.h" | |||
| const uint32_t kMaxPath = 4096; | |||
| std::pair<bool, std::string> GetRealpath(const std::string &path) { | |||
| char resolvedPath[kMaxPath]; | |||
| #ifndef DVPP_UTST | |||
| if (path.size() > kMaxPath) { | |||
| API_LOGD("path size too large."); | |||
| return std::make_pair(false, std::string(strerror(errno))); | |||
| } | |||
| #endif // !DVPP_UTST | |||
| #ifdef _WIN32 | |||
| auto err = _fullpath(resolvedPath, path.c_str(), kMaxPath); | |||
| #else | |||
| auto err = realpath(path.c_str(), resolvedPath); | |||
| #endif | |||
| if (err == nullptr) { | |||
| return std::make_pair(false, std::string(strerror(errno))); | |||
| } else { | |||
| return std::make_pair(true, std::string(resolvedPath, strlen(resolvedPath))); | |||
| } | |||
| } | |||
| bool IsDirectory(const std::string &path) { | |||
| struct stat buf; | |||
| if (stat(path.c_str(), &buf) != 0) { | |||
| return false; | |||
| } | |||
| if (S_ISDIR(buf.st_mode)) { | |||
| return true; | |||
| } else { | |||
| return false; | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_DP_TOOLS_H | |||
| #define SOFT_DP_TOOLS_H | |||
| #include <cstdint> | |||
| #include <string> | |||
| #include <utility> | |||
| template <typename T1, typename T2> | |||
| T1 AlignUp(T1 num, T2 align) { | |||
| if (num % align) { | |||
| num = (num / align + 1) * align; | |||
| } | |||
| return num; | |||
| } | |||
| template <typename T1, typename T2> | |||
| T1 AlignDown(T1 num, T2 align) { | |||
| if (num % align) { | |||
| num = num / align * align; | |||
| } | |||
| return num; | |||
| } | |||
| template <typename T> | |||
| bool IsInTheScope(T num, T left_point, T right_point) { | |||
| if (num >= left_point && num <= right_point) { | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| template <typename T> | |||
| T TruncatedFunc(T num, T min, T max) { | |||
| if (num < min) { | |||
| return min; | |||
| } | |||
| if (num > max) { | |||
| return max; | |||
| } | |||
| return num; | |||
| } | |||
| std::pair<bool, std::string> GetRealpath(const std::string &path); | |||
| bool IsDirectory(const std::string &path); | |||
| #endif // SOFT_DP_TOOLS_H | |||
| @@ -0,0 +1,246 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_jpegd.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_log.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_tools.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_check.h" | |||
| #include <turbojpeg.h> | |||
| #include <securec.h> | |||
| #include <cstring> | |||
| #include <cstdlib> | |||
| #include <cstdint> | |||
| #include <cstdio> | |||
| #include <string> | |||
| const uint32_t yuv400UvValue = 0x80; | |||
| const int32_t num2 = 2; | |||
| const uint32_t channel3 = 3; | |||
| const uint32_t zeroBufSize = 0; | |||
| const int32_t decodePadding = 1; | |||
| const int32_t minValue = 32; | |||
| const int32_t maxValue = 8192; | |||
| const int32_t decodeSucc = 0; | |||
| const int32_t decodeErr = 1; | |||
| SoftJpegd::SoftJpegd() : soft_decode_out_buf_(nullptr) {} | |||
| /* | |||
| * @brief : Use libjpeg to determine the image format. | |||
| * @param [in] jpeg_decompress_struct& libjpeg_handler : libjpeg | |||
| * @param [in] VpcInfo& vpc_input_info : vpc input information | |||
| */ | |||
| void SetFormat(struct jpeg_decompress_struct *libjpeg_handler, struct VpcInfo *vpc_input_info) { | |||
| // yuv400: component 1 1x1 | |||
| // yuv420: component 3 2x2 1x1 1x1 | |||
| // yuv422: component 3 2x1 1x1 1x1 | |||
| // yuv444: component 3 1x1 1x1 1x1 | |||
| if ((libjpeg_handler->num_components == 1) && | |||
| (libjpeg_handler->comp_info[0].h_samp_factor == libjpeg_handler->comp_info[0].v_samp_factor)) { | |||
| vpc_input_info->format = INPUT_YUV420_PLANNER; | |||
| vpc_input_info->is_fake420 = true; | |||
| } else if ((libjpeg_handler->num_components == channel3) && | |||
| (libjpeg_handler->comp_info[1].h_samp_factor == libjpeg_handler->comp_info[2].h_samp_factor) && | |||
| (libjpeg_handler->comp_info[1].v_samp_factor == libjpeg_handler->comp_info[2].v_samp_factor)) { | |||
| if (libjpeg_handler->comp_info[0].h_samp_factor == ((libjpeg_handler->comp_info[1].h_samp_factor) * num2)) { | |||
| if (libjpeg_handler->comp_info[0].v_samp_factor == ((libjpeg_handler->comp_info[1].v_samp_factor) * num2)) { | |||
| vpc_input_info->format = INPUT_YUV420_PLANNER; | |||
| } else if (libjpeg_handler->comp_info[0].v_samp_factor == libjpeg_handler->comp_info[1].v_samp_factor) { | |||
| vpc_input_info->format = INPUT_YUV422_PLANNER; | |||
| } | |||
| } else if (libjpeg_handler->comp_info[0].h_samp_factor == libjpeg_handler->comp_info[1].h_samp_factor) { | |||
| if (libjpeg_handler->comp_info[0].v_samp_factor == libjpeg_handler->comp_info[1].v_samp_factor) { | |||
| vpc_input_info->format = INPUT_YUV444_PLANNER; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void LibjpegErrorExit(j_common_ptr cinfo) { | |||
| char jpegLastErrorMsg[JMSG_LENGTH_MAX]; | |||
| (*(cinfo->err->format_message))(cinfo, jpegLastErrorMsg); | |||
| JPEGD_LOGE("run libjpeg get error : %s", jpegLastErrorMsg); | |||
| throw std::runtime_error(jpegLastErrorMsg); | |||
| } | |||
| bool CallLibjpeg(struct jpeg_decompress_struct *libjpeg_handler, uint8_t *addr, uint32_t size) { | |||
| struct jpeg_error_mgr libjpegErrorMsg; | |||
| libjpeg_handler->err = jpeg_std_error(&libjpegErrorMsg); | |||
| libjpegErrorMsg.error_exit = LibjpegErrorExit; | |||
| try { | |||
| jpeg_mem_src(libjpeg_handler, addr, size); | |||
| jpeg_read_header(libjpeg_handler, TRUE); | |||
| return true; | |||
| } catch (...) { | |||
| return false; | |||
| } | |||
| } | |||
| /* | |||
| * @brief : Obtains the JPEG header information through libjpeg to complete the decoding preparation process. | |||
| * @param [in] jpeg_decompress_struct& libjpeg_handler : libjpeg. | |||
| * @param [in] VpcInfo& vpc_input_info : vpc input information. | |||
| * @param [in] SoftDpProcsessInfo& dp_soft_process_info : soft dp struct. | |||
| * @return : decodeSucc:parse jpeg head succ, decodeErr:parse jpeg head fail. | |||
| */ | |||
| uint32_t PrepareDecode(jpeg_decompress_struct *libjpeg_handler, struct VpcInfo *vpc_input_info, | |||
| struct SoftDpProcsessInfo *dp_soft_process_info) { | |||
| bool call_libjpeg_succ = | |||
| CallLibjpeg(libjpeg_handler, dp_soft_process_info->input_buffer, dp_soft_process_info->input_buffer_size); | |||
| if (!call_libjpeg_succ) { | |||
| JPEGD_LOGE("CallLibjpeg failed!"); | |||
| return decodeErr; | |||
| } | |||
| SetFormat(libjpeg_handler, vpc_input_info); | |||
| return decodeSucc; | |||
| } | |||
| /* | |||
| * @brief : Check the parameters. The width and height range are as follows: [32,8192] | |||
| * @param [in] int32_t height : image height | |||
| * @param [in] int32_t width : image width | |||
| * @return : decodeSucc:params are valid, decodeErr:params are invalid. | |||
| */ | |||
| uint32_t CheckInputParam(int32_t height, int32_t width) { | |||
| JPEGD_CHECK_COND_FAIL_PRINT_RETURN((width >= minValue), decodeErr, "width(%d) should be >= 32.", width); | |||
| JPEGD_CHECK_COND_FAIL_PRINT_RETURN((width <= maxValue), decodeErr, "width(%d) should be <= 8192.", width); | |||
| JPEGD_CHECK_COND_FAIL_PRINT_RETURN((height >= minValue), decodeErr, "height(%d) should be >= 32.", height); | |||
| JPEGD_CHECK_COND_FAIL_PRINT_RETURN((height <= maxValue), decodeErr, "height(%d) should be <= 8192.", height); | |||
| return decodeSucc; | |||
| } | |||
| uint32_t SoftJpegd::AllocOutputBuffer(struct VpcInfo *vpc_input_info, int32_t *width, int32_t *height, | |||
| int32_t *sub_sample) { | |||
| CheckInputParam(*height, *width); | |||
| uint32_t output_size = tjBufSizeYUV2(*width, decodePadding, *height, *sub_sample); | |||
| if (output_size == zeroBufSize) { | |||
| JPEGD_LOGE("get outbuffer size failed!"); | |||
| return decodeErr; | |||
| } | |||
| if (vpc_input_info->is_fake420) { | |||
| output_size = output_size * channel3 / num2; | |||
| } | |||
| soft_decode_out_buf_ = new (std::nothrow) uint8_t[output_size]; | |||
| if (soft_decode_out_buf_ == nullptr) { | |||
| JPEGD_LOGE("alloc outbuffer failed!"); | |||
| return decodeErr; | |||
| } | |||
| return decodeSucc; | |||
| } | |||
| uint32_t SoftJpegd::ConfigVpcInputData(struct VpcInfo *vpc_input_info, int32_t *width, int32_t *height) { | |||
| vpc_input_info->real_height = *height; | |||
| vpc_input_info->real_width = *width; | |||
| if ((vpc_input_info->format == INPUT_YUV420_PLANNER || vpc_input_info->format == INPUT_YUV422_PLANNER) && | |||
| (*width % num2 == 1)) { | |||
| *width = reinterpret_cast<int32_t>(AlignUp(*width, num2)); | |||
| JPEGD_LOGW("vpc width needs align up %d, height is %d.", width, height); | |||
| } | |||
| if ((vpc_input_info->format == INPUT_YUV420_PLANNER || vpc_input_info->format == INPUT_YUV422_PLANNER) && | |||
| (*height % num2 == 1)) { | |||
| *height = reinterpret_cast<int32_t>(AlignUp(*height, num2)); | |||
| JPEGD_LOGW("vpc height needs align up %d, height is %d.", width, height); | |||
| } | |||
| vpc_input_info->addr = soft_decode_out_buf_; | |||
| vpc_input_info->height = *height; | |||
| vpc_input_info->width = *width; | |||
| if (vpc_input_info->is_fake420) { | |||
| uint8_t *u_start = vpc_input_info->addr + vpc_input_info->width * vpc_input_info->height; | |||
| int32_t uv_size = vpc_input_info->width * vpc_input_info->height / num2; | |||
| int32_t safe_ret = memset_s(reinterpret_cast<void *>((uintptr_t)u_start), uv_size, yuv400UvValue, uv_size); | |||
| if (safe_ret != 0) { | |||
| JPEGD_LOGE("config yuv400 uv memory failed."); | |||
| delete[] soft_decode_out_buf_; | |||
| soft_decode_out_buf_ = nullptr; | |||
| vpc_input_info->addr = nullptr; | |||
| return decodeErr; | |||
| } | |||
| } | |||
| return decodeSucc; | |||
| } | |||
| /* | |||
| * @brief : destory libjpeg source | |||
| * @param [in] struct jpeg_decompress_struct &libjpeg_handler : libjpeg handle. | |||
| * @param [in] tjhandle &handle : tjhandle. | |||
| */ | |||
| void DestoryLibjpegSource(struct jpeg_decompress_struct *libjpeg_handler, const tjhandle &handle) { | |||
| (void)tjDestroy(handle); | |||
| jpeg_destroy_decompress(libjpeg_handler); | |||
| } | |||
| uint32_t SoftJpegd::JpegdSoftwareDecodeProcess(struct VpcInfo *vpc_input_info, | |||
| struct SoftDpProcsessInfo *soft_dp_process_info) { | |||
| int32_t width = 0; | |||
| int32_t height = 0; | |||
| int32_t sub_sample = 0; | |||
| int32_t color_spase = 0; | |||
| struct jpeg_decompress_struct libjpeg_handler; | |||
| jpeg_create_decompress(&libjpeg_handler); | |||
| tjhandle handle = tjInitDecompress(); | |||
| int32_t prepare_decode_res = PrepareDecode(&libjpeg_handler, vpc_input_info, soft_dp_process_info); | |||
| if (prepare_decode_res != decodeSucc) { | |||
| JPEGD_LOGE("prepare decode failed!"); | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeErr; | |||
| } | |||
| int32_t decode_header_res = | |||
| tjDecompressHeader3(handle, soft_dp_process_info->input_buffer, soft_dp_process_info->input_buffer_size, &width, | |||
| &height, &sub_sample, &color_spase); | |||
| if (decode_header_res != decodeSucc) { | |||
| JPEGD_LOGE("Decompress header failed, width = %d, height = %d.", width, height); | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeErr; | |||
| } | |||
| int32_t alloc_out_buf_res = AllocOutputBuffer(vpc_input_info, &width, &height, &sub_sample); | |||
| if (alloc_out_buf_res != decodeSucc) { | |||
| JPEGD_LOGE("alloc output buffer failed!"); | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeErr; | |||
| } | |||
| int32_t decode_res = | |||
| tjDecompressToYUV2(handle, soft_dp_process_info->input_buffer, soft_dp_process_info->input_buffer_size, | |||
| soft_decode_out_buf_, width, decodePadding, height, JDCT_ISLOW); | |||
| if (decode_res != decodeSucc) { | |||
| JPEGD_LOGE("Decompress jpeg failed."); | |||
| delete[] soft_decode_out_buf_; | |||
| soft_decode_out_buf_ = nullptr; | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeErr; | |||
| } | |||
| int32_t config_vpc_res = ConfigVpcInputData(vpc_input_info, &width, &height); | |||
| if (config_vpc_res != decodeSucc) { | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeErr; | |||
| } | |||
| DestoryLibjpegSource(&libjpeg_handler, handle); | |||
| return decodeSucc; | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_JPEGD_H | |||
| #define SOFT_JPEGD_H | |||
| #include <stdint.h> | |||
| #include <cstdint> | |||
| #include <cstdio> | |||
| #include <iostream> | |||
| #include "./jpeglib.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/external_soft_dp.h" | |||
| class SoftJpegd { | |||
| public: | |||
| SoftJpegd(); | |||
| ~SoftJpegd() {} | |||
| /* | |||
| * @brief : decode interface | |||
| * @param [in] VpcInfo& vpc_input_info : vpc input information | |||
| * @param [in] SoftDpProcsessInfo& soft_dp_process_info : softDp process info | |||
| * @return : decodeSucc:decode success, decodeErr:decode failed. | |||
| */ | |||
| uint32_t JpegdSoftwareDecodeProcess(struct VpcInfo *vpc_input_info, struct SoftDpProcsessInfo *soft_dp_process_info); | |||
| private: | |||
| uint8_t *soft_decode_out_buf_; | |||
| /* | |||
| * @brief : alloc output buffer | |||
| * @param [in] VpcInfo& vpc_input_info : vpc input information | |||
| * @param [in] int32_t& width : output width | |||
| * @param [in] int32_t& height : output height | |||
| * @param [in] int32_t& sub_sample : level of chrominance subsampling in the image | |||
| * @param [in] int32_t& color_spase : pointer to an integer variable that will receive one of the JPEG | |||
| * constants, indicating the colorspace of the JPEG image. | |||
| * @return : decodeSucc:alloc output buf success, decodeErr:alloc output buf failed. | |||
| */ | |||
| uint32_t AllocOutputBuffer(struct VpcInfo *vpc_input_info, int32_t *width, int32_t *height, int32_t *sub_sample); | |||
| /* | |||
| * @brief : config decode output | |||
| * @param [in] VpcInfo& vpc_input_info : vpc input information | |||
| * @param [in] int32_t& width : output width | |||
| * @param [in] int32_t& height : output height | |||
| * @return : decodeSucc:config output buf succes, decodeErr:config output buf failed. | |||
| */ | |||
| uint32_t ConfigVpcInputData(struct VpcInfo *vpc_input_info, int32_t *width, int32_t *height); | |||
| }; | |||
| #endif // SOFT_JPEGD_H | |||
| @@ -0,0 +1,780 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_vpc.h" | |||
| #include <securec.h> | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_check.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_tools.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/yuv_scaler_para_set.h" | |||
| constexpr int32_t dpSucc = 0; | |||
| constexpr int32_t dpFail = -1; | |||
| constexpr uint32_t yuvCoeffiNum4 = 4; | |||
| constexpr uint32_t yuvCoeffiNum5 = 5; | |||
| constexpr uint32_t uvReductCoeffNum = 5; | |||
| constexpr int32_t uvReductCoeff[uvReductCoeffNum] = {13, 65, 100, 65, 13}; // yuv444 dimension reduction filter. | |||
| constexpr uint32_t scalerTap4 = 4; | |||
| constexpr uint32_t scalerTap6 = 6; | |||
| constexpr uint32_t scalerCoeff = 16; // yuv conversion coefficient | |||
| constexpr uint32_t low3BitVal = 0x7; | |||
| constexpr int32_t low16BitVal = 0xffff; | |||
| constexpr uint32_t bit8Offset = 8; | |||
| constexpr uint32_t bit13Offset = 13; | |||
| constexpr uint32_t bit16Offset = 16; | |||
| constexpr uint32_t maxCoeff = 65536; | |||
| constexpr uint32_t num2 = 2; | |||
| constexpr int32_t scalerTap2 = 2; | |||
| // yuv convert rgb coefficient table | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR0c0 = (256); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR0c1 = (0); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR0c2 = (359); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR1c0 = (256); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR1c1 = (-88); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR1c2 = (-183); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR2c0 = (256); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR2c1 = (454); | |||
| constexpr int32_t rtAippYuv2RgbCscMatrixR2c2 = (0); | |||
| constexpr int32_t rtAippYuv2RgbCscInputBias0 = (0); | |||
| constexpr int32_t rtAippYuv2RgbCscInputBias1 = (128); | |||
| constexpr int32_t rtAippYuv2RgbCscInputBias2 = (128); | |||
| constexpr int32_t rtAippConverCoeffi = (256); | |||
| SoftVpc::SoftVpc() | |||
| : in_format_(INPUT_VPC_UNKNOWN), | |||
| in_width_(0), | |||
| in_height_(0), | |||
| in_data_(nullptr), | |||
| in_y_data_(nullptr), | |||
| in_u_data_(nullptr), | |||
| in_v_data_(nullptr), | |||
| left_(0), | |||
| right_(0), | |||
| up_(0), | |||
| down_(0), | |||
| out_width_(0), | |||
| out_height_(0), | |||
| out_data_(nullptr), | |||
| out_y_data_(nullptr), | |||
| out_u_data_(nullptr), | |||
| out_v_data_(nullptr), | |||
| pre_scaler_num_(0), | |||
| half_line_mode_(false), | |||
| horizon_coeff_(0), | |||
| vertical_coeff_(0), | |||
| horizon_bypass_(false), | |||
| vertical_bypass_(false), | |||
| y_horizon_tap_(nullptr), | |||
| uv_horizon_tap_(nullptr), | |||
| vertical_tap_(nullptr) {} | |||
| void SoftVpc::SetYuv422OutBuffer() { | |||
| out_y_data_ = out_data_; | |||
| out_u_data_ = out_y_data_ + out_width_ * out_height_; | |||
| out_v_data_ = out_u_data_ + out_width_ * out_height_ / yuvCoeffiNum2; | |||
| } | |||
| int32_t SoftVpc::CheckParamter() { | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((left_ < right_), dpFail, "left(%u) should be < right(%u).", left_, right_); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((right_ < in_width_), dpFail, "right(%u) should be < inWidth(%u).", right_, | |||
| in_width_); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((up_ < down_), dpFail, "up(%u) should be < down(%u).", up_, down_); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((down_ < in_height_), dpFail, "down_(%u) should be < in_height(%u).", down_, | |||
| in_height_); | |||
| uint32_t crop_width = right_ - left_ + 1; | |||
| uint32_t crop_height = down_ - up_ + 1; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((crop_width >= 10), dpFail, // mini width is 10 | |||
| "right(%u) - left(%u) + 1 = crop_width(%u) should be >= 10.", right_, left_, | |||
| crop_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((in_width_ <= 8192), dpFail, // max width is 8192 | |||
| "inWidth(%u) should be <= 8192.", in_width_); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((crop_height >= 6), dpFail, // mini height is 6 | |||
| "down(%u) - up(%u) + 1 = crop_height(%u) should be >= 6.", down_, up_, crop_height); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((in_height_ <= 8192), dpFail, // max height is 8192 | |||
| "inHeight(%u) should be <= 8192.", in_height_); | |||
| uint32_t out_width = out_width_; | |||
| uint32_t out_height = out_height_; | |||
| bool flag = (out_width * 16 >= crop_width) ? true : false; // Up to 16x magnification | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN(flag, dpFail, | |||
| "Max magnification is 16. Please check left(%u), right(%u), out_width(%u).", left_, | |||
| right_, out_width); | |||
| flag = (crop_width * 32 >= out_width) ? true : false; // A maximum of 32x zoom-out | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN(flag, dpFail, | |||
| "Max reduction multiple is 32. Please check left(%u), right(%u), out_width(%u).", | |||
| left_, right_, out_width); | |||
| flag = (out_height * 16 >= crop_height) ? true : false; // Up to 16x magnification | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN( | |||
| flag, dpFail, "Max magnification is 16. Please check up(%u), down(%u), out_height(%u).", up_, down_, out_height); | |||
| flag = (crop_height * 32 >= out_height) ? true : false; // A maximum of 32x zoom-out | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN(flag, dpFail, | |||
| "Max reduction multiple is 32. Please check up(%u), down(%u), out_height(%u).", up_, | |||
| down_, out_height); | |||
| return dpSucc; | |||
| } | |||
| void SoftVpc::Init(VpcInfo input, SoftDpCropInfo crop, VpcInfo output) { | |||
| in_info_ = input; | |||
| out_info_ = output; | |||
| left_ = (crop.left & 0x1) ? (crop.left + 1) : crop.left; // Round up the value to an even number. | |||
| right_ = (crop.right & 0x1) ? crop.right : (crop.right - 1); // Take an odd number downwards. | |||
| up_ = (crop.up & 0x1) ? (crop.up + 1) : crop.up; // Round up the value to an even number. | |||
| down_ = (crop.down & 0x1) ? crop.down : (crop.down - 1); // Take an odd number downwards. | |||
| in_format_ = input.format; | |||
| in_width_ = input.width; | |||
| in_height_ = input.height; | |||
| in_data_ = input.addr; | |||
| // Offset the start address of each channel to the cropped address. | |||
| in_y_data_ = in_data_ + up_ * in_width_ + left_; | |||
| in_u_data_ = in_data_ + in_width_ * in_height_ + up_ * in_width_ / yuvCoeffiNum4 + left_ / yuvCoeffiNum2; | |||
| in_v_data_ = in_data_ + in_width_ * in_height_ * yuvCoeffiNum5 / yuvCoeffiNum4 + up_ * in_width_ / yuvCoeffiNum4 + | |||
| left_ / yuvCoeffiNum2; | |||
| if (in_format_ == INPUT_YUV422_PLANNER) { | |||
| in_u_data_ = in_data_ + in_width_ * in_height_ + up_ * in_width_ / yuvCoeffiNum2 + left_ / yuvCoeffiNum2; | |||
| in_v_data_ = in_data_ + in_width_ * in_height_ * yuvCoeffiNum3 / yuvCoeffiNum2 + up_ * in_width_ / yuvCoeffiNum2 + | |||
| left_ / yuvCoeffiNum2; | |||
| } | |||
| if (in_format_ == INPUT_YUV444_PLANNER) { | |||
| in_u_data_ = in_data_ + in_width_ * in_height_ + up_ * in_width_ + left_; | |||
| in_v_data_ = in_data_ + in_width_ * in_height_ * yuvCoeffiNum2 + up_ * in_width_ + left_; | |||
| } | |||
| out_width_ = output.width; | |||
| out_height_ = output.height; | |||
| } | |||
| // Converts the input result of the chip sub-module to the input of the next level and releases the input memory. | |||
| void SoftVpc::OutputChangeToInput() { | |||
| in_width_ = out_width_; | |||
| in_height_ = out_height_; | |||
| left_ = 0; | |||
| right_ = in_width_ - 1; | |||
| up_ = 0; | |||
| down_ = in_height_ - 1; | |||
| delete[] in_data_; | |||
| in_data_ = out_data_; | |||
| in_y_data_ = out_y_data_; | |||
| in_u_data_ = out_u_data_; | |||
| in_v_data_ = out_v_data_; | |||
| } | |||
| // For the tasks that cannot be processed by the chip at a time, split the tasks whose scaling coefficients in the | |||
| // horizontal direction are greater than those in the vertical direction. | |||
| void SoftVpc::HorizonSplit(ResizeUnit *pre_unit, ResizeUnit *can_process_unit) { | |||
| uint32_t in_width = pre_unit->in_width; | |||
| uint32_t out_width = pre_unit->out_width; | |||
| uint32_t in_height = pre_unit->in_height; | |||
| uint32_t out_height = pre_unit->out_height; | |||
| if (out_width > 4 * in_width) { // The horizontal scaling ratio is greater than 4x. | |||
| // Ensure that the output is less than four times of the input and the input is an even number. | |||
| can_process_unit->in_width = AlignUp(out_width, 8) / 4; | |||
| if (out_height > 4 * in_height) { // The vertical scaling ratio is greater than 4x. | |||
| // Ensure that the output is less than four times of the input and the input is an even number. | |||
| can_process_unit->in_height = AlignUp(out_height, 8) / 4; | |||
| } else if (out_height >= in_height) { // The vertical scaling range is [1, 4]. | |||
| can_process_unit->in_height = in_height; | |||
| } else if (out_height * 4 >= in_height) { // The vertical scaling range is [1/4, 1) | |||
| can_process_unit->in_height = out_height; | |||
| } else { | |||
| can_process_unit->in_height = out_height * 4; // vertical scaling range is smaller than 1/4x | |||
| } | |||
| } else { // The horizontal scaling ratio is less than or equal to 4x. | |||
| can_process_unit->in_width = in_width; | |||
| can_process_unit->in_height = out_height * 4; // The vertical scaling ratio is less than 1/4. | |||
| } | |||
| can_process_unit->out_width = out_width; | |||
| can_process_unit->out_height = out_height; | |||
| pre_unit->out_width = can_process_unit->in_width; | |||
| pre_unit->out_height = can_process_unit->in_height; | |||
| } | |||
| // For the tasks that cannot be processed by the chip at a time, split the tasks whose vertical scaling coefficients | |||
| // are greater than the horizontal scaling coefficients. | |||
| void SoftVpc::VerticalSplit(ResizeUnit *pre_unit, ResizeUnit *can_process_unit) { | |||
| uint32_t in_width = pre_unit->in_width; | |||
| uint32_t out_width = pre_unit->out_width; | |||
| uint32_t in_height = pre_unit->in_height; | |||
| uint32_t out_height = pre_unit->out_height; | |||
| if (out_height > 4 * in_height) { // The vertical scaling ratio is greater than 4x. | |||
| // // Ensure that the output is less than four times of the input and the input is an even number. | |||
| can_process_unit->in_height = AlignUp(out_height, 8) / 4; | |||
| if (out_width > 4 * in_width) { | |||
| can_process_unit->in_width = AlignUp(out_width, 8) / 4; | |||
| } else if (out_width >= in_width) { | |||
| can_process_unit->in_width = in_width; | |||
| } else if (out_width * 4 >= in_width) { | |||
| can_process_unit->in_width = out_width; | |||
| } else { | |||
| can_process_unit->in_width = out_width * 4; | |||
| } | |||
| } else { | |||
| // If the vertical scaling ratio is less than or equal to 4x, the horizontal scaling | |||
| // ratio must be less than 1/4. | |||
| can_process_unit->in_height = in_height; | |||
| can_process_unit->in_width = out_width * 4; // The horizontal scaling ratio is less than 1/4. | |||
| } | |||
| can_process_unit->out_width = out_width; | |||
| can_process_unit->out_height = out_height; | |||
| pre_unit->out_width = can_process_unit->in_width; | |||
| pre_unit->out_height = can_process_unit->in_height; | |||
| } | |||
| // Check whether the VPC chip can complete the processing at a time based on the input and output sizes. | |||
| bool SoftVpc::CanVpcChipProcess(const ResizeUnit &pre_unit) { | |||
| uint32_t input_width = pre_unit.in_width; | |||
| uint32_t output_width = pre_unit.out_width; | |||
| uint32_t input_height = pre_unit.in_height; | |||
| uint32_t output_height = pre_unit.out_height; | |||
| uint32_t pre_scaler_num = 0; | |||
| // 4 and 16 inorder to check whether the aspect ratio ranges from 1/4 to 4. | |||
| while (!(IsInTheScope(4 * output_width, input_width, 16 * input_width)) || | |||
| !(IsInTheScope(4 * output_height, input_height, 16 * input_height))) { | |||
| // The number of used prescalers increases by 1. | |||
| ++pre_scaler_num; | |||
| // Each time the prescaler is used, the input size is reduced to 1/2 of the original size divided by 2, | |||
| // and the size must be 2-pixel aligned. | |||
| input_width = AlignDown(input_width / 2, 2); | |||
| // The value divided by 2 indicates that the input size is reduced to half of | |||
| // the original size and must be 2-pixel aligned. | |||
| input_height = AlignDown(input_height / 2, 2); | |||
| // If the scaling coefficient is still greater than 4 after prescaler, false is returned. If the | |||
| // scaling coefficient is greater than 4 or the number of prescalers is greater than 3, false is returned. | |||
| if ((output_width > (4 * input_width)) || (output_height > (4 * input_height)) || (pre_scaler_num > 3)) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| // Creates a scaling parameter stack based on the user input and output information. The elements in the stack are | |||
| // the input and output information, and the input and output information stores the scaling information. | |||
| void SoftVpc::BuildResizeStack() { | |||
| uint32_t in_width = right_ - left_ + 1; | |||
| uint32_t in_height_ = down_ - up_ + 1; | |||
| ResizeUnit pre_unit = {in_width, in_height_, out_width_, out_height_}; // Scaling information to be split. | |||
| while (!CanVpcChipProcess(pre_unit)) { | |||
| uint32_t input_width = pre_unit.in_width; | |||
| uint32_t output_width = pre_unit.out_width; | |||
| uint32_t input_height = pre_unit.in_height; | |||
| uint32_t output_height = pre_unit.out_height; | |||
| ResizeUnit can_process_unit = {0, 0, 0, 0}; // Scaling information that can be processed by the chip. | |||
| // Split the input and output, the horizontal scaling coefficient is greater than | |||
| // the vertical scaling coefficient. | |||
| if (output_width * input_height > output_height * input_width) { | |||
| HorizonSplit(&pre_unit, &can_process_unit); | |||
| } else { // The horizontal scaling coefficient is less than the vertical scaling coefficient. | |||
| VerticalSplit(&pre_unit, &can_process_unit); | |||
| } | |||
| can_process_unit.out_width = output_width; | |||
| can_process_unit.out_height = output_height; | |||
| pre_unit.out_width = can_process_unit.in_width; | |||
| pre_unit.out_height = can_process_unit.in_height; | |||
| // Pushes a set of scaled information that can be processed into a stack. | |||
| resize_stack_.push(can_process_unit); | |||
| } | |||
| // Push the information that can be processed by the chip for one time into the stack. | |||
| resize_stack_.push(pre_unit); | |||
| } | |||
| int32_t SoftVpc::Yuv422pToYuv420p() { | |||
| in_format_ = INPUT_YUV420_PLANNER; | |||
| out_width_ = in_width_; | |||
| out_height_ = in_height_; | |||
| uint32_t buffer_size = out_width_ * out_height_ * yuvCoeffiNum3 / yuvCoeffiNum2; | |||
| out_data_ = new (std::nothrow) uint8_t[buffer_size]; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((out_data_ != nullptr), dpFail, "alloc buffer fail."); | |||
| out_y_data_ = out_data_; | |||
| out_u_data_ = out_y_data_ + out_width_ * out_height_; | |||
| out_v_data_ = out_u_data_ + out_width_ * out_height_ / yuvCoeffiNum4; | |||
| for (uint32_t i = 0; i < out_height_; i++) { // Y data remains unchanged. | |||
| for (uint32_t j = 0; j < out_width_; j++) { | |||
| out_y_data_[i * out_width_ + j] = in_y_data_[i * out_width_ + j]; | |||
| } | |||
| } | |||
| uint32_t yuv420_uv_w = out_width_ / yuvCoeffiNum2; | |||
| uint32_t yuv420_uv_h = out_height_ / yuvCoeffiNum2; | |||
| // The UV data is reduced by half. Only the UV data of 422 odd rows is obtained. | |||
| for (uint32_t i = 0; i < yuv420_uv_h; i++) { | |||
| for (uint32_t j = 0; j < yuv420_uv_w; j++) { | |||
| out_u_data_[i * yuv420_uv_w + j] = in_u_data_[i * out_width_ + j]; | |||
| out_v_data_[i * yuv420_uv_w + j] = in_v_data_[i * out_width_ + j]; | |||
| } | |||
| } | |||
| OutputChangeToInput(); | |||
| return dpSucc; | |||
| } | |||
| void SoftVpc::ChipPreProcess() { | |||
| pre_scaler_num_ = 0; | |||
| uint32_t crop_width = (right_ - left_ + 1); | |||
| uint32_t crop_height = (down_ - up_ + 1); | |||
| // The minimum scaling ratio of the scaler module is 1/4. If the scaling ratio is less than 1/4, the prescaler is | |||
| // used for scaling. One prescaler is scaled by 1/2. | |||
| while ((out_width_ * scalerTap4 < crop_width) || (out_height_ * scalerTap4 < crop_height)) { | |||
| pre_scaler_num_++; | |||
| crop_width /= yuvCoeffiNum2; | |||
| crop_width = AlignDown(crop_width, yuvCoeffiNum2); | |||
| crop_height /= yuvCoeffiNum2; | |||
| crop_height = AlignDown(crop_height, yuvCoeffiNum2); | |||
| } | |||
| // Each time a prescaler is used, the alignment value needs to be doubled. | |||
| uint32_t align_size = (yuvCoeffiNum2 << pre_scaler_num_); | |||
| crop_width = (right_ - left_ + 1); | |||
| uint32_t gap = crop_width % align_size; | |||
| left_ += AlignDown(gap / yuvCoeffiNum2, yuvCoeffiNum2); | |||
| right_ -= AlignUp(gap / yuvCoeffiNum2, yuvCoeffiNum2); | |||
| crop_width -= gap; | |||
| crop_height = (down_ - up_ + 1); | |||
| gap = crop_height % align_size; | |||
| up_ += AlignDown(gap / yuvCoeffiNum2, yuvCoeffiNum2); | |||
| down_ -= AlignUp(gap / yuvCoeffiNum2, yuvCoeffiNum2); | |||
| crop_height -= gap; | |||
| uint32_t move_step = scalerCoeff - pre_scaler_num_; | |||
| horizon_coeff_ = (crop_width << move_step) / out_width_; | |||
| horizon_bypass_ = (horizon_coeff_ == maxCoeff) ? true : false; | |||
| vertical_coeff_ = (crop_height << move_step) / out_height_; | |||
| vertical_bypass_ = (vertical_coeff_ == maxCoeff) ? true : false; | |||
| half_line_mode_ = false; | |||
| // If the width is less than 2048, the half mode is used. | |||
| if ((vertical_coeff_ >= 0x2aab) && (vertical_coeff_ <= 0x8000) && (out_width_ <= 2048)) { | |||
| half_line_mode_ = true; | |||
| } | |||
| YuvWPara *yuv_scaler_paraset = YuvScalerParaSet::GetInstance(); | |||
| YuvScalerPara *scale = yuv_scaler_paraset->scale; | |||
| int32_t index = GetScalerParamterIndex(horizon_coeff_, yuv_scaler_paraset); | |||
| y_horizon_tap_ = scale[index].taps_6; | |||
| uv_horizon_tap_ = scale[index].taps_4; | |||
| index = GetScalerParamterIndex(vertical_coeff_, yuv_scaler_paraset); | |||
| vertical_tap_ = (half_line_mode_) ? scale[index].taps_6 : scale[index].taps_4; | |||
| } | |||
| void SoftVpc::SetUvValue(int32_t *u_value, int32_t *v_value, int32_t y, int32_t pos) { | |||
| int32_t crop_width = right_ - left_ + 1; | |||
| int32_t in_w_stride = in_width_; | |||
| // 5-order filtering dimension reduction algorithm. | |||
| for (uint32_t i = 0; i < uvReductCoeffNum; i++) { | |||
| int32_t index = pos + i - uvReductCoeffNum / yuvCoeffiNum2; | |||
| if ((index + static_cast<int32_t>(left_) % 0x80) < 0) { | |||
| index = -index; | |||
| } | |||
| if (index > (crop_width - 1)) { | |||
| index = yuvCoeffiNum2 * (crop_width - 1) - index; | |||
| } | |||
| *u_value += in_u_data_[y * in_w_stride + index] * uvReductCoeff[i]; | |||
| *v_value += in_v_data_[y * in_w_stride + index] * uvReductCoeff[i]; | |||
| } | |||
| } | |||
| int32_t SoftVpc::Yuv444PackedToYuv422Packed() { | |||
| int32_t in_w_stride = in_width_; | |||
| int32_t crop_width = right_ - left_ + 1; | |||
| int32_t crop_height = down_ - up_ + 1; | |||
| out_width_ = crop_width; | |||
| out_height_ = crop_height; | |||
| out_data_ = new (std::nothrow) uint8_t[out_width_ * out_height_ * yuvCoeffiNum2]; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((out_data_ != nullptr), dpFail, "alloc buffer fail."); | |||
| SetYuv422OutBuffer(); | |||
| for (int32_t i = 0; i < crop_height; i++) { // 拷贝y数据 | |||
| int32_t ret = memcpy_s(out_y_data_ + i * crop_width, crop_width, in_y_data_ + i * in_w_stride, crop_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| } | |||
| int32_t uv_width = crop_width / yuvCoeffiNum2; | |||
| // Reduces the dimension of the UV data. The 5-order filtering algorithm is used for dimension reduction. | |||
| for (int32_t y = 0; y < crop_height; y++) { | |||
| for (int32_t x = 0; x < uv_width; x++) { | |||
| int32_t pos = static_cast<uint32_t>(x) << 1; | |||
| int32_t u_value = 0; | |||
| int32_t v_value = 0; | |||
| SetUvValue(&u_value, &v_value, y, pos); | |||
| // The most significant eight bits of the dimension reduction result are used. | |||
| u_value = static_cast<uint32_t>(u_value + 0x80) >> 8; | |||
| v_value = static_cast<uint32_t>(v_value + 0x80) >> 8; | |||
| if (u_value > 0xff) u_value = 0xff; | |||
| if (v_value > 0xff) v_value = 0xff; | |||
| out_u_data_[y * uv_width + x] = u_value; | |||
| out_v_data_[y * uv_width + x] = v_value; | |||
| } | |||
| } | |||
| in_format_ = INPUT_YUV422_PLANNER; | |||
| OutputChangeToInput(); | |||
| return dpSucc; | |||
| } | |||
| // For the YUV420 input, the output width and height are reduced by 1/2, the output format is YUV422, | |||
| // and the amount of output UV data is reduced by only half. | |||
| void SoftVpc::Yuv420PlannerUvPrescaler(uint8_t *(&in_uv_data)[yuvCoeffiNum2], uint8_t *(&out_uv_data)[yuvCoeffiNum2], | |||
| uint32_t in_w_stride) { | |||
| for (uint32_t k = 0; k < yuvCoeffiNum2; k++) { | |||
| for (uint32_t i = 0; i < out_height_; i++) { | |||
| for (uint32_t j = 0; j < out_width_ / yuvCoeffiNum2; j++) { // Zoom out by 1/2 | |||
| uint8_t a = in_uv_data[k][i * in_w_stride / yuvCoeffiNum2 + yuvCoeffiNum2 * j]; | |||
| uint8_t b = in_uv_data[k][i * in_w_stride / yuvCoeffiNum2 + yuvCoeffiNum2 * j + 1]; | |||
| out_uv_data[k][i * out_width_ / yuvCoeffiNum2 + j] = (a + b + 1) / yuvCoeffiNum2; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // For the YUV420 input, the output width and height are reduced by 1/2, the output format is YUV422, and the | |||
| // amount of output UV data is reduced by 3/4. The prescaler scaling algorithm is a bilinear interpolation | |||
| // algorithm. The scaling ratio is 1/2 horizontally and vertically. That is, two horizontal points are combined | |||
| // into one point, and two vertical points are combined into one point. | |||
| void SoftVpc::Yuv422PackedUvPrescaler(uint8_t *(&in_uv_data)[yuvCoeffiNum2], uint8_t *(&out_uv_data)[yuvCoeffiNum2], | |||
| uint32_t in_w_stride) { | |||
| for (uint32_t k = 0; k < yuvCoeffiNum2; k++) { | |||
| for (uint32_t i = 0; i < out_height_; i++) { | |||
| for (uint32_t j = 0; j < out_width_ / yuvCoeffiNum2; j++) { | |||
| uint8_t a = in_uv_data[k][i * in_w_stride + yuvCoeffiNum2 * j]; | |||
| uint8_t b = in_uv_data[k][i * in_w_stride + yuvCoeffiNum2 * j + 1]; | |||
| uint8_t aa = (a + b + 1) / yuvCoeffiNum2; | |||
| uint8_t c = in_uv_data[k][(yuvCoeffiNum2 * i + 1) * in_w_stride / yuvCoeffiNum2 + yuvCoeffiNum2 * j]; | |||
| uint8_t d = in_uv_data[k][(yuvCoeffiNum2 * i + 1) * in_w_stride / yuvCoeffiNum2 + yuvCoeffiNum2 * j + 1]; | |||
| uint8_t bb = (c + d + 1) / yuvCoeffiNum2; | |||
| out_uv_data[k][i * out_width_ / yuvCoeffiNum2 + j] = (aa + bb + 1) / yuvCoeffiNum2; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void SoftVpc::UvPrescaler() { | |||
| uint32_t in_w_stride = in_width_; | |||
| uint8_t *in_uv_data[yuvCoeffiNum2] = {in_u_data_, in_v_data_}; | |||
| uint8_t *out_uv_data[yuvCoeffiNum2] = {out_u_data_, out_v_data_}; | |||
| if (in_format_ == INPUT_YUV420_PLANNER) { | |||
| Yuv420PlannerUvPrescaler(in_uv_data, out_uv_data, in_w_stride); | |||
| } else { | |||
| Yuv422PackedUvPrescaler(in_uv_data, out_uv_data, in_w_stride); | |||
| } | |||
| } | |||
| int32_t SoftVpc::PreScaler() { | |||
| uint32_t in_w_stride = in_width_; | |||
| uint32_t crop_width = right_ - left_ + 1; | |||
| uint32_t crop_height = down_ - up_ + 1; | |||
| out_width_ = crop_width / yuvCoeffiNum2; | |||
| out_height_ = crop_height / yuvCoeffiNum2; | |||
| out_data_ = new (std::nothrow) uint8_t[out_width_ * out_height_ * yuvCoeffiNum2]; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((out_data_ != nullptr), dpFail, "alloc buffer fail."); | |||
| SetYuv422OutBuffer(); | |||
| // The scaling algorithm of the rescaler is a bilinear interpolation algorithm. The scaling ratio is 1/2 | |||
| // horizontally and vertically. That is, two horizontal points are combined into one point, | |||
| // and two vertical points are combined into one point. | |||
| for (uint32_t i = 0; i < out_height_; i++) { | |||
| for (uint32_t j = 0; j < out_width_; j++) { | |||
| uint8_t a = in_y_data_[yuvCoeffiNum2 * i * in_w_stride + yuvCoeffiNum2 * j]; | |||
| uint8_t b = in_y_data_[yuvCoeffiNum2 * i * in_w_stride + yuvCoeffiNum2 * j + 1]; | |||
| uint8_t aa = (a + b + 1) / yuvCoeffiNum2; | |||
| uint8_t c = in_y_data_[(yuvCoeffiNum2 * i + 1) * in_w_stride + yuvCoeffiNum2 * j]; | |||
| uint8_t d = in_y_data_[(yuvCoeffiNum2 * i + 1) * in_w_stride + yuvCoeffiNum2 * j + 1]; | |||
| uint8_t bb = (c + d + 1) / yuvCoeffiNum2; | |||
| out_y_data_[i * out_width_ + j] = (aa + bb + 1) / yuvCoeffiNum2; | |||
| } | |||
| } | |||
| UvPrescaler(); | |||
| in_format_ = INPUT_YUV422_PLANNER; | |||
| OutputChangeToInput(); | |||
| return dpSucc; | |||
| } | |||
| int32_t SoftVpc::BypassHorizonScaler() { | |||
| uint32_t in_w_stride = in_width_; | |||
| uint32_t crop_width = right_ - left_ + 1; | |||
| uint32_t crop_height = down_ - up_ + 1; | |||
| for (uint32_t i = 0; i < crop_height; i++) { | |||
| int32_t ret = memcpy_s(out_y_data_ + i * crop_width, crop_width, in_y_data_ + i * in_w_stride, crop_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| } | |||
| uint32_t uv_w_stride = in_w_stride / yuvCoeffiNum2; | |||
| uint32_t uv_width = crop_width / yuvCoeffiNum2; | |||
| // The input format is 420. After the format is converted to 422, the UV data is doubled. | |||
| // Therefore, the data needs to be copied twice. | |||
| if (in_format_ == INPUT_YUV420_PLANNER) { | |||
| uint32_t uv_height = crop_height / yuvCoeffiNum2; | |||
| for (uint32_t i = 0; i < uv_height; i++) { | |||
| int32_t ret = | |||
| memcpy_s(out_u_data_ + uv_width * i * yuvCoeffiNum2, uv_width, in_u_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| ret = | |||
| memcpy_s(out_u_data_ + uv_width * (i * yuvCoeffiNum2 + 1), uv_width, in_u_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| ret = memcpy_s(out_v_data_ + uv_width * i * yuvCoeffiNum2, uv_width, in_v_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| ret = | |||
| memcpy_s(out_v_data_ + uv_width * (i * yuvCoeffiNum2 + 1), uv_width, in_v_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| } | |||
| } else { | |||
| uint32_t uv_height = crop_height; | |||
| for (uint32_t i = 0; i < uv_height; i++) { | |||
| int32_t ret = memcpy_s(out_u_data_ + uv_width * i, uv_width, in_u_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| ret = memcpy_s(out_v_data_ + uv_width * i, uv_width, in_v_data_ + uv_w_stride * i, uv_width); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "memcpy fail."); | |||
| } | |||
| } | |||
| return dpSucc; | |||
| } | |||
| void SoftVpc::StartHorizonScalerEx(uint32_t width_index, uint32_t tmp_offset, uint8_t *(&in_data)[yuvCoeffiNum3], | |||
| uint8_t *(&out_data)[yuvCoeffiNum3]) { | |||
| int16_t *taps[yuvCoeffiNum3] = {y_horizon_tap_, uv_horizon_tap_, uv_horizon_tap_}; | |||
| int32_t crop_w = right_ - left_; | |||
| int32_t in_w[yuvCoeffiNum3] = {crop_w, crop_w / scalerTap2, crop_w / scalerTap2}; | |||
| uint32_t taps_num[yuvCoeffiNum3] = {scalerTap6, scalerTap4, scalerTap4}; | |||
| uint32_t out_w[yuvCoeffiNum3] = {out_width_, out_width_ / yuvCoeffiNum2, out_width_ / yuvCoeffiNum2}; | |||
| uint32_t mid_num = (taps_num[width_index] >> 1) - 1; | |||
| uint32_t acc = 0; | |||
| // higher order filter algorithm | |||
| // Map the output position to the input position, calculate the phase based on the input position, and find the | |||
| // corresponding filter (6-order or 4-order filter window) based on the phase. | |||
| // The input data and the filter perform convolution operation to obtain the output data. | |||
| for (uint32_t j = 0; j < out_w[width_index]; j++) { | |||
| uint32_t pos = acc >> bit16Offset; | |||
| uint32_t phase = (acc >> bit13Offset) & low3BitVal; | |||
| int16_t *coeffs = taps[width_index] + taps_num[width_index] * phase; | |||
| int32_t value = 0; | |||
| for (uint32_t k = 0; k < taps_num[width_index]; k++) { // convolution operation | |||
| int32_t index = pos + k - mid_num; | |||
| index = TruncatedFunc(index, 0, in_w[width_index]); | |||
| int32_t v1 = static_cast<int32_t>(in_data[width_index][tmp_offset + index]); | |||
| int32_t v2 = static_cast<int32_t>(coeffs[k]); | |||
| value += v1 * v2; | |||
| } | |||
| value = TruncatedFunc((value + 0x80), 0, low16BitVal); | |||
| value = static_cast<uint32_t>(value) >> bit8Offset; | |||
| *out_data[width_index]++ = static_cast<uint8_t>(value); | |||
| acc += horizon_coeff_; | |||
| } | |||
| return; | |||
| } | |||
| void SoftVpc::HorizonScalerEx() { | |||
| uint8_t *in_data[yuvCoeffiNum3] = {in_y_data_, in_u_data_, in_v_data_}; | |||
| uint8_t *out_data[yuvCoeffiNum3] = {out_y_data_, out_u_data_, out_v_data_}; | |||
| uint32_t in_w_stride[yuvCoeffiNum3] = {in_width_, in_width_ / yuvCoeffiNum2, in_width_ / yuvCoeffiNum2}; | |||
| for (uint32_t m = 0; m < yuvCoeffiNum3; m++) { | |||
| for (uint32_t i = 0; i < out_height_; i++) { | |||
| auto tmp_offset = i * in_w_stride[m]; // Offset of each row of data relative to the start position. | |||
| if ((m > 0) && (in_format_ == INPUT_YUV420_PLANNER)) { | |||
| // The width of the UV channel is half of that of the Y channel. | |||
| tmp_offset = i / yuvCoeffiNum2 * in_w_stride[m]; | |||
| } | |||
| StartHorizonScalerEx(m, tmp_offset, in_data, out_data); | |||
| } | |||
| } | |||
| } | |||
| int32_t SoftVpc::HorizonScaler() { | |||
| uint32_t crop_width = right_ - left_ + 1; | |||
| uint32_t crop_height = down_ - up_ + 1; | |||
| out_width_ = (crop_width << scalerCoeff) / horizon_coeff_; | |||
| out_height_ = crop_height; | |||
| out_data_ = new (std::nothrow) uint8_t[out_width_ * out_height_ * yuvCoeffiNum2]; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((out_data_ != nullptr), dpFail, "alloc buffer fail."); | |||
| SetYuv422OutBuffer(); | |||
| // in bypass mode, the input and output sizes are the same. | |||
| // To be compatible with the YUV420 output, the YUV422 format is used. | |||
| if (horizon_bypass_) { | |||
| int32_t ret = BypassHorizonScaler(); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "BypassHorizonScaler fail."); | |||
| } else { | |||
| HorizonScalerEx(); | |||
| } | |||
| in_format_ = INPUT_YUV422_PLANNER; | |||
| OutputChangeToInput(); | |||
| return dpSucc; | |||
| } | |||
| void SoftVpc::StartVerticalScaler(uint32_t yuv_index, uint32_t out_w[], uint8_t *(&in_data)[yuvCoeffiNum3], | |||
| uint8_t *(&out_data)[yuvCoeffiNum3]) { | |||
| uint32_t num_taps = half_line_mode_ ? scalerTap6 : scalerTap4; | |||
| uint32_t mid_num = (num_taps >> 1) - 1; | |||
| int32_t max_offset = in_height_ - 1; | |||
| // higher order filter algorithm | |||
| // Map the output position to the input position, calculate the phase based on the input position, and find the | |||
| // corresponding filter (6-order or 4-order filter window) based on the phase. The input data and the filter | |||
| // perform convolution operation to obtain the output data. | |||
| for (uint32_t i = 0; i < out_height_; i++) { | |||
| uint32_t acc = i * vertical_coeff_; | |||
| uint32_t pos = acc >> bit16Offset; | |||
| uint32_t phase = (acc >> bit13Offset) & low3BitVal; | |||
| int16_t *coeffs = vertical_tap_ + num_taps * phase; | |||
| for (uint32_t j = 0; j < out_w[yuv_index]; j++) { | |||
| int32_t value = 0; | |||
| for (uint32_t k = 0; k < num_taps; k++) { // convolution operation | |||
| int32_t index = pos + k - mid_num; | |||
| index = TruncatedFunc(index, 0, max_offset); | |||
| int32_t v1 = in_data[yuv_index][index * out_w[yuv_index] + j]; | |||
| int32_t v2 = coeffs[k]; | |||
| value += v1 * v2; | |||
| } | |||
| value = TruncatedFunc((value + 0x80), 0, low16BitVal); | |||
| value = static_cast<uint32_t>(value) >> bit8Offset; | |||
| *out_data[yuv_index]++ = static_cast<uint8_t>(value); | |||
| } | |||
| } | |||
| return; | |||
| } | |||
| int32_t SoftVpc::VerticalScaler() { | |||
| out_width_ = in_width_; | |||
| out_height_ = (in_height_ << scalerCoeff) / vertical_coeff_; | |||
| out_data_ = new (std::nothrow) uint8_t[out_width_ * out_height_ * yuvCoeffiNum2]; | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((out_data_ != nullptr), dpFail, "alloc buffer fail."); | |||
| SetYuv422OutBuffer(); | |||
| uint8_t *in_data[yuvCoeffiNum3] = {in_y_data_, in_u_data_, in_v_data_}; | |||
| uint8_t *out_data[yuvCoeffiNum3] = {out_y_data_, out_u_data_, out_v_data_}; | |||
| uint32_t out_w[yuvCoeffiNum3] = {out_width_, out_width_ / yuvCoeffiNum2, out_width_ / yuvCoeffiNum2}; | |||
| for (uint32_t m = 0; m < yuvCoeffiNum3; m++) { | |||
| StartVerticalScaler(m, out_w, in_data, out_data); | |||
| } | |||
| OutputChangeToInput(); | |||
| return dpSucc; | |||
| } | |||
| // yuv scalser is core scaler, The high-order filtering and scaling algorithm is used. | |||
| int32_t SoftVpc::YuvScaler() { | |||
| int32_t ret = HorizonScaler(); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "HorizonScaler fail."); | |||
| if (!vertical_bypass_) { | |||
| ret = VerticalScaler(); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "VerticalScaler fail."); | |||
| } | |||
| return ret; | |||
| } | |||
| int32_t SoftVpc::ChipProcess() { | |||
| ChipPreProcess(); | |||
| // Determine whether dimension reduction is required. | |||
| if (in_format_ == INPUT_YUV444_PLANNER) { | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((Yuv444PackedToYuv422Packed() == dpSucc), dpFail, | |||
| "Yuv444PackedToYuv422Packed fail."); | |||
| } | |||
| // Analog chip PreScaler function | |||
| for (uint32_t i = 0; i < pre_scaler_num_; i++) { | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((PreScaler() == dpSucc), dpFail, "PreScaler fail."); | |||
| } | |||
| // Analog chip Yuv Scaler function | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((YuvScaler() == dpSucc), dpFail, "YuvScaler fail."); | |||
| return dpSucc; | |||
| } | |||
| void SoftVpc::YuvToRgb() { | |||
| uint8_t *out_data = out_info_.addr; | |||
| int32_t yy, uu, vv; | |||
| int32_t rr, gg, bb; | |||
| for (uint32_t j = 0; j < in_height_; j++) { | |||
| for (uint32_t i = 0; i < in_width_; i++) { | |||
| yy = in_y_data_[(j * in_width_) + i]; | |||
| uu = in_u_data_[((j - (j % num2)) * (in_width_ / yuvCoeffiNum2)) + (i / yuvCoeffiNum2)]; | |||
| vv = in_v_data_[((j - (j % num2)) * (in_width_ / yuvCoeffiNum2)) + (i / yuvCoeffiNum2)]; | |||
| // yuv convert rgb formula | |||
| rr = ((yy - rtAippYuv2RgbCscInputBias0) * rtAippYuv2RgbCscMatrixR0c0 + | |||
| (uu - rtAippYuv2RgbCscInputBias1) * rtAippYuv2RgbCscMatrixR0c1 + | |||
| (vv - rtAippYuv2RgbCscInputBias2) * rtAippYuv2RgbCscMatrixR0c2) / | |||
| rtAippConverCoeffi; | |||
| gg = ((yy - rtAippYuv2RgbCscInputBias0) * rtAippYuv2RgbCscMatrixR1c0 + | |||
| (uu - rtAippYuv2RgbCscInputBias1) * rtAippYuv2RgbCscMatrixR1c1 + | |||
| (vv - rtAippYuv2RgbCscInputBias2) * rtAippYuv2RgbCscMatrixR1c2) / | |||
| rtAippConverCoeffi; | |||
| bb = ((yy - rtAippYuv2RgbCscInputBias0) * rtAippYuv2RgbCscMatrixR2c0 + | |||
| (uu - rtAippYuv2RgbCscInputBias1) * rtAippYuv2RgbCscMatrixR2c1 + | |||
| (vv - rtAippYuv2RgbCscInputBias2) * rtAippYuv2RgbCscMatrixR2c2) / | |||
| rtAippConverCoeffi; | |||
| *out_data++ = (rr < 0) ? 0 : ((rr < 0xff) ? rr : 0xff); | |||
| *out_data++ = (gg < 0) ? 0 : ((gg < 0xff) ? gg : 0xff); | |||
| *out_data++ = (bb < 0) ? 0 : ((bb < 0xff) ? bb : 0xff); | |||
| } | |||
| } | |||
| delete[] in_data_; | |||
| in_data_ = nullptr; | |||
| } | |||
| int32_t SoftVpc::Process(VpcInfo input, const SoftDpCropInfo crop, const VpcInfo output) { | |||
| Init(input, crop, output); | |||
| int32_t ret = CheckParamter(); | |||
| if (ret != dpSucc) { | |||
| delete[] input.addr; | |||
| return ret; | |||
| } | |||
| BuildResizeStack(); | |||
| while (!resize_stack_.empty()) { | |||
| ResizeUnit &unit = resize_stack_.top(); | |||
| resize_stack_.pop(); | |||
| out_width_ = unit.out_width; | |||
| out_height_ = unit.out_height; | |||
| ret = ChipProcess(); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "ChipProcess fail."); | |||
| if (!resize_stack_.empty()) { | |||
| ret = Yuv422pToYuv420p(); | |||
| VPC_CHECK_COND_FAIL_PRINT_RETURN((ret == dpSucc), dpFail, "Yuv422pToYuv420p fail."); | |||
| } | |||
| } | |||
| YuvToRgb(); | |||
| return dpSucc; | |||
| } | |||
| @@ -0,0 +1,256 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #ifndef SOFT_VPC_H | |||
| #define SOFT_VPC_H | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp.h" | |||
| #include <stack> | |||
| constexpr uint32_t yuvCoeffiNum2 = 2; | |||
| constexpr uint32_t yuvCoeffiNum3 = 3; | |||
| struct ResizeUnit { | |||
| uint32_t in_width; | |||
| uint32_t in_height; | |||
| uint32_t out_width; | |||
| uint32_t out_height; | |||
| }; | |||
| class SoftVpc { | |||
| public: | |||
| SoftVpc(); | |||
| ~SoftVpc() {} | |||
| /* | |||
| * @brief : vpc Cropping and Scaling APIs. | |||
| * @param [in] VpcInfo input : Structure input to the VPC for processing. | |||
| * @param [in] SoftDpCropInfo crop : crop struct. | |||
| * @param [in] VpcInfo output : vpc output struct. | |||
| * @return : dpSucc:vpc process succ,dpFail:vpc process failed. | |||
| */ | |||
| int32_t Process(VpcInfo input, SoftDpCropInfo crop, VpcInfo output); | |||
| private: | |||
| enum JpegdToVpcFormat in_format_; | |||
| uint32_t in_width_; | |||
| uint32_t in_height_; | |||
| uint8_t *in_data_; | |||
| uint8_t *in_y_data_; | |||
| uint8_t *in_u_data_; | |||
| uint8_t *in_v_data_; | |||
| // crop area | |||
| uint32_t left_; | |||
| uint32_t right_; | |||
| uint32_t up_; | |||
| uint32_t down_; | |||
| // output config | |||
| uint32_t out_width_; | |||
| uint32_t out_height_; | |||
| uint8_t *out_data_; | |||
| uint8_t *out_y_data_; | |||
| uint8_t *out_u_data_; | |||
| uint8_t *out_v_data_; | |||
| // resize config | |||
| uint32_t pre_scaler_num_; | |||
| // If the image is amplified by 2x or more and the output width is less than 2048 pixels, | |||
| // the half-line mode is required. | |||
| bool half_line_mode_; | |||
| uint32_t horizon_coeff_; // Horizontal scaling coefficient | |||
| uint32_t vertical_coeff_; // Vertical scaling coefficient. | |||
| bool horizon_bypass_; | |||
| bool vertical_bypass_; | |||
| int16_t *y_horizon_tap_; // Filtering coefficients for horizontal scaling of channel y | |||
| int16_t *uv_horizon_tap_; // Filtering coefficients of the horizontal scaling UV channel. | |||
| int16_t *vertical_tap_; // Filtering coefficient table for vertical scaling. Y and UV signals share the same table. | |||
| // Scaling unit stack, used to store the input and output information processed by the chip at a time. | |||
| std::stack<ResizeUnit> resize_stack_; | |||
| VpcInfo in_info_; // Original input information. | |||
| VpcInfo out_info_; // Original output information. | |||
| /* | |||
| * @brief : set output format is YUV422 | |||
| */ | |||
| void SetYuv422OutBuffer(); | |||
| /* | |||
| * @brief : check params | |||
| * @return : dpSucc:check succ, dpFail:check failed. | |||
| */ | |||
| int32_t CheckParamter(); | |||
| /* | |||
| * @brief : init vpc output info struct | |||
| * @param [in] VpcInfo input : Structure input to the VPC for processing. | |||
| * @param [in] SoftDpCropInfo crop : crop struct. | |||
| * @param [in] VpcInfo output : vpc output struct. | |||
| */ | |||
| void Init(VpcInfo input, SoftDpCropInfo crop, VpcInfo output); | |||
| void OutputChangeToInput(); | |||
| /* | |||
| * @brief : For the tasks that cannot be processed by the chip at a time, split the tasks whose scaling | |||
| * coefficients in the horizontal direction are greater than those in the vertical direction. | |||
| * @param [in] ResizeUnit *pre_unit : input resize unit. | |||
| * @param [in] ResizeUnit *can_process_unit : chip can process resize unit. | |||
| */ | |||
| void HorizonSplit(ResizeUnit *pre_unit, ResizeUnit *can_process_unit); | |||
| /* | |||
| * @brief : For the tasks that cannot be processed by the chip at a time, split the tasks whose vertical scaling | |||
| * coefficients are greater than the horizontal scaling coefficients. | |||
| * @param [in] ResizeUnit *pre_unit : input resize unit. | |||
| * @param [in] ResizeUnit *can_process_unit : chip can process resize unit. | |||
| */ | |||
| void VerticalSplit(ResizeUnit *pre_unit, ResizeUnit *can_process_unit); | |||
| /* | |||
| * @brief : Check whether the VPC chip can complete the processing at a time based on the input and output sizes. | |||
| * @param [in] const ResizeUnit& pre_unit : input resize unit. | |||
| * @return : true:vpc process succ, false:vpc process failed. | |||
| */ | |||
| bool CanVpcChipProcess(const ResizeUnit &pre_unit); | |||
| /* | |||
| * @brief : Creates a scaling parameter stack based on the user input and output information. The elements | |||
| * in the stack are the input and output information. The input and output information stores the | |||
| * scaling information task. | |||
| */ | |||
| void BuildResizeStack(); | |||
| /* | |||
| * @brief : YUV422 planner format convert YUV420 format | |||
| * @return : dpSucc: downsampling success, dpFail: downsampling failed | |||
| */ | |||
| int32_t Yuv422pToYuv420p(); | |||
| /* | |||
| * @brief : Preprocesses the chip, calculates the number of chip prescalers, and adjusts the cropping area based on | |||
| * the input and output information. | |||
| */ | |||
| void ChipPreProcess(); | |||
| /* | |||
| * @brief : when YUV444 packed format convert YUV422 packed, Calculate the conversion of UV. | |||
| * @param [in] int32_t *u_value : u value. | |||
| * @param [in] int32_t *v_value : v value. | |||
| * @param [in] int32_t y :y value. | |||
| * @param [in] int32_t pos : | |||
| */ | |||
| void SetUvValue(int32_t *u_value, int32_t *v_value, int32_t y, int32_t pos); | |||
| /* | |||
| * @brief : YUV444 packed convert YUV422 packed. | |||
| * @return : dpSucc:Downsampling succ, dpFail:Downsampling failed. | |||
| */ | |||
| int32_t Yuv444PackedToYuv422Packed(); | |||
| /* | |||
| * @brief : Pre-scaling the UV image. | |||
| */ | |||
| void UvPrescaler(); | |||
| /* | |||
| * @brief : Prescaling the UV in YUV420 format. | |||
| * @param [in] uint8_t* (&in_uv_data)[yuvCoeffiNum2] : input uv data | |||
| * @param [in] uint8_t* (&out_uv_data)[yuvCoeffiNum2] : output uv data | |||
| * @param [in] uint32_t in_w_stride : input stride | |||
| */ | |||
| void Yuv420PlannerUvPrescaler(uint8_t *(&in_uv_data)[yuvCoeffiNum2], uint8_t *(&out_uv_data)[yuvCoeffiNum2], | |||
| uint32_t in_w_stride); | |||
| /* | |||
| * @brief : Prescaling the UV in YUV422 format. | |||
| * @param [in] uint8_t* (&in_uv_data)[yuvCoeffiNum2] : input uv data | |||
| * @param [in] uint8_t* (&out_uv_data)[yuvCoeffiNum2]: output uv data | |||
| * @param [in] uint32_t in_w_stride : input stride | |||
| */ | |||
| void Yuv422PackedUvPrescaler(uint8_t *(&in_uv_data)[yuvCoeffiNum2], uint8_t *(&out_uv_data)[yuvCoeffiNum2], | |||
| uint32_t in_w_stride); | |||
| /* | |||
| * @brief : Chip prescaler processing. | |||
| */ | |||
| int32_t PreScaler(); | |||
| /* | |||
| * @brief : Horizontal scaling bypass. | |||
| */ | |||
| int32_t BypassHorizonScaler(); | |||
| /* | |||
| * @brief : Single-channel horizontal scaling of the chip. | |||
| * @param [in] uint32_t width_index : index of output width array. | |||
| * @param [in] uint32_t tmp_offset : Offset of each row of data relative to the start position. | |||
| * @param [in] uint8_t* (&in_data)[yuvCoeffiNum3] : input y,u,v data array. | |||
| * @param [in] uint8_t* (&out_data)[yuvCoeffiNum3] : output y,u,v data array. | |||
| */ | |||
| void StartHorizonScalerEx(uint32_t width_index, uint32_t tmp_offset, uint8_t *(&in_data)[yuvCoeffiNum3], | |||
| uint8_t *(&out_data)[yuvCoeffiNum3]); | |||
| /* | |||
| * @brief : Horizontal scaling. | |||
| */ | |||
| void HorizonScalerEx(); | |||
| /* | |||
| * @brief : Horizontal scaling. | |||
| * @return : dpSucc : Horizontal scaling succ, dpFail:Horizontal scaling failed. | |||
| */ | |||
| int32_t HorizonScaler(); | |||
| /* | |||
| * @brief : start Vertical scaling. | |||
| * @param [in] uint32_t yuv_index : index of output width array. | |||
| * @param [in] uint32_t out_w[] : output width array. | |||
| * @param [in] uint8_t* (&in_data)[yuvCoeffiNum3] : input y,u,v data array. | |||
| * @param [in] uint8_t* (&out_data)[yuvCoeffiNum3] : output y,u,v data array. | |||
| */ | |||
| void StartVerticalScaler(uint32_t yuv_index, uint32_t out_w[], uint8_t *(&in_data)[yuvCoeffiNum3], | |||
| uint8_t *(&out_data)[yuvCoeffiNum3]); | |||
| /* | |||
| * @brief : Vertical scaling | |||
| * @return : dpSucc : Vertical scaling succ, dpFail : Vertical scaling failed. | |||
| */ | |||
| int32_t VerticalScaler(); | |||
| /* | |||
| * @brief : Yuv Scaler Horizontal scaling and vertical scaling. | |||
| * @return : dpSucc:yuv scaler succ. dpFail:yuv scaler failed. | |||
| */ | |||
| int32_t YuvScaler(); | |||
| /* | |||
| * @brief : Software Implementation of the Simulation Chip PreScaler and Yuv Scaler function. | |||
| * @return : dpSucc : Analog chip scaling succ, dpFail: Analog chip scaling failed. | |||
| */ | |||
| int32_t ChipProcess(); | |||
| /* | |||
| * @brief : YUV planner convert RGB format. | |||
| */ | |||
| void YuvToRgb(); | |||
| }; | |||
| #endif // SOFT_VPC_H | |||
| @@ -0,0 +1,280 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| */ | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/yuv_scaler_para_set.h" | |||
| #include <securec.h> | |||
| #include <fstream> | |||
| #include <sstream> | |||
| #include <utility> | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_check.h" | |||
| #include "minddata/dataset/kernels/image/soft_dvpp/utils/soft_dp_tools.h" | |||
| pthread_mutex_t YuvScalerParaSet::g_mutex_ = PTHREAD_MUTEX_INITIALIZER; | |||
| YuvWPara *YuvScalerParaSet::g_m_instance_ = nullptr; | |||
| YuvScalerParaSet::GarbageCollector YuvScalerParaSet::g_collector_; | |||
| const int32_t dpSucc = 0; | |||
| const int32_t dpFail = -1; | |||
| /* | |||
| * @brief : Replaces the specified symbol in a string with another symbol. | |||
| * @param [in] const string &strSrc : src string. | |||
| * @param [in] const string &strDst : dest string. | |||
| */ | |||
| void StringReplace(std::string *str_big, const std::string &str_src, const std::string &str_dst) { | |||
| std::string::size_type pos = 0; | |||
| std::string::size_type src_len = str_src.size(); | |||
| std::string::size_type dst_len = str_dst.size(); | |||
| while ((pos = str_big->find(str_src, pos)) != std::string::npos) { | |||
| str_big->replace(pos, src_len, str_dst); | |||
| pos += dst_len; | |||
| } | |||
| } | |||
| /* | |||
| * @brief : Parse the data in the character string and transfer the data to the structure. | |||
| * @param [in] string strLine : parsed string. | |||
| * @param [in] int32_t *flagCtl : the number of char. | |||
| * @param [in] int32_t *flagTap : the flag of char. | |||
| * @param [in] YuvWPara *yuvScalerParaSet : yuv scaler param sets. | |||
| * @param [in] ScalerCoefficientIndex *index : scaler index. | |||
| */ | |||
| void GetParaSet(std::string str_line, int32_t *flag_ctl, int32_t *flag_tap, YuvWPara *yuv_scaler_paraset, | |||
| ScalerCoefficientIndex *index) { | |||
| std::stringstream ss; | |||
| StringReplace(&str_line, ",", " "); // Replaces commas in a string with spaces. | |||
| ss.str(str_line); | |||
| int32_t cnt = yuv_scaler_paraset->real_count; // Number of saved arrays. | |||
| const int32_t arrTypeNum = 3; | |||
| const int32_t initBracketNum = 3; | |||
| // {start,end} | |||
| if ((*flag_ctl - initBracketNum) % arrTypeNum == 1) { | |||
| char chTmp; | |||
| ss >> chTmp >> yuv_scaler_paraset->scale[cnt].range.start >> yuv_scaler_paraset->scale[cnt].range.end; | |||
| if (ss.fail()) { // read failed. | |||
| #ifndef DVPP_UTST | |||
| ss.clear(); | |||
| #endif | |||
| } | |||
| } | |||
| // taps_4, the second character in the square brackets is the start address of the array block. | |||
| if ((*flag_ctl - initBracketNum) % arrTypeNum == 2) { | |||
| while (1) { | |||
| ss >> yuv_scaler_paraset->scale[cnt].taps_4[index->first_index++]; | |||
| if (ss.fail()) { // rerad failed. | |||
| index->first_index = index->first_index - 1; | |||
| ss.clear(); | |||
| break; | |||
| } | |||
| if (index->first_index == kScalerCoffNb4) { // read finish | |||
| index->first_index = 0; | |||
| *flag_tap = 0; | |||
| ss.clear(); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| // taps_6 | |||
| if ((*flag_ctl - initBracketNum) % arrTypeNum == 0) { | |||
| while (1) { | |||
| ss >> yuv_scaler_paraset->scale[cnt].taps_6[index->second_index++]; | |||
| if (ss.fail()) { // read failed. | |||
| index->second_index = index->second_index - 1; | |||
| ss.clear(); | |||
| break; | |||
| } | |||
| if (index->second_index == kScalerCoffNb6) { // read finish. | |||
| index->second_index = 0; | |||
| *flag_tap = 0; | |||
| ss.clear(); | |||
| ++(yuv_scaler_paraset->real_count); | |||
| *flag_ctl = *flag_ctl - 4; // The filtering parameter set has four large blocks. | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| int32_t CheckParamater(std::pair<bool, std::string> rlt, uint32_t i) { | |||
| int32_t ret = dpSucc; | |||
| if (rlt.first == false) { | |||
| API_LOGE("Get real path failed. index = %u", i); | |||
| return dpFail; | |||
| } | |||
| if (IsDirectory(rlt.second)) { | |||
| API_LOGE("It is a directory, not file path. index = %u", i); | |||
| return dpFail; | |||
| } | |||
| return ret; | |||
| } | |||
| // Read the parameter set file and skip the comments in the file. | |||
| int32_t ParseFileToVar(std::string *para_set_name, uint32_t yuv_scaler_paraset_size, YuvWPara *yuv_scaler_paraset) { | |||
| int32_t ret = dpSucc; | |||
| VPC_CHECK_COND_FAIL_RETURN(para_set_name != nullptr, dpFail); | |||
| VPC_CHECK_COND_FAIL_RETURN(yuv_scaler_paraset != nullptr, dpFail); | |||
| uint32_t i = 0; | |||
| while (i < yuv_scaler_paraset_size && i < maxFileCount && (!para_set_name[i].empty())) { | |||
| std::string str_line; | |||
| // Standardize the file path and check whether the path exists. | |||
| std::pair<bool, std::string> rlt = GetRealpath(para_set_name[i]); | |||
| ret = CheckParamater(rlt, i); | |||
| if (ret != dpSucc) { | |||
| return ret; | |||
| } | |||
| std::ifstream inFile(rlt.second); | |||
| int32_t flag_tap = 1; | |||
| int32_t flag_ctl = 0; | |||
| int32_t flag_anno = 0; | |||
| ScalerCoefficientIndex index; | |||
| const int32_t initBracketNum = 3; | |||
| yuv_scaler_paraset[i].real_count = 0; | |||
| while (getline(inFile, str_line)) { // read each row of data. | |||
| // Skip the comments. | |||
| if (str_line.find("/*") != std::string::npos) { | |||
| flag_anno = 1; | |||
| continue; | |||
| } | |||
| if (flag_anno) { | |||
| if (str_line.find("*/") != std::string::npos) { | |||
| flag_anno = 0; | |||
| continue; | |||
| } | |||
| continue; | |||
| } | |||
| if (str_line.find("//") != std::string::npos) { | |||
| continue; | |||
| } | |||
| // cale the number of "{",check the location of the data. | |||
| if (str_line.find("{") != std::string::npos) { | |||
| flag_ctl++; | |||
| flag_tap = 1; | |||
| } | |||
| if (flag_ctl > initBracketNum && flag_tap == 1) { // parse params | |||
| GetParaSet(str_line, &flag_ctl, &flag_tap, &yuv_scaler_paraset[i], &index); | |||
| } | |||
| } | |||
| inFile.close(); | |||
| ++i; | |||
| } | |||
| return ret; | |||
| } | |||
| YuvWPara *YuvScalerParaSet::GetInstance(std::string *paraset_name, uint32_t yuv_scaler_paraset_size) { | |||
| if (g_m_instance_ == nullptr) { | |||
| (void)pthread_mutex_lock(&g_mutex_); | |||
| if (g_m_instance_ == nullptr) { | |||
| if (paraset_name == nullptr) { | |||
| #ifndef API_MAR_UT | |||
| #ifdef DVPP_UTST | |||
| YuvWPara p_tmp[10]; // 10: 滤波参数集最大数 | |||
| p_tmp[0] = YUV_W_PARA; | |||
| g_m_instance_ = p_tmp; | |||
| #else | |||
| auto p_tmp = static_cast<YuvWPara *>(malloc(sizeof(YuvWPara) * maxFileCount)); | |||
| if (p_tmp == nullptr) { | |||
| API_LOGE("malloc YuvWPara fail!"); | |||
| g_m_instance_ = nullptr; | |||
| (void)pthread_mutex_unlock(&g_mutex_); | |||
| return g_m_instance_; | |||
| } | |||
| uint32_t ret = memcpy_s(&p_tmp[0], sizeof(p_tmp[0]), &YUV_W_PARA, sizeof(YUV_W_PARA)); | |||
| if (ret != EOK) { | |||
| API_LOGE("memcpy_s p_tmp[0] fail!"); | |||
| g_m_instance_ = nullptr; | |||
| free(p_tmp); | |||
| p_tmp = nullptr; | |||
| (void)pthread_mutex_unlock(&g_mutex_); | |||
| return g_m_instance_; | |||
| } | |||
| g_m_instance_ = p_tmp; | |||
| #endif | |||
| #endif | |||
| } else { | |||
| auto p_tmp = static_cast<YuvWPara *>(malloc(sizeof(YuvWPara) * maxFileCount)); | |||
| if (p_tmp == nullptr) { | |||
| #ifndef DVPP_UTST | |||
| API_LOGE("malloc YuvWPara fail!"); | |||
| g_m_instance_ = nullptr; | |||
| (void)pthread_mutex_unlock(&g_mutex_); | |||
| return g_m_instance_; | |||
| #endif | |||
| } | |||
| if (ParseFileToVar(paraset_name, yuv_scaler_paraset_size, p_tmp) == -1) { | |||
| free(p_tmp); | |||
| g_m_instance_ = nullptr; | |||
| } else { | |||
| g_m_instance_ = p_tmp; | |||
| } | |||
| } | |||
| } | |||
| (void)pthread_mutex_unlock(&g_mutex_); | |||
| } | |||
| return g_m_instance_; | |||
| } | |||
| // Searching for the index number of the filtering parameter by using the dichotomy | |||
| int32_t GetScalerParamterIndex(uint32_t paramter, YuvWPara *paramterset) { | |||
| int32_t count = paramterset->real_count; | |||
| int32_t left = 0; | |||
| int32_t right = count - 1; | |||
| YuvScalerPara *scaler = paramterset->scale; | |||
| int32_t index = 0; | |||
| if (paramter <= scalerRadio1Time) { | |||
| index = 0; | |||
| } else { | |||
| paramter = paramter >> paramterInterval; | |||
| while (left <= right) { | |||
| index = (left + right) / 2; // 2-point search | |||
| if (paramter > scaler[index].range.start && paramter <= scaler[index].range.end) { | |||
| break; | |||
| } | |||
| if (paramter > scaler[index].range.end) { | |||
| left = index + 1; | |||
| } else if (paramter <= scaler[index].range.start) { | |||
| right = index - 1; | |||
| } | |||
| } | |||
| } | |||
| if (left > right) { | |||
| index = count - 1; | |||
| } | |||
| return index; | |||
| } | |||
| @@ -121,6 +121,8 @@ constexpr char kResizeOp[] = "ResizeOp"; | |||
| constexpr char kResizeWithBBoxOp[] = "ResizeWithBBoxOp"; | |||
| constexpr char kSwapRedBlueOp[] = "SwapRedBlueOp"; | |||
| constexpr char kUniformAugOp[] = "UniformAugOp"; | |||
| constexpr char kSoftDvppDecodeRandomCropResizeJpegOp[] = "SoftDvppDecodeRandomCropResizeJpegOp"; | |||
| constexpr char kSoftDvppDecodeReiszeJpegOp[] = "SoftDvppDecodeReiszeJpegOp"; | |||
| // text | |||
| constexpr char kBasicTokenizerOp[] = "BasicTokenizerOp"; | |||
| @@ -48,7 +48,7 @@ from .validators import check_prob, check_crop, check_resize_interpolation, chec | |||
| check_mix_up_batch_c, check_normalize_c, check_random_crop, check_random_color_adjust, check_random_rotation, \ | |||
| check_range, check_resize, check_rescale, check_pad, check_cutout, check_uniform_augment_cpp, \ | |||
| check_bounding_box_augment_cpp, check_random_select_subpolicy_op, check_auto_contrast, check_random_affine, \ | |||
| FLOAT_MAX_INTEGER | |||
| check_soft_dvpp_decode_random_crop_resize_jpeg, FLOAT_MAX_INTEGER | |||
| DE_C_INTER_MODE = {Inter.NEAREST: cde.InterpolationMode.DE_INTER_NEAREST_NEIGHBOUR, | |||
| Inter.LINEAR: cde.InterpolationMode.DE_INTER_LINEAR, | |||
| @@ -878,3 +878,57 @@ class RandomSelectSubpolicy(cde.RandomSelectSubpolicyOp): | |||
| @check_random_select_subpolicy_op | |||
| def __init__(self, policy): | |||
| super().__init__(policy) | |||
| class SoftDvppDecodeResizeJpeg(cde.SoftDvppDecodeResizeJpegOp): | |||
| """ | |||
| Tensor operation to decode and resize jpeg image using the simulation algorithm of ascend series chip DVPP module. | |||
| It is recommended to use this algorithm in the following scenarios: | |||
| When training, the DVPP of the ascend chip is not used, | |||
| and the DVPP of the ascend chip is used during inference, | |||
| and the accuracy of inference is lower than the accuracy of training. | |||
| Args: | |||
| size (Union[int, sequence]): The output size of the resized image. | |||
| If size is an int, smaller edge of the image will be resized to this value with | |||
| the same image aspect ratio. | |||
| If size is a sequence of length 2, it should be (height, width). | |||
| """ | |||
| @check_resize | |||
| def __init__(self, size): | |||
| if isinstance(size, int): | |||
| size = (size, size) | |||
| self.size = size | |||
| super().__init__(*size) | |||
| class SoftDvppDecodeRandomCropResizeJpeg(cde.SoftDvppDecodeRandomCropResizeJpegOp): | |||
| """ | |||
| Tensor operation to decode, random crop and resize jpeg image using the simulation algorithm of | |||
| ascend series chip DVPP module. | |||
| The usage scenario is consistent with SoftDvppDecodeReiszeJpeg. | |||
| Args: | |||
| size (Union[int, sequence], optional): The size of the output image. | |||
| If size is an int, a square crop of size (size, size) is returned. | |||
| If size is a sequence of length 2, it should be (height, width). | |||
| scale (tuple, optional): Range (min, max) of respective size of the | |||
| original size to be cropped (default=(0.08, 1.0)). | |||
| ratio (tuple, optional): Range (min, max) of aspect ratio to be | |||
| cropped (default=(3. / 4., 4. / 3.)). | |||
| max_attempts (int, optional): The maximum number of attempts to propose a valid crop_area (default=10). | |||
| If exceeded, fall back to use center_crop instead. | |||
| """ | |||
| @check_soft_dvpp_decode_random_crop_resize_jpeg | |||
| def __init__(self, size, scale=(0.08, 1.0), ratio=(3. / 4., 4. / 3.), max_attempts=10): | |||
| if isinstance(size, int): | |||
| size = (size, size) | |||
| self.size = size | |||
| self.scale = scale | |||
| self.ratio = ratio | |||
| self.max_attempts = max_attempts | |||
| super().__init__(*size, *scale, *ratio, max_attempts) | |||
| @@ -175,30 +175,35 @@ def check_resize(method): | |||
| return new_method | |||
| def check_size_scale_ration_max_attempts_paras(size, scale, ratio, max_attempts): | |||
| """Wrapper method to check the parameters of RandomCropDecodeResize and SoftDvppDecodeRandomCropResizeJpeg.""" | |||
| check_crop_size(size) | |||
| if scale is not None: | |||
| type_check(scale, (tuple,), "scale") | |||
| type_check_list(scale, (float, int), "scale") | |||
| check_range(scale, [0, FLOAT_MAX_INTEGER]) | |||
| if scale[0] > scale[1]: | |||
| raise ValueError("scale should be in (min,max) format. Got (max,min).") | |||
| if ratio is not None: | |||
| type_check(ratio, (tuple,), "ratio") | |||
| type_check_list(ratio, (float, int), "ratio") | |||
| check_range(ratio, [0, FLOAT_MAX_INTEGER]) | |||
| if ratio[0] > ratio[1]: | |||
| raise ValueError("ratio should be in (min,max) format. Got (max,min).") | |||
| if max_attempts is not None: | |||
| check_value(max_attempts, (1, FLOAT_MAX_INTEGER)) | |||
| def check_random_resize_crop(method): | |||
| """A wrapper that wraps a parameter checker to the original function(random resize crop operation).""" | |||
| @wraps(method) | |||
| def new_method(self, *args, **kwargs): | |||
| [size, scale, ratio, interpolation, max_attempts], _ = parse_user_args(method, *args, **kwargs) | |||
| check_crop_size(size) | |||
| if scale is not None: | |||
| type_check(scale, (tuple,), "scale") | |||
| type_check_list(scale, (float, int), "scale") | |||
| check_range(scale, [0, FLOAT_MAX_INTEGER]) | |||
| if scale[0] > scale[1]: | |||
| raise ValueError("scale should be in (min,max) format. Got (max,min).") | |||
| if ratio is not None: | |||
| type_check(ratio, (tuple,), "ratio") | |||
| type_check_list(ratio, (float, int), "ratio") | |||
| check_range(ratio, [0, FLOAT_MAX_INTEGER]) | |||
| if ratio[0] > ratio[1]: | |||
| raise ValueError("ratio should be in (min,max) format. Got (max,min).") | |||
| if interpolation is not None: | |||
| type_check(interpolation, (Inter,), "interpolation") | |||
| if max_attempts is not None: | |||
| check_value(max_attempts, (1, FLOAT_MAX_INTEGER)) | |||
| check_size_scale_ration_max_attempts_paras(size, scale, ratio, max_attempts) | |||
| return method(self, *args, **kwargs) | |||
| @@ -658,3 +663,15 @@ def check_random_select_subpolicy_op(method): | |||
| return method(self, *args, **kwargs) | |||
| return new_method | |||
| def check_soft_dvpp_decode_random_crop_resize_jpeg(method): | |||
| """Wrapper method to check the parameters of SoftDvppDecodeRandomCropResizeJpeg.""" | |||
| @wraps(method) | |||
| def new_method(self, *args, **kwargs): | |||
| [size, scale, ratio, max_attempts], _ = parse_user_args(method, *args, **kwargs) | |||
| check_size_scale_ration_max_attempts_paras(size, scale, ratio, max_attempts) | |||
| return method(self, *args, **kwargs) | |||
| return new_method | |||
| @@ -0,0 +1,90 @@ | |||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| # ============================================================================== | |||
| """ | |||
| Testing soft dvpp SoftDvppDecodeResizeJpeg and SoftDvppDecodeRandomCropResizeJpeg in DE | |||
| """ | |||
| import mindspore.dataset as ds | |||
| import mindspore.dataset.transforms.vision.c_transforms as vision | |||
| from mindspore import log as logger | |||
| from util import diff_mse, visualize_image | |||
| DATA_DIR = ["../data/dataset/test_tf_file_3_images/train-0000-of-0001.data"] | |||
| SCHEMA_DIR = "../data/dataset/test_tf_file_3_images/datasetSchema.json" | |||
| def test_soft_dvpp_decode_resize_jpeg(plot=False): | |||
| """ | |||
| Test SoftDvppDecodeResizeJpeg op | |||
| """ | |||
| logger.info("test_random_decode_resize_op") | |||
| # First dataset | |||
| data1 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, columns_list=["image"], shuffle=False) | |||
| decode_op = vision.Decode() | |||
| resize_op = vision.Resize((256, 512)) | |||
| data1 = data1.map(input_columns=["image"], operations=[decode_op, resize_op]) | |||
| # Second dataset | |||
| data2 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, columns_list=["image"], shuffle=False) | |||
| soft_dvpp_decode_resize_op = vision.SoftDvppDecodeResizeJpeg((256, 512)) | |||
| data2 = data2.map(input_columns=["image"], operations=soft_dvpp_decode_resize_op) | |||
| num_iter = 0 | |||
| for item1, item2 in zip(data1.create_dict_iterator(), data2.create_dict_iterator()): | |||
| if num_iter > 0: | |||
| break | |||
| image1 = item1["image"] | |||
| image2 = item2["image"] | |||
| mse = diff_mse(image1, image2) | |||
| assert mse <= 0.02 | |||
| logger.info("random_crop_decode_resize_op_{}, mse: {}".format(num_iter + 1, mse)) | |||
| if plot: | |||
| visualize_image(image1, image2, mse) | |||
| num_iter += 1 | |||
| def test_soft_dvpp_decode_random_crop_resize_jpeg(plot=False): | |||
| """ | |||
| Test SoftDvppDecodeRandomCropResizeJpeg op | |||
| """ | |||
| logger.info("test_random_decode_resize_op") | |||
| # First dataset | |||
| data1 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, columns_list=["image"], shuffle=False) | |||
| random_crop_decode_resize_op = vision.RandomCropDecodeResize((256, 512), (1, 1), (0.5, 0.5)) | |||
| data1 = data1.map(input_columns=["image"], operations=random_crop_decode_resize_op) | |||
| # Second dataset | |||
| data2 = ds.TFRecordDataset(DATA_DIR, SCHEMA_DIR, columns_list=["image"], shuffle=False) | |||
| soft_dvpp_random_crop_decode_resize_op = vision.SoftDvppDecodeRandomCropResizeJpeg((256, 512), (1, 1), (0.5, 0.5)) | |||
| data2 = data2.map(input_columns=["image"], operations=soft_dvpp_random_crop_decode_resize_op) | |||
| num_iter = 0 | |||
| for item1, item2 in zip(data1.create_dict_iterator(), data2.create_dict_iterator()): | |||
| if num_iter > 0: | |||
| break | |||
| image1 = item1["image"] | |||
| image2 = item2["image"] | |||
| mse = diff_mse(image1, image2) | |||
| assert mse <= 0.06 | |||
| logger.info("random_crop_decode_resize_op_{}, mse: {}".format(num_iter + 1, mse)) | |||
| if plot: | |||
| visualize_image(image1, image2, mse) | |||
| num_iter += 1 | |||
| if __name__ == "__main__": | |||
| test_soft_dvpp_decode_resize_jpeg(plot=True) | |||
| test_soft_dvpp_decode_random_crop_resize_jpeg(plot=True) | |||