Introduction to OpenCV
You can view this slides on your device
2
Agenda
3
How OpenCV is organized
4
Before we start
5
Basic operations: load, display, manipulate images
Open images, open video, grab frames from a camera
6
import cv2
print(cv2.__version__)
img_color = cv2.imread('data/lena.png', cv2.IMREAD_COLOR)
img_gray = cv2.imread('data/lena.png', cv2.IMREAD_GRAYSCALE)
cap = cv2.VideoCapture('data/shuttle.mp4')
ret, frame = cap.read()
cap.release()
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
Basic operations: load, display, manipulate images
Display images
7
cv2.imshow('color', img_color)
cv2.waitKey()
cv2.destroyWindow('color')
cv2.imshow('gray', img_gray)
cv2.waitKey(5000)
cv2.destroyAllWindows()
Basic operations: load, display, manipulate images
Display images
8
cap = cv2.VideoCapture('data/shuttle.mp4')
while True:
ret, frame = cap.read()
cv2.imshow('video', frame)
if cv2.waitKey(30) == ord('e'):
break
cv2.destroyAllWindows()
cap.release()
Basic operations: load, display, manipulate images
Basic draw functions, save results
9
img_color = cv2.circle(img_color, (256, 256),
10, (0, 255, 0), 5)
img_color = cv2.line(img_color, (0, 0),
(1024, 1024), (0, 0, 255), 3)
img_color = cv2.rectangle(img_color, (100, 100),
(250, 350), (255, 0, 0), 3)
cv2.imwrite('result.png', img_color)
Basic operations: load, display, manipulate images
Numpy: access to pixels, channels, ROIs
10
import numpy as np
print(img_color.shape)
print(img_gray.shape)
(512, 512, 3)�(512, 512)
Basic operations: load, display, manipulate images
Numpy: access to pixels, channels, ROIs
11
img_color[256, 256] = (0, 255, 0)
for i in range(100):
for j in range(100):
img_color[i, j] = (0, 255, 0)
cv2.imshow('color', img_color)
cv2.waitKey()
cv2.destroyWindow('color')
Basic operations: load, display, manipulate images
Numpy: access to pixels, channels, ROIs
12
img_color[10:90, 10:90] = 0
img_color[400:420, :] = 0
cv2.imshow('color', img_color)
cv2.waitKey()
cv2.destroyWindow('color')
Basic operations: load, display, manipulate images
Numpy: access to pixels, channels, ROIs
13
cv2.imshow('color', img_color[:, :, 0])
cv2.waitKey()
cv2.destroyWindow('color')
Basic operations: load, display, manipulate images
Numpy: some useful operations
14
img = img_gray
img[...] = 0 # actually change img_gray
img = np.copy(img_color)
img[...] = 0
black = np.zeros((100, 100, 3), dtype=np.uint8)
white = 255*np.ones((100, 100, 3), dtype=np.uint8)
blue = np.full((100, 100, 3), (255, 0, 0), np.uint8)
white_padded = np.pad(white, ((64,)*2, (64,)*2, (0,)*2), 'constant', constant_values=0)
Basic operations: load, display, manipulate images
Numpy: some useful operations
15
np.save('white.npy', white)
white_loaded = np.load('white.npy')
assert (white == white_loaded).all()
img_h = np.hstack((black, white))
img_v = np.vstack((black, white))
print(np.pi)
3.141592653589793
Simple object detection: color filtering, masks, contours
Conversions between color spaces and data types
16
img_bgr = cv2.imread('data/lena.png', cv2.IMREAD_COLOR)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
img_rgb_fp32 = img_rgb.astype(np.float32)
cv2.imshow('rgb float', img_rgb_fp32)
cv2.imshow('rgb float/255', img_rgb_fp32 / 255)
cv2.waitKey()
cv2.destroyAllWindows()
Simple object detection: color filtering, masks, contours
Conversions between color spaces and data types
17
Simple object detection: color filtering, masks, contours
Color filtering
18
duck_0 = cv2.imread('data/duck_2.jpg')
duck_0_hsv = cv2.cvtColor(duck_0, cv2.COLOR_BGR2HSV)
dark_yellow = np.array([15, 100, 100])
light_yellow = np.array([50, 255, 255])
mask = cv2.inRange(duck_0_hsv, dark_yellow, light_yellow)
duck_0_masked = np.copy(duck_0)
duck_0_masked[mask == 0] = 0
cv2.imshow('', duck_0_masked)
cv2.waitKey()
cv2.destroyAllWindows()
Simple object detection: color filtering, masks, contours
Color filtering
19
Simple object detection: color filtering, masks, contours
Color filtering
20
Simple object detection: color filtering, masks, contours
Morphology operations
21
kernel_open = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10, 10))
kernel_close = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (50, 50))
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_open)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel_close)
duck_0_masked = np.copy(duck_0)
duck_0_masked[mask == 0] = 0
cv2.imshow('', duck_0_masked)
cv2.waitKey()
cv2.destroyAllWindows()
Simple object detection: color filtering, masks, contours
Morphology operations
22
Simple object detection: color filtering, masks, contours
Contours
23
img, contours, hierarchy = cv2.findContours(mask_closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour_duck_index = max(range(len(contours)), key=lambda i: cv2.arcLength(contours[i], True))
hierarchy = hierarchy.squeeze()
contour_eye_index = -1
for i in range(len(hierarchy)):
if hierarchy[i][2] < 0 and hierarchy[i][3] == contour_duck_index:
contour_eye_index = i
break
duck_0_masked = cv2.drawContours(duck_0_masked, contours, contour_duck_index, (0, 255, 0), 4)
duck_0_masked = cv2.drawContours(duck_0_masked, contours, contour_eye_index, (0, 0, 255), 4)
cv2.imshow('', duck_0_masked)
cv2.waitKey()
cv2.destroyAllWindows()
Simple object detection: color filtering, masks, contours
Contours
24
Camera calibration
Main idea
25
Camera calibration
Main idea
We need to find:
Let’s shoot an object with known geometry and try to find such camera matrix and distortion coefficients which minimize error between 2D object points in photos and reprojected 3D object points
26
Camera calibration
How to do
27
Camera calibration
How to do
28
img = cv2.imread('data/chessboard.png')
pattern_size = (10, 7)
res, corners = cv2.findChessboardCorners(img, pattern_size)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-3)
corners_subpix = cv2.cornerSubPix(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY),
corners, (10, 10), (-1,-1), criteria)
for c in corners.squeeze():
img = cv2.circle(img, tuple(c), 10, (0, 0, 255))
cv2.drawChessboardCorners(img, pattern_size, corners_subpix, res)
Camera calibration
How to do
29
Camera calibration
How to do
30
pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
rms, camera_matrix, dist_coefs, rvecs, tvecs = \
cv2.calibrateCamera([pattern_points], [corners_subpix], img[0].shape, None, None)
From 2D to 3D
When can we retrieve 3D information?
31
From 2D to 3D
Undistortion of images
32
img = cv2.imread('data/chessboard.png')
camera_matrix = np.load('data/camera_mat.npy')
dist_coefs = np.load('data/dist_coefs.npy')
img_undistorted = cv2.undistort(img, camera_matrix, dist_coefs)
cv2.imshow('', img_undistorted)
cv2.waitKey()
cv2.destroyAllWindows()
From 2D to 3D
Undistortion of images
33
From 2D to 3D
How to reproject points from the image
34
ud_corners = cv2.undistortPoints(corners_subpix, camera_matrix, dist_coefs)
print(ud_corners[0])
ud_corners = np.c_[ud_corners.squeeze(), np.ones(len(ud_corners))]
img_pts, _ = cv2.projectPoints(ud_corners, (0, 0, 0), (0, 0, 0), camera_matrix, None)
for c in img_pts.squeeze().astype(np.float32):
cv2.circle(img_undistorted, tuple(c), 5, (0, 0, 255), 2)
cv2.imshow('', img_undistorted)
cv2.waitKey()
cv2.destroyAllWindows()
[[-0.16817029 -0.11604928]]
From 2D to 3D
How to reproject points from the image
35
From 2D to 3D
How to reproject points from the image
36
img_pts = ud_corners @ camera_matrix.T
img_pts /= img_pts[:, 2, None]
img_pts = img_pts[:, :2]
for c in img_pts.squeeze().astype(np.float32):
cv2.circle(img_undistorted, tuple(c), 5, (0, 255, 0), 2)
cv2.imshow('', img_undistorted)
cv2.waitKey()
cv2.destroyAllWindows()
From 2D to 3D
How to reproject points from the image
37
From 2D to 3D
Find 6-DOF position of the object
38
ret, rvec, tvec = \
cv2.solvePnP(pattern_points, corners_subpix, camera_matrix, dist_coefs)
ArUCo markers
Generate marker image
39
import cv2
import cv2.aruco as aruco # opencv_contrib
import numpy as np
aruco_dict = aruco.getPredefinedDictionary(aruco.DICT_6X6_1000)
marker_42 = aruco.drawMarker(aruco_dict, 42, 500)
marker_42 = np.pad(marker_42, 50, 'constant', constant_values=255)
cv2.imshow('', marker_42)
cv2.waitKey()
cv2.destroyAllWindows()
cv2.imwrite('data/marker_42_DICT_6X6_1000.png', marker_42)
ArUCo markers
Detection
40
marker_img = cv2.imread('data/marker_42_0.0078.png')
detect_params = aruco.DetectorParameters_create()
detect_params.cornerRefinementMethod = aruco.CORNER_REFINE_SUBPIX
detect_params.cornerRefinementWinSize = 15
corners, ids, _ = aruco.detectMarkers(marker_img, aruco_dict, None, None, detect_params)
detected_m_img = aruco.drawDetectedMarkers(marker_img, corners, ids, (0, 255, 0))
cv2.imshow('', detected_m_img)
cv2.waitKey()
cv2.destroyAllWindows()
ArUCo markers
Detection
41
ArUCo markers
Estimate pose and draw 3D axes
42
camera_matrix = np.load('data/camera_mat.npy')
dist_coefs = np.load('data/dist_coefs.npy')
rvecs, tvecs, _ = aruco.estimatePoseSingleMarkers(corners, 0.0078, camera_matrix, dist_coefs)
detected_m_img = aruco.drawAxis(detected_m_img, camera_matrix, dist_coefs, rvecs[0], tvecs[0], 0.005)
cv2.imshow('', detected_m_img)
cv2.waitKey()
cv2.destroyAllWindows()
ArUCo markers
Estimate pose and draw 3D axes
43
CV ideas
Detect the “duck”
44
CV ideas
Estimate distance to the “duck”
45
CV ideas
ArUCo
46
Deep Learning, even in OpenCV
47
Python tools
48
Books
49
Useful links
50
Questions & Discussion
51