Q:平移
在相同大小的范围内,原图像上下左右移动。
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include"iostream"
#include"math.h"
using namespace cv;
using namespace std;
Mat Affine_Translation(Mat img,double mx,double my)//向上向右为正,向下向左为负
{
Mat out=Mat::zeros(img.rows,img.cols,CV_8UC3);
double i_m,j_m;
for(int i=0;i<img.rows;i++)
{
for(int j=0;j<img.cols;j++)
{
i_m=(int)(i+my);
if(i_m<0||i_m>=img.rows)
continue;
j_m=(int)(j-mx);
if(j_m<0||j_m>=img.cols)
continue;
for(int k=0;k<img.channels();k++)
{
out.at<Vec3b>(i,j)[k]=img.at<Vec3b>(i_m,j_m)[k];
}
}
}
return out;
}
void main()
{
Mat img = imread("ck567.jpg");
imshow("orignal jpg",img);
Mat out = Affine_Translation(img,100,100);
imshow("Affine_Translation",out);
waitKey(0);
destroyAllWindows();
}
效果如下
Q:缩放加平移
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include"iostream"
#include"math.h"
using namespace cv;
using namespace std;
Mat Affine(Mat img,double dx,double dy,double mx,double my)//向上向右为正,向下向左为负
{
int h=img.rows*dx;
int w=img.cols*dy;
Mat out=Mat::zeros(h,w,CV_8UC3);
double i_b,j_b,x,y,mi,mj;
for(int i=0;i<h;i++)
{
i_b=(int)(i/dx);
x=min((int)i_b,img.rows-1);
mi=(int)(x+mx);
if(mi<0||mi>=img.rows)
continue;
for(int j=0;j<w;j++)
{
j_b=(int)(j/dy);
y=min((int)j_b,img.cols-1);
mj=(int)(y-my);
if(mj<0||mj>=img.cols)
continue;
for(int k=0;k<img.channels();k++)
{
out.at<Vec3b>(i,j)[k]=img.at<Vec3b>((int)mi,(int)mj)[k];
}
}
}
return out;
}
void main()
{
Mat img = imread("ck567.jpg");
imshow("orignal jpg",img);
Mat out = Affine(img,1.5,0.8,50,50);
imshow("Affine",out);
waitKey(0);
destroyAllWindows();
}
效果如下
仿射系列的操作不再是对于像素点单独赋值处理,而是通过矩阵运算得到响亮的结果,在统一赋值。
以下从旋转和倾斜来应用
旋转矩阵
初始化的tx和ty为0,在程序的中心定位那里,用变化前后的差值来赋给tx,ty。因为矩阵中用abcd来表示sin和cos函数且其他数值非0即1,是固定的,所以就直接在程序内部定义,没有当做调用函数的参数。
倾斜矩阵
关系式中的h和w是原图像的尺寸,在程序中还是用abcd来表示变换矩阵左上方的四个数值,关系式中都是用a表示,但在程序中在x方向和y方向的变换矩阵中分别由a和c表示,tx和ty都是0。
其中x撇y撇表示要生成图像的像素值,xy表示原图像的像素值,原图像已知,所以将上述的矩阵反过来求得xy,将已知的值带入程序赋值像素值。在运算的过程中要用到线性代数中矩阵的逆。具体体现在程序中det=ad-bc,(d * cx - b * cy) / det,
(- c * cx + a * cy) / det,这几行代码就是求得矩阵的逆。原型如下
Q:旋转
仿射旋转代码如下
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include"iostream"
#include"math.h"
#include <iostream>
#define M_PI 3.1415926
using namespace cv;
using namespace std;
Mat affine(Mat img,double theta)
{
Mat out=Mat::zeros(img.rows,img.cols,CV_8UC3);
if(theta==0)
out=img;
else
{
double rad=theta / 180. * M_PI;
double a = cos(rad);
double b = -sin(rad);
double c = sin(rad);
double d = cos(rad);
double det = a * d - b * c;
double cx = img.cols / 2.;
double cy = img.rows / 2.;
double new_cx = (d * cx - b * cy) / det;
double new_cy = (- c * cx + a * cy) / det;
double tx = new_cx - cx;
double ty = new_cy - cy;
int i_b,j_b;
for(int i=0;i<img.rows;i++)
{
for(int j=0;j<img.cols;j++)
{
j_b=(int)((d*j-b*i)/det-tx);
if(j_b<0||j_b>=img.cols)
continue;
i_b=(int)((-c*j+a*i)/det-ty);
if(i_b<0||i_b>=img.rows)
continue;
for(int k=0;k<img.channels();k++)
{
out.at<Vec3b>(i,j)[k] = img.at<Vec3b>(i_b, j_b)[k];
}
}
}
}
return out;
}
void main()
{
Mat img = cv::imread("ck567.jpg");
Mat out = affine(img,30);
imshow("img",img);
imshow("affine", out);
waitKey(0);
destroyAllWindows();
}
效果如下
Q:倾斜
x方向和y方向同时倾斜80度
代码如下
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include"iostream"
#include"math.h"
#include <iostream>
using namespace cv;
using namespace std;
Mat affine(Mat img,double dx,double dy)
{
int width = (int)(img.cols + dx);
int height = (int)(img.rows + dy);
Mat out=Mat::zeros(height,width, CV_8UC3);
double a = 1;
double b = 0;
double c = 0;
double d = 1;
if (dx != 0)
b = dx / img.rows;
if (dy != 0)
c = dy / img.cols;
double det = a * d - b * c;
int i_b,j_b;
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
j_b=(int)((d*j-b*i)/det);
if(j_b<0||j_b>=img.cols)
continue;
i_b=(int)((-c*j+a*i)/det);
if(i_b<0||i_b>=img.rows)
continue;
for(int k=0;k<img.channels();k++)
{
out.at<Vec3b>(i,j)[k] = img.at<Vec3b>(i_b, j_b)[k];
}
}
}
return out;
}
void main()
{
Mat img = cv::imread("ck567.jpg");
Mat out = affine(img,80,80);
imshow("img",img);
imshow("affine", out);
waitKey(0);
destroyAllWindows();
}
效果如下