投影变换##
在放射变换中,物体是在⼆维空间中变换的。如果物体在三维空间中发⽣了旋转,那么这种变换就成为投影变换,在投影变换中就会出现阴影或者遮挡,我们可以运⽤⼆维投影对三维投影变换进⾏模块化,来处理阴影或者遮挡。在OpenCV中有类似于getAffineTransform函数:getPerspectiveTransform(src,dst)函数 ⽤来处理计算投影变换矩阵。与getAffineTransform函数不同的是传⼊的参数是三维空间坐标系的空间坐标,也就是4*2的⼆维ndarray,其中每⼀⾏代表⼀个坐标并且传⼊的数据类型必须为float32.⽰例:
import cv2
import numpy as np
src=np.array([[0,0],[100,0],[0,100],[100,100]],np.float32)dst=np.array([[100,10],[100,10],[50,70],[200,150]],np.float32)P=cv2.getPerspectiveTransform(src,dst)print(P)
运⾏结果:
[[-7.77156117e-16 -1.00000000e+00 1.00000000e+02] [-2.77555756e-15 -1.00000000e-01 1.00000000e+01] [-2.66713734e-17 -1.00000000e-02 1.00000000e+00]]
由结果可以看出当前输出的类型是float.对于仿射变换在OpenCV中提供了如下的函数
cv2.warpPerspective(src,M,dsize[,dst[,flags[,borderMode[,borderValue]]]])
输⼊的矩阵类型是3⾏3列的投影变换矩阵。⽰例:
import cv2
import numpy as npimport matplotlib
def Perspect(path):
img=cv2.imread(path,cv2.IMREAD_GRAYSCALE) if not isinstance(img, np.ndarray): print('PASS') pass else:
h,w=img.shape #设置变换坐标变化
src=np.array([[0,0],[w-1,0],[0,h-1],[w-1,h-1]],np.float32)
dst=np.array([[100,100],[w/3,100],[100,h-1],[w-1,h-1]],np.float32) #计算投影变换矩阵
P=cv2.getPerspectiveTransform(src,dst) #利⽤变化矩阵进⾏投影变换
r=cv2.warpPerspective(img,P,(w,h),borderValue=126) #显⽰图像
cv2.imshow('A',img ) cv2.imshow('B',r) cv2.waitKey(0)
cv2.destroyAllWindows() print(P)
Perspect('img/aa.jpg')
极坐标变换##
极坐标变换主要处理校正图像中的圆形物体或者在圆形中物体
\\(r=\\sqrt{(x-(\\overline{x})^2)+(y-(\\overline{y})^2)}\\)
\\[\heta= \\left\\{ \\begin{matrix} 2\\pi +arctan2(y-\\overline{y},x-\\overline{x}), &y-\\overline{y}\\leq0\\\\ arctan2(y-\\overline{y},x-\\overline{x},&y-\\overline{y}>0 \\end{matrix} \\right\\} \\]以变换中⼼为圆⼼的同⼀个圆⼼上的点,在极坐标系\\(\heta\\)or中显⽰为⼀条直线。其中\\(\heta\\)的取值范围为[0,2\\(\\pi\\)],函数arctan2返回的⾓度和笛卡尔积坐标点所在的象限有关系。举例,(9,15)以(2,10)为中⼼进⾏极坐标的变换,⽰例代码:
#半径转换
r=math.sqrt(math.pow(9-2,2)+math.pow(15-10,2));#⾓度转换
theta=math.atan2(15-10,9-2)/math.pi*180
该⽰例可以这样理解,先把坐标原点移动到(2,10)处,则(9,15)平移后的坐标变为(7,5),然后再以(0,0)为中⼼进⾏转换。在OpenCV中的函数cartToPolar(x,y[,magnitude[,angle[,angleIndegress
]]])实现的就是将原点移动到变换中⼼后的笛卡尔积坐标向极坐标的变换,返回值magnitude,angle是与参数x,y具有相同尺⼨和数据类型的ndarray。
angleInDegrees的值为True时,返回值为⾓度,反之返回值为弧度。
例如:计算(0,0)、(1,0)、(2,0)、(0,1)、(1,1)、(2,1)、(0,2)、(1,2)、(2,2)这九个点以(1,1)为中⼼进⾏的坐标转换。⾸先将坐标原点
移动到(1,1)处,按照平移放射矩阵计算出这九个点平移后的新坐标值,然后利⽤函数cartToPolar进⾏极坐标的转换。代码表⽰为:
import cv2
import numpy as np
x=np.array([[0,1,2],[0,1,2],[0,1,2]],np.float)-1y=np.array([[0,0,0],[1,1,1],[2,2,2]],np.float)-1r,theta = cv2.cartToPolar(x,y,angleInDegrees=True)print(\"r: %s\"%r)print(\"theta: %s\"%theta)
运⾏结果:
可以看到执⾏后的极坐标(\\(\heta\\),r)
以上九个点的图像表⽰就是以(1,1)为圆⼼的九个点,距离变换中⼼相等的点转换为极坐标后在极坐标系中位于同⼀条直线上。这样就直观的给出了极坐标变换是如何校正图像中的圆形物体或者圆环中的物体的。
极坐标的变换是可逆的,在已知极坐标和笛卡⼉坐标的条件下,计算哪个笛卡⼉坐标以(\\(\\overline{x}\\),\\(\\overline{y}\\))为中⼼的极坐标变换时(\\(\heta\\),r),计算公式为:\\[x= \\overline{x}+rcos\heta, y=\\overline{y}+rsin\heta \\]
在OpenCV中的实现函数是 cv2.polarToCart(magnitude,angle[,x[, y[, angleInDegrees ]]] )来实现将极坐标转化为笛卡尔坐标。其参数与cartToPolar参数类似。代码举例 实现 根据极坐标系的(30,20),(31,21),(30,10),(30,10)四个点计算迪卡⼉坐标系的哪四个点以(-6,6)为中⼼变换得到的。
import cv2
import numpy as np
# 将迪卡⼉坐标转换为极坐标
angle = np.array([[30, 31], [30, 30]], np.float32)r = np.array([[20, 21], [10, 10]], np.float32)
x, y = cv2.polarToCart(r, angle, angleInDegrees=True)print(\"变换中⼼为(0,0) 得到的四个迪卡⼉坐标\")print(\"x: %s\" % x)print(\"y: %s\" % y)x+=-6y+=6
print(\"变换中⼼为(-6,6) 得到的四个迪卡⼉坐标\")print(\"x: %s\" % x)print(\"y: %s\" % y)
运⾏结果:
我们利⽤极坐标和迪卡⼉坐标的意义对应关系得到O的每⼀个像素值:\\[O(r,\heta)=f_{1}( \\overline{x}+rcos\heta,\\overline{y}+rsin\heta) \\]
此公式中的图像输出是以1为步长进⾏离散化的,但是这样的化输出的图像矩阵会出现失真的情况,丢失跟多的图像信息,。我们的解决⽅法是将与(\\(\\overline{x}\\),\\(\\overline{y}\\))的距离范围为[\\(r_{min}\\),\\(r_{max}\\)]并且⾓度范围在 \\([\heta_{min},\heta_{max}]\\)内的点进⾏极坐标向笛卡尔坐标的变换,并且进⾏离散化。\\(\heta\\)的变换步长\\(\heta_{step}\\)⼀般取\\(\frac{360}{180*N}\\),N\\(\\ge\\) 2,此时输出的宽为w \\(\\approx\\) \\(\frac{r_{max}-r_{min}}{r_{step}}\\) 图像矩阵的第i⾏第j列可通过以下的公式进⾏计算:
\\[O(i,j)= F_1 (\\overline{x}+(r_{min}+r_{step}i)* cos(\heta_{min}+\heta_{step}j),\\overline{y}+(r_{min}+r_{step}i)*sin(\heta_{min}+\heta_{step}j)) \\]下⾯我们通过⼀个具体的实例来实现极坐标的变换:将⼀个圆环图像变成矩形图像
import cv2
import numpy as npimport sys
#实现图像的极坐标的转换 center代表及坐标变换中⼼‘;r是⼀个⼆元元组,代表最⼤与最⼩的距离;theta代表⾓度范围#rstep代表步长; thetastap代表⾓度的变化步长
def polar(image,center,r,theta=(0,360),rstep=0.5,thetastep=360.0/(180*4)): #得到距离的最⼩值、最⼤值 minr,maxr=r #⾓度的最⼩范围 mintheta,maxtheta=theta
#输出图像的⾼、宽 O:指定形状类型的数组float H=int((maxr-minr)/rstep)+1
W=int((maxtheta-mintheta)/thetastep)+1 O=125*np.ones((H,W),image.dtype)
#极坐标转换 利⽤tile函数实现W*1铺成的r个矩阵 并对⽣成的矩阵进⾏转置 r=np.linspace(minr,maxr,H) r=np.tile(r,(W,1)) r=np.transpose(r)
theta=np.linspace(mintheta,maxtheta,W) theta=np.tile(theta,(H,1))
x,y=cv2.polarToCart(r,theta,angleInDegrees=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 py<=h-1)): O[i][j]=image[py][px] return O
if __name__==\"__main__\":
img = cv2.imread(\"img/yu.jpg\ # 传⼊的图像宽:600 ⾼:400 h, w = img.shape[:2] print(\"h:%s w:%s\"%(h,w)) # 极坐标的变换中⼼(300,200) cx, cy = 300, 200
# 圆的半径为10 颜⾊:灰 最⼩位数3
cv2.circle(img, (int(cx), int(cy)), 10, (255, 0, 0, 0), 3) L = polar(img, (cx, cy), (100, 350)) # 旋转
L = cv2.flip(L, 0) # 显⽰与输出
cv2.imshow('img', img) cv2.imshow('O', L) cv2.waitKey(0)
cv2.destroyAllWindows()
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- huatuo3.com 版权所有 蜀ICP备2023022190号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务