C++版OpenCV_02_几何变换
几何变换
- 2.1 仿射变换
- 2.2 投影变换
- 2.3 极坐标变换
- 2.3.1 笛卡尔坐标转极坐标
- 2.3.2 极坐标转换为笛卡儿坐标
- 2.3.3 图像极坐标变换
- 2.3.4 线性极坐标函数
- 2.3.5 对数极坐标函数 logPolar
几何变换:
- 仿射变换:平移、放大缩小、旋转、计算仿射矩阵(方程法、矩阵法)、插值(最近邻、双线性插值)、
- 投影变换
- 极坐标变换
2.1 仿射变换
平移
x_ = 1*x + 0*y+ tx
y_ = 0*x + 1*y+ ty
放大缩小
/*
x_ = sx*x + 0*y+ 0*tx
y_ = 0*x + sy*y+ 0*tyvoid resize(InputArray scr,outputArray dst,Size dsize,double fx=0,double fy=0,int interpolation=INTER_LINEAR)
scr: 输入图像
dst: 输出图像
dsize:(宽高)
fx: 水平方向上的缩放比例
fy: 垂直方向上的缩放比例
interpolation: 插值法 INTER_NEAREST、INTER_LINEAR*/
#include<opencv/core/core.hpp>
#include<opencv/highgui/highgui.hpp>
#include<opencv/imgproc/imgproc.hpp>
using namespace cv;
int main(int argv,char*argv[])
{Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);if(!I.data)return -1;Mat s = (Mat_<float>(2,2)<<0.5,0,0,0,0.5,0);Mat dst;warpAffine(I,dst,s,Size(I.cols/2,I.rows/2));Mat dst1;resize(I,dst1,Size(I.cols/2,I.rows/2),0.5,0.5);
}
旋转
/*
x_ = cosa*x + sina*y+ 0*tx
y_ = -sina*x + cosa*y+ 0*ty
void rotate(InputArray scr,outputArray dst,int rotateCode)
rotateCode: ROTATE_90_CLOCKWISE,ROTATE_180,ROTATE_90_COUNTERCLOCKWISE,270度
*/#include<opencv/core/core.hpp>
#include<opencv/highgui/highgui.hpp>using namespace cv;
int main(int argv,char*argv[])
{Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);if(!I.data)return -1;Mat dst;rotate(I,dst,ROTATE_90_CLOCKWISE);}
计算仿射矩阵
方程法求仿射矩阵
// 仿射矩阵有6个自由度,因此需要src,dst3对不共线的点求解
// 把对应点存在数组中
Point2f src[]={Point2f(0,0),Point2f(10,24),Point2f(60,120)};
Point2f dst[]={Point2f(0,0),Point2f(30,64),Point2f(50,98)};
Mat A = getAffineTransform(src,dst)// 把对应点存在矩阵中
Mat src = (Mat_<float>(3,2)<<0,0,10,24,60,120);
Mat dst = (Mat_<float>(3,2)<<0,0,30,64,50,98);
Mat A = getAffineTransform(src,dst)
计算仿射矩阵
矩阵法:
// 获取旋转矩阵
Mat A = getRotationMatrixD(Point2f(x,y),angle,scale);
2.2 投影变换
/*
Point2f src[]={Point2f(0,0),Point2f(100,0),Point2f(0,100),Point2f(100,100)};
Point2f dst[]={Point2f(100,30),Point2f(200,30),Point2f(70,80),Point2f(230,90)};
Mat P=getPerspectiveTransform(src,dst);Point2f src=(Mat_<float>(4,2)<<0,0,20,10,40,89,100,100);
Point2f dst=(Mat_<float>(4,2)<<10,20,30,80,80,90,200,150);
Mat P=getPerspectiveTransform(src,dst);
*/
2.3 极坐标变换
2.3.1 笛卡尔坐标转极坐标
/*
笛卡尔坐标转极坐标
已知任意一点(x,y),中心(x',y'),(a,r)
r = ((x-x')**2+(y-y')**2)**0.5
a = 2pi+arctan2(y-y',x-x') 当y-y' <=0 or arctan2(y-y',x-x') 当y-y' >0cartToPolar(x,y magnitude,angle,angleInDegrees)
angleInDegrees: ture 返回角度,反之,返回弧度。*/
// 笛卡儿坐标转换为极坐标
Mat x = (Mat_<float>(1,8)<<0,1,2,0,2,0,1,2)-1;
Mat y = (Mat_<float>(1,8)<<0,0,0,1,1,2,2,2)-1;
Mat r,theta;
cartToPolar(x,y,r,theta,True);
/* 结果
1.41 3.93
1.0 4.71
1.41 5.5
1.0 3.14
1.0 0.0
1.41 2.36
1.0 1.57
1.41 0.79
*/
2.3.2 极坐标转换为笛卡儿坐标
/*
x = x'+r*cosa
y = y'+r*sina
polarTocart(magnitude,angle,x,y,angleInDegrees));
返回的是以(0,0)为中心的笛卡尔坐标,已知(r,theta)和(x',y')得到(x-x',y-y')
*/
Mat angle = (Mat_<float>(2,2)<<30,31,30,31);
Mat r = (Mat_<float>(2,2)<<10,10,11,11);
Mat x,y;
polarTocart(r,angle,x,y,true);
2.3.3 图像极坐标变换
/*
O(i,j) = I(x'+(r_min+r_step*i)*cos(a_min+a_step*j), y'+(r_min+r_step*i)*sin(a_min+a_step*j))
*/
import cv2
import numpy as np
import matplotlib.pyplot as pltdef polar(img, center, r, theta=(0, 360), rstep=1.0, thetastep=360.0 / (180 * 8)):cx, cy = centerr_min, r_max = rtheta_min, theta_max = thetaH = int((r_max - r_min) / rstep) + 1W = int((theta_max - theta_min) / thetastep) + 1out = np.ones((H, W), img.dtype) * 125r = np.linspace(r_min, r_max, H)r = np.tile(r, (W, 1)).T # (H,W)theta = np.linspace(theta_min, theta_max, W)theta = np.tile(theta, (H, 1)) # (H,W)x, y = cv2.polarToCart(r, theta, True)for i in range(H):for j in range(W):px = int(round(x[i, j]) + cx)py = int(round(y[i, j]) + cy)if (px >= 0 and px <= W - 1) and (py >= 0 and px <= H - 1):out[i, j] = img[px, py]return outif __name__ == "__main__":img = np.zeros([300, 300, ], np.uint8)img = cv2.circle(img, (150, 150), 80, (255), -1)plt.imshow(img, 'gray')o = polar(img, center=(150, 150), r=(0, 100), theta=(0, 360), rstep=0.25)plt.imshow(o, 'gray')
/*
根据中心(cx,cy)、最小半径、最小角度、半径步长、角度步长获取最大半径和最大步长,把r、theta转换成x,y。把(x,y)对应的像素值赋值给对应坐标(r、theta)。
*/
Mat polar(Mat I,Point2f center,Size size,float minr = 0,float mintheta=0,float thetaStep = 1.0/4,float rStep;=1.0)
{// 构建 r[size.height,size.width]Mat ri = Mat::zeroes(Size(1,size.height),CV_32FC1);for (int i = 0;i <size.height;++i){ri.at<float>(i,0) = minr+i*rStep;}Mat r = repeat(ri,1,size.width);// 构建 theta[size.height,size.width]Mat thetaj = Mat::zeroes(Size(size.width,1),CV_32FC1);for (int j = 0;j <size.width;++j){thetaj.at<float>(0,j) = mintheta+j*thetaStep;}Mat theta = repeat(thetaj,size.height,1// 把极坐标转换为笛卡尔坐标Mat x,y;polarToCart(r,theta,x,y,true);x += center.x;y += center.y;// 最近邻插值Mat dst = 125*Mat::ones(size,CV_8UC1);for (int i=0;i<size.height,++i){for (int j=0;j<size.width,++j){float xij = x.at<float>(i,j);float yij = y.at<float>(i,j);int x_near = int(round(xij));int y_near = int(round(yij));}if((x_near>=0&&x_near<=I.cols)&&(y_near>=0&&y_near<=I.rows)){dst.at<uchar>(i,j)=I.at<uchar>(y_near,x_near)}}return dst;
}int main(int argc,char*argv[])
{Mat I = imread(argv[1],CV_LOAD_IMAGE_GRAYSCALE);if(!I.data)return -1;float thetaStep=1.0/4;float minr = 270;Size size(int(360/thetaStep),80);Mat dst = polar(I,Point2f(500,508),size,minr);flip(dst,dst,0);
}
2.3.4 线性极坐标函数
/*
void linearPolar( InputArray src, OutputArray dst,Point2f center, double
maxRadius, int flags );
src :输入图像矩阵(单、多通道矩阵都可以)
dst :输出图像矩阵,其尺寸和 src 是相同的
center :极坐标变换中心
maxRadius :极坐标变换的最大距离
flags :插值算法,同函数 resize、warpAffine 的插值算法
角度 𝜃 的变换步长大约为 36/0𝐻
,𝑟 的变换步长大约为 maxRadius/𝑊
;
*/
#include<opencv2/core.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char*argv[])
{//输入图像Mat src = imread(argv[1], IMREAD_ANYCOLOR);if (!src.data)return -1;//极坐标变换Mat dst;linearPolar(src, dst, Point2f(508, 503), 550, CV_INTER_LINEAR);//显示原图和极坐标变换图imshow("原图", src);imshow("极坐标变换图", dst);waitKey(0);return 0;
}
2.3.5 对数极坐标函数 logPolar
/*
void logPolar(InputArray src,OutputArray dst,Point2f center, double M, int
flags )
src: 输入图像矩阵(单、多通道矩阵都可以)
dst: 输出图像矩阵,其尺寸和 src 是相同的
center: 极坐标变换中心
M: 系数,该值大一点效果会好一些
flags:
WARP_FILL_OUTLIERS:笛卡儿坐标向对数极坐标变换
WARP_INVERSE_MAP:对数极坐标向笛卡儿坐标变换笛卡儿坐标转换为对数极坐
标:
r = M*log(((x-cx)**2+(y-cy)**2)**0.5)
theta = actan2(y-cy,x-cx); if y>cy,theta=theta else theta+=2*pi
将对数极坐标转换为笛卡儿坐标:
x = cx+exp(r/M)cosa;y = cy+exp(r/M)sina
*/
int main(int argc, char*argv[])
{//读入图像Mat src = imread(argv[1], IMREAD_ANYCOLOR);//对数极坐标变换Mat dst;Point2f center(508, 503);float M = 100;logPolar(src, dst, center, M, WARP_FILL_OUTLIERS);//显示对数极坐标变换的结果imshow("对数极坐标变换", dst);imshow("原图", src);waitKey(0);return 0;
}