前言
基于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。
enum BorderTypes {
BORDER_CONSTANT = 0,
BORDER_REPLICATE = 1,
BORDER_REFLECT = 2,
BORDER_WRAP = 3,
BORDER_REFLECT_101 = 4,
BORDER_TRANSPARENT = 5,
BORDER_REFLECT101 = BORDER_REFLECT_101,
BORDER_DEFAULT = BORDER_REFLECT_101,
BORDER_ISOLATED = 16
};
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。
示例代码
geometricTransform.h
#pragma once
#include <iostream>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
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;
}
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++)
{
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);
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);
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;
}
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);
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;
}
结果展示
|