!3874 add SoftDvppDecodeResizeJpegOp and SoftDvppDecodeRandomCropResizeJpeg op

Merge pull request !3874 from qianlong21st/soft_dvpp
This commit is contained in:
mindspore-ci-bot 2020-08-11 19:00:36 +08:00 committed by Gitee
commit a2827eb657
30 changed files with 15185 additions and 36 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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_

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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 : decodeSuccparse 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 : decodeSuccparams 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;
}

View File

@ -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 : decodeSuccdecode 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 : decodeSuccalloc 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 : decodeSuccconfig 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

View File

@ -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;
}

View File

@ -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 succdpFail: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

View File

@ -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;
}

View File

@ -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";

View File

@ -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)

View File

@ -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

View File

@ -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)