程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python uses opencv to calibrate the camera to obtain parameters, and correct the image according to the distortion parameters. All codes are attached (smooth and painless version)

編輯:Python

python利用opencvPerform camera calibration to obtain parameters,And according to the distortion parameters to correct the image with all the codes

一、前言

Today's low-cost single-hole camera(照相機)It will bring a lot of distortion to the image.There are two main types of distortion
種:Radial distortion and tangential distortion.如下圖所示,Mark the two sides of the chessboard with red lines,
But you will find that the border of the chessboard does not coincide with the red line.Everything we think should be straight is also convex
出來了.

在 3D 相關應用中,These distortions must be corrected first.in order to find these correction parameters,我們必
Some sample images containing obvious pattern patterns are required(For example a chessboard).We can find it there
to some special point(such as the four corners of a chessboard).We play where these special points are in the picture as well
Their real location.有了這些信息,We can then solve for the distortion coefficient mathematically.這
That's the summary of the whole story.為了得到更好的結果,我們至少需要 10 個這樣的圖
case mode.

二、Obtain the camera to be calibrated to take a picture with a checkerboard diagram

1、Run the program that generates the checkerboard diagram:

import cv2
import numpy as np
# 定義棋盤格的尺寸
size = 140
# 定義標定板尺寸
boardx = size * 10
boardy = size * 10
canvas = np.zeros((boardy, boardx, 1), np.uint8) # 創建畫布
for i in range(0, boardx):
for j in range(0, boardy):
if (int(i/size) + int(j/size)) % 2 != 0: # 判定是否為奇數格
canvas[j, i] = 255
cv2.imwrite("./chessboard.png", canvas)

生成結果如下:

2、Print the picture and post it on the tablet

Use a chessboard diagramA4紙打印,並將將A4The paper is attached to a very flat board and fixed
例子如下:
Rich big man,You can buy the calibration board directly.
注意,If it is a printed checkerboard, it must be flat,Otherwise, the calibration will be inaccurate

3、Take a distorted image

Use the camera from different angles,Shot in different locations(15-20)Zhang calibration diagram.類似這樣的:

python調用opencvCamera photo code(例):


import cv2
camera = cv2.VideoCapture(0)
i = 0
ret, img = camera.read()
print('輸入j,Download the current picture')
print('輸入q,終止程序')
while ret:
cv2.imshow('img', img)
ret, img = camera.read()
if cv2.waitKey(1) & 0xFF == ord('j'): # 按j保存一張圖片
i += 1
firename = str('./img' + str(i) + '.jpg')
cv2.imwrite(firename, img)
print('寫入:', firename)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.release()
cv2.destroyAllWindows()

按j拍攝圖片,will be saved in batches in order,按q退出程序.

三、The camera calibration procedure flow and related principles are explained

注:This part is for explanation only and no practical operation,Formal operations can skip the fourth step directly

1、利用opencvFind the chessboard

To find the pattern of the checkerboard,我們要使用函數 cv2.findChessboardCorners().
We also need to pass in the type of pattern,比如說 8x8 Grid or 5x5 grid, etc.在本例中
我們使用的9×6 的格子.(Usually the chessboard is 8x8 或者 7x7).它會返
Back to the corner,Return value type if image is obtained(Retval)就會是 True.These corners will
按順序排列(從左到右,從上到下)

This function may not find the pattern it should in all images.So a good way is to edit
寫代碼,Start the camera and check every frame for what it should be.After we get the pattern we want to find the corners and save them as a list.Set a certain interval before reading the next frame of image,This gives us enough time to adjust the direction of the board.Continue this process until we get enough good patterns.Even if we take this example,在所有的14 I don't know how many of the images are good.So we have to read each image and find the good ones from it.

除 了 使 用 棋 盤 之 外, 我 們 還 可 以 使 用 環 形 格 子, 但 是 要 使 用 函 數
cv2.findCirclesGrid() to find patterns.It is said that very few images are required to use the annular lattice 就可以了.

After finding these corners we can use the function cv2.cornerSubPix() Increase accuracy
度.我們使用函數 cv2.drawChessboardCorners() 繪制圖案.所有的這
These steps are included in the code below:

2、標定

After getting these object points and image points,We are ready to do camera calibration.
The function we are going to use is cv2.calibrateCamera().It returns the camera matrix,畸
變系數,Rotate and transform vectors, etc.

3、畸變矯正

Now we found what we were looking for,We can find an image to correct him
了.OpenCV 提供了兩種方法,Let's all learn.But until then we can use it
從函數 cv2.getOptimalNewCameraMatrix() The resulting free zoom factor is photographed
The camera matrix is ​​optimized.如果縮放系數 alpha = 0,The undistorted image is returned with a minimal amount
of unwanted pixels.It's even possible to remove some pixels at the corners of the image.如果 alpha = 1,所
Some pixels will be returned,There are also some black images.It will also return one ROI 圖像,我們可以
Used to crop the result.

函數:cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))中參數1是個坑,

這裡我們使用cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),0,(w,h))參數設置為0

4 、Distorted to undistorted
下面代碼中

  • dst1Image used is cv2.undistort() 這是最簡單的方法.Just use this function and what you got above ROI Crop the result

  • dst2Image used isremapping 這應該屬於“曲線救國”了.First we need to find the mapping equation from the distorted image to the undistorted image.Use the remapping equation again.(There are detailed usages in the code)

The two effects can be compared by themselves

Correct before and after comparison:

5、反向投影誤差

We can use the backprojection error to estimate the accuracy of the parameters we found.得到的
結果越接近 0 越好.With internal parameters,Distortion parameters and rotation transformation matrix,我們就可以使
用 cv2.projectPoints() Convert object points to image points.Then the transformation can be calculated
The absolute difference between the image and the corner detection algorithm is bad.Then we compute the mean of the errors over all the calibration images.

(But this article doesn't need it,So it is not written)

四、相機標定程序

目的:Get the camera's internal parameters after correcting the distortion

1、配置環境

a、安裝opencv-python

pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple/

b、安裝glob

pip install glob2 -i https://pypi.tuna.tsinghua.edu.cn/simple/

2、Run the program to get internal parameters

import cv2
import numpy as np
import glob
# 找棋盤格角點
# 設置尋找亞像素角點的參數,采用的停止准則是最大循環次數30和最大誤差容限0.001
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 阈值
#棋盤格模板規格
w = 9 # 10 - 1 
h = 9 # 10 - 1
# 世界坐標系中的棋盤格點,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐標,記為二維矩陣
objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
objp = objp*18.1 # 18.1 mm
# 儲存棋盤格角點的世界坐標和圖像坐標對
objpoints = [] # 在世界坐標系中的三維點
imgpoints = [] # 在圖像平面的二維點
#加載pic文件夾下所有的jpg圖像
images = glob.glob('./*.jpg') # 拍攝的十幾張棋盤圖片所在目錄
i=0
for fname in images:
img = cv2.imread(fname)
# 獲取畫面中心點
#獲取圖像的長寬
h1, w1 = img.shape[0], img.shape[1]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
u, v = img.shape[:2]
# 找到棋盤格角點
ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
# 如果找到足夠點對,將其存儲起來
if ret == True:
print("i:", i)
i = i+1
# 在原角點的基礎上尋找亞像素角點
cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
#Append to world 3D points and plane 2D points
objpoints.append(objp)
imgpoints.append(corners)
# 將角點在圖像上顯示
cv2.drawChessboardCorners(img, (w,h), corners, ret)
cv2.namedWindow('findCorners', cv2.WINDOW_NORMAL)
cv2.resizeWindow('findCorners', 640, 480)
cv2.imshow('findCorners',img)
cv2.waitKey(200)
cv2.destroyAllWindows()
#%% 標定
print('正在計算')
#標定
ret, mtx, dist, rvecs, tvecs = \
cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("ret:",ret )
print("mtx:\n",mtx) # 內參數矩陣
print("dist畸變值:\n",dist ) # 畸變系數 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("rvecs旋轉(向量)外參:\n",rvecs) # 旋轉向量 # 外參數
print("tvecs平移(向量)外參:\n",tvecs ) # 平移向量 # 外參數
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (u, v), 0, (u, v))
print('newcameramtx外參',newcameramtx)
#打開攝像機
camera=cv2.VideoCapture(0)
while True:
(grabbed,frame)=camera.read()
h1, w1 = frame.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (u, v), 0, (u, v))
# 糾正畸變
dst1 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
#dst2 = cv2.undistort(frame, mtx, dist, None, newcameramtx)
mapx,mapy=cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w1,h1),5)
dst2=cv2.remap(frame,mapx,mapy,cv2.INTER_LINEAR)
# 裁剪圖像,輸出糾正畸變以後的圖片
x, y, w1, h1 = roi
dst1 = dst1[y:y + h1, x:x + w1]
#cv2.imshow('frame',dst2)
#cv2.imshow('dst1',dst1)
cv2.imshow('dst2', dst2)
if cv2.waitKey(1) & 0xFF == ord('q'): # 按q保存一張圖片
cv2.imwrite("../u4/frame.jpg", dst1)
break
camera.release()
cv2.destroyAllWindows()

Put the code in the same folder as the picture and run it directly
運行結果如下:

五、Correct the camera according to the internal parameters obtained in the previous step


The previous program can be run to get the distortion internal parameters,將mtx值保存在k,
將dist保存在d

注:復制的時候,You need to manually add a comma inside the array

1、video program

import cv2 as cv
import numpy as np
def undistort(frame):
k=np.array( [[408.96873567 , 0. ,329.01126845],
[ 0. , 409.20308599 ,244.73617469],
[ 0. , 0. , 1. ]])
d=np.array([-0.33880708 , 0.16416173 ,-0.00039069 ,-0.00056267 ,-0.056967 ])
h,w=frame.shape[:2]
mapx,mapy=cv.initUndistortRectifyMap(k,d,None,k,(w,h),5)
return cv.remap(frame,mapx,mapy,cv.INTER_LINEAR)
cap=cv.VideoCapture(0)# Replace with the camera number to be turned on
ret,frame=cap.read()
while ret:
cv.imshow('later',frame)
cv.imshow('img',undistort(frame))
ret,frame=cap.read()
if cv.waitKey(1)&0xff==27:
break
cap.release()
cv.destroyAllWindows()

2、Correct the result

效果對比
Before and after correction:


可以看到,The distortion is almost corrected.
Distortion This program can be run once,之後的話,You can add the above one every time the camera acquires an image


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved