OpenCV2:幼兒園篇 第五章 圖像幾何變換

一.簡介

圖像的幾何變換有距離變換 座標映射 平移  鏡像 旋轉  縮放  仿射變換等ios

 

二.重映射

把一張圖像從新排列像素,好比倒置ui

 

CV_EXPORTS_W void remap( InputArray src, OutputArray dst,

                                                   InputArray map1, InputArray map2,

                                                   int interpolation, int borderMode=BORDER_CONSTANT,

                                                   const Scalar& borderValue=Scalar());spa

  • src
    源圖像
  • dst
    目標圖像
  • map1
    x座標
  • map2
    y座標
  • interpolation
    表示插值方法
  • borderMode
    表示邊界插值類型
  • borderValue

   表示插值數值blog

 

#include <iostream>
#include "opencv2/opencv.hpp"

using namespace std;

int main(int argc, char* argv[]) {


	cv::Mat srcImage = cv::imread("a.jpg");
	if(!srcImage.data)
		return -1;

	// 輸出矩陣
	cv::Mat resultImage(srcImage.size(), srcImage.type());
	

	// x與y方向矩陣
	cv::Mat xMapImage(srcImage.size(), CV_32FC1);
	cv::Mat yMapImage(srcImage.size(), CV_32FC1);

	// 取圖像的寬高
	int rows = srcImage.rows;
	int cols = srcImage.cols;

	// 圖像遍歷
	for( int j = 0; j < rows; j++ )
	{
		for( int i = 0; i < cols; i++ )
		{

			//x與y均翻轉
			xMapImage.at<float>(j,i) = cols - i;
			yMapImage.at<float>(j,i) = rows - j; 
		}
	}
	

	// 重映射操做
	remap(srcImage, resultImage, xMapImage, yMapImage, CV_INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0,0,0));

	// 輸出結果
	cv::imshow("srcImage", srcImage);
	cv::imshow("resultImage", resultImage);

	cv::waitKey(0);

	return 0;

}

 

三.平移

圖像的平移操做是將圖像的全部像素座標進行水平或垂直方向移動ip

//圖像平移而且圖像大小不變和改變

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

// 平移操做 圖像大小不變
cv::Mat imageTranslation1(cv::Mat& srcImage,int xOffset,int yOffset) 
{

	int nRows = srcImage.rows;
	int nCols = srcImage.cols;

	cv::Mat resultImage(srcImage.size(), srcImage.type());

	// 遍歷圖像
	for(int i = 0; i < nRows; ++i)
	{
		for(int j = 0; j < nCols; ++j)
		{
			// 映射變換
			int x = j - xOffset;
			int y = i - yOffset;

			// 邊界判斷
			if(x >= 0 && y >= 0 && x < nCols && y < nRows)
				resultImage.at<cv::Vec3b>(i,j) = srcImage.ptr<cv::Vec3b>(y)[x];
		}
	}
	return resultImage;
}

// 平移操做,圖像大小改變
cv::Mat imageTranslation2(cv::Mat& srcImage, int xOffset, int yOffset)
{

	// 設置平移尺寸
	int nRows = srcImage.rows + abs(yOffset);
	int nCols = srcImage.cols + abs(xOffset);

	cv::Mat resultImage(nRows, nCols, srcImage.type());

	// 圖像遍歷
	for(int i = 0; i < nRows; ++i)
	{
		for(int j = 0; j < nCols; ++j)
		{

			// 映射變換
			int x = j - xOffset;
			int y = i - yOffset;

			// 邊界判斷
			if(x >= 0 && y >= 0 && x < nCols && y < nRows)
				resultImage.at<cv::Vec3b>(i,j) = srcImage.ptr<cv::Vec3b>(y)[x];
		}
	}
	return resultImage;
}

int main()
{

	// 圖像讀取及斷定是否正確讀入
	cv::Mat srcImage = cv::imread("a.jpg");
	if(!srcImage.data)
		return -1;

	cv::imshow("srcImage", srcImage);
	int xOffset = 50, yOffset = 80;

	// 圖像左平移不改變大小
	cv::Mat resultImage1 = imageTranslation1(srcImage, xOffset, yOffset);
	cv::imshow("resultImage1", resultImage1);

	// 圖像左平移改變大小
	cv::Mat resultImage2 = imageTranslation2(srcImage, xOffset, yOffset);
	cv::imshow("resultImage2", resultImage2);

	//圖像右平移不改變大小
	 xOffset = -50, yOffset = -80;
	 cv::Mat resultImage3 = imageTranslation1(srcImage, xOffset, yOffset);
	 cv::imshow("resultImage3", resultImage3);

	 cv::waitKey(0);
	 return 0;
}

 

 

四.縮放

 圖像縮放會減小或增長圖像數據的像素個數,形成信息的丟失rem

1.基於等間隔提取圖像縮放

等間隔提取圖像縮放是經過對源圖像進行均勻採樣來完成的it

 

2.基於區域子塊提取圖像縮放

區域子塊提取圖像縮放是經過對源圖像進行區域子塊劃分,而後提取子塊中像素值做爲採樣像素以構成新圖像來完成io

提取子塊像素值經常使用的有計算子塊像素的中值計算子塊像素的均值opencv

對源圖像的區域劃分也有根據縮放因子等比例提取子塊自適應因子提取子塊ast

 

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;

// 基於等間隔提取圖像縮放
cv::Mat imageReduction1(cv::Mat& srcImage, float kx, float ky)
{
	// 獲取輸出圖像分辨率
	int nRows = cvRound(srcImage.rows * kx);
	int nCols = cvRound(srcImage.cols * ky);
	cv::Mat resultImage(nRows, nCols, srcImage.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;
			resultImage.at<cv::Vec3b>(i, j) = srcImage.at<cv::Vec3b>(x, y);
		}
	}
	return resultImage;
}

cv::Vec3b areaAverage(const cv::Mat& srcImage,Point_<int> leftPoint, Point_<int> rightPoint)
{
	int temp1 = 0, temp2 = 0, temp3 = 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++)
			{

				temp1 += srcImage.at<cv::Vec3b>(i, j)[0];
				temp2 += srcImage.at<cv::Vec3b>(i, j)[1];
				temp3 += srcImage.at<cv::Vec3b>(i, j)[2];
			}
		}

		// 對每一個通道求均值
		Vec3b vecTemp;
		vecTemp[0] = temp1 / nPix;
		vecTemp[1] = temp2 / nPix;
		vecTemp[2] = temp3 / nPix;

		return vecTemp;
	}

}

cv::Mat imageReduction2(const Mat& srcImage, double kx, double ky)
{
	// 獲取輸出圖像分辨率
	int nRows = cvRound(srcImage.rows * kx);
	int nCols = cvRound(srcImage.cols * ky);
	cv::Mat resultImage(nRows, nCols, srcImage.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;
			// 求解區域子塊的均值
			resultImage.at<Vec3b>(i, j) = areaAverage(srcImage, Point_<int>(leftRowCoordinate, leftColCoordinate), Point_<int>(x, y));
			// 更新下子塊左上角的列座標,行座標不變
			leftColCoordinate = y + 1;
		}
		leftColCoordinate = 0;
		// 更新下子塊左上角的行座標
		leftRowCoordinate = x + 1;
	}

	return resultImage;
}



int main()
{

	cv::Mat srcImage = cv::imread("a.jpg");
	if (!srcImage.data)
		return -1;
	cv::imshow("srcImage", srcImage);

	cv::Mat resultImage1 = imageReduction1(srcImage, 0.5, 0.5);
	cv::imshow("res1", resultImage1);

	cv::Mat resultImage2 = imageReduction2(srcImage, 0.5, 0.5);
	cv::imshow("res2", resultImage2);

	cv::waitKey(0);
	return 0;
}

 

 

五.旋轉

 1.角度旋轉

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath>

using namespace cv;
using namespace std;

cv::Mat angleRotate(cv::Mat& src, int angle)
{
	// 角度變換
	float alpha = angle * CV_PI / 180;

	// 構造旋轉矩陣
	float rotateMat[3][3] = {
		{cos(alpha), -sin(alpha), 0},
		{sin(alpha), cos(alpha), 0},
		{0, 0, 1}
	};

	int nSrcRows = src.rows;
	int nSrcCols = src.cols;

	// 計算旋轉後圖像矩陣的各個頂點位置
	float a1 = nSrcCols * rotateMat[0][0];
	float b1 = nSrcCols * rotateMat[1][0];
	float a2 = nSrcCols * rotateMat[0][0] + nSrcRows * rotateMat[0][1];
	float b2 = nSrcCols * rotateMat[1][0] + nSrcRows * rotateMat[1][1];
	float a3 = nSrcRows * rotateMat[0][1];
	float b3 = nSrcRows * rotateMat[1][1];

	// 計算出極值點
	float kxMin = min( min( min(0.0f, a1), a2), a3);
	float kxMax = max( max( max(0.0f, a1), a2), a3);
	float kyMin = min( min( min(0.0f, b1), b2), b3);
	float kyMax = max( max( max(0.0f, b1), b2), b3);

	// 計算輸出矩陣的尺寸
	int nRows = abs(kxMax - kxMin);
	int nCols = abs(kyMax - kyMin);
	cv::Mat dst(nRows, nCols, src.type(), cv::Scalar::all(0));
	for (int i = 0; i < nRows; ++i)
	{
		for (int j = 0; j < nCols; ++j)
		{
			// 旋轉座標轉換
			int x = (j + kxMin) * rotateMat[0][0] - (i + kyMin) * rotateMat[0][1];
			int y = -(j + kxMin) * rotateMat[1][0] + (i + kyMin) * rotateMat[1][1];

			// 區域選擇
			if((x >= 0) && (x < nSrcCols) && (y >= 0) && (y < nSrcRows))
			{
				dst.at<cv::Vec3b>(i, j) = src.at<cv::Vec3b>(y, x);
			}
		}
	}
	return dst;
}

int main()
{
	cv::Mat srcImage = cv::imread("a.jpg");
	if (!srcImage.data)
		return -1;
	cv::imshow("srcImage", srcImage);
	int angle = 30;
	cv::Mat resultImage = angleRotate(srcImage, angle);
	imshow("resultImage", resultImage);
	cv::waitKey(0);
	return 0;
}

 

2.直接翻轉

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <cmath>

using namespace cv;
using namespace std;

int main()
{

	cv::Mat srcImage = cv::imread("a.jpg");
	if (!srcImage.data)
		return -1;

	// 逆時針旋轉90度
	cv::Mat resultImage1;
	transpose(srcImage, resultImage1);

	// 水平翻轉
	cv::Mat resultImage2;
	flip(resultImage1, resultImage2, 1);

	// 垂直翻轉
	cv::Mat resultImage3;
	flip(resultImage1, resultImage3, 0);

	// 垂直和水平翻轉
	cv::Mat resultImage4;
	flip(srcImage, resultImage4, -1);

	cv::imshow("srcImage", srcImage);
	cv::imshow("resultImage1", resultImage1);
	cv::imshow("resultImage2", resultImage2);
	cv::imshow("resultImage3", resultImage3);
	cv::imshow("resultImage4", resultImage4);

	cv::waitKey(0);
	return 0;
}

 

 

六.仿射變換

相關文章
相關標籤/搜索