??在圖片處理中,經(jīng)常會(huì)遇到點(diǎn)的旋轉(zhuǎn)和坐標(biāo)系的旋轉(zhuǎn)問(wèn)題,這里對(duì)一個(gè)點(diǎn)(x, y)繞另一個(gè)點(diǎn)(x0, y0)旋轉(zhuǎn)的問(wèn)題做一個(gè)總結(jié)。
??一、在介紹之前,先總結(jié)一下編程的問(wèn)題,因?yàn)樵趯?shí)現(xiàn)的過(guò)程中碰到了一些坑:
??(1)c++中,三角函數(shù)的輸入和反三角函數(shù)的輸出都是:弧度。
??(2)opencv中涉及的都是角度,比如旋轉(zhuǎn)矩形的角度、仿射變換時(shí)旋轉(zhuǎn)圖片的角度。
??二、假設(shè)有兩個(gè)點(diǎn),一個(gè)點(diǎn)為p(x, y),另一個(gè)點(diǎn)為p0(x0, y0)。讓點(diǎn)p繞著點(diǎn)p0旋轉(zhuǎn)α(角度或者弧度都可以),求旋轉(zhuǎn)之后點(diǎn)的坐標(biāo)p1(x1, y1)。我們可以分成三個(gè)步驟來(lái)完成:(1)先將原點(diǎn)移動(dòng)到旋轉(zhuǎn)中心。(2)讓p0圍繞原點(diǎn)旋轉(zhuǎn)α。(3)移回坐標(biāo)原點(diǎn)。
??1、將原點(diǎn)移動(dòng)到旋轉(zhuǎn)中心p0處。那么點(diǎn)p0在新坐標(biāo)系中的坐標(biāo)為:(0, 0),點(diǎn)p1在新坐標(biāo)系中的坐標(biāo)為:(x - x0, y- y0)。
??2、將點(diǎn)(x - x0, y- y0)繞著原點(diǎn)旋轉(zhuǎn)角度α,將旋轉(zhuǎn)之后點(diǎn)的坐標(biāo)記為p2(x2, y2)。那么:
????x2 = (x - x0) * cosα + (y - y0) * sinα, ????y2 = -(x - x0) * sinα + (y - y0) * cosα
??3、將坐標(biāo)原點(diǎn)移回到原來(lái)的位置,那么可以根據(jù)點(diǎn)p2得到我們最終的結(jié)果p1(x1, y1)。即:
????x2 = (x - x0) * cosα + (y - y0) * sinα + x0, ??y2 = -(x - x0) * sinα + (y - y0) * cosα + y0
??三、應(yīng)用舉例
??圖片中有一條線段,線段L的兩個(gè)頂點(diǎn)分別為:p1(x1, y1),p2(x2, y3)。我們的目標(biāo)是將L旋轉(zhuǎn)為水平,旋轉(zhuǎn)之后的線段記為L',L'的兩個(gè)頂點(diǎn)分別為p3(x3, y3),p4(x4, y4),其中p3和p1對(duì)應(yīng),p4和p2對(duì)應(yīng),我們需要計(jì)算旋轉(zhuǎn)之后的點(diǎn)p3和p4的坐標(biāo)。
??實(shí)現(xiàn)代碼如下:
void point_rotate() {
// 得到一張空白的灰度圖
Mat image = Mat::zeros(Size(500, 500), CV_8UC1);
float x0 = image.cols / 2;
float y0 = image.rows / 2;
// 初始化兩個(gè)點(diǎn), p1和p2
Point p1 = Point(100, 100);
Point p2 = Point(200, 120);
//分別得到兩個(gè)點(diǎn)的坐標(biāo)
float x1 = p1.x;
float y1 = p1.y;
float x2 = p2.x;
float y2 = p2.y;
//在圖上畫(huà)出兩個(gè)點(diǎn),以及兩個(gè)點(diǎn)連成的線L
circle(image, p1, 3, Scalar(255), -1);
circle(image, p2, 3, Scalar(255), -1);
line(image, p1, p2, Scalar(255));
// 計(jì)算L的偏轉(zhuǎn)角度
float angle = atan((y2 - y1) / (x2 - x1)); //注意:這里得到的是弧度
//以rotate_angle角度來(lái)旋轉(zhuǎn)圖片m,注意,opencv中的都是角度,所以這里需要把弧度轉(zhuǎn)化為角度
// 旋轉(zhuǎn)的時(shí)候也需要注意,opencv中,負(fù)角度指的是順時(shí)針
Mat rotate_img;
float rotate_angle = angle * 180 / 3.14159265358979323846;
Mat m = getRotationMatrix2D(Point2f(x0, y0), rotate_angle, 1);
warpAffine(image, rotate_img, m, Size(image.cols, image.rows), 1, 0, 255);
//計(jì)算p1在新圖片中對(duì)應(yīng)的坐標(biāo)p3
float x3 = (x1 - x0) * cos(angle) + (y1 - y0) * sin(angle) + x0;
float y3 = -(x1 - x0) * sin(angle) + (y1 - y0) * cos(angle) + y0;
Point p3 = Point(int(x3), int(y3));
//計(jì)算p2在新圖片中對(duì)應(yīng)的坐標(biāo)p4
float x4 = (x2 - x0) * cos(angle) + (y2 - y0) * sin(angle) + x0;
float y4 = -(x2 - x0) * sin(angle) + (y2 - y0) * cos(angle) + y0;
Point p4 = Point(int(x4), int(y4));
//在旋轉(zhuǎn)之后的圖片中畫(huà)出點(diǎn)p1, p2, p3, p4, 以及p1和p2的連線L,p3和p4的連線L'
circle(rotate_img, p1, 3, Scalar(255), -1);
circle(rotate_img, p2, 3, Scalar(255), -1);
line(rotate_img, p1, p2, Scalar(255));
circle(rotate_img, p3, 3, Scalar(255), -1);
circle(rotate_img, p4, 3, Scalar(255), -1);
line(rotate_img, p3, p4, Scalar(255));
//標(biāo)識(shí)每個(gè)點(diǎn)的位置
putText(rotate_img, "p1", p1, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
putText(rotate_img, "p2", p2, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
putText(rotate_img, "p3", p3, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
putText(rotate_img, "p4", p4, FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
//畫(huà)出旋轉(zhuǎn)中心,以及p1,p3分別和旋轉(zhuǎn)中心的連線
Point center = Point(x0, y0);
circle(rotate_img, center, 3, Scalar(255), -1);
line(rotate_img, p1, center, Scalar(255));
line(rotate_img, p3, center, Scalar(255));
//沿著p1點(diǎn)畫(huà)一條水平基準(zhǔn)線
line(rotate_img, Point(0, 100), Point(rotate_img.cols, 100), Scalar(255));
// 保存圖片image, rotate_img
imwrite("E:\\image.bmp", image);
imwrite("E:\\rotate_img.bmp", rotate_img);
}
??結(jié)果如下圖所示:

??在上圖的角度標(biāo)識(shí)中,角度1為:計(jì)算出的線段L的角度;角度2為:圖片旋轉(zhuǎn)的角度;角度3為:點(diǎn)p1旋轉(zhuǎn)的角度。從視覺(jué)效果上來(lái)看,這三個(gè)角度應(yīng)該是一致的。