国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

python 手眼標(biāo)定OpenCV手眼標(biāo)定(calibrateHandeye())二

這篇具有很好參考價(jià)值的文章主要介紹了python 手眼標(biāo)定OpenCV手眼標(biāo)定(calibrateHandeye())二。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

這一章我們來根據(jù)上一章的分析,為手眼標(biāo)定函數(shù)calibrateHandEye 準(zhǔn)備他那些麻煩的參數(shù)
更詳細(xì)的參數(shù)參考鏈接
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣

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è)歐拉角
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
示例代碼

# -*- 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ī)外參。
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣

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)行任何的畸變矯正操作)
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣

然后我們使用cv2.findChessboardCorners進(jìn)行角點(diǎn)尋找,如下經(jīng)過測(cè)試8-11 或 11-8 可找到可用角點(diǎn),下圖的窗口是我分裝的滑塊窗口調(diào)試的,不是這個(gè)函數(shù)運(yùn)行就這樣哈。
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
如上圖
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’
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
上圖為3.png

cornerSubPix()對(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)參矩陣,遇到了的話參考該鏈接)

opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
因此如果可以明確的知道以上四個(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ù),
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣
這里我們需要對(duì)之前的

  1. 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))示例:
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣

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文件

生成文件的代碼見博客中
可生成畸變矯正后的圖像
opencv 手眼標(biāo)定,opencv,opencv,python,矩陣文章來源地址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)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • (已修正精度 1mm左右)Realsense d435i深度相機(jī)+Aruco+棋盤格+OpenCV手眼標(biāo)定全過程記錄

    (已修正精度 1mm左右)Realsense d435i深度相機(jī)+Aruco+棋盤格+OpenCV手眼標(biāo)定全過程記錄

    最近幫別人做了個(gè)手眼標(biāo)定,然后我標(biāo)定完了大概精度能到1mm左右。所以原文中誤差10mm可能是當(dāng)時(shí)那個(gè)臂本身的坐標(biāo)系有問題。然后用的代碼改成了基于python的,放在下面。 新來的小伙伴可以只參考前面的代碼就可以完成標(biāo)定了。 有問題的話可以留言,一起交流~ 手眼標(biāo)定

    2024年02月04日
    瀏覽(49)
  • 機(jī)械臂 手眼標(biāo)定 手眼矩陣 eye-in-hand 原理、實(shí)踐及代碼

    機(jī)械臂 手眼標(biāo)定 手眼矩陣 eye-in-hand 原理、實(shí)踐及代碼

    所謂 手眼系統(tǒng) ,就是人眼睛看到一個(gè)東西的時(shí)候要讓手去抓取,就需要大腦知道眼睛和手的坐標(biāo)關(guān)系。而相機(jī)知道的是像素坐標(biāo),機(jī)械手是空間坐標(biāo)系,所以手眼標(biāo)定就是得到像素坐標(biāo)系和空間機(jī)械手坐標(biāo)系的坐標(biāo)轉(zhuǎn)化關(guān)系。 目前工業(yè)上通常使用兩種方法進(jìn)行機(jī)械臂的手眼

    2024年02月03日
    瀏覽(24)
  • OpenCV開發(fā)筆記(七十七):相機(jī)標(biāo)定(二):通過棋盤標(biāo)定計(jì)算相機(jī)內(nèi)參矩陣矯正畸變攝像頭圖像

    OpenCV開發(fā)筆記(七十七):相機(jī)標(biāo)定(二):通過棋盤標(biāo)定計(jì)算相機(jī)內(nèi)參矩陣矯正畸變攝像頭圖像

    若該文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明原文出處 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/136616551 各位讀者,知識(shí)無窮而人力有窮,要么改需求,要么找專業(yè)人士,要么自己研究 紅胖子(紅模仿)的博文大全:開發(fā)技術(shù)集合(包含Qt實(shí)用技術(shù)、樹莓派、三維、OpenCV、OpenGL、

    2024年03月13日
    瀏覽(33)
  • Python之OpenCV相機(jī)標(biāo)定

    Python之OpenCV相機(jī)標(biāo)定

    本文結(jié)合OpenCV官方樣例,對(duì)官方樣例中的代碼進(jìn)行修改,使其能夠正常運(yùn)行,并對(duì)自己采集的數(shù)據(jù)進(jìn)行實(shí)驗(yàn)和講解。 OpenCV使用棋盤格板進(jìn)行標(biāo)定,如下圖所示。為了標(biāo)定相機(jī),我們需要輸入一系列三維點(diǎn)和它們對(duì)應(yīng)的二維圖像點(diǎn)。在黑白相間的棋盤格上,二維圖像點(diǎn)很容易通

    2024年02月03日
    瀏覽(25)
  • 機(jī)器人手眼標(biāo)定原理與python實(shí)現(xiàn)

    機(jī)器人手眼標(biāo)定原理與python實(shí)現(xiàn)

    機(jī)器人手眼標(biāo)定分為eye in hand與eye to hand兩種。介紹之前進(jìn)行變量定義說明: : base基坐標(biāo)系 {g}: gripper夾具坐標(biāo)系 {t}: target標(biāo)定板坐標(biāo)系 {c}: camera相機(jī)坐標(biāo)系 1、眼在手上(eye in hand) 眼在手上,相機(jī)固定在機(jī)器人上。 圖1. eye in hand示意圖 由以上兩公式得: 經(jīng)變換得: 可得:

    2024年02月02日
    瀏覽(19)
  • python opencv實(shí)現(xiàn)相機(jī)內(nèi)參標(biāo)定

    python opencv實(shí)現(xiàn)相機(jī)內(nèi)參標(biāo)定

    使用python opencv 標(biāo)定相機(jī)內(nèi)參。 (1)從網(wǎng)絡(luò)上下載一張棋盤格圖片,粘貼到word文檔上,設(shè)定尺寸大小為合適值,作為標(biāo)定板。 (2)在不同距離,不同角度下用手機(jī)相機(jī)拍攝棋盤圖片。 (3)調(diào)用 opencv findChessboardCorners 和 cornerSubPix 函數(shù)提取棋盤的角點(diǎn)。 (4)調(diào)用 opencv cal

    2024年02月13日
    瀏覽(36)
  • 機(jī)械臂進(jìn)行手眼標(biāo)定(眼在手上)python代碼

    執(zhí)行手眼標(biāo)定(eye in hand)步驟: 收集數(shù)據(jù):使用相機(jī)拍攝多張不同角度的標(biāo)定板圖像,并記錄相機(jī)和機(jī)械臂的位姿數(shù)據(jù)。 提取標(biāo)定板角點(diǎn):使用OpenCV庫中的函數(shù)cv2.findChessboardCorners()提取標(biāo)定板圖像中的角點(diǎn)坐標(biāo)。 計(jì)算相機(jī)內(nèi)參矩陣:使用OpenCV庫中的函數(shù)cv2.calibrateCamera()計(jì)

    2024年02月16日
    瀏覽(26)
  • OpenCV基礎(chǔ)(28)使用OpenCV進(jìn)行攝像機(jī)標(biāo)定Python和C++

    OpenCV基礎(chǔ)(28)使用OpenCV進(jìn)行攝像機(jī)標(biāo)定Python和C++

    攝像頭是機(jī)器人、監(jiān)控、太空探索、社交媒體、工業(yè)自動(dòng)化甚至娛樂業(yè)等多個(gè)領(lǐng)域不可或缺的一部分。 對(duì)于許多應(yīng)用,必須了解相機(jī)的參數(shù)才能有效地將其用作視覺傳感器。 在這篇文章中,您將了解相機(jī)校準(zhǔn)所涉及的步驟及其意義。 我們還共享 C++ 和 Python 代碼以及棋盤圖案

    2024年02月04日
    瀏覽(18)
  • 4、OpenCV-Python雙目標(biāo)定流程

    4、OpenCV-Python雙目標(biāo)定流程

    ?? 雙目標(biāo)定的目的是獲取左右目相機(jī)的內(nèi)參矩陣、畸變向量、旋轉(zhuǎn)矩陣和平移矩陣。 ?? 除了Matlab的標(biāo)定工具箱之外,OpenCV同樣也實(shí)現(xiàn)了張友正標(biāo)定法,而我們只需要調(diào)用相關(guān)的函數(shù)即可對(duì)相機(jī)進(jìn)行標(biāo)定。 雙目相機(jī)標(biāo)定步驟: 檢測(cè)棋盤格角點(diǎn) 對(duì)角點(diǎn)進(jìn)行亞像素精細(xì)化

    2024年01月16日
    瀏覽(20)
  • 相機(jī)標(biāo)定原理與實(shí)戰(zhàn)【python-opencv】

    相機(jī)標(biāo)定原理與實(shí)戰(zhàn)【python-opencv】

    相機(jī)的功能就是將真實(shí)的三維世界拍攝形成二維的圖片。所以可以將相機(jī)成像的過程看做一個(gè)函數(shù),輸入是一個(gè)三維的場(chǎng)景,輸出是二維的圖片。但是,當(dāng)我們想將二維的圖片反映射成三維場(chǎng)景時(shí),很明顯,我們無法僅通過一張二維圖來得到真實(shí)的三維場(chǎng)景。也就是說,上述

    2024年02月09日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包