Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add camera calibration example #125

Merged
merged 2 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/opencv/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pixi environments
.pixi
haarcascade_frontalface_default.xml
*.png
29 changes: 29 additions & 0 deletions examples/opencv/README.md
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)

132 changes: 132 additions & 0 deletions examples/opencv/calibrate.py
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()
Loading