這一章我們來根據(jù)上一章的分析,為手眼標(biāo)定函數(shù)calibrateHandEye 準(zhǔn)備他那些麻煩的參數(shù)
更詳細(xì)的參數(shù)參考鏈接
R,T=cv2.calibrateHandEye(R_all_end_to_base_1,T_all_end_to_base_1,R_all_chess_to_cam_1,T_all_chess_to_cam_1)#手眼標(biāo)定
一.為首的兩個(gè)機(jī)械臂抓手相對(duì)于機(jī)器人基坐標(biāo)系的旋轉(zhuǎn)矩陣與平移向量,
即R_all_end_to_base_1,T_all_end_to_base_1,
我們可用通過輸入的機(jī)械臂提供的6組參數(shù)得到,3個(gè)位姿與3個(gè)歐拉角
示例代碼
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import glob
from math import *
import pandas as pd
import os
from elephant import elephant_command
import time
import random
import math
erobot = elephant_command()
X0 = 100.0
Y0 = 360.0
Z0 = 375.0 # mm
RX0 = 180.0
RY0 = 0.0
RZ0 = -22.0
ZG = 180.0 # mm
#用于根據(jù)歐拉角計(jì)算旋轉(zhuǎn)矩陣
def myRPY2R_robot(x, y, z):
Rx = np.array([[1, 0, 0], [0, cos(x), -sin(x)], [0, sin(x), cos(x)]])
Ry = np.array([[cos(y), 0, sin(y)], [0, 1, 0], [-sin(y), 0, cos(y)]])
Rz = np.array([[cos(z), -sin(z), 0], [sin(z), cos(z), 0], [0, 0, 1]])
R = Rz@Ry@Rx
return R
#用于根據(jù)位姿計(jì)算變換矩陣
def pose_robot(x, y, z, Tx, Ty, Tz):
thetaX = x / 180 * pi
thetaY = y / 180 * pi
thetaZ = z / 180 * pi
R = myRPY2R_robot(thetaX, thetaY, thetaZ)
t = np.array([[Tx], [Ty], [Tz]])
RT1 = np.column_stack([R, t]) # 列合并
RT1 = np.row_stack((RT1, np.array([0,0,0,1])))
# RT1=np.linalg.inv(RT1)
return RT1
# 獲得 旋轉(zhuǎn)角度和基于基底的坐標(biāo)軸 例:[563.777086,-264.753645,216.192196,171.417423,0.173813,54.855032]
# while True:
# time.sleep(0.5)
# a=erobot.get_coords()
#
# a.decode()
# a=str(a)
# a=a[2:]
# print(a)
a=erobot.get_coords()
a.decode()
a=str(a)
a=a[2:-1]
print(a)
print(type(a))
b = eval(a)
print(b)
print(type(b))
R_all_end_to_base_1=[]
T_all_end_to_base_1=[]
RT = pose_robot(b[3],b[4],b[5],b[0],b[1],b[2])
# RT=np.column_stack(((cv2.Rodrigues(np.array([[sheet_1.iloc[i-1]['ax']],[sheet_1.iloc[i-1]['ay']],[sheet_1.iloc[i-1]['az']]])))[0],
# np.array([[sheet_1.iloc[i-1]['dx']],
# [sheet_1.iloc[i-1]['dy']],[sheet_1.iloc[i-1]['dz']]])))
# RT = np.row_stack((RT, np.array([0, 0, 0, 1])))
# RT = np.linalg.inv(RT)
R_all_end_to_base_1.append(RT[:3, :3])
T_all_end_to_base_1.append(RT[:3, 3].reshape((3, 1)))
print(R_all_end_to_base_1)
print("*"*100)
print(T_all_end_to_base_1)
二. 接著是R_all_chess_to_cam_1,T_all_chess_to_cam_1,這倆統(tǒng)稱為相機(jī)外參,具體是標(biāo)定板相對(duì)于雙目相機(jī)的齊次矩陣,這里,我們需要用到的函數(shù)為
**cv2.findChessboardCorners** 角點(diǎn)查找函數(shù)
**cv2.calibrateCamera** 相機(jī)標(biāo)定函數(shù)
**cv2.solvePnP** N點(diǎn)透視位姿求解函數(shù)
這里是關(guān)系是 通過 cv2.findChessboardCorners 角點(diǎn)查找函數(shù)和
cv2.calibrateCamera 相機(jī)標(biāo)定函數(shù)得到的結(jié)果,處理后放入 cv2.solvePnP N點(diǎn)透視位姿求解函數(shù)求得的結(jié)果經(jīng)過轉(zhuǎn)換最后變成 所謂的相機(jī)外參。
1.準(zhǔn)備角點(diǎn)
通過 cv2.findChessboardCorners 角點(diǎn)查找函數(shù) 進(jìn)行查找
如上圖此時(shí)從機(jī)械臂收到的數(shù)據(jù)為:[434.578026,-49.310804,524.948340,-178.730009,-4.475156,-15.869448]當(dāng)然和角點(diǎn)沒啥關(guān)系,我就是說明下當(dāng)前機(jī)械臂末端與基座的坐標(biāo)關(guān)系。
此時(shí)攝像頭拍到的圖像長(zhǎng)這樣(注意此時(shí)沒有對(duì)圖片進(jìn)行任何的畸變矯正操作)
然后我們使用cv2.findChessboardCorners進(jìn)行角點(diǎn)尋找,如下經(jīng)過測(cè)試8-11 或 11-8 可找到可用角點(diǎn),下圖的窗口是我分裝的滑塊窗口調(diào)試的,不是這個(gè)函數(shù)運(yùn)行就這樣哈。
如上圖
x方向角點(diǎn)個(gè)數(shù):8
y方向角點(diǎn)個(gè)數(shù): 11
單位棋盤格長(zhǎng)度為: 30 mm
角點(diǎn)檢測(cè)代碼,附對(duì)應(yīng)圖片,如果報(bào)錯(cuò),說明沒有按照w和h的方式得到對(duì)應(yīng)角點(diǎn)
Traceback (most recent call last): File
“I:/Python/BasicDemo/ele/cs1.py”, line 20, in
cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) cv2.error: OpenCV(4.5.3)
C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-_xlv4eex\opencv\modules\imgproc\src\cornersubpix.cpp:58:
error: (-215:Assertion failed) count >= 0 in function
‘cv::cornerSubPix’
上圖為3.pngcornerSubPix()對(duì)檢測(cè)到的角點(diǎn)作進(jìn)一步的優(yōu)化計(jì)算,可使角點(diǎn)的精度達(dá)到亞像素級(jí)別。
函數(shù)形式
void cornerSubPix( InputArray image, InputOutputArray corners, Size
winSize, Size zeroZone, TermCriteria criteria )參數(shù)說明
具體調(diào)用形式如下:
void cv::cornerSubPix(
cv::InputArray image, // 輸入圖像
cv::InputOutputArray corners, // 角點(diǎn)(既作為輸入也作為輸出)
cv::Size winSize, // 區(qū)域大小為 NXN; N=(winSize*2+1)
cv::Size zeroZone, // 類似于winSize,但是總具有較小的范圍,Size(-1,-1)表示忽略
cv::TermCriteria criteria // 停止優(yōu)化的標(biāo)準(zhǔn)
);第一個(gè)參數(shù)是輸入圖像,和cv::goodFeaturesToTrack()中的輸入圖像是同一個(gè)圖像。
第二個(gè)參數(shù)是檢測(cè)到的角點(diǎn),既是輸入也是輸出。第三個(gè)參數(shù)是計(jì)算亞像素角點(diǎn)時(shí)考慮的區(qū)域的大小,大小為NN, N=(winSize2+1)。
第四個(gè)參數(shù)作用類似于winSize,但是總是具有較小的范圍,通常忽略(即Size(-1, -1))。
第五個(gè)參數(shù)用于表示計(jì)算亞像素時(shí)停止迭代的標(biāo)準(zhǔn),可選的值有cv::TermCriteria::MAX_ITER
、cv::TermCriteria::EPS(可以是兩者其一,或兩者均選),前者表示迭代次數(shù)達(dá)到了最大次數(shù)時(shí)停止,后者表示角點(diǎn)位置變化的最小值已經(jīng)達(dá)到最小時(shí)停止迭代。二者均使用cv::TermCriteria()構(gòu)造函數(shù)進(jìn)行指定。
import cv2
import numpy as np
w = 7
h = 7
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 這里的30是最大迭代次數(shù),0.001是即要求的收斂閾值 參考: https://blog.csdn.net/warningm_dm/article/details/111501071
# 世界坐標(biāo)系中的棋盤格點(diǎn),例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐標(biāo),記為二維矩陣
objp = np.zeros((w * h, 3), np.float32)
objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
objpoints = [] # 在世界坐標(biāo)系中的三維點(diǎn)
imgpoints = [] # 在圖像平面的二維點(diǎn)
img_path = "3.png"
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("cs",gray)
ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
print(corners)
cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
objpoints.append(objp)
imgpoints.append(corners)
# 將角點(diǎn)在圖像上顯示
cv2.drawChessboardCorners(gray, (w, h), corners, ret)
cv2.imshow("cs2",gray)
cv2.waitKey(0)
2.進(jìn)行相機(jī)標(biāo)定
提供一個(gè)標(biāo)定板下載鏈接
!!! 2023補(bǔ)提示:相機(jī)標(biāo)定是為了求相機(jī)的內(nèi)參,如果有內(nèi)參數(shù)據(jù)可以跳過這步。沒有的話標(biāo)定的時(shí)候一定要和手眼標(biāo)定區(qū)別開,相機(jī)標(biāo)定是相機(jī)不動(dòng),標(biāo)定板移動(dòng)。 而這里的眼在手上的手眼標(biāo)定是相機(jī)安裝在機(jī)械臂末端移動(dòng)而下方的標(biāo)定板不動(dòng),所以準(zhǔn)備這兩個(gè)的標(biāo)定圖像是不一樣的!不要弄混了!
cv2.calibrateCamera 相機(jī)標(biāo)定函數(shù)
補(bǔ)提示:標(biāo)定時(shí)并不需要知道每一格的尺寸
出如下錯(cuò)的時(shí)候,說明角點(diǎn)沒有找對(duì)
cv2.error: OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-_xlv4eex\opencv\modules\calib3d\src\calibration.cpp:3694: error: (-215:Assertion failed) nimages > 0 in function 'cv::calibrateCameraRO'
# 標(biāo)定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
詳細(xì)看這里
這里,ret表示的是重投影誤差;mtx是相機(jī)的內(nèi)參矩陣;dist表述的相機(jī)畸變參數(shù);rvecs表示標(biāo)定棋盤格世界坐標(biāo)系到相機(jī)坐標(biāo)系的旋轉(zhuǎn)參數(shù):rotation vectors,需要進(jìn)行羅德里格斯轉(zhuǎn)換;tvecs表示translation vectors,主要是平移參數(shù)。
其中 mtx就是我們需要獲得的相機(jī)內(nèi)參,通過獲得的mtx送入 接下來的 solvePnP中,然后再通過solvePnP求得 手眼標(biāo)定函數(shù)的最后兩位參數(shù)。。。。。。。
2023補(bǔ):
一般情況下工業(yè)相機(jī)的廠商有提供內(nèi)參的,內(nèi)參矩陣的具體物理含義與相機(jī)對(duì)應(yīng)的x軸y軸上的焦距fx,fy(注意這里opencv calibrateCamera返回的 是以像元為單位,比例fx為10,而x軸上的一個(gè)像元尺寸為3.5微米,那么fx代表是實(shí)際焦距就是:10乘以3.5微米 ),和x軸與y軸上對(duì)應(yīng)的距離光學(xué)中心的距離cx,cy,單位也是像元為單位,一般情況下一個(gè)完美的相機(jī)cx與cy就是分辨率的一半,例如一個(gè)400*600的相機(jī)cx就是200,cy就是300(如下圖為opencv的cv2.calibrateCamera 相機(jī)標(biāo)定函數(shù)函數(shù)返回的內(nèi)參格式矩陣 opencv官方calibrateCamera 參數(shù)解釋
(當(dāng)然有些使用像素來描述x,y軸方向焦距的長(zhǎng)度的內(nèi)參矩陣,遇到了的話參考該鏈接)
因此如果可以明確的知道以上四個(gè)參數(shù)也可以直接寫個(gè)矩陣填進(jìn)去,如下寫法:
K=np.matrix([[293.920628294608, 0.0, 95.19676414624162],
[0.0, 293.7271139511578, 159.43897526273312],
[0.0, 0.0, 1.0]],dtype=np.float64)#內(nèi)參例子
以下為我修改寫的角點(diǎn)與標(biāo)定的代碼分裝,
# 標(biāo)定模塊使用說明,通過計(jì)算 "save_img_path": "Demarcate_img" 下的文件夾內(nèi)包含的多張圖片,主要為輸入calibrateCamera( ) 函數(shù)的
# 前兩個(gè)參數(shù)
# objectPoints :世界坐標(biāo)系中的點(diǎn)。在使用時(shí),應(yīng)該輸入vector< vector< Point3f > >。
# imagePoints :其對(duì)應(yīng)的圖像點(diǎn)。和objectPoints一樣,應(yīng)該輸入vector< vector< Point2f > >型的變量。
# 分別通過兩個(gè)列表存儲(chǔ)
# // Trackbar_class 的1568行核心代碼
# 所以這里標(biāo)定模塊使用的主要目的,是為Demarcate_img文件夾中準(zhǔn)備盡可能準(zhǔn)確及較多數(shù)量的標(biāo)定模塊樣本
# 注意點(diǎn)擊 Calculate_switch 置為 1 的時(shí)候,程序會(huì)將當(dāng)前顯示的標(biāo)定樣本的,長(zhǎng)寬(w,h)作為 Demarcate_img 內(nèi)所有準(zhǔn)備的標(biāo)定圖片樣本w,h輸入,
# 所以務(wù)必保證文件夾內(nèi)與現(xiàn)在顯示的這個(gè)大爺?shù)膚,h 是一樣的!
def out_demarcate_param(w, h, save_img_path, criteria):
"""解析儲(chǔ)存的標(biāo)定圖片數(shù)據(jù),輸出標(biāo)定參數(shù)"""
objp = np.zeros((w * h, 3), np.float32)
objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
# 儲(chǔ)存棋盤格角點(diǎn)的世界坐標(biāo)和圖像坐標(biāo)對(duì)
objpoints = [] # 在世界坐標(biāo)系中的三維點(diǎn)
imgpoints = [] # 在圖像平面的二維點(diǎn)
images = glob(save_img_path + '/*.bmp')
print("1040 開始標(biāo)定分析。。。。。。")
for fname in images:
print("標(biāo)定圖片:" + str(fname))
img = cv2.imread(fname)
try:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
except:
gray = img
# 找到棋盤格角點(diǎn)
ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
# 如果找到足夠點(diǎn)對(duì),將其存儲(chǔ)起來
if ret == True:
cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
objpoints.append(objp)
imgpoints.append(corners)
# 標(biāo)定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("1056 標(biāo)定分析完畢,返回參數(shù)")
return ret, mtx, dist, rvecs, tvecs, objpoints, imgpoints
def eliminate_distortion(ret, mtx, dist, rvecs, tvecs, img2, objpoints, imgpoints):
# 去畸變
pr_ll("cs_down")
h, w = img2.shape[:2]
pr_ll(mtx)
pr_ll(mtx.dtype)
pr_ll(type(mtx))
pr_ll(dist)
pr_ll(dist.dtype)
pr_ll(type(dist))
pr_ll(w)
pr_ll(h)
pr_ll("cs_up")
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h)) # 自由比例參數(shù)
dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# 根據(jù)前面ROI區(qū)域裁剪圖片
# x,y,w,h = roi
# dst = dst[y:y+h, x:x+w]
# 反投影誤差
total_error = 0
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
total_error += error
#print("1093 total error: " + str(total_error / len(objpoints)))
return dst
def demarcate_angular_get(img, update_param_dict, fixed_param_dict, img_datas=None):
"""用于為標(biāo)定檢測(cè)角點(diǎn), 調(diào)控獲得標(biāo)定數(shù)據(jù)"""
wind_hint_show_bool, show_img = wind_hint_show_fun(fixed_param_dict)
global global_save_img_button
global global_save_json_button
global global_demarcate_param_list
global global_w2
global global_h2
w = update_param_dict["w"]
h = update_param_dict["h"]
save_img_button = update_param_dict["Img_save_button"]
# 結(jié)果存入json文件,需先進(jìn)行標(biāo)注計(jì)算
save_json_button = update_param_dict["Json_save_button"]
# 通過矯正模塊進(jìn)行矯正處理
correct_switch = update_param_dict["Correct_switch"]
# 計(jì)算標(biāo)定
# cv2.error: OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-_
# xlv4eex\opencv\modules\calib3d\src\calibration.cpp:3694: error: (-215:Assertion failed) nimages > 0 in function 'cv::calibrateCameraRO'
# 報(bào)以上錯(cuò)誤說明角點(diǎn)找尋有問題
calculate_switch = update_param_dict["Calculate_switch"]
# 固定的圖像文件存儲(chǔ)路徑
save_img_path = fixed_param_dict["save_img_path"]
#固定的json文件存儲(chǔ)路徑
demarcate_json_path = fixed_param_dict["demarcate_json_path"]
# 為真進(jìn)入自動(dòng)查找角點(diǎn)
Auto_bool = update_param_dict["Auto_bool"]
# 找棋盤格角點(diǎn)
# 閾值
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 棋盤格模板規(guī)格
# w = 9
# h = 6
# w = 12
# h = 9
# 世界坐標(biāo)系中的棋盤格點(diǎn),例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐標(biāo),記為二維矩陣
objp = np.zeros((w * h, 3), np.float32)
objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
# 儲(chǔ)存棋盤格角點(diǎn)的世界坐標(biāo)和圖像坐標(biāo)對(duì)
objpoints = [] # 在世界坐標(biāo)系中的三維點(diǎn)
imgpoints = [] # 在圖像平面的二維點(diǎn)
show_img = img.copy()
try:
gray = cv2.cvtColor(show_img, cv2.COLOR_BGR2GRAY)
except:
gray = show_img
if Auto_bool == 1:
# 找到棋盤格角點(diǎn)
try:
ret, corners = cv2.findChessboardCorners(gray, (global_w2, global_h2), None)
except:
pass
else:
# 找到棋盤格角點(diǎn)
ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
# 如果找到足夠點(diǎn)對(duì),將其存儲(chǔ)起來
if ret == True:
if Auto_bool == 1:
print("找到角點(diǎn):" + str(global_w2) + "," + str(global_h2))
cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
objpoints.append(objp)
imgpoints.append(corners)
# 將角點(diǎn)在圖像上顯示
cv2.drawChessboardCorners(show_img, (w, h), corners, ret)
#print("\n")
else:
if Auto_bool == 1:
if global_h2<= 12:
if global_w2<=12:
global_w2 = global_w2 + 1
else:
global_w2 = 4
global_h2 = global_h2 + 1
print("測(cè)試角點(diǎn):" + str(global_w2) + "," + str(global_h2))
else:
print("沒有找到角點(diǎn)")
##print("1005 未找到角點(diǎn),失?。?)
pass
if save_img_button != global_save_img_button:
t = time.localtime()
t_sting = str(t.tm_year) + "_" + str(t.tm_mon) + "_" + str(t.tm_mday) + "_" \
+ str(t.tm_hour) + "_" + str(t.tm_min) + "_" + str(t.tm_sec) + "_" + str(t.tm_wday) + ".bmp"
path_name = save_img_path + "/" + t_sting
cv2.imwrite(path_name, img)
global_save_img_button = save_img_button
#print("存入圖片: " + path_name)
if calculate_switch == 1:
# 開啟后系統(tǒng)會(huì)自動(dòng)分析在對(duì)應(yīng)存儲(chǔ)文件夾中已保存的圖片,并且將值記錄在程序變量中
print("1018 進(jìn)入標(biāo)定參數(shù)計(jì)算程序")
for data in out_demarcate_param(w, h, save_img_path, criteria):
global_demarcate_param_list.append(data)
elif calculate_switch == 0:
#print("清空標(biāo)定數(shù)據(jù)")
global_demarcate_param_list = []
else:
pass
if correct_switch == 1:
# 開啟標(biāo)定矯正
#print("開啟矯正")
if global_demarcate_param_list != []:
#print("矯正數(shù)據(jù):" + str(global_demarcate_param_list))
ret = global_demarcate_param_list[0]
mtx = global_demarcate_param_list[1]
dist = global_demarcate_param_list[2]
rvecs = global_demarcate_param_list[3]
tvecs = global_demarcate_param_list[4]
objpoints = global_demarcate_param_list[5]
imgpoints = global_demarcate_param_list[6]
show_img = eliminate_distortion(ret, mtx, dist, rvecs, tvecs, img, objpoints, imgpoints)
#print(type(show_img))
else:
pr_ll("讀入配置文件測(cè)試")
data_dict = set_setting_file("Distortion_correct.json")
ret = data_dict["ret"]
mtx = list_to_np_list(data_dict["mtx"],type_name="float64")
dist = list_to_np_list(data_dict["dist"],type_name="float64")
rvecs = list_to_np_list(data_dict["rvecs"])
tvecs = list_to_np_list(data_dict["tvecs"])
objpoints = list_to_np_list(data_dict["objpoints"])
imgpoints = list_to_np_list(data_dict["imgpoints"])
show_img = eliminate_distortion(ret, mtx, dist, rvecs, tvecs, img, objpoints, imgpoints)
#print(type(show_img))
#print("1037 請(qǐng)先獲得標(biāo)定參數(shù)")
if save_json_button != global_save_json_button:
#print("存入當(dāng)前標(biāo)定數(shù)據(jù)到j(luò)son文件")
global_save_json_button = save_json_button
if global_demarcate_param_list != []:
param_dict = {}
ret = global_demarcate_param_list[0]
mtx = global_demarcate_param_list[1] # <class 'numpy.ndarray'>
dist = global_demarcate_param_list[2] # <class 'numpy.ndarray'>
rvecs = global_demarcate_param_list[3] # list <class 'numpy.ndarray'>
tvecs = global_demarcate_param_list[4] # list <class 'numpy.ndarray'>
objpoints = global_demarcate_param_list[5] # list <class 'numpy.ndarray'>
imgpoints = global_demarcate_param_list[6] # list <class 'numpy.ndarray'>
pr_ll("mtx")
#print(mtx)
#print(type(mtx))
pr_ll("mtx")
param_dict["w"] = w
param_dict["h"] = h
param_dict["ret"] = global_demarcate_param_list[0]
param_dict["mtx"] = global_demarcate_param_list[1].tolist()
param_dict["dist"] = np_list_to_list(global_demarcate_param_list[2])
param_dict["rvecs"] = np_list_to_list(global_demarcate_param_list[3])
param_dict["tvecs"] = np_list_to_list(global_demarcate_param_list[4])
param_dict["objpoints"] = np_list_to_list(global_demarcate_param_list[5])
param_dict["imgpoints"] = np_list_to_list(global_demarcate_param_list[6])
save_setting_file(demarcate_json_path,param_dict)
else:
logger_flow.warning("1037 請(qǐng)先獲得標(biāo)定參數(shù)")
return show_img, show_img, img_datas
3.基于PNP (Perspective-n-Point)方法的相機(jī)位置求解
參考鏈接
solvepnp通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿(R,t)
通過特征點(diǎn),這里即棋盤格角點(diǎn)的世界坐標(biāo)(三維坐標(biāo))、2D坐標(biāo)(像素坐標(biāo))、相機(jī)內(nèi)參矩陣、相機(jī)畸變參數(shù)矩陣 以上四個(gè)參數(shù)即可以解得相機(jī)與標(biāo)志物之間的外參(R、T)
來到了倒數(shù)第二步,通過solvePnP函數(shù)為標(biāo)定函數(shù)準(zhǔn)備最后兩個(gè)參數(shù),
這里我們需要對(duì)之前的
- objectPonints 由x方向格子數(shù),y方向格子數(shù),單位棋盤格長(zhǎng)度(單位毫米)來構(gòu)造以棋盤格左上角為原點(diǎn)的三維坐標(biāo)矩陣,(由于棋盤格可用認(rèn)作是一個(gè)平面,所以z軸為0)
2.通過角點(diǎn)尋找函數(shù)獲得的角點(diǎn),構(gòu)成的二維矩陣(這里可以提前自己審核后存到j(luò)son或者xml文件中,以避免下面由于圖片問題角點(diǎn)找不齊的問題)
#用來從棋盤格圖片得到相機(jī)外參
def get_RT_from_chessboard(img_path,chess_board_x_num,chess_board_y_num,K,chess_board_len):
'''
:param img_path: 讀取圖片路徑
:param chess_board_x_num: 棋盤格x方向格子數(shù)
:param chess_board_y_num: 棋盤格y方向格子數(shù)
:param K: 相機(jī)內(nèi)參
:param chess_board_len: 單位棋盤格長(zhǎng)度,mm
:return: 相機(jī)外參
'''
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, (chess_board_x_num, chess_board_y_num), None)
# print(corners)
corner_points=np.zeros((2,corners.shape[0]),dtype=np.float64)
for i in range(corners.shape[0]):
corner_points[:,i]=corners[i,0,:]
# print(corner_points)
object_points=np.zeros((3,chess_board_x_num*chess_board_y_num),dtype=np.float64)
flag=0
for i in range(chess_board_y_num):
for j in range(chess_board_x_num):
object_points[:2,flag]=np.array([(11-j-1)*chess_board_len,(8-i-1)*chess_board_len])
flag+=1
# print(object_points)
retval,rvec,tvec = cv2.solvePnP(object_points.T,corner_points.T, K, distCoeffs=None)
# print(rvec.reshape((1,3)))
# RT=np.column_stack((rvec,tvec))
RT=np.column_stack(((cv2.Rodrigues(rvec))[0],tvec))
RT = np.row_stack((RT, np.array([0, 0, 0, 1])))
# RT=pose(rvec[0,0],rvec[1,0],rvec[2,0],tvec[0,0],tvec[1,0],tvec[2,0])
# print(RT)
# print(retval, rvec, tvec)
# print(RT)
# print('')
return RT
送入后出現(xiàn)如下報(bào)錯(cuò),
File “I:/Python/BasicDemo/ele/cs1.py”, line 116, in
get_RT_from_chessboard
retval, rvec, tvec = cv2.solvePnP(object_points.T, corner_points.T, K, distCoeffs=dist) cv2.error: OpenCV(4.5.3)
C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-_xlv4eex\opencv\modules\calib3d\src\solvepnp.cpp:833:
error: (-215:Assertion failed) ( (npoints >= 4) || (npoints == 3 &&
flags == SOLVEPNP_ITERATIVE && useExtrinsicGuess) || (npoints >= 3 &&
flags == SOLVEPNP_SQPNP) ) && npoints ==
std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2,
CV_64F)) in function ‘cv::solvePnPGeneric’
說明標(biāo)定板(我這里是棋盤格),通過輸入輸入的棋盤格x方向,y方向,棋盤格格子的長(zhǎng)度,通過代碼生成的三維坐標(biāo)點(diǎn)(下右),和通過角點(diǎn)尋找函數(shù)得到的角點(diǎn)構(gòu)成的映射的二維坐標(biāo)矩陣(下左),匹配錯(cuò)誤, 如下我的錯(cuò)誤就是角點(diǎn)查找函數(shù)輸出時(shí)少輸出了一個(gè)角點(diǎn)(這里主要是和自己準(zhǔn)備的圖片樣本有關(guān))示例:
4.代入手眼標(biāo)定函數(shù)calibrateHandeye()
經(jīng)過上面一堆的步驟,終于籌齊了該函數(shù)需要的4個(gè)參數(shù),現(xiàn)在將其輸入進(jìn)去,即可得到輸出的一個(gè)旋轉(zhuǎn)矩陣,一個(gè)平移矩陣,然后把這倆個(gè)列合并,然后變成齊次式的形式
RT=np.column_stack((R,T))
RT = np.row_stack((RT, np.array([0, 0, 0, 1])))
手眼矩陣分解得到的旋轉(zhuǎn)矩陣
[[ 0.91155556 -0.05663482 -0.40725785]
[-0.07167205 0.95341986 -0.29300801]
[ 0.40488217 0.29628208 0.86503604]]
手眼矩陣分解得到的平移矩陣
[[ 57.60044963]
[-101.07768643]
[ 124.24813674]]
相機(jī)相對(duì)于末端的變換矩陣為:
[[ 9.11555562e-01 -5.66348167e-02 -4.07257848e-01 5.76004496e+01]
[-7.16720453e-02 9.53419858e-01 -2.93008007e-01 -1.01077686e+02]
[ 4.04882175e-01 2.96282081e-01 8.65036041e-01 1.24248137e+02]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
以下為帶注釋的代碼,自己做json文件和對(duì)應(yīng)的圖片哈
import cv2
import numpy as np
import glob
from math import *
import pandas as pd
import os
import json
# K=np.array([[4283.95148301687,-0.687179973528103,2070.79900757240],
# [0,4283.71915784510,1514.87274457919],
# [0,0,1]],dtype=np.float64)#大恒相機(jī)內(nèi)參
K=np.matrix([[4283.95148301687,-0.687179973528103,2070.79900757240],
[0,4283.71915784510,1514.87274457919],
[0,0,1]],dtype=np.float64)#大恒相機(jī)內(nèi)參
#
# K=np.array( [[1358.1241306355312, 0.0, 979.3369840601881],
# [0.0, 1373.7959382800464, 746.2664607155928],
# [0.0, 0.0, 1.0]],dtype=np.float64)#大恒相機(jī)內(nèi)參
dist = np.array([0.0, 0.0, 0.0, 0.0])
#
# dist = np.array([[0.027380026193468753, -0.08801521475213679, 0.0011824388616034057,
# -0.0008063100320946023, 0.18819181491200773]],dtype=np.float64)
chess_board_x_num=11#棋盤格x方向格子數(shù)
chess_board_y_num=8#棋盤格y方向格子數(shù)
chess_board_len=30#單位棋盤格長(zhǎng)度,mm
#用于根據(jù)歐拉角計(jì)算旋轉(zhuǎn)矩陣
def myRPY2R_robot(x, y, z):
Rx = np.array([[1, 0, 0], [0, cos(x), -sin(x)], [0, sin(x), cos(x)]])
Ry = np.array([[cos(y), 0, sin(y)], [0, 1, 0], [-sin(y), 0, cos(y)]])
Rz = np.array([[cos(z), -sin(z), 0], [sin(z), cos(z), 0], [0, 0, 1]])
R = Rz@Ry@Rx
return R
#用于根據(jù)位姿計(jì)算變換矩陣
def pose_robot(x, y, z, Tx, Ty, Tz):
thetaX = x / 180 * pi
thetaY = y / 180 * pi
thetaZ = z / 180 * pi
R = myRPY2R_robot(thetaX, thetaY, thetaZ)
t = np.array([[Tx], [Ty], [Tz]])
RT1 = np.column_stack([R, t]) # 列合并
RT1 = np.row_stack((RT1, np.array([0,0,0,1])))
# RT1=np.linalg.inv(RT1)
return RT1
#用來從棋盤格圖片得到相機(jī)外參
def get_RT_from_chessboard(img_path,chess_board_x_num,chess_board_y_num,K,chess_board_len):
'''
:param img_path: 讀取圖片路徑
:param chess_board_x_num: 棋盤格x方向格子數(shù)
:param chess_board_y_num: 棋盤格y方向格子數(shù)
:param K: 相機(jī)內(nèi)參
:param chess_board_len: 單位棋盤格長(zhǎng)度,mm
:return: 相機(jī)外參
'''
img=cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, (chess_board_x_num, chess_board_y_num), None)
corner_points=np.zeros((2,corners.shape[0]),dtype=np.float64)
for i in range(corners.shape[0]):
corner_points[:,i]=corners[i,0,:]
# print(corner_points)
object_points=np.zeros((3,chess_board_x_num*chess_board_y_num),dtype=np.float64)
flag=0
for i in range(chess_board_y_num):
for j in range(chess_board_x_num):
object_points[:2,flag]=np.array([(11-j-1)*chess_board_len,(8-i-1)*chess_board_len])
flag+=1
# retval,rvec,tvec = cv2.solvePnP(object_points.T,corner_points.T, K, distCoeffs=None)
# print("object_points.T:")
# print(object_points.T)
# print(type(object_points.T))
# print("-" * 20)
#
# print("corner_points.T:")
# print(corner_points.T)
# print(type(corner_points.T))
# print("-" * 20)
# print("objp:")
# print(object_points)
# print(type(object_points))
# print("*" * 20)
#
# print("imgp:")
# print(corner_points)
# print(type(corner_points))
# print("*" * 20)
# print("K:")
# print(K)
# print(type(K))
# print("*" * 20)
#
# print("D_0:")
# print(dist)
# print(type(dist))
# print("*" * 20)
print("開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿")
print("\n")
retval, rvec, tvec = cv2.solvePnP(object_points.T, corner_points.T, K, distCoeffs=dist)
# print(rvec.reshape((1,3)))
# RT=np.column_stack((rvec,tvec))
RT=np.column_stack(((cv2.Rodrigues(rvec))[0],tvec))
RT = np.row_stack((RT, np.array([0, 0, 0, 1])))
# RT=pose(rvec[0,0],rvec[1,0],rvec[2,0],tvec[0,0],tvec[1,0],tvec[2,0])
# print(RT)
# print(retval, rvec, tvec)
# print(RT)
# print('')
return RT
def set_setting_file(path):
try:
with open(path) as json_file:
setting_dict_string = json_file.readline()[:-2]
return json.loads(setting_dict_string)
except:
return {}
def read_xyz_Rxyz(good_picture, folder, ele_data_dict={}):
"""用于讀取每個(gè)圖片對(duì)應(yīng)的json文件中,對(duì)應(yīng)的"""
for i in good_picture:
ele_data_dict[i] = set_setting_file(folder+'/'+str(i)+'.json')
return ele_data_dict
folder = r"save_cail_data"#棋盤格圖片存放文件夾
# files = os.listdir(folder)
# file_num=len(files)
# RT_all=np.zeros((4,4,file_num))
# print(get_RT_from_chessboard('calib/2.bmp', chess_board_x_num, chess_board_y_num, K, chess_board_len))
'''
這個(gè)地方很奇怪的特點(diǎn),有些棋盤格點(diǎn)檢測(cè)得出來,有些檢測(cè)不了,可以通過函數(shù)get_RT_from_chessboard的運(yùn)行時(shí)間來判斷
'''
# good_picture=[2,3,4,5,6,7,8,9]#存放可以檢測(cè)出棋盤格角點(diǎn)的圖片
# good_picture=[1,3,10,11,12]
good_picture=[2,3,4,5,7,8,9]#存放可以檢測(cè)出棋盤格角點(diǎn)的圖片
ele_data_dict = read_xyz_Rxyz(good_picture,folder)
# print(ele_data_dict)
file_num=len(good_picture)
#計(jì)算board to cam 變換矩陣
R_all_chess_to_cam_1=[]
T_all_chess_to_cam_1=[]
for i in good_picture:
# print(i)
image_path=folder+'/'+str(i)+'.bmp'
print("開始解析"+ folder+'/'+str(i)+'.bmp'+ "的角點(diǎn)信息")
RT=get_RT_from_chessboard(image_path, chess_board_x_num, chess_board_y_num, K, chess_board_len)
# RT=np.linalg.inv(RT)
R_all_chess_to_cam_1.append(RT[:3,:3])
T_all_chess_to_cam_1.append(RT[:3, 3].reshape((3,1)))
# print(T_all_chess_to_cam.shape)
#計(jì)算end to base變換矩陣
R_all_end_to_base_1=[]
T_all_end_to_base_1=[]
# print(sheet_1.iloc[0]['ax'])
for i in good_picture:
print("開始分析第" + str(i) + "張圖片對(duì)應(yīng)的json文件")
# RT=pose_robot(sheet_1.iloc[i-1]['ax'],sheet_1.iloc[i-1]['ay'],sheet_1.iloc[i-1]['az'],sheet_1.iloc[i-1]['dx'],
# sheet_1.iloc[i-1]['dy'],sheet_1.iloc[i-1]['dz'])
RT = pose_robot(ele_data_dict[i]["x"], ele_data_dict[i]["y"], ele_data_dict[i]["z"],
ele_data_dict[i]["Rx"],ele_data_dict[i]["Ry"],ele_data_dict[i]["Rz"])
R_all_end_to_base_1.append(RT[:3, :3])
T_all_end_to_base_1.append(RT[:3, 3].reshape((3, 1)))
print("基坐標(biāo)系的旋轉(zhuǎn)矩陣與平移向量求解完畢......")
print("進(jìn)入手眼標(biāo)定函數(shù)。。。。。。")
# print(R_all_end_to_base_1)
# print(T_all_end_to_base_1)
print("\n")
R,T=cv2.calibrateHandEye(R_all_end_to_base_1,T_all_end_to_base_1,R_all_chess_to_cam_1,T_all_chess_to_cam_1)#手眼標(biāo)定
print("手眼矩陣分解得到的旋轉(zhuǎn)矩陣")
print(R)
print("\n")
print("手眼矩陣分解得到的平移矩陣")
print(T)
RT=np.column_stack((R,T))
RT = np.row_stack((RT, np.array([0, 0, 0, 1])))#即為cam to end變換矩陣
print("\n")
print('相機(jī)相對(duì)于末端的變換矩陣為:')
print(RT)
#結(jié)果驗(yàn)證,原則上來說,每次結(jié)果相差較小
for i in range(len(good_picture)):
# 得到機(jī)械手末端到基座的變換矩陣,通過機(jī)械手末端到基座的旋轉(zhuǎn)矩陣與平移向量先按列合并,然后按行合并形成變換矩陣格式
RT_end_to_base=np.column_stack((R_all_end_to_base_1[i],T_all_end_to_base_1[i]))
RT_end_to_base=np.row_stack((RT_end_to_base,np.array([0,0,0,1])))
# print(RT_end_to_base)
# 標(biāo)定版相對(duì)于相機(jī)的齊次矩陣
RT_chess_to_cam=np.column_stack((R_all_chess_to_cam_1[i],T_all_chess_to_cam_1[i]))
RT_chess_to_cam=np.row_stack((RT_chess_to_cam,np.array([0,0,0,1])))
# print(RT_chess_to_cam)
# 手眼標(biāo)定變換矩陣
RT_cam_to_end=np.column_stack((R,T))
RT_cam_to_end=np.row_stack((RT_cam_to_end,np.array([0,0,0,1])))
# print(RT_cam_to_end)
# 即為固定的棋盤格相對(duì)于機(jī)器人基坐標(biāo)系位姿
RT_chess_to_base=RT_end_to_base@RT_cam_to_end@RT_chess_to_cam
RT_chess_to_base=np.linalg.inv(RT_chess_to_base)
print('第',i,'次')
print(RT_chess_to_base[:3,:])
print('')
輸出
I:\NI\Anaconda\envs\cv2\python.exe I:/Python/BasicDemo/ele/cs2.py
開始解析save_cail_data/2.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/3.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/4.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/5.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/7.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/8.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始解析save_cail_data/9.bmp的角點(diǎn)信息
開始根據(jù)角點(diǎn)信息與對(duì)應(yīng)該組信息的機(jī)械臂返回,通過2D點(diǎn)和3D點(diǎn)求解相機(jī)的位姿
開始分析第2張圖片對(duì)應(yīng)的json文件
開始分析第3張圖片對(duì)應(yīng)的json文件
開始分析第4張圖片對(duì)應(yīng)的json文件
開始分析第5張圖片對(duì)應(yīng)的json文件
開始分析第7張圖片對(duì)應(yīng)的json文件
開始分析第8張圖片對(duì)應(yīng)的json文件
開始分析第9張圖片對(duì)應(yīng)的json文件
基坐標(biāo)系的旋轉(zhuǎn)矩陣與平移向量求解完畢......
進(jìn)入手眼標(biāo)定函數(shù)。。。。。。
手眼矩陣分解得到的旋轉(zhuǎn)矩陣
[[ 0.91155556 -0.05663482 -0.40725785]
[-0.07167205 0.95341986 -0.29300801]
[ 0.40488217 0.29628208 0.86503604]]
手眼矩陣分解得到的平移矩陣
[[ 57.60044963]
[-101.07768643]
[ 124.24813674]]
相機(jī)相對(duì)于末端的變換矩陣為:
[[ 9.11555562e-01 -5.66348167e-02 -4.07257848e-01 5.76004496e+01]
[-7.16720453e-02 9.53419858e-01 -2.93008007e-01 -1.01077686e+02]
[ 4.04882175e-01 2.96282081e-01 8.65036041e-01 1.24248137e+02]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
第 0 次
[[ 2.33572044e-01 -9.10009016e-01 3.42531300e-01 7.72449880e+02]
[ 4.00302828e-01 -2.31041758e-01 -8.86779201e-01 -1.56513760e+02]
[ 8.86116102e-01 3.44243079e-01 3.10314286e-01 -1.77002869e+03]]
第 1 次
[[ 2.78244828e-01 -8.84523147e-01 3.74431060e-01 7.78947806e+02]
[ 1.83357762e-01 -3.33742558e-01 -9.24659849e-01 -1.17473049e+02]
[ 9.42846619e-01 3.25936661e-01 6.93220441e-02 -1.76238460e+03]]
第 2 次
[[ 2.46706389e-01 -9.14939020e-01 3.19409686e-01 8.03039487e+02]
[ 2.14992414e-01 -2.69710750e-01 -9.38634313e-01 -1.28440399e+02]
[ 9.44941384e-01 3.00237741e-01 1.30165583e-01 -1.76815689e+03]]
第 3 次
[[ 5.89266715e-01 -6.25720741e-01 5.11114756e-01 6.42562840e+02]
[ 2.32373222e-01 -4.74629044e-01 -8.48958159e-01 -1.33993275e+02]
[ 7.73800636e-01 6.19032168e-01 -1.34282353e-01 -1.71947250e+03]]
第 4 次
[[ 5.47363417e-01 -3.14921335e-01 7.75382384e-01 6.04746992e+02]
[ 6.50659114e-01 -4.22559881e-01 -6.30940460e-01 -2.26083803e+02]
[ 5.26342100e-01 8.49863342e-01 -2.63873836e-02 -1.68417190e+03]]
第 5 次
[[ 7.82415161e-01 -2.89829020e-01 5.51203824e-01 5.75035151e+02]
[ 3.91139161e-01 -4.60040208e-01 -7.97102982e-01 -1.80266317e+02]
[ 4.84599498e-01 8.39262859e-01 -2.46578953e-01 -1.66563927e+03]]
第 6 次
[[ 6.79225047e-01 -2.15407133e-01 7.01607513e-01 5.84337739e+02]
[ 5.82864803e-01 -4.22614543e-01 -6.94021303e-01 -2.20238484e+02]
[ 4.46006678e-01 8.80338977e-01 -1.61497147e-01 -1.66336005e+03]]
進(jìn)程已結(jié)束,退出代碼 0
2023補(bǔ) 畸變矯正代碼
生成的畸變矯正用的測(cè)試json文件文章來源:http://www.zghlxwxcb.cn/news/detail-790267.html
生成文件的代碼見博客中
可生成畸變矯正后的圖像文章來源地址http://www.zghlxwxcb.cn/news/detail-790267.html
import json
import cv2
import numpy as np
class Dist_corre():
def __init__(self):
self.open_corre_bool = True
self.corre_json_dict = {}
self.get_setting_file("Demarcate_json/Distortion_correct.json")
def open_correct(self, img):
if self.open_corre_bool:
# print("矯正-圖像")
return self.correct_flow(img)
else:
# print("原始圖像")
return img
def correct_flow(self, img):
"""矯正流程"""
ret = self.corre_json_dict["ret"]
mtx = self.list_to_np_list(self.corre_json_dict["mtx"], type_name="float64")
dist = self.list_to_np_list(self.corre_json_dict["dist"], type_name="float64")
rvecs = self.list_to_np_list(self.corre_json_dict["rvecs"])
tvecs = self.list_to_np_list(self.corre_json_dict["tvecs"])
objpoints = self.list_to_np_list(self.corre_json_dict["objpoints"])
imgpoints = self.list_to_np_list(self.corre_json_dict["imgpoints"])
correct_img = self.eliminate_distortion(ret, mtx, dist, rvecs, tvecs, img, objpoints, imgpoints)
return correct_img
def eliminate_distortion(self, ret, mtx, dist, rvecs, tvecs, img2, objpoints, imgpoints):
# 去畸變
h, w = img2.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h)) # 自由比例參數(shù)
dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)
# print("44 畸變?nèi)コ?)
# dst = cv2.undistort(img2, mtx, dist)
# 根據(jù)前面ROI區(qū)域裁剪圖片
# x,y,w,h = roi
# dst = dst[y:y+h, x:x+w]
"""反投影誤差"""
# total_error = 0
# for i in range(len(objpoints)):
# imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
# error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
# total_error += error
# print("反投影誤差: " + str(total_error / len(objpoints)))
return dst
def list_to_np_list(self, data_list, type_name=""):
finall_list = []
# 將讀到的 list轉(zhuǎn)換成 np格式的 多維數(shù)組
if type_name == "":
for i in data_list:
finall_list.append(np.array(i))
elif type_name == "float64":
finall_list = np.array(data_list, dtype=float)
return finall_list
else:
print("不存在當(dāng)前類型")
return finall_list
def np_list_to_list(self, list_cs):
tem_list = []
# 通過 tolist() 將 array 類型的數(shù)值轉(zhuǎn)換成,python自帶的類型
for i in list_cs:
tem_list.append(i.tolist())
return tem_list
def get_setting_file(self, path):
"""讀取"""
try:
with open(path) as json_file:
setting_dict_string = json_file.readline()[:-2]
self.corre_json_dict = json.loads(setting_dict_string)
print("矯正流程文件 Distortion_correct.json 讀取成功")
except:
print("?。。。。。。。。。。。。。?!矯正流程文件 Distortion_correct.json 讀取失敗,請(qǐng)檢查是否存在且格式是否正常?。。。。。。。。。。。。。?!")
D_cor = Dist_corre()
if __name__ == '__main__':
img = cv2.imread("cs/rgb1.png")
D_cor = Dist_corre()
dst_img = D_cor.open_correct(img)
cv2.imshow("out", dst_img)
cv2.waitKey(10000)
到了這里,關(guān)于python 手眼標(biāo)定OpenCV手眼標(biāo)定(calibrateHandeye())二的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!