opencv中提供了3个将浮点数转换为整数的方法;
cvRound()函数返回和参数最接近的整数值;
cvFloor()返回不大于参数的最大整数值;
cvCeil()返回小于参数的最小整数值;
1. 最近邻插值
关键点事找到缩放倍数,然后邻域向上取整完成坐标映射;
cv::Mat nNeighbourInterpolation(cv::Mat srcImage)
{
CV_Assert(srcImage.data != NULL);
int rows = srcImage.rows;
int cols = srcImage.cols;
//构建目标图像
cv::Mat dstImage = cv::Mat(cv::Size(150,150), srcImage.type(), cv::Scalar::all(0));
int dstRows = dstImage.rows;
int dstCols = dstImage.cols;
//坐标转换,求取缩放倍数
float cx = (float)cols / dstCols;
float ry = (float)rows / dstRows;
//遍历图像,完成缩放操作
for(int i = 0; i < dstCols; i++){
int ix = cvFloor(i * cx);
for(int j = 0; j < dstRows; j++){
int jy = cvFloor(j * ry);
//边界处理
if(ix > cols -1)
ix = cols - 1;
if(jy > rows - 1)
jy = rows - 1;
//映射矩阵
dstImage.at<cv::Vec3b>(j, i) = srcImage.at<Vec3b>(jy, ix);
}
}
return dstImage;
}
2. 双线性插值
无
3. resize()函数实现图像大小变换
函数原型如下:
/*
实现图像尺寸大小变换功能;
_src:源图像
_dst:目的图像
dsize:输出图像的尺寸,若为0,尺寸将被计算为Size(round(fx*src.cols),round(fy*src.rows));
inv_scale_x:水平缩放因子;
inv_scale_y:垂直缩放因子;
interpolation:插值方法;
*/
void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
double inv_scale_x, double inv_scale_y, int interpolation )
提供了5中插值方法:最近邻,双线性,像素区域,立方插值,兰索斯插值;
void ResizeExample(cv::Mat srcImage)
{
CV_Assert(srcImage.data != NULL);
cv::Mat dstImage(256,256,CV_8UC3);
//默认参数为双线性插值
double tTime;
tTime = (double)getTickCount();
const int nTimes = 100;
for(int i = 0 ;i < nTimes ; i++){
resize(srcImage,dstImage,Size(dstImage.rows,dstImage.cols),0,0);
}
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
tTime /= nTimes;
std::cout << "test1 = " << tTime << endl;
cv::imwrite("./lena_resize1.jpg", dstImage);
//最近邻插值
tTime = (double)getTickCount();
for(int i = 0 ;i < nTimes ; i++){
resize(srcImage,dstImage,Size(dstImage.rows,dstImage.cols),0,0,cv::INTER_NEAREST);
}
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
tTime /= nTimes;
std::cout << "test2 = " << tTime << endl;
cv::imwrite("./lena_resize2.jpg", dstImage);
//像素区域插值
tTime = (double)getTickCount();
for(int i = 0 ;i < nTimes ; i++){
resize(srcImage,dstImage,Size(dstImage.rows,dstImage.cols),0.5,0.5,cv::INTER_AREA);
}
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
tTime /= nTimes;
std::cout << "test3 = " << tTime << endl;
cv::imwrite("./lena_resize3.jpg", dstImage);
//立方插值
tTime = (double)getTickCount();
for(int i = 0 ;i < nTimes ; i++){
resize(srcImage,dstImage,Size(dstImage.rows,dstImage.cols),0.5,0.5,cv::INTER_CUBIC);
}
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
tTime /= nTimes;
std::cout << "test4 = " << tTime << endl;
cv::imwrite("./lena_resize4.jpg", dstImage);
//兰索斯插值
tTime = (double)getTickCount();
for(int i = 0 ;i < nTimes ; i++){
resize(srcImage,dstImage,Size(dstImage.rows,dstImage.cols),0.5,0.5,cv::INTER_LANCZOS4);
}
tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency();
tTime /= nTimes;
std::cout << "test5 = " << tTime << endl;
cv::imwrite("./lena_resize5.jpg", dstImage);
/*
test1 = 0.076032
test2 = 0.0625323
test3 = 0.103261
test4 = 1.16022
test5 = 2.11283
*/
}
4. 图像金字塔
向下采样采用的是高斯金字塔,向上重建技术采用拉普拉斯金字塔;
void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
int main()
{
cv::Mat srcImage = cv::imread("./lena.jpg");
if(srcImage.empty()){
std::cout << "imread failed" << endl;
return -1;
}
//下采样
cv::Mat dstImage;
pyrDown(srcImage, dstImage, Size(srcImage.rows/2,srcImage.cols/2));
//上采样,对下采样进行重构;
cv::Mat buildImage;
pyrUp(dstImage, buildImage, Size(dstImage.rows*2,dstImage.cols*2));
//源图像与重构图像作差
cv::Mat diffImage;
cv::absdiff(srcImage, buildImage, diffImage);
cv::imwrite("./lena_diff.jpg", diffImage);
return 0;
}