-
Notifications
You must be signed in to change notification settings - Fork 206
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add camera calibration example (#125)
- Loading branch information
1 parent
cbae55f
commit efeeede
Showing
5 changed files
with
4,462 additions
and
4,298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# pixi environments | ||
.pixi | ||
haarcascade_frontalface_default.xml | ||
*.png |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# OpenCV example | ||
OpenCV is a powerfull tool to do computer vision and fully opensource. | ||
|
||
Here are some example on how to use it with `pixi`. | ||
|
||
## Simple face detection algorithm | ||
```shell | ||
pixi run start | ||
``` | ||
![Face detection result](https://github.com/ruben-arts/pixi/assets/12893423/c0151496-caae-407c-9e90-0f71f3c19aa7) | ||
|
||
|
||
## Simple camera calibration script | ||
```shell | ||
pixi run calibrate | ||
``` | ||
|
||
You'll need a checkerboard for this to work. | ||
Print this: [![chessboard](https://github.com/opencv/opencv/blob/4.x/doc/pattern.png?raw=true)](https://github.com/opencv/opencv/blob/4.x/doc/pattern.png) | ||
|
||
To make a picture for calibration press `SPACE` | ||
Do this approximately 10 times with the chessboard in view of the camera | ||
|
||
After that press `ESC` which will start the calibration. | ||
|
||
When the calibration is done the camera will be used again to find the distance to the checkerboard. | ||
|
||
![callibrated camera result](https://github.com/ruben-arts/pixi/assets/12893423/f42825d7-5010-4805-9f6b-b02075395413) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import cv2 | ||
import numpy as np | ||
|
||
# Termination criteria | ||
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 0.001) | ||
|
||
# Prepare object points | ||
# The example chessboard is 9x6. | ||
CHESSBOARD_X = 6 | ||
CHESSBOARD_Y = 9 | ||
# The example chessboard printed on a A4 paper will approximaly be 24mm in width and height. | ||
SQUARE_SIZE_MM = 22.5 | ||
|
||
objp = np.zeros((CHESSBOARD_X * CHESSBOARD_Y, 3), np.float32) | ||
objp[:,:2] = np.mgrid[0:CHESSBOARD_Y, 0:CHESSBOARD_X].T.reshape(-1, 2) * (SQUARE_SIZE_MM * 0.001) | ||
|
||
# Arrays to store object points and image points | ||
objpoints = [] | ||
imgpoints = [] | ||
|
||
# Initialize the camera | ||
cap = cv2.VideoCapture(0) | ||
|
||
# Set the frame width and height | ||
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) | ||
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) | ||
|
||
img_counter = 0 | ||
|
||
print("Press SPACE to capture an image for calibration.") | ||
print("Press ESC to calibrate the camera using the previously captured images.") | ||
|
||
while True: | ||
ret, frame = cap.read() | ||
if not ret: | ||
break | ||
|
||
frame_clean = cv2.copyTo(frame, None) | ||
# Find the chess board corners | ||
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | ||
ret, corners = cv2.findChessboardCorners(gray, (CHESSBOARD_Y, CHESSBOARD_X), None) | ||
|
||
if ret: | ||
cv2.drawChessboardCorners(frame, (CHESSBOARD_Y, CHESSBOARD_X), corners, ret) | ||
|
||
cv2.imshow("Test", frame) | ||
k = cv2.waitKey(1) | ||
|
||
if k%256 == 27: | ||
# ESC pressed | ||
print("Escape hit, closing...") | ||
break | ||
elif k%256 == 32: | ||
# SPACE pressed | ||
img_name = "opencv_frame_{}.png".format(img_counter) | ||
cv2.imwrite(img_name, frame_clean) | ||
print("{} written!".format(img_name)) | ||
img_counter += 1 | ||
|
||
# Convert to grayscale | ||
gray = cv2.cvtColor(frame_clean, cv2.COLOR_BGR2GRAY) | ||
|
||
# Find the chess board corners | ||
ret, corners = cv2.findChessboardCorners(gray, (CHESSBOARD_Y, CHESSBOARD_X), None) | ||
|
||
# If found, add object points, image points (after refining them) | ||
if ret: | ||
objpoints.append(objp) | ||
|
||
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) | ||
imgpoints.append(corners2) | ||
else: | ||
print("No chessboard detected in this image: {img_name}") | ||
|
||
cv2.destroyAllWindows() | ||
|
||
if len(objpoints) > 0: | ||
# Perform camera calibration | ||
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) | ||
|
||
# Print out the camera calibration results | ||
print("Camera matrix : \n") | ||
print(mtx) | ||
print("dist : \n") | ||
print(dist) | ||
print("rvecs : \n") | ||
print(rvecs) | ||
print("tvecs : \n") | ||
print(tvecs) | ||
|
||
while True: | ||
ret, frame = cap.read() | ||
if not ret: | ||
break | ||
k = cv2.waitKey(1) | ||
|
||
if k%256 == 27: | ||
# ESC pressed | ||
print("Escape hit, closing...") | ||
break | ||
|
||
# Convert to grayscale | ||
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | ||
|
||
# Find the chess board corners | ||
ret, corners = cv2.findChessboardCorners(gray, (CHESSBOARD_Y, CHESSBOARD_X), None) | ||
|
||
if ret: | ||
corners2 = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) | ||
imgpoints.append(corners2) | ||
|
||
# Draw and display the corners | ||
frame = cv2.drawChessboardCorners(frame, (CHESSBOARD_Y, CHESSBOARD_X), corners2, ret) | ||
|
||
# Estimate pose of pattern | ||
_, rvecs, tvecs, _ = cv2.solvePnPRansac(objp, corners2, mtx, dist) | ||
|
||
# Compute distance from camera to pattern | ||
x_distance = tvecs[0][0] | ||
y_distance = tvecs[1][0] | ||
z_distance = tvecs[2][0] | ||
|
||
text = f"X: {x_distance:.2f}m, Y: {y_distance:.2f}m, Z: {z_distance:.2f}m" | ||
cv2.putText(frame, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv2.LINE_AA) | ||
|
||
cv2.imshow('Result', frame) | ||
|
||
else: | ||
print("Not enough images where corners were found. Please capture more images.") | ||
|
||
cap.release() | ||
cv2.destroyAllWindows() |
Oops, something went wrong.