基于等间隔提取图像缩放:
等间隔提取图像缩放是通过对原图像进行均匀采样来完成的。对于源图像数据f(x,y),其分辨率为M x N,若将其分辨率改为m x n,对于等间隔采样而言,其宽度缩放因子kx = M / m,高度缩放因子为 ky = N / n。图像缩放在其水平方向的等间隔采样为kx,垂直方向等间隔采样为ky。当kx = ky时,源图像数据将等比例缩放。否则源图像不发生等比例缩放,从而造成图像的扭曲变形。从f(x,y) 到 g(x', y')矩阵映射关系如下:
基于区域子块提取图像缩放:
区域子块提取图像缩放是通过对源图像进行区域子块划分,然后提取子块中像素值作为采样像素以构成新图像来实现的。提取子块像素值常用方法有计算子块像素中的中值与计算子块像素的均值。对源图像进行区域划分同样也有多种不同的方法,常用方法是根据缩放因子等比例提取子块与自适应因子提取子块。如:图像数据f(x,y)分辨率为8*8,图像g(x',y')分辨率为2*2,其区域子块提取方式为
子块区域提取后g(x',y')为下式
其中,A11,A12,A21,A22的计算方法是通过计算f(x,y)中提取子块的均值或中值得到的。
代码:
#include<iostream>
#include<opencv2/core.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/highgui.hpp>
using namespace std;
using namespace cv;
基于等间隔提取图像缩放
Mat imgDown_1(Mat& srcimg, float kx, float ky)
{
提取图像的分辨率
int nrows = cvRound(srcimg.rows * kx);
int ncols = cvRound(srcimg.cols * ky);
Mat resimg(nrows, ncols, srcimg.type());
for (int i = 0; i < nrows; i++)
{
for (int j = 0; j < ncols; j++)
{
//根据水平因子计算坐标
int x = static_cast<int>((i + 1) / kx + 0.5) - 1;
//根据垂直因子计算坐标
int y = static_cast<int>((j + 1) / ky + 0.5) - 1;
resimg.at<Vec3b>(i, j) = srcimg.at<Vec3b>(x, y);
}
}
return resimg;
}
//对图像进行放大
Mat imgUp_1(Mat& srcimg, float kx, float ky)
{
int nrows =srcimg.rows * kx;
int ncols =srcimg.cols * ky;
Mat resimg(nrows, ncols, srcimg.type());
for (int i = 0; i < nrows; i++)
{
//int x = i / kx;
int x = static_cast<int>((i + 1) / kx + 0.7) - 1;
for (int j = 0; j < ncols; j++)
{
//int y = j / ky;
int y = static_cast<int>((j + 1) / ky + 0.7) - 1;
resimg.at<Vec3b>(i, j) = srcimg.at<Vec3b>(x, y);
}
}
return resimg;
}
Vec3b areaAverage(const Mat& srcimg, Point_<int> leftPoint, Point_<int> rightPoint)
{
int tmp1 = 0, tmp2 = 0, tmp3 = 0;
计算区域字块像素点个数
int nPix = (rightPoint.x - leftPoint.x + 1) * (rightPoint.y - leftPoint.y + 1);
//对区域字块各个通道对像素值求和
for (int i = leftPoint.x; i <= rightPoint.x; i++)
{
for (int j = leftPoint.y; j <= rightPoint.y; j++)
{
tmp1 += srcimg.at<Vec3b>(i, j)[0];
tmp2 += srcimg.at<Vec3b>(i, j)[1];
tmp3 += srcimg.at<Vec3b>(i, j)[2];
}
}
//对每个通道求均值
Vec3b vecTmp;
vecTmp[0] = tmp1 / nPix ;
vecTmp[1] = tmp2 / nPix ;
vecTmp[2] = tmp3 / nPix ;
return vecTmp;
}
Mat imgDown_2(const Mat& srcimg, double kx, double ky)
{
int nrows = srcimg.rows * kx;
int ncols = srcimg.cols * ky;
/*
int nrows = cvRound(srcimg.rows * kx);
int ncols = cvRound(srcimg.cols * ky);
*/
Mat resimg(nrows, ncols, srcimg.type());
//区域子块的左上角行列坐标
int leftRowCoordinate = 0;
int leftColCoordinate = 0;
for (int i = 0; i < nrows; i++)
{
//根据水平因子计算坐标
int x = static_cast<int>((i + 1) / kx + 0.5) - 1;
for (int j = 0; j < ncols; j++)
{
//根据垂直因子计算坐标
int y = static_cast<int>((j + 1) / ky + 0.5) - 1;
//求解区域子块的均值
resimg.at<Vec3b>(i, j) = areaAverage(srcimg, Point_<int>(leftRowCoordinate, leftColCoordinate), Point_<int>(x, y));
//resimg.at<Vec3b>(i, j) = srcimg.at<Vec3b>(x, y);
//更新下子块左上角的列坐标,行坐标不变
leftColCoordinate = y + 1;
}
leftColCoordinate = 0;
//更新下子块左上角的行坐标
leftRowCoordinate = x + 1;
}
return resimg;
}
//对图像进行放大
Mat imgUp_2(const Mat& srcimg, double kx, double ky)
{
int nrows = srcimg.rows * kx;
int ncols = srcimg.cols * ky;
Mat resimg(nrows, ncols, srcimg.type());
int leftRowCoordinate = 0;
int leftColCoordinate = 0;
for (int i = 0; i < nrows; i++)
{
int x = i / kx;
for (int j = 0; j < ncols; j++)
{
int y = j / ky;
//resimg.at<Vec3b>(i, j) = areaAverage(srcimg, Point_<int>(leftRowCoordinate, leftColCoordinate), Point_<int>(x, y));
resimg.at<Vec3b>(i, j) = srcimg.at<Vec3b>(x, y);
leftColCoordinate = y + 1;
}
leftColCoordinate = 0;
leftRowCoordinate = x + 1;
}
return resimg;
}
int main()
{
//Mat srcimg = imread("C:\\Users\\H\\Desktop\\1.png");
Mat srcimg = imread("C:\\Users\\H\\Desktop\\4.bmp");
if (srcimg.empty())
{
return -1;
}
imshow("srcimg", srcimg);
//自定义图像缩放模式
Mat upimg1 = imgUp_1(srcimg, 2, 2);
imshow("upimg1", upimg1);
Mat resimg1 = imgDown_1(srcimg, 0.5, 0.5);
imshow("resimg1", resimg1);
Mat resimg2 = imgDown_2(srcimg, 0.5, 0.5);
imshow("resimg2", resimg2);
Mat upimg2 = imgUp_2(srcimg, 2, 2);
imshow("upimg2", upimg2);
//图像金子塔实现图像的缩放
Mat pyrDownimg;
pyrDown(srcimg, pyrDownimg);
imshow("pyrDownimg", pyrDownimg);
Mat pyrUpimg;
pyrUp(srcimg, pyrUpimg);
imshow("pyrUpimg", pyrUpimg);
//resize方式实现图像的缩放
Mat dstimg;
const double scaleVal = 2;
//resize(srcimg, dstimg, Size(srcimg.cols*0.5, srcimg.rows*0.5));
resize(srcimg, dstimg, Size(srcimg.cols*2, srcimg.rows*2));
imshow("dstimg", dstimg);
waitKey(0);
return 0;
}
结果展示:图片过大过多这里了就不放了,可以自己任意找张图实验。
对于通过区域子块方式进行图像的放大,不知道有什么好的建议,欢迎下方留言。