基于opencv的c++接口,实现常用的图像几何变换方法,包括了图像平移、旋转、缩放、坐标映射变换、仿射变换。
相关的opencv接口解析CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
函数 remap 使用指定的映射转换源图像。
@param src 源图像。
@param dst 目标图像。 它的大小与 map1 相同,类型与 src 相同。
@param map1 第一个 (x,y) 点的映射,或者只是 x 类型为 CV_16SC2 的值,
CV_32FC1 或 CV_32FC2。 有关将浮点表示转换为定点以提高速度的详细信息,请参阅 convertMaps。
@param map2 分别具有 CV_16UC1、CV_32FC1 或 none 类型的 y 值的第二个映射(如果 map1 是 (x,y) 点,则为空映射)。
@param interpolation 插值方法(请参阅#InterpolationFlags)。 此函数不支持方法#INTER_AREA。
@param borderMode 像素外推法(参见#BorderTypes)。 当borderMode=#BORDER_TRANSPARENT 时,表示目标图像中与源图像中的“异常值”对应的像素未被函数修改。
@param borderValue 用于恒定边框的值。 默认为 0。
//! Various border types, image boundaries are denoted with `|`
//! @see borderInterpolate, copyMakeBorder
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`
BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
CV_EXPORTS Mat getAffineTransform( const Point2f src[], const Point2f dst[] );
该函数计算仿射变换的矩阵。
@param src 源图像中三角形顶点的坐标。
@param dst 目标图像中相应三角形顶点的坐标。
CV_EXPORTS_W void warpAffine( InputArray src, OutputArray dst,
InputArray M, Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
函数 warpAffine 使用指定的矩阵变换源图像。
@param src 输入图像。
@param dst 输出图像,其大小为 dsize 且类型与 src 相同。
@param M 变换矩阵。
@param dsize 输出图像的大小。
@param flags 插值方法的组合(请参阅#InterpolationFlags)和可选标志 #WARP_INVERSE_MAP,这意味着 M 是逆变换。
@param borderMode 像素外推方法(参见#BorderTypes); 当borderMode=#BORDER_TRANSPARENT时,表示目标图像中与源图像中的“异常值”对应的像素未被函数修改。
@param borderValue 值在恒定边框的情况下使用; 默认情况下,它是 0。
#pragma once
#include
#include
#include
#include
using namespace std;
using namespace cv;
#define PROCESS_IMG_SUCESS 0
#define PROCESS_IMG_FAIL 1
namespace ImgEnhance
{
//图像几何变换
class GeometricTransformate
{
public:
GeometricTransformate() { cout << "GeometricTransformate is being created" << endl; } // 这是构造函数声明
~GeometricTransformate() { cout << "GeometricTransformate is being deleted" << endl; } // 这是析构函数声明
int RemapTransformate(cv::Mat srcImage, cv::Mat &dstImage);//坐标映射变换
cv::Mat imageTranslation1(cv::Mat & srcImage, int xOffset, int yOffset);// 平移 *** 作 图像大小不变
cv::Mat imageTranslation2(cv::Mat & srcImage, int xOffset, int yOffset);// 平移 *** 作 图像大小改变
int MoveTransformate(cv::Mat srcImage, cv::Mat &dstImage, int xOffset, int yOffset);//图像平移
cv::Mat imageReduction1(cv::Mat &srcImage, float kx, float ky);// 基于等间隔提取图像缩放
cv::Vec3b areaAverage(const cv::Mat &srcImage, Point_<int> leftPoint, Point_<int> rightPoint);
cv::Mat imageReduction2(const Mat &srcImage, double kx, double ky);
int ScaleTransformate(cv::Mat srcImage, cv::Mat &dstImage, float kx, float ky);//图像缩放
cv::Mat angelRotate(cv::Mat& src, int angle);//旋转
int RotateTransformate(cv::Mat srcImage, cv::Mat &dstImage, int angle);//图像旋转
int AffineTransformate(cv::Mat srcImage, cv::Mat &dstImage, cv::Point2f srcPoint[], cv::Point2f resPoint[]);//仿射变换
};
}
geometricTransform.cpp
#include"geometricTransform.h"
int ImgEnhance::GeometricTransformate::RemapTransformate(cv::Mat srcImage, cv::Mat &dstImage)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 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, dstImage, xMapImage, yMapImage, INTER_LINEAR, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
return 0;
}
// 平移 *** 作 图像大小不变
cv::Mat ImgEnhance::GeometricTransformate::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 ImgEnhance::GeometricTransformate::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 ImgEnhance::GeometricTransformate::MoveTransformate(cv::Mat srcImage, cv::Mat &dstImage, int xOffset, int yOffset)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 图像平移不改变大小
dstImage = imageTranslation1(srcImage, xOffset, yOffset);
// 图像平移改变大小
//dstImage = imageTranslation1(srcImage, xOffset, yOffset);
return 0;
}
// 基于等间隔提取图像缩放
cv::Mat ImgEnhance::GeometricTransformate::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 ImgEnhance::GeometricTransformate::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 ImgEnhance::GeometricTransformate::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 ImgEnhance::GeometricTransformate::ScaleTransformate(cv::Mat srcImage, cv::Mat &dstImage, float kx, float ky)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
dstImage = imageReduction1(srcImage, kx, ky);// 基于等间隔提取图像缩放
//dstImage = imageReduction2(srcImage, kx, ky);
return 0;
}
cv::Mat ImgEnhance::GeometricTransformate::angelRotate(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 ImgEnhance::GeometricTransformate::RotateTransformate(cv::Mat srcImage, cv::Mat &dstImage, int angle)
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
dstImage = angelRotate(srcImage, angle);
return 0;
}
int ImgEnhance::GeometricTransformate::AffineTransformate(cv::Mat srcImage, cv::Mat &dstImage, cv::Point2f srcPoint[], cv::Point2f resPoint[])
{
if (srcImage.empty())
{
printf("cannot load!!\n");
return 1;
}
// 计算仿射变换矩阵,即仿射变换的2*3数组
// 定义仿射变换矩阵2X3
cv::Mat warpMat(cv::Size(2, 3), CV_32F);
warpMat = cv::getAffineTransform(srcPoint, resPoint);
// 根据仿射矩阵计算图像仿射变换
cv::warpAffine(srcImage, dstImage, warpMat, dstImage.size());
return 0;
}
test.cpp
#include"geometricTransform.h"
ImgEnhance::GeometricTransformate ImgG;//几何变换
int main()
{
// 读取源图像及判断
cv::Mat srcImage = cv::imread("boudingRect.jpg");
if (!srcImage.data)
{
return 1;
}
cv::namedWindow("原始图", 0);
cv::imshow("原始图", srcImage);
// 转化为灰度图像
cv::Mat srcGray;
if (srcImage.channels() == 3)
{
cv::cvtColor(srcImage, srcGray, COLOR_RGB2GRAY);
}
else
{
srcGray = srcImage.clone();
}
cv::namedWindow("灰度图", 0);
cv::imshow("灰度图", srcGray);
//坐标映射变换
Mat remapImage;
ImgG.RemapTransformate(srcImage, remapImage);
cv::namedWindow("坐标映射变换结果图", 0);
cv::imshow("坐标映射变换结果图", remapImage);
//图像平移
Mat moveImage;
ImgG.MoveTransformate(srcImage, moveImage,50,50);
cv::namedWindow("图像平移结果图", 0);
cv::imshow("图像平移结果图", moveImage);
//图像缩放
Mat scaleImage;
ImgG.ScaleTransformate(srcImage, scaleImage, 0.5, 0.5);
cv::namedWindow("图像缩放结果图", 0);
cv::imshow("图像缩放结果图", scaleImage);
//图像旋转
Mat rotateImage;
ImgG.RotateTransformate(srcImage, rotateImage, -30);
cv::namedWindow("图像旋转结果图", 0);
cv::imshow("图像旋转结果图", rotateImage);
仿射变换
/*vector srcPoint;
vector resPoint;
srcPoint.push_back(cv::Point2f(0, 0));
srcPoint.push_back(cv::Point2f(3, 3));
srcPoint.push_back(cv::Point2f(15, 15));
resPoint.push_back(cv::Point2f(0, 0));
resPoint.push_back(cv::Point2f(3, 3));
resPoint.push_back(cv::Point2f(25, 25));*/
int nRows = srcImage.rows;
int nCols = srcImage.cols;
//定义仿射变换的二维点数组
//源图像和目标图像对应映射的三点
cv::Point2f srcPoint[3];
cv::Point2f resPoint[3];
srcPoint[0] = cv::Point2f(0, 0);
srcPoint[1] = cv::Point2f(nCols - 1, 0);
srcPoint[2] = cv::Point2f(0, nRows - 1);
resPoint[0] = cv::Point2f(nCols * 0, nRows*0.33);
resPoint[1] = cv::Point2f(nCols*0.85, nRows*0.25);
resPoint[2] = cv::Point2f(nCols*0.15, nRows*0.7);
Mat affineImage;
ImgG.AffineTransformate(srcImage, affineImage, srcPoint, resPoint);
cv::namedWindow("仿射变换结果图", 0);
cv::imshow("仿射变换结果图", affineImage);
cv::waitKey(0);
return 0;
}
结果展示
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)