Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add image rotation to input connector #1447

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/dto/input_connector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,53 @@ namespace dd
DTO_FIELD(Int32, height);
DTO_FIELD(Int32, crop_width);
DTO_FIELD(Int32, crop_height);

DTO_FIELD_INFO(bw)
{
info->description = "whether to convert to black & white.";
}
DTO_FIELD(Boolean, bw);

DTO_FIELD_INFO(rgb)
{
info->description = "whether to convert to rgb.";
}
DTO_FIELD(Boolean, rgb);

DTO_FIELD_INFO(histogram_equalization)
{
info->description = "whether to apply histogram equalizer.";
}
DTO_FIELD(Boolean, histogram_equalization);

DTO_FIELD(Boolean, unchanged_data);
DTO_FIELD(Boolean, shuffle);
DTO_FIELD(Int32, seed);
DTO_FIELD(Float64, test_split);

DTO_FIELD_INFO(mean)
{
info->description = "mean image pixels, to be subtracted from images.";
}
DTO_FIELD(Vector<Float32>, mean);

DTO_FIELD_INFO(std)
{
info->description = "std, to divide image values.";
}
DTO_FIELD(Vector<Float32>, std);

DTO_FIELD(Any, scale); // bool for csv/csvts, float for img
DTO_FIELD(Boolean, scaled);
DTO_FIELD(Int32, scale_min);
DTO_FIELD(Int32, scale_max);

DTO_FIELD_INFO(rotate)
{
info->description = "Rotate input image of 90, 180 or 270 degrees.";
}
DTO_FIELD(Int32, rotate);

DTO_FIELD(Boolean, keep_orig);
DTO_FIELD(String, interp);

Expand Down
96 changes: 76 additions & 20 deletions src/imginputfileconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,38 +96,63 @@ namespace dd
void prepare(const cv::Mat &src, cv::Mat &dst,
const std::string &img_name) const
{
dst = src;

try
{
if (_scaled)
scale(src, dst);
else if (_width == 0 || _height == 0)
if (_rotate != 0)
{
if (_width == 0 && _height == 0)
if (_rotate == 90)
{
cv::transpose(dst, dst);
cv::flip(dst, dst, 1);
}
else if (_rotate == 180)
{
// Do nothing and keep native resolution. May cause issues if
// batched images are different resolutions
dst = src;
cv::flip(dst, dst, -1);
}
else if (_rotate == 270)
{
cv::transpose(dst, dst);
cv::flip(dst, dst, 0);
}
else
{
throw InputConnectorBadParamException(
"Bad rotation value: " + std::to_string(_rotate));
}
}

if (_scaled)
scale(dst, dst);
else if (_width == 0 || _height == 0)
{
if (_width != 0 || _height != 0)
{
// Resize so that the larger dimension is set to whichever
// (width or height) is non-zero, maintaining aspect ratio
// XXX - This may cause issues if batch images are different
// resolutions
size_t currMaxDim = std::max(src.rows, src.cols);
size_t currMaxDim = std::max(dst.rows, dst.cols);
double scale = static_cast<double>(std::max(_width, _height))
/ static_cast<double>(currMaxDim);
cv::resize(src, dst, cv::Size(), scale, scale,
cv::resize(dst, dst, cv::Size(), scale, scale,
select_cv_interp());
}
// Otherwise do nothing and keep native resolution. May cause
// issues if batched images are different resolutions
}
else
{
// Resize normally to the specified width and height
cv::resize(src, dst, cv::Size(_width, _height), 0, 0,
cv::resize(dst, dst, cv::Size(_width, _height), 0, 0,
select_cv_interp());
}
}
catch (InputConnectorBadParamException &e)
{
throw e;
}
catch (...)
{
throw InputConnectorBadParamException("failed resizing image "
Expand Down Expand Up @@ -195,38 +220,63 @@ namespace dd
void prepare_cuda(const cv::cuda::GpuMat &src, cv::cuda::GpuMat &dst,
const std::string &img_name) const
{
dst = src;

try
{
if (_scaled)
scale_cuda(src, dst);
else if (_width == 0 || _height == 0)
if (_rotate != 0)
{
if (_width == 0 && _height == 0)
if (_rotate == 90)
{
cv::cuda::transpose(dst, dst);
cv::cuda::flip(dst, dst, 1);
}
else if (_rotate == 180)
{
// Do nothing and keep native resolution. May cause issues if
// batched images are different resolutions
dst = src;
cv::cuda::flip(dst, dst, -1);
}
else if (_rotate == 270)
{
cv::cuda::transpose(dst, dst);
cv::cuda::flip(dst, dst, 0);
}
else
{
throw InputConnectorBadParamException(
"Bad rotation value: " + std::to_string(_rotate));
}
}

if (_scaled)
scale_cuda(dst, dst);
else if (_width == 0 || _height == 0)
{
if (_width != 0 || _height != 0)
{
// Resize so that the larger dimension is set to whichever
// (width or height) is non-zero, maintaining aspect ratio
// XXX - This may cause issues if batch images are different
// resolutions
size_t currMaxDim = std::max(src.rows, src.cols);
size_t currMaxDim = std::max(dst.rows, dst.cols);
double scale = static_cast<double>(std::max(_width, _height))
/ static_cast<double>(currMaxDim);
cv::cuda::resize(src, dst, cv::Size(), scale, scale,
cv::cuda::resize(dst, dst, cv::Size(), scale, scale,
select_cv_interp(), *_cuda_stream);
}
// Otherwise do nothing and keep native resolution. May cause
// issues if batched images are different resolutions
}
else
{
// Resize normally to the specified width and height
cv::cuda::resize(src, dst, cv::Size(_width, _height), 0, 0,
cv::cuda::resize(dst, dst, cv::Size(_width, _height), 0, 0,
select_cv_interp(), *_cuda_stream);
}
}
catch (InputConnectorBadParamException &e)
{
throw e;
}
catch (...)
{
throw InputConnectorBadParamException("failed resizing image "
Expand Down Expand Up @@ -533,6 +583,7 @@ namespace dd
bool _scaled = false;
int _scale_min = 600;
int _scale_max = 1000;
int _rotate = 0;
bool _keep_orig = false;
bool _b64 = false;
std::string _interp = "cubic";
Expand Down Expand Up @@ -667,6 +718,9 @@ namespace dd
_scale_max = params->scale_max;
}

if (params->rotate)
_rotate = params->rotate;

// whether to keep original image (for chained ops, e.g. cropping)
_keep_orig |= params->keep_orig;

Expand Down Expand Up @@ -697,6 +751,7 @@ namespace dd
dimg._scaled = _scaled;
dimg._scale_min = _scale_min;
dimg._scale_max = _scale_max;
dimg._rotate = _rotate;
dimg._keep_orig = _keep_orig;
dimg._interp = _interp;
#ifdef USE_CUDA_CV
Expand Down Expand Up @@ -1105,6 +1160,7 @@ namespace dd
bool _scaled = false;
int _scale_min = 600;
int _scale_max = 1000;
int _rotate = 0; /**< rotate the input image of 90, 180 or 270 degrees. */
bool _keep_orig = false;
std::string _interp = "cubic";
#ifdef USE_CUDA_CV
Expand Down
4 changes: 2 additions & 2 deletions tests/ut-torchapi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,10 @@ TEST(torchapi, service_predict_object_detection)
// Check confidence threshold
ASSERT_TRUE(preds[preds.Size() - 1]["prob"].GetDouble() >= 0.8);

// best
// best + rotate
jpredictstr = "{\"service\":\"detectserv\",\"parameters\":{"
"\"input\":{\"height\":224,"
"\"width\":224},\"output\":{\"bbox\":true, "
"\"width\":224, \"rotate\": 90},\"output\":{\"bbox\":true, "
"\"best_bbox\":3}},\"data\":[\""
+ detect_repo + "cat.jpg\"]}";
joutstr = japi.jrender(japi.service_predict(jpredictstr));
Expand Down