之前实现过C实现纵横比保持的RGB图像缩放,其实计算效率是不高的。
opencv的好多实现都是自带mmx, sse加速的。所以就来研究一下如何用opencv来实现纵横比保持的图像缩放。
查看了一下opencv resize函数的详细定义:
resize函数
函数原型:
void cv::resize(
InputArray _src,
OutputArray _dst,
Size dsize,
double inv_scale_x = 0,
double inv_scale_y = 0,
int interpolation = INTER_LINEAR
)
参数说明:
-
src
,输入图像,Mat类型即可; -
dst
,输出图像,当其非零时,有着dsize(第三个参数)的尺寸或者有src.size()计算出来; -
dsize
,输出图像的大小。如果它等于0,由下式计算:dsize = Size( round(fx*src.cols, round(fy*src.rows))); 其中fx,fy,dsize都能不为0
-
fx
,沿水平轴的缩放系数,默认值为0,且等于0时,由下式计算:inv_scale_x = (double)dsize.width/ssize.width;
-
fy
,沿垂直轴的缩放系数,默认值为0,且等于0时,由下式计算:inv_scale_y = (double)dsize.height/ssize.height;
-
interpolation
,用于指定插值方式,默认值为INTER_LINEAR(线性插值),可选插值方式如下:
取值 | 说明 |
---|---|
INTER_NEAREST | 最近邻插值 |
INTER_LINEAR | 线性插值(默认值) |
INTER_AREA | 区域插值(利用像素区域关系的重采样插值) |
INTER_CUBIC | 三次样条插值(超过4×4像素领域内的双三次插值) |
INTER_LANCZOS4 | Lanczos插值(超过8×8像素邻域的Lanczos插值) |
注意:要缩小图像,一般情况下用INTER_AREA来插值;而若要放大图像,一般情况下用INTER_CUBIC
(效率不高,不推荐)或INTER_LINEAR
(效率高,推荐)
但是该函数实现不了任意尺寸的纵横比保持的图像缩放。
仔细想了一下,可以先做crop操作,然后再缩放,分两步,这样就可以达到纵横比保持的图像缩放。
代码如下:
#include "opencv2/opencv.hpp"
#include "opencv2/opencv.hpp"
#include<fstream>
#include <chrono>
using namespace std;
using namespace cv;
int main(int, char**)
{
cv::Size szSize(3840 , 2160);
uchar *b_Buffer = new uchar[szSize.width * szSize.height * 2];
uchar *rgb_Buffer = new uchar[szSize.width * szSize.height * 3];
string binFile("input.yuv");
ifstream File_VideoFile;
File_VideoFile.open(binFile, ios::in | ios::binary);
if (!File_VideoFile.is_open())
{
std::cerr << "[ERROR] cannot open the YUV Input File " << binFile << endl;
std::cerr << std::endl;
assert(0);
}
File_VideoFile.read((char*)b_Buffer, sizeof(uchar)*szSize.width*szSize.height*2);
File_VideoFile.close();
cv::Mat mSrc(szSize,CV_8UC2, b_Buffer);
cv::Mat mSrc_BGR(szSize, CV_8UC3);
auto time1 = std::chrono::steady_clock::now();
cvtColor(mSrc, mSrc_BGR, COLOR_YUV2BGR_YUYV);
auto time2 = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(time2-time1).count();
printf("cv time: %.2f ms.\n", (float)duration / 1000);
Size dstSize(1600, 1600);
Size srcSize(3840, 2160);
Mat dst_img(dstSize, CV_8UC3);
//crop first
double fx = dstSize.width / srcSize.width;
double fy = dstSize.height / srcSize.height;
int xmin = 0, xmax = 0;
int ymin = 0, ymax = 0;
if (fx > fy) {
//crop y
xmin = 0;
xmax = srcSize.width;
ymin = (srcSize.height - srcSize.width) >> 1;
ymax = srcSize.height - ymin;
} else {
//crop x
ymin = 0;
ymax = srcSize.height;
xmin = (srcSize.width - srcSize.height) >> 1;
xmax = srcSize.width - xmin;
}
Mat crop_img = mSrc_BGR(Range(ymin, ymax), Range(xmin, xmax));
//scale second
resize(crop_img, dst_img, dstSize);
imwrite( "dst.bmp", dst_img);
imwrite( "rgb24.bmp", mSrc_BGR);
delete[] b_Buffer;
delete[] rgb_Buffer;
return 0;
}