Opencv之图像的缩放(resize,pyrUp,pyrDown以及基于等间隔提取图像缩放和基于区域子块提取图像缩放)

基于等间隔提取图像缩放:

        等间隔提取图像缩放是通过对原图像进行均匀采样来完成的。对于源图像数据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)中提取子块的均值或中值得到的。

 关于:金字塔图像缩放与resize可参见OpenCV3之——图像金字塔与图片尺寸缩放(pyrUp、pyrDown、resize)_衣带渐宽人憔悴-CSDN博客_pyrdown如果要放大或缩小图片的尺寸,可以使用OpenCV提供的两种方法: resize函数,是最直接的方式; pyrUp,pyrDown函数,即图像金字塔相关的两个函数,对图像进行上采样和下采样的操作。一、  resize函数(resize函数在imgproc模块的Geometric Image transformations子模块里)源码溯源:(resize函数位于..\opencv\so...https://blog.csdn.net/qq_35294564/article/details/81232123

代码:

#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;
}

结果展示:图片过大过多这里了就不放了,可以自己任意找张图实验。

对于通过区域子块方式进行图像的放大,不知道有什么好的建议,欢迎下方留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值