OPENCV+PYTHON 棋盘格及其使用 探索学习
1.opencv+python 如何使用橡素坐标和numpy实现图像平移、旋转2.opencv-python 轮廓线的最小面积的外接旋转矩形 和 旋转
3.OPENCV+PYTHON 棋盘格及其使用 探索学习
提问 文心一言:
OPENCV+PYTHON 棋盘格的函数
答案:
在 OpenCV 和 Python 中,棋盘格(Chessboard)常用于相机标定(Camera Calibration)中,因为它提供了一种已知图案,用于计算相机的内部参数和外部参数。棋盘格图案通常由交替的黑白方块组成。
以下是一些常用的与棋盘格相关的函数和步骤:
- 生成棋盘格图像:
虽然通常使用预打印的棋盘格图案,但你也可以使用 OpenCV 生成一个棋盘格图像。
import cv2 import numpy as np def generate_chessboard(squares_per_row, squares_per_col, square_size): # 棋盘格的大小 rows = squares_per_row + 1 cols = squares_per_col + 1 # 创建一个空白图像 img = np.ones((rows * square_size, cols * square_size, 3), dtype=np.uint8) * 255 for i in range(squares_per_row + 1): for j in range(squares_per_col + 1): if (i + j) % 2 == 0: # 填充黑色方块 cv2.rectangle(img, (j * square_size, i * square_size), ((j + 1) * square_size, (i + 1) * square_size), 0, -1) return img
# 生成一个8x11 棋盘格(棋盘格的大小:内部角点的数量),每个方块大小为 50 像素
# 即生成一个有9x12 方格 的棋盘格(棋盘格的大小:方块的数量),每个方块大小为 50 像素
chessboard_img = generate_chessboard(8, 11, 50)
cv2.waitKey(0) cv2.destroyAllWindows()
- 找到棋盘格角点:
使用cv2.findChessboardCorners
函数来检测棋盘格的角点。
import cv2 # 棋盘格的大小 (内部角点的数量) chessboard_size = (8, 11) # 读取棋盘格图像 img = cv2.imread('chessboard.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) # 如果找到角点,则绘制并显示它们 if ret: img = cv2.drawChessboardCorners(img, chessboard_size, corners, ret) cv2.imshow('Chessboard Corners', img) cv2.waitKey(0) cv2.destroyAllWindows() else: print("Chessboard corners not found")
- 相机标定:
使用cv2.calibrateCamera
函数进行相机标定。这需要使用多张从不同角度拍摄的棋盘格图像。
import cv2 import numpy as np import glob # 棋盘格的大小 (内部角点的数量) chessboard_size = (8, 6) # 准备对象点 (例如 (0,0,0), (1,0,0), (2,0,0), ....,(7,5,0)) objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) # 存储所有图像的对象点和图像点 objpoints = [] # 3d 点在真实世界空间 imgpoints = [] # 2d 点在图像平面 # 读取所有棋盘格图像 images = glob.glob('chessboard_images/*.jpg') for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) # 如果找到角点,则添加对象点和图像点 if ret: objpoints.append(objp) imgpoints.append(corners) # 标定相机 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) print("相机矩阵:\n", mtx) print("畸变系数:\n", dist)
以上代码展示了如何生成棋盘格图像、检测棋盘格角点以及进行相机标定。注意,相机标定通常需要多张从不同角度拍摄的棋盘格图像,因此请确保你有足够的图像来进行标定。
提问:如何校正原图像
import cv2 import numpy as np # 假设你已经通过cv2.calibrateCamera得到了mtx和dist # mtx是相机内参矩阵,dist是畸变系数 # img是你想要校正的原图像 # 读取图像(这里以灰度图像为例,但也可以是彩色图像) img = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_GRAYSCALE) # 如果是彩色图像,使用cv2.IMREAD_COLOR # img = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_COLOR) # 使用cv2.undistort函数校正图像 # 注意:如果img是彩色图像,你需要将每个通道分别校正,但OpenCV通常会自动处理这一点 undistorted_img = cv2.undistort(img, mtx, dist) # 显示校正前后的图像 cv2.imshow('Original Image', img) cv2.imshow('Undistorted Image', undistorted_img) cv2.waitKey(0) cv2.destroyAllWindows() # 保存校正后的图像(可选) cv2.imwrite('undistorted_image.jpg', undistorted_img)
# 求矩阵的逆,由像素求在相机坐标系中,Z=1平面的X,Y坐标 # def inv_matrix(matrix): # try: # # 使用 numpy.linalg.inv 计算逆矩阵 # inv_mat = np.linalg.inv(matrix) # except np.linalg.LinAlgError: # print("Matrix is singular and cannot be inverted.") # return None # else: # return inv_mat # # print(inv_matrix(mtx)) # point_c= np.dot(inv_matrix(mtx),np.array(point_pixel )) # 投影 # print(point_c*z_prime)
1)图像不要少于20张(中间,四周,远近),否则失败。相机的内参数要合理
2) 棋盘格坐标点经过 刚性变换(外参数矩阵)、相机矩阵得到 像素坐标,与经过校正图像找到的对应点像素坐标 一致么?
3)距离是否合理,特别是相机的外参数
import cv2 import numpy as np import glob # json import json import os # 棋盘格的大小 (内部角点的数量) 长对应X,宽对应Y chessboard_size = (11, 8) # 准备对象点 (例如 (0,0,0), (1,0,0), (2,0,0), ....,(7,5,0)) objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) objp = objp*1 # 存储所有图像的对象点和图像点 objpoints = [] # 3d 点在真实世界空间 imgpoints = [] # 2d 点在图像平面 # 读取所有棋盘格图像 #images = glob.glob('D:\Python_OpenCV\SC_vantage\SingleCamera\calibrationSingleCamera\*.png') images = glob.glob('D:/Python_OpenCV/vantage1080/stero_calibration_imgs_2\left\*.png') #gray = cv2.cvtColor(images[0],cv2.COLOR_BGR2GRAY) # 亚像素 termination criteria criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) # 如果找到角点,则添加对象点和图像点 if ret: # If found, add object points, image points (after refining them) objpoints.append(objp) # 亚像素 cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) imgpoints.append(corners) # 标定相机 mtx,dist 是列表; rvecs, tvecs 是numpy数组 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) print("相机矩阵:\n", mtx) print("畸变系数 k1,k2,p1,p2,k3:\n", dist) # print("旋转矩阵:\n", rvecs) # print("平移矩阵:\n", tvecs ) #****************棋盘格坐标计算相机坐标**************************************** # 由旋转向量得到旋转矩阵 rmat, _ = cv2.Rodrigues(rvecs[0]) # 转换第 i 个旋转向量 # rmat 是已经转换得到的旋转矩阵,tvec 是对应的平移向量,构造4X4矩阵,三维空间的齐次坐标实现 homog_mat = np.eye(4) # 创建一个 4x4 的单位矩阵 homog_mat[:3, :3] = rmat # 填充旋转部分 homog_mat[:3, 3] = np.transpose(tvecs[0]) # 填充平移部分 # 取得棋盘格坐标上一点 X,Y,Z = objp[1] print("棋盘格坐标系的点坐标:") print(X,Y,Z) point_homog = np.dot(homog_mat, np.array([X, Y, Z, 1])) # 应用 4x4 变换,三维空间的齐次坐标[X, Y, Z, 1] x_C = point_homog[0] #/ point_homog[2] # 透视除法得到 x' y_C = point_homog[1] #/ point_homog[2] # 透视除法得到 y' z_C = point_homog[2] print(x_C,y_C,z_C)# 相机坐标系,使用物理空间坐标 point1_2d =np.array([x_C,y_C,z_C])#将用来计算空间距离 #****************由计算相机坐标计算像平面坐标**************************************** point_pixel = np.dot(mtx,np.array([x_C/z_C,y_C/z_C,1])) # 投影 print("由棋盘坐标计算来的像素坐标:") print(point_pixel) # 像平面,使用像素坐标 # 打印 objp[1]在原图像的对应的像素坐标 print(imgpoints[0][1]) #****************棋盘格坐标计算相机坐标**************************************** # 取得棋盘格坐标上一点 X,Y,Z = objp[0] print("棋盘格坐标系的点坐标:") print(X,Y,Z) point_homog = np.dot(homog_mat, np.array([X, Y, Z, 1])) # 应用 4x4 变换,三维空间的齐次坐标[X, Y, Z, 1] x_C = point_homog[0] #/ point_homog[2] # 透视除法得到 x' y_C = point_homog[1] #/ point_homog[2] # 透视除法得到 y' z_C = point_homog[2] print(x_C,y_C,z_C)# 相机坐标系,使用物理空间坐标 point2_2d =np.array([x_C,y_C,z_C])#将用来计算空间距离 #****************由计算相机坐标计算像平面坐标**************************************** point_pixel = np.dot(mtx,np.array([x_C/z_C,y_C/z_C,1])) # 投影 print(point_pixel) # 像平面,使用像素坐标 #point2_2d = point_pixel print("由棋盘坐标计算来的像素坐标:") print(imgpoints[0][0]) #****************计算距离,是否符合**************************************** # 计算两点之间的欧几里得距离 distance_2d = np.linalg.norm(point1_2d - point2_2d) print(distance_2d) # ***************求矩阵的逆,由像素求在相机坐标系中,Z=1平面的X,Y坐标*********** def inv_matrix(matrix): try: # 使用 numpy.linalg.inv 计算逆矩阵 inv_mat = np.linalg.inv(matrix) except np.linalg.LinAlgError: print("Matrix is singular and cannot be inverted.") return None else: return inv_mat print("相机内矩阵的逆:") print(inv_matrix(mtx)) # print("在相机坐标系内Z=1平面的交点的XYZ坐标:") point_c= np.dot(inv_matrix(mtx),np.array(point_pixel )) # 投影 print(point_c) # # # ***************使用相机内参数,校正图像*********** # 创建目录,存放零件模板 if not os.path.exists("calibration_pic"): os.makedirs("calibration_pic") for original_filename in images: img = cv2.imread(original_filename) # 注意:如果img是彩色图像,你需要将每个通道分别校正,但OpenCV通常会自动处理这一点 undistorted_img = cv2.undistort(img, mtx, dist) #更改文件类型 # 分离文件路径和文件名 #import os path, filename = os.path.split(original_filename) # 去除原始扩展名 name, ext = os.path.splitext(filename) # 添加新的扩展名 new_filename = os.path.join(path, name + '.jpg') # 保存校正后的图像(可选) cv2.imwrite(new_filename, undistorted_img) #***************对矫正图像,寻找棋盘格的角点********************** fname = images[0] img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) # 如果找到角点,则添加对象点和图像点 if ret: # If found, add object points, image points (after refining them) #objpoints.append(objp) # 亚像素 cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) #imgpoints.append(corners) print("校正后的图像点") print(corners[0])
# 猜想:#校正后的图像特定点,经过 相机内参数 mtx方阵的逆 变换 就可以得到 在Z=1平面上的坐标 x,y,1。如何知道此像素点的实物与相机的距离,就可以算出此物的在相机坐标系的空间位###置。
#比较难,可以实现
确定空间一物体在相机坐标系的位置
1)长方体木块各面异色,已经知道长,宽,高。即知道物体自身的坐标系。
2)利用识别算法,可以识别出图像中的长方体木块,进而找出一个面的四个角点及像素坐标
3)建立像素坐标和物体坐标的点对
4)利用点对估算物体相对相机坐标系的位姿。
# 已经知道物体自身的特征点坐标 # 已经知相机的内参数 # 求取 物体对相机坐标系的姿态 import cv2 import numpy as np import glob # json import json import os # 棋盘格的大小 (内部角点的数量) 长对应X,宽对应Y chessboard_size = (11, 8) # 准备对象点 (例如 (0,0,0), (1,0,0), (2,0,0), ....,(7,5,0)) objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) square_size = 15 # 每个格子的大小,单位可以是毫米或米等 objp = objp*square_size # 存储所有图像的对象点和图像点 objpoints = [] # 3d 点在真实世界空间 imgpoints = [] # 2d 点在图像平面 # 读取所有棋盘格图像 images = glob.glob('D:\Python_OpenCV\SC_vantage\SingleCamera\calibrationSingleCamera\*.png') #images = glob.glob('D:/Python_OpenCV/vantage1080/stero_calibration_imgs_2\left\*.png') # 假设相机内参数矩阵和畸变系数已经通过标定获得 camera_matrix = np.array([ [311.28794266, 0.0 ,322.43776776], [ 0.0 , 311.80630946 ,224.42678219], [ 0.0 , 0.0 ,1.0 ] ], dtype=np.float32) #畸变系数 k1,k2,p1,p2,k3 dist_coeffs = np.array([ 0.02349178, -0.1442722, 0.00367356, 0.00248951, 0.08352093], dtype=np.float32) # 畸变系数 # 亚像素 termination criteria criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) # 如果找到角点,则添加对象点和图像点 if ret: # If found, add object points, image points (after refining them) objpoints.append(objp) # 亚像素 cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) imgpoints.append(corners) # 使用 cv2.solvePnP 计算外参数矩阵(旋转矩阵和平移向量) # 注意:我们只需要一幅图像的点对来计算外参数矩阵,但使用多幅图像可以提高精度 ret, rvec, tvec = cv2.solvePnP(objp, corners, camera_matrix, dist_coeffs) # 将旋转向量转换为旋转矩阵 rmat, _ = cv2.Rodrigues(rvec) # 输出旋转矩阵和平移向量 print("Rotation Matrix:") print(rmat) print("Translation Vector:") print(tvec)
合集:
opencv-python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)