我扩展了阿里扎的答案,允许零分配答案。
- 允许用户提供预先分配的或
cv::Mat
作为输入
cv::resize
立即将输入图像调整为输出mat
- 使用
cv::rectangle
对顶部和底部框进行颜色填充
#include <opencv2/imgproc.hpp>
void resizeKeepAspectRatio(const cv::Mat& src, cv::Mat& dst, const cv::Size& dstSize, const cv::Scalar& backgroundColor = {})
{
if(dstSize.width <= 0 || dstSize.height <= 0)
return;
if(src.cols == dstSize.width && src.rows == dstSize.height)
{
dst = src;
return;
}
cv::Mat output = [&]()
{
if(dst.data != src.data && dst.cols == dstSize.width && dst.rows == dstSize.height && dst.type() == src.type())
return dst;
return cv::Mat(dstSize.height, dstSize.width, src.type());
}();
const auto imageBox = [&]()
{
const auto h1 = int(dstSize.width * (src.rows / (double)src.cols));
const auto w2 = int(dstSize.height * (src.cols / (double)src.rows));
const bool horizontal = h1 <= dstSize.height;
const auto width = horizontal ? dstSize.width : w2;
const auto height = horizontal ? h1 : dstSize.height;
const auto x = horizontal ? 0 : int(double(dstSize.width - width) / 2.);
const auto y = horizontal ? int(double(dstSize.height - height) / 2.) : 0;
return cv::Rect(x, y, width, height);
}();
cv::Rect firstBox;
cv::Rect secondBox;
if(imageBox.width > imageBox.height)
{
firstBox.x = 0;
firstBox.width = dstSize.width;
firstBox.y = 0;
firstBox.height = imageBox.y;
secondBox.x = 0;
secondBox.width = dstSize.width;
secondBox.y = imageBox.y + imageBox.height;
secondBox.height = dstSize.height - secondBox.y;
}
else
{
firstBox.y = 0;
firstBox.height = dstSize.height;
firstBox.x = 0;
firstBox.width = imageBox.x;
secondBox.y = 0;
secondBox.height = dstSize.height;
secondBox.x = imageBox.x + imageBox.width;
secondBox.width = dstSize.width - secondBox.x;
}
cv::Mat outputImage = output(imageBox);
assert(outputImage.cols == imageBox.width);
assert(outputImage.rows == imageBox.height);
const auto* dataBeforeResize = outputImage.data;
cv::resize(src, outputImage, cv::Size(outputImage.cols, outputImage.rows));
assert(dataBeforeResize == outputImage.data);
const auto drawBox = [&](const cv::Rect& box)
{
if(box.width > 0 && box.height > 0)
{
cv::rectangle(output, cv::Point(box.x, box.y), cv::Point(box.x + box.width, box.y + box.height), backgroundColor, -1);
}
};
drawBox(firstBox);
drawBox(secondBox);
dst = output;
}
使用此函数,
dst
矩阵可以被重复使用而无需重新分配内存。
cv::Mat src(200, 100, CV_8UC3, cv::Scalar(1,100,200));
cv::Size dstSize(300, 400)
cv::Mat dst;
resizeKeepAspectRatio(src, dst, dstSize);
resizeKeepAspectRatio(src, dst, dstSize);