图像旋转--矩阵变换

一,求点(x1, y1)关于点(x0, y0)逆时针旋转a度后的坐标

1、首先可以将问题简化,先算点(x1, y1)关于源点逆时针旋转a度后的坐标,求出之后加上x0,y0即可。

2、关于源点旋转,用极坐标表示

设x1 = Rcos(θ), y1 = Rsin(θ),绕源点逆时针旋转β度后得到坐标(x2, y2)等于(Rcos(θ + β) , Rsin(θ + β))

3、展开(Rcos(θ + β) , Rsin(θ + β))

变成 x2 = Rcos(θ)cos(β) - Rsin(θ)sin(β)   y2 = Rsin(θ)cos(β) + Rcos(θ)sin(β)

结合上面的x1 = Rcos(θ), y1 = Rsin(θ)

得到:x2 = x1cos(β) - y1sin(β)     y2 = x1sin(β) + y1cos(β)

而对于从θ处回到轴处,最好用

x2 = x1cos(β) +y1sin(β)     y2 = -x1sin(β) + y1cos(β)

二,利用opencv fit一条直线。判断夹角,对图片里的轮廓旋转

path = './data/sichuan_pig_mistake_label/2018-9-14IMG_8057.JPG'
image=cv2.imread(path,cv2.IMREAD_GRAYSCALE)
img_size = cv2.resize(image, (500, 300))

height, width = img_size.shape[:2]
image_thre = cv2.threshold(img_size, 127, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(image_thre, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
c = sorted(cnts, key=cv2.contourArea, reverse=True)
c = np.squeeze(c[0])
plt.plot(c[:, 0], c[:, 1])
plt.show()
#vy/vx代表斜率  x, y是直线上的任意一点
[vx, vy, x, y] = cv2.fitLine(c, cv2.DIST_L2, 0, 0.01, 0.01)
#y=k*x+b  b=-k*x1+y1
b = int((-x * vy / vx) + y)
#y=k*(cols-1)+b=(cols-1-x1)*k+y1
righty = int(((width- 1-x) * vy / vx) + y)
plt.plot(c[:, 0], c[:, 1])
plt.plot((0,width-1),(b,righty))
plt.show()

# print('vy',vy)
# print('vx',vx)
#对轮廓的点进行矩阵变换
print('theta=',np.arctan(vy/vx)*180/math.pi)
theta=np.arctan(vy/vx)[0]
rotate = np.array([[math.cos(theta), math.sin(theta)], [-math.sin(theta), math.cos(theta)]])
#显示变换过的轮廓
rotate_c = np.dot(c, rotate)
plt.plot(rotate_c[:,0],rotate_c[:,1])
plt.show()

可看出,并未做平移,出了第一象限坐标。

旋转矩阵简介,来源以下链接:

https://www.cnblogs.com/zhoug2020/p/7842808.html

计算机图形学中的应用非常广泛的变换是一种称为仿射变换的特殊变换,在仿射变换中的基本变换包括平移、旋转、缩放、剪切这几种。本文以及接下来的几篇文章重点介绍一下关于旋转的变换,包括二维旋转变换、三维旋转变换以及它的一些表达方式(旋转矩阵、四元数、欧拉角等)。

2. 绕原点二维旋转

首先要明确旋转在二维中是绕着某一个点进行旋转,三维中是绕着某一个轴进行旋转。二维旋转中最简单的场景是绕着坐标原点进行的旋转,如下图所示:

 

如图所示点v 绕 原点旋转θ 角,得到点v’,假设 v点的坐标是(x, y) ,那么可以推导得到 v’点的坐标(x’, y’)(设原点到v的距离是r,原点到v点的向量与x轴的夹角是ϕ ) 
x=rcosϕy=rsinϕ 
x′=rcos(θ+ϕ)y′=rsin(θ+ϕ
通过三角函数展开得到 
x′=rcosθcosϕrsinθsinϕ 
y′=rsinθcosϕ+rcosθsinϕ 
带入x和y表达式得到 
x′=xcosθysinθ 
y′=xsinθ+ycosθ 
写成矩阵的形式是:

 

尽管图示中仅仅表示的是旋转一个锐角θ的情形,但是我们推导中使用的是三角函数的基本定义来计算坐标的,因此当旋转的角度是任意角度(例如大于180度,导致v’点进入到第四象限)结论仍然是成立的。

3. 绕任意点的二维旋转

绕原点的旋转是二维旋转最基本的情况,当我们需要进行绕任意点旋转时,我们可以把这种情况转换到绕原点的旋转,思路如下: 
1. 首先将旋转点移动到原点处 
2. 执行如2所描述的绕原点的旋转 
3. 再将旋转点移回到原来的位置

 

也就是说在处理绕任意点旋转的情况下需要执行两次平移的操作。假设平移的矩阵是T(x,y),也就是说我们需要得到的坐标 v’=T(x,y)*R*T(-x,-y)(我们使用的是列坐标描述点的坐标,因此是左乘,首先执行T(-x,-y))

在计算机图形学中,为了统一将平移、旋转、缩放等用矩阵表示,需要引入齐次坐标。(假设使用2x2的矩阵,是没有办法描述平移操作的,只有引入3x3矩阵形式,才能统一描述二维中的平移、旋转、缩放操作。同理必须使用4x4的矩阵才能统一描述三维的变换)。

对于二维平移,如下图所示,P点经过x和y方向的平移到P’点,可以得到:

 

x′=x+tx

y′=y+ty 
由于引入了齐次坐标,在描述二维坐标的时候,使用(x,y,w)的方式(一般w=1),于是可以写成下面矩阵的形式


按矩阵乘法展开,正好得到上面的表达式。也就是说平移矩阵是

 

如果平移值是(-tx,-ty)那么很明显平移矩阵式

 

我们可以把2中描述的旋转矩阵也扩展到3x3的方式,变为:

 


从平移和旋转的矩阵可以看出,3x3矩阵的前2x2部分是和旋转相关的,第三列与平移相关。有了上面的基础之后,我们很容易得出二维中绕任意点旋转的旋转矩阵了,只需要把三个矩阵乘起来即可:
 

对于代码:

path = './data/2018-9-14IMG_8057.JPG'
img_size = cv2.imread(path, cv2.IMREAD_GRAYSCALE)

black=np.zeros([img_size.shape[0],img_size.shape[1]])
#二值化找轮廓
image_thre = cv2.threshold(img_size, 127, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(image_thre, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = cnts[0] if imutils.is_cv2() else cnts[1]
c_ = sorted(contours, key=cv2.contourArea, reverse=True)

c = np.squeeze(c_[0])
one=np.ones(shape=(c.shape[0],1))
#构建输入矩阵
mat_c=np.hstack((c,one))
# vy/vx代表斜率  x, y是直线上的任意一点
[vx, vy, x, y] = cv2.fitLine(c, cv2.DIST_L2, 0, 0.01, 0.01)
#求旋转角
theta = np.arctan(vy / vx)[0]
print('theta=',theta)
#旋转矩阵
rotate = np.array([[math.cos(theta), -math.sin(theta),0],
                       [math.sin(theta), math.cos(theta),0],
                       [0,0,1]])
rotate_c = np.dot(mat_c, rotate)
print(rotate_c)
#平移量
tx =abs(np.min(rotate_c[:,0],axis=0)) if np.min(rotate_c[:,0],axis=0)<0 else 0
print(tx)

ty =abs(np.min(rotate_c[:,1],axis=0)) if np.min(rotate_c[:,1],axis=0)<0 else 0
print(ty)
#平移矩阵
mobile=np.array([[1,0,0],
                 [0,1,0],
                 [tx,ty,1]])
contour_list=[]
rotate_c=np.dot(rotate_c,mobile)
print(rotate_c[100:110])

rotate_c=rotate_c[:,:2]
rotate_c=rotate_c[:,np.newaxis,:].astype(int)
print(rotate_c.shape)
print('====================')
contour_list.append(rotate_c)
# print(a)
black=cv2.drawContours(black, contour_list, -1, (255, 255, 255), thickness=-1)
cv2.imwrite('./data/3.jpg',black)
cv2.waitKey(0)

猜你喜欢

转载自blog.csdn.net/fanzonghao/article/details/82981560