旋转图片相关内容
背景
1、做带角度的图像数据增强,一般使用rotate函数就可以,不过有时图片部分角就会旋转出去,如果不丢失信息,且补边呢?
2、如果标注的label是一个矩形,如果旋转后,想让label也跟着旋转,怎么计算
旋转理论
旋转图片一般用到了仿射变换,仿射变换的原理可以从几何理解,也可以从极坐标方式理解,具体计算方式就是矩阵相乘
OpenCV旋转操作及原理
OpenCV的方法是cv2.getRotationMatrix2D()方法,调用如下:
# 你是在
matRotate2 = cv2.getRotationMatrix2D((0, 0),30, 1.0)
print(matRotate2)
#output
[[ 0.8660254 0.5 -0.1830127]
[-0.5 0.8660254 0.3169873]]
其中这个函数的源码如下:
cv::Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )
{
angle *= CV_PI/180;
double alpha = cos(angle)*scale;
double beta = sin(angle)*scale;
Mat M(2, 3, CV_64F);
double* m = (double*)M.data;
m[0] = alpha;
m[1] = beta;
m[2] = (1-alpha)*center.x - beta*center.y;
m[3] = -beta;
m[4] = alpha;
m[5] = beta*center.x + (1-alpha)*center.y;
return M;
}
}
代码参考的公式为1
那这个公式是怎么推导的呢,原理是将旋转轴心转移到坐标中心点,旋转后,再放回原来位置2
旋转图像及标注框
基本操作就是所有的像素点与之变换矩阵相乘,标签与之相乘,具体代码详解参考了图像增强3,新的宽高计算入下图4
图像旋转代码如下4:
def rotate_box(bb, cx, cy, h, w):
new_bb = list(bb)
for i,coord in enumerate(bb):
# opencv calculates standard transformation matrix
M = cv2.getRotationMatrix2D((cx, cy), theta, 1.0)
# Grab the rotation components of the matrix)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cx
M[1, 2] += (nH / 2) - cy
# Prepare the vector to be transformed
v = [coord[0],coord[1],1]
# Perform the actual rotation and return the image
calculated = np.dot(M,v)
new_bb[i] = (calculated[0],calculated[1])
return new_bb
点的转换模型如下:
def rotate_box(bb, cx, cy, h, w):
new_bb = list(bb)
for i,coord in enumerate(bb):
# opencv calculates standard transformation matrix
M = cv2.getRotationMatrix2D((cx, cy), theta, 1.0)
# Grab the rotation components of the matrix)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cx
M[1, 2] += (nH / 2) - cy
# Prepare the vector to be transformed
v = [coord[0],coord[1],1]
# Perform the actual rotation and return the image
calculated = np.dot(M,v)
new_bb[i] = (calculated[0],calculated[1])
return new_bb
效果图如下
附代码,基本参考是Image rotation using OpenCV
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
File Name: a6_rotate_with_box.py
Description :
Author : lj_tal
date: 2020/12/26
-------------------------------------------------
"""
import cv2
import numpy as np
def cocoBbox2Point4(coco_bbox):
xmin = coco_bbox[0]
ymin = coco_bbox[1]
xmax = coco_bbox[2]
ymax = coco_bbox[3]
points = np.array([[xmin, ymax], [xmin, ymin], [xmax, ymin], [xmax, ymax]], dtype=np.int).reshape(4, 2)
return points
def point42CocoBbox(bbox_numpy):
bbox_temp = bbox_numpy.reshape(4,2)
xmin = np.min(bbox_temp[:,0])
xmax = np.max(bbox_temp[:,0])
ymin = np.min(bbox_temp[:,1])
ymax = np.max(bbox_temp[:,1])
# print([xmin,ymin,xmax,ymax])
return np.array([xmin,ymin,xmax,ymax]).astype(np.int)
# point2 = point42CocoBbox(points)
point4 = np.asarray([35 , 50, 175, 215])
print(point4)
def rotate_bound(image, angle):
# grab the dimensions of the image and then determine the
# center
(h, w) = image.shape[:2]
(cX, cY) = (w // 2, h // 2)
# grab the rotation matrix (applying the negative of the
# angle to rotate clockwise), then grab the sine and cosine
# (i.e., the rotation components of the matrix)
M = cv2.getRotationMatrix2D((cX, cY), angle, 1.0)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cX
M[1, 2] += (nH / 2) - cY
# perform the actual rotation and return the image
return cv2.warpAffine(image, M, (nW, nH))
def rotate_box(bb, cx, cy, h, w,angle):
new_bb = list(bb)
for i,coord in enumerate(bb):
# opencv calculates standard transformation matrix
M = cv2.getRotationMatrix2D((cx, cy), angle, 1.0)
# Grab the rotation components of the matrix)
cos = np.abs(M[0, 0])
sin = np.abs(M[0, 1])
# compute the new bounding dimensions of the image
nW = int((h * sin) + (w * cos))
nH = int((h * cos) + (w * sin))
# adjust the rotation matrix to take into account translation
M[0, 2] += (nW / 2) - cx
M[1, 2] += (nH / 2) - cy
# Prepare the vector to be transformed
v = [coord[0],coord[1],1]
# Perform the actual rotation and return the image
calculated = np.dot(M,v)
new_bb[i] = [calculated[0],calculated[1]]
return new_bb
if __name__ == '__main__':
img = cv2.imread('cat.jpg')
print(img.shape)
theta = 20
point8_list = np.asarray([[[776.9486798180992, 383.9884930278827], [881.0203274611703, 380.39981552294927], [884.6090049661037, 498.8261731857542], [780.5373573230327, 498.8261731857542]],
[[897.1693762333709, 534.712948235089], [999.4466851239752, 538.3016257400226], [1003.0353626289086, 653.139305897894], [900.7580537383044, 653.139305897894]],
[[1279.3635305087869, 111.24900265293799], [1293.718240528521, 805.6580998575671], [624.4298858584261, 787.7147123328997], [628.0185633633596, 113.04334140540473]]])
rotated_img = rotate_bound(img,theta)
a_img = img.copy()
for point8 in point8_list:
point4 = point42CocoBbox(point8)
cv2.rectangle(a_img, (point4[0], point4[1]), (point4[2], point4[3]), (255, 0, 0), 1)
#
cv2.imshow('aa',a_img)
cv2.imwrite('cat_a.jpg',a_img)
cv2.waitKey(0)
# Calculate the shape of rotated images
(heigth, width) = img.shape[:2]
(cx, cy) = (width // 2, heigth // 2)
(new_height, new_width) = rotated_img.shape[:2]
(new_cx, new_cy) = (new_width // 2, new_height // 2)
print(cx,cy,new_cx,new_cy)
new_bb = {}
for points8 in point8_list:
points8_rotate= rotate_box(points8, cx, cy, heigth, width,theta)
points8_rotate = np.asarray(points8_rotate).astype(np.int)
print(points8_rotate)
points8_rotate = points8_rotate.reshape((-1, 1, 2))
new_image = cv2.polylines(rotated_img, [points8_rotate], True, (255, 0, 0), 1)
cv2.imwrite('cat_b.jpg',new_image)
cv2.imshow('bb',new_image)
cv2.waitKey(0)
参考
-
https://blog.csdn.net/u011681952/article/details/98942207 ↩︎
-
https://math.stackexchange.com/questions/2093314/rotation-matrix-of-rotation-around-a-point-other-than-the-origin ↩︎
-
https://blog.paperspace.com/data-augmentation-for-object-detection-rotation-and-shearing/ ↩︎
-
https://cristianpb.github.io/blog/image-rotation-opencv ↩︎ ↩︎