什么网站内链建设,小程序定制公司哪里有,韩漫网站建设,专业制作网站工业制品流程相机校准至少需要10个测试图案#xff0c;所需的重要输入数据是3D现实世界点集以及图像中这些点的相应2D坐标。3D点称为对象点#xff0c;而2D图像点称为图像点。
准备工作
除了棋盘#xff0c;我们还可以使用圆形网格。 在这种情况下#xff0c;我们必须使用函数cv.find…相机校准至少需要10个测试图案所需的重要输入数据是3D现实世界点集以及图像中这些点的相应2D坐标。3D点称为对象点而2D图像点称为图像点。
准备工作
除了棋盘我们还可以使用圆形网格。 在这种情况下我们必须使用函数cv.findCirclesGrid()来找到模式。 较少的图像足以使用圆形网格执行相机校准。 一旦找到拐角就可以使用cv.cornerSubPix()来提高其精度。我们还可以使用cv.drawChessboardCorners()绘制图案。
import numpy as np
import cv2 as cv
import glob
# 终止条件
criteria (cv.TERM_CRITERIA_EPS cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 准备对象点 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp np.zeros((6*7,3), np.float32)
objp[:,:2] np.mgrid[0:7,0:6].T.reshape(-1,2)
# 用于存储所有图像的对象点和图像点的数组。
objpoints [] # 真实世界中的3d点
imgpoints [] # 图像中的2d点
images glob.glob(*.jpg)
for fname in images:img cv.imread(fname)
gray cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 找到棋盘角落
ret, corners cv.findChessboardCorners(gray, (7,6), None)
# 如果找到添加对象点图像点细化之后
if ret True:objpoints.append(objp)
corners2 cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
imgpoints.append(corners)
# 绘制并显示拐角
cv.drawChessboardCorners(img, (7,6), corners2, ret)
cv.imshow(img, img)
cv.waitKey(500)
cv.destroyAllWindows()校准
现在我们有了目标点和图像点现在可以进行校准了。我们可以使用函数cv.calibrateCamera()返回相机矩阵失真系数旋转和平移矢量等。
ret, mtx, dist, rvecs, tvecs cv.calibrateCamera(objpoints, imgpoints,
gray.shape[::-1], None, None)不失真
现在我们可以拍摄图像并对其进行扭曲。OpenCV提供了两种方法来执行此操作。但是首先我们可以使用cv.getOptimalNewCameraMatrix()基于自由缩放参数来优化相机矩阵。如果缩放参数alpha 0则返回具有最少不需要像素的未失真图像。因此它甚至可能会删除图像角落的一些像素。如果alpha 1则所有像素都保留有一些额外的黑色图像。此函数还返回可用于裁剪结果的图像ROI。
使用cv.undistort()
这是最简单的方法。只需调用该函数并使用上面获得的ROI裁剪结果即可。
使用remapping
该方式有点困难。首先找到从扭曲图像到未扭曲图像的映射函数。然后使用重映射功能。
img cv.imread(left12.jpg)
h, w img.shape[:2]
newcameramtx, roi cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
# 1
dst cv.undistort(img, mtx, dist, None, newcameramtx)
# 剪裁图像
x, y, w, h roi
dst dst[y:yh, x:xw]
cv.imwrite(calibresult.png, dst)
# 2
mapx, mapy cv.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5)
dst cv.remap(img, mapx, mapy, cv.INTER_LINEAR)
# 裁剪图像
x, y, w, h roi
dst dst[y:yh, x:xw]
cv.imwrite(calibresult.png, dst)参数重投影误差
重投影误差可以很好地估计找到的参数的精确程度。重投影误差越接近零我们发现的参数越准确。给定固有失真旋转和平移矩阵我们必须首先使用cv.projectPoints()将对象点转换为图像点。然后我们可以计算出通过变换得到的绝对值和拐角发现算法之间的绝对值范数。为了找到平均误差我们计算为所有校准图像计算的误差的算术平均值。
mean_error 0
for i in xrange(len(objpoints)):
imgpoints2, _ cv.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error cv.norm(imgpoints[i], imgpoints2, cv.NORM_L2)/len(imgpoints2)
mean_error error
print( total error: {}.format(mean_error/len(objpoints)) )姿态估计
先优化。然后使用函数cv.solvePnPRansac()计算旋转和平移。一旦有了这些变换矩阵就可以使用它们将轴点投影到图像平面上。
for fname in glob.glob(left*.jpg):
img cv.imread(fname)
gray cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, corners cv.findChessboardCorners(gray, (7,6),None)
if ret True:
corners2 cv.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
# 找到旋转和平移矢量。
ret,rvecs, tvecs cv.solvePnP(objp, corners2, mtx, dist)
# 将3D点投影到图像平面
imgpts, jac cv.projectPoints(axis, rvecs, tvecs, mtx, dist)
img draw(img,corners2,imgpts)
cv.imshow(img,img)
k cv.waitKey(0) 0xFF
if k ord(s):
cv.imwrite(fname[:6].png, img)
cv.destroyAllWindows()对极几何
首先我们需要在两个图像之间找到尽可能多的匹配项以找到基本矩阵。为此我们将SIFT描述符与基于FLANN的匹配器和比率测试结合使用。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img1 cv.imread(myleft.jpg,0) #索引图像 # left image
img2 cv.imread(myright.jpg,0) #训练图像 # right image
sift cv.SIFT()
# 使用SIFT查找关键点和描述符
kp1, des1 sift.detectAndCompute(img1,None)
kp2, des2 sift.detectAndCompute(img2,None)
# FLANN 参数
FLANN_INDEX_KDTREE 1
index_params dict(algorithm FLANN_INDEX_KDTREE, trees 5)
search_params dict(checks50)
flann cv.FlannBasedMatcher(index_params,search_params)
matches flann.knnMatch(des1,des2,k2)
good []
pts1 []
pts2 []
# 根据Lowe的论文进行比率测试
for i,(m,n) in enumerate(matches):
if m.distance 0.8*n.distance:
good.append(m)
pts2.append(kp2[m.trainIdx].pt)
pts1.append(kp1[m.queryIdx].pt)现在我们获得了两张图片的最佳匹配列表。 让我们找到基本面矩阵。
pts1 np.int32(pts1)
pts2 np.int32(pts2)
F, mask cv.findFundamentalMat(pts1,pts2,cv.FM_LMEDS)
# 我们只选择内点
pts1 pts1[mask.ravel()1]
pts2 pts2[mask.ravel()1]接下来我们找到Epilines。在第二张图像上绘制与第一张图像中的点相对应的Epilines。因此在这里提到正确的图像很重要。我们得到了一行线。因此我们定义了一个新功能来在图像上绘制这些线条。
def drawlines(img1,img2,lines,pts1,pts2):img1 - 我们在img2相应位置绘制极点生成的图像
lines - 对应的极点
r,c img1.shape
img1 cv.cvtColor(img1,cv.COLOR_GRAY2BGR)
img2 cv.cvtColor(img2,cv.COLOR_GRAY2BGR)
for r,pt1,pt2 in zip(lines,pts1,pts2):
color tuple(np.random.randint(0,255,3).tolist())
x0,y0 map(int, [0, -r[2]/r[1] ])
x1,y1 map(int, [c, -(r[2]r[0]*c)/r[1] ])
img1 cv.line(img1, (x0,y0), (x1,y1), color,1)
img1 cv.circle(img1,tuple(pt1),5,color,-1)
img2 cv.circle(img2,tuple(pt2),5,color,-1)
return img1,img2现在我们在两个图像中都找到了Epiline并将其绘制。
# 在右图第二张图中找到与点相对应的极点然后在左图绘制极线
lines1 cv.computeCorrespondEpilines(pts2.reshape(-1,1,2), 2,F)
lines1 lines1.reshape(-1,3)
img5,img6 drawlines(img1,img2,lines1,pts1,pts2)
# 在左图第一张图中找到与点相对应的Epilines然后在正确的图像上绘制极线
lines2 cv.computeCorrespondEpilines(pts1.reshape(-1,1,2), 1,F)
lines2 lines2.reshape(-1,3)
img3,img4 drawlines(img2,img1,lines2,pts2,pts1)
plt.subplot(121),plt.imshow(img5)
plt.subplot(122),plt.imshow(img3)
plt.show()立体图像的深度图
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
imgL cv.imread(tsukuba_l.png,0)
imgR cv.imread(tsukuba_r.png,0)
stereo cv.StereoBM_create(numDisparities16, blockSize15)
disparity stereo.compute(imgL,imgR)
plt.imshow(disparity,gray)
plt.show()结果受到高度噪声的污染。通过调整numDisparities和blockSize的值可以获得更好的结果。 参数
texture_threshold过滤出纹理不足以进行可靠匹配区域斑点范围和大小基于块的匹配器通常会在对象边界附近产生“斑点”其中匹配窗口捕获一侧的前景和背景在另一场景中匹配器似乎还在桌子上投影的纹理中找到小的虚假匹配项。为了消除这些伪像我们使用由speckle_size和speckle_range参数控制的散斑滤镜对视差图像进行后处理。speckle_size是将视差斑点排除为“斑点”的像素数。speckle_range控制必须将值差异视为同一对象的一部分的程度视差数量滑动窗口的像素数。它越大可见深度的范围就越大但是需要更多的计算min_disparity从开始搜索的左像素的x位置开始的偏移量uniqueness_ratio另一个后过滤步骤。如果最佳匹配视差不足够好于搜索范围中的所有其他视差则将像素滤出。如果texture_threshold和斑点过滤仍在通过虚假匹配则可以尝试进行调整prefilter_size和prefilter_cap预过滤阶段可标准化图像亮度并增强纹理以准备块匹配通常你不需要调整这些