├── CalibrationByArucoGridboard ├── CalibrateCamera.py └── README.md ├── CalibrationByCharucoBoard ├── CalibrateCamera.py └── README.md ├── CalibrationByChessboard ├── CalibrateCamera.py ├── README.md └── chessboard-to-print.pdf ├── GenerateArucoMarker ├── GenArucoGridboard.py ├── GenArucoMarker.py ├── GenChArucoboard.py ├── README.md └── test_gridboard.pdf ├── LICENSE ├── PostureEstimation ├── EstimatePosturePerMarker.py ├── EstimatePostureWithArucoGridboard.py ├── EstimatePostureWithCharucoBoard.py └── README.md ├── README.md └── SimpleMarkerDetection ├── DetectMarkersAndPrint.py └── README.md /CalibrationByArucoGridboard/CalibrateCamera.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import cv2.aruco as aruco 4 | import pickle 5 | 6 | aruco_dict = aruco.Dictionary_get(aruco.DICT_5X5_1000) 7 | 8 | # Creating a theoretical board we'll use to calculate marker positions 9 | board = aruco.GridBoard_create( 10 | markersX=5, 11 | markersY=7, 12 | markerLength=0.04, 13 | markerSeparation=0.01, 14 | dictionary=aruco_dict) 15 | 16 | 17 | # Read an image or a video to calibrate your camera 18 | # I'm using a video and waiting until my entire gridboard is seen before calibrating 19 | # The following code assumes you have a 5X7 Aruco gridboard to calibrate with 20 | cam = cv2.VideoCapture('gridboard-test-at-kyles-desk.mp4') 21 | 22 | while(cam.isOpened()): 23 | # Capturing each frame of our video stream 24 | ret, QueryImg = cam.read() 25 | if ret == True: 26 | # grayscale image 27 | gray = cv2.cvtColor(QueryImg, cv2.COLOR_BGR2GRAY) 28 | parameters = aruco.DetectorParameters_create() 29 | 30 | # Detect Aruco markers 31 | corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, aruco_dict, parameters=parameters) 32 | 33 | # Make sure markers were detected before continuing 34 | if ids is not None and corners is not None and len(ids) > 0 and len(corners) > 0 and len(corners) == len(ids): 35 | # The next if makes sure we see all matrixes in our gridboard 36 | if len(ids) == len(board.ids): 37 | # Calibrate the camera now using cv2 method 38 | ret, cameraMatrix, distCoeffs, _, _ = cv2.calibrateCamera( 39 | objectPoints=board.objPoints, 40 | imagePoints=corners, 41 | imageSize=gray.shape, #[::-1], # may instead want to use gray.size 42 | cameraMatrix=None, 43 | distCoeffs=None) 44 | 45 | # # Calibrate camera now using Aruco method 46 | # ret, cameraMatrix, distCoeffs, _, _ = aruco.calibrateCameraAruco( 47 | # corners=corners, 48 | # ids=ids, 49 | # counter=35, 50 | # board=board, 51 | # imageSize=gray.shape[::-1], 52 | # cameraMatrix=None, 53 | # distCoeffs=None) 54 | 55 | # Print matrix and distortion coefficient to the console 56 | print(cameraMatrix) 57 | print(distCoeffs) 58 | 59 | # Output values to be used where matrix+dist is required 60 | f = open('calibration.pckl', 'wb') 61 | pickle.dump((cameraMatrix, distCoeffs), f) 62 | f.close() 63 | 64 | # PRint to console our success 65 | print('Calibration successful.') 66 | 67 | break 68 | 69 | # Exit at the end of the video on the EOF key 70 | if cv2.waitKey(1) & 0xFF == ord('q'): 71 | break 72 | 73 | cv2.destroyAllWindows() 74 | -------------------------------------------------------------------------------- /CalibrationByArucoGridboard/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This code is a test I did to test out calibrating my camera with Python Aruco's Gridboard. The gridboard was generated using the gridboard generation script detailed in this repository. Please note that only one frame is used for the calibration, and that I prefer the results used in a method such as the chessboard calibration method also detailed in this repository. 4 | 5 | ## Systems 6 | 7 | This code was successfully run on the following system: 8 | - Linux Debian dist 9 | - Linux Mint 18.1 Cinnamon 64-bit 10 | - Python 2.7 with OpenCV 3.2.0 11 | - MacBook Air 12 | - macOS Sierra 10.12.4 13 | - Python 2.7 with OpenCV 3.2.0 14 | -------------------------------------------------------------------------------- /CalibrationByCharucoBoard/CalibrateCamera.py: -------------------------------------------------------------------------------- 1 | # System information: 2 | # - Linux Mint 18.1 Cinnamon 64-bit 3 | # - Python 2.7 with OpenCV 3.2.0 4 | 5 | import numpy 6 | import cv2 7 | from cv2 import aruco 8 | import pickle 9 | import glob 10 | 11 | 12 | # ChAruco board variables 13 | CHARUCOBOARD_ROWCOUNT = 7 14 | CHARUCOBOARD_COLCOUNT = 5 15 | ARUCO_DICT = aruco.Dictionary_get(aruco.DICT_5X5_1000) 16 | 17 | # Create constants to be passed into OpenCV and Aruco methods 18 | CHARUCO_BOARD = aruco.CharucoBoard_create( 19 | squaresX=CHARUCOBOARD_COLCOUNT, 20 | squaresY=CHARUCOBOARD_ROWCOUNT, 21 | squareLength=0.04, 22 | markerLength=0.02, 23 | dictionary=ARUCO_DICT) 24 | 25 | # Create the arrays and variables we'll use to store info like corners and IDs from images processed 26 | corners_all = [] # Corners discovered in all images processed 27 | ids_all = [] # Aruco ids corresponding to corners discovered 28 | image_size = None # Determined at runtime 29 | 30 | 31 | # This requires a set of images or a video taken with the camera you want to calibrate 32 | # I'm using a set of images taken with the camera with the naming convention: 33 | # 'camera-pic-of-charucoboard-.jpg' 34 | # All images used should be the same size, which if taken with the same camera shouldn't be a problem 35 | images = glob.glob('./camera-pic-of-charucoboard-*.jpg') 36 | 37 | # Loop through images glob'ed 38 | for iname in images: 39 | # Open the image 40 | img = cv2.imread(iname) 41 | # Grayscale the image 42 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 43 | 44 | # Find aruco markers in the query image 45 | corners, ids, _ = aruco.detectMarkers( 46 | image=gray, 47 | dictionary=ARUCO_DICT) 48 | 49 | # Outline the aruco markers found in our query image 50 | img = aruco.drawDetectedMarkers( 51 | image=img, 52 | corners=corners) 53 | 54 | # Get charuco corners and ids from detected aruco markers 55 | response, charuco_corners, charuco_ids = aruco.interpolateCornersCharuco( 56 | markerCorners=corners, 57 | markerIds=ids, 58 | image=gray, 59 | board=CHARUCO_BOARD) 60 | 61 | # If a Charuco board was found, let's collect image/corner points 62 | # Requiring at least 20 squares 63 | if response > 20: 64 | # Add these corners and ids to our calibration arrays 65 | corners_all.append(charuco_corners) 66 | ids_all.append(charuco_ids) 67 | 68 | # Draw the Charuco board we've detected to show our calibrator the board was properly detected 69 | img = aruco.drawDetectedCornersCharuco( 70 | image=img, 71 | charucoCorners=charuco_corners, 72 | charucoIds=charuco_ids) 73 | 74 | # If our image size is unknown, set it now 75 | if not image_size: 76 | image_size = gray.shape[::-1] 77 | 78 | # Reproportion the image, maxing width or height at 1000 79 | proportion = max(img.shape) / 1000.0 80 | img = cv2.resize(img, (int(img.shape[1]/proportion), int(img.shape[0]/proportion))) 81 | # Pause to display each image, waiting for key press 82 | cv2.imshow('Charuco board', img) 83 | cv2.waitKey(0) 84 | else: 85 | print("Not able to detect a charuco board in image: {}".format(iname)) 86 | 87 | # Destroy any open CV windows 88 | cv2.destroyAllWindows() 89 | 90 | # Make sure at least one image was found 91 | if len(images) < 1: 92 | # Calibration failed because there were no images, warn the user 93 | print("Calibration was unsuccessful. No images of charucoboards were found. Add images of charucoboards and use or alter the naming conventions used in this file.") 94 | # Exit for failure 95 | exit() 96 | 97 | # Make sure we were able to calibrate on at least one charucoboard by checking 98 | # if we ever determined the image size 99 | if not image_size: 100 | # Calibration failed because we didn't see any charucoboards of the PatternSize used 101 | print("Calibration was unsuccessful. We couldn't detect charucoboards in any of the images supplied. Try changing the patternSize passed into Charucoboard_create(), or try different pictures of charucoboards.") 102 | # Exit for failure 103 | exit() 104 | 105 | # Now that we've seen all of our images, perform the camera calibration 106 | # based on the set of points we've discovered 107 | calibration, cameraMatrix, distCoeffs, rvecs, tvecs = aruco.calibrateCameraCharuco( 108 | charucoCorners=corners_all, 109 | charucoIds=ids_all, 110 | board=CHARUCO_BOARD, 111 | imageSize=image_size, 112 | cameraMatrix=None, 113 | distCoeffs=None) 114 | 115 | # Print matrix and distortion coefficient to the console 116 | print(cameraMatrix) 117 | print(distCoeffs) 118 | 119 | # Save values to be used where matrix+dist is required, for instance for posture estimation 120 | # I save files in a pickle file, but you can use yaml or whatever works for you 121 | f = open('calibration.pckl', 'wb') 122 | pickle.dump((cameraMatrix, distCoeffs, rvecs, tvecs), f) 123 | f.close() 124 | 125 | # Print to console our success 126 | print('Calibration successful. Calibration file used: {}'.format('calibration.pckl')) 127 | 128 | -------------------------------------------------------------------------------- /CalibrationByCharucoBoard/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | The code in this directory is a test camera calibration done on a series of images I captured of a printed out Charuco Board. You can generate a similar charuco board using the generation scripts in this repository. This camera calibration is required for using Aruco camera posture estimation. 4 | 5 | It is based off of the OpenCV-Python tutorial here: http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html 6 | 7 | The calibration file to be used with posturing is saved to calibration.pckl 8 | 9 | ## Systems 10 | 11 | This code was successfully run on the following system: 12 | - Linux Debian dist 13 | - Linux Mint 18.1 Cinnamon 64-bit 14 | - Python 2.7 with OpenCV 3.2.0 15 | - MacBook Air 16 | - macOS Sierra 10.12.4 17 | - Python 2.7 with OpenCV 3.2.0 18 | -------------------------------------------------------------------------------- /CalibrationByChessboard/CalibrateCamera.py: -------------------------------------------------------------------------------- 1 | # System information: 2 | # - Linux Mint 18.1 Cinnamon 64-bit 3 | # - Python 2.7 with OpenCV 3.2.0 4 | # Resources: 5 | # - OpenCV-Python tutorial for calibration: http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html 6 | # - Variable names were changed for clarity 7 | 8 | import numpy 9 | import cv2 10 | import pickle 11 | import glob 12 | 13 | # Create arrays you'll use to store object points and image points from all images processed 14 | objpoints = [] # 3D point in real world space where chess squares are 15 | imgpoints = [] # 2D point in image plane, determined by CV2 16 | 17 | # Chessboard variables 18 | CHESSBOARD_CORNERS_ROWCOUNT = 9 19 | CHESSBOARD_CORNERS_COLCOUNT = 6 20 | 21 | # Theoretical object points for the chessboard we're calibrating against, 22 | # These will come out like: 23 | # (0, 0, 0), (1, 0, 0), ..., 24 | # (CHESSBOARD_CORNERS_ROWCOUNT-1, CHESSBOARD_CORNERS_COLCOUNT-1, 0) 25 | # Note that the Z value for all stays at 0, as this is a printed out 2D image 26 | # And also that the max point is -1 of the max because we're zero-indexing 27 | # The following line generates all the tuples needed at (0, 0, 0) 28 | objp = numpy.zeros((CHESSBOARD_CORNERS_ROWCOUNT*CHESSBOARD_CORNERS_COLCOUNT,3), numpy.float32) 29 | # The following line fills the tuples just generated with their values (0, 0, 0), (1, 0, 0), ... 30 | objp[:,:2] = numpy.mgrid[0:CHESSBOARD_CORNERS_ROWCOUNT,0:CHESSBOARD_CORNERS_COLCOUNT].T.reshape(-1, 2) 31 | 32 | # Need a set of images or a video taken with the camera you want to calibrate 33 | # I'm using a set of images taken with the camera with the naming convention: 34 | # 'camera-pic-of-chessboard-.jpg' 35 | images = glob.glob('./camera-pic-of-chessboard-*.jpg') 36 | # All images used should be the same size, which if taken with the same camera shouldn't be a problem 37 | imageSize = None # Determined at runtime 38 | 39 | # Loop through images glob'ed 40 | for iname in images: 41 | # Open the image 42 | img = cv2.imread(iname) 43 | # Grayscale the image 44 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 45 | 46 | # Find chessboard in the image, setting PatternSize(2nd arg) to a tuple of (#rows, #columns) 47 | board, corners = cv2.findChessboardCorners(gray, (CHESSBOARD_CORNERS_ROWCOUNT,CHESSBOARD_CORNERS_COLCOUNT), None) 48 | 49 | # If a chessboard was found, let's collect image/corner points 50 | if board == True: 51 | # Add the points in 3D that we just discovered 52 | objpoints.append(objp) 53 | 54 | # Enhance corner accuracy with cornerSubPix 55 | corners_acc = cv2.cornerSubPix( 56 | image=gray, 57 | corners=corners, 58 | winSize=(11, 11), 59 | zeroZone=(-1, -1), 60 | criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)) # Last parameter is about termination critera 61 | imgpoints.append(corners_acc) 62 | 63 | # If our image size is unknown, set it now 64 | if not imageSize: 65 | imageSize = gray.shape[::-1] 66 | 67 | # Draw the corners to a new image to show whoever is performing the calibration 68 | # that the board was properly detected 69 | img = cv2.drawChessboardCorners(img, (CHESSBOARD_CORNERS_ROWCOUNT, CHESSBOARD_CORNERS_COLCOUNT), corners_acc, board) 70 | # Pause to display each image, waiting for key press 71 | cv2.imshow('Chessboard', img) 72 | cv2.waitKey(0) 73 | else: 74 | print("Not able to detect a chessboard in image: {}".format(iname)) 75 | 76 | # Destroy any open CV windows 77 | cv2.destroyAllWindows() 78 | 79 | # Make sure at least one image was found 80 | if len(images) < 1: 81 | # Calibration failed because there were no images, warn the user 82 | print("Calibration was unsuccessful. No images of chessboards were found. Add images of chessboards and use or alter the naming conventions used in this file.") 83 | # Exit for failure 84 | exit() 85 | 86 | # Make sure we were able to calibrate on at least one chessboard by checking 87 | # if we ever determined the image size 88 | if not imageSize: 89 | # Calibration failed because we didn't see any chessboards of the PatternSize used 90 | print("Calibration was unsuccessful. We couldn't detect chessboards in any of the images supplied. Try changing the patternSize passed into findChessboardCorners(), or try different pictures of chessboards.") 91 | # Exit for failure 92 | exit() 93 | 94 | # Now that we've seen all of our images, perform the camera calibration 95 | # based on the set of points we've discovered 96 | calibration, cameraMatrix, distCoeffs, rvecs, tvecs = cv2.calibrateCamera( 97 | objectPoints=objpoints, 98 | imagePoints=imgpoints, 99 | imageSize=imageSize, 100 | cameraMatrix=None, 101 | distCoeffs=None) 102 | 103 | # Print matrix and distortion coefficient to the console 104 | print(cameraMatrix) 105 | print(distCoeffs) 106 | 107 | # Save values to be used where matrix+dist is required, for instance for posture estimation 108 | # I save files in a pickle file, but you can use yaml or whatever works for you 109 | f = open('calibration.pckl', 'wb') 110 | pickle.dump((cameraMatrix, distCoeffs, rvecs, tvecs), f) 111 | f.close() 112 | 113 | # Print to console our success 114 | print('Calibration successful. Calibration file used: {}'.format('calibration.pckl')) 115 | 116 | -------------------------------------------------------------------------------- /CalibrationByChessboard/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | The code in this directory is a test camera calibration done on a series of images I captured of a printed out chessboard. You can find the chessboard .pdf I printed in this directory. This camera calibration is required for using Aruco camera posture estimation. 4 | 5 | It is based off of the OpenCV-Python tutorial here: http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html 6 | 7 | The calibration file to be used with posturing is saved to calibration.pckl 8 | 9 | ## Systems 10 | 11 | This code was successfully run on the following system: 12 | - Linux Debian dist 13 | - Linux Mint 18.1 Cinnamon 64-bit 14 | - Python 2.7 with OpenCV 3.2.0 15 | - MacBook Air 16 | - macOS Sierra 10.12.4 17 | - Python 2.7 with OpenCV 3.2.0 18 | -------------------------------------------------------------------------------- /CalibrationByChessboard/chessboard-to-print.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyle-bersani/opencv-examples/15f8de4e82f03aea3d6b64c14a308e6a75607d83/CalibrationByChessboard/chessboard-to-print.pdf -------------------------------------------------------------------------------- /GenerateArucoMarker/GenArucoGridboard.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import cv2.aruco as aruco 3 | 4 | # Create gridboard, which is a set of Aruco markers 5 | # the following call gets a board of markers 5 wide X 7 tall 6 | gridboard = aruco.GridBoard_create( 7 | markersX=5, 8 | markersY=7, 9 | markerLength=0.04, 10 | markerSeparation=0.01, 11 | dictionary=aruco.Dictionary_get(aruco.DICT_5X5_1000)) 12 | 13 | # Create an image from the gridboard 14 | img = gridboard.draw(outSize=(988, 1400)) 15 | cv2.imwrite("test_gridboard.jpg", img) 16 | 17 | # Display the image to us 18 | cv2.imshow('Gridboard', img) 19 | # Exit on any key 20 | cv2.waitKey(0) 21 | cv2.destroyAllWindows() 22 | 23 | -------------------------------------------------------------------------------- /GenerateArucoMarker/GenArucoMarker.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import cv2.aruco as aruco 4 | 5 | # Select type of aruco marker (size) 6 | aruco_dict = aruco.Dictionary_get(aruco.DICT_5X5_1000) 7 | 8 | # Create an image from the marker 9 | # second param is ID number 10 | # last param is total image size 11 | img = aruco.drawMarker(aruco_dict, 2, 700) 12 | cv2.imwrite("test_marker.jpg", img) 13 | 14 | # Display the image to us 15 | cv2.imshow('frame', img) 16 | # Exit on any key 17 | cv2.waitKey(0) 18 | cv2.destroyAllWindows() 19 | -------------------------------------------------------------------------------- /GenerateArucoMarker/GenChArucoboard.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import cv2.aruco as aruco 3 | 4 | # Create ChArUco board, which is a set of Aruco markers in a chessboard setting 5 | # meant for calibration 6 | # the following call gets a ChArUco board of tiles 5 wide X 7 tall 7 | gridboard = aruco.CharucoBoard_create( 8 | squaresX=5, 9 | squaresY=7, 10 | squareLength=0.04, 11 | markerLength=0.02, 12 | dictionary=aruco.Dictionary_get(aruco.DICT_5X5_1000)) 13 | 14 | # Create an image from the gridboard 15 | img = gridboard.draw(outSize=(988, 1400)) 16 | cv2.imwrite("test_charuco.jpg", img) 17 | 18 | # Display the image to us 19 | cv2.imshow('Gridboard', img) 20 | # Exit on any key 21 | cv2.waitKey(0) 22 | cv2.destroyAllWindows() 23 | 24 | -------------------------------------------------------------------------------- /GenerateArucoMarker/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This code uses the Aruco library in OpenCV to generate Aruco markers and gridboards. 4 | 5 | ## Systems 6 | 7 | This code was successfully run on the following systems: 8 | - Linux Debian dist 9 | - Linux Mint 18.1 Cinnamon 64-bit 10 | - Python 2.7 with OpenCV 3.2.0 11 | - MacBook Air 12 | - macOS Sierra 10.12.4 13 | - Python 2.7 with OpenCV 3.2.0 14 | -------------------------------------------------------------------------------- /GenerateArucoMarker/test_gridboard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyle-bersani/opencv-examples/15f8de4e82f03aea3d6b64c14a308e6a75607d83/GenerateArucoMarker/test_gridboard.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Kyle Elsalhi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PostureEstimation/EstimatePosturePerMarker.py: -------------------------------------------------------------------------------- 1 | # The following code is used to watch a video stream, detect Aruco markers, and use 2 | # a set of markers to determine the posture of the camera in relation to the plane 3 | # of markers. 4 | # 5 | # Assumes that all markers are on the same plane, for example on the same piece of paper 6 | # 7 | # Requires camera calibration (see the rest of the project for example calibration) 8 | 9 | import numpy 10 | import cv2 11 | import cv2.aruco as aruco 12 | import os 13 | import pickle 14 | 15 | # Check for camera calibration data 16 | if not os.path.exists('./calibration.pckl'): 17 | print("You need to calibrate the camera you'll be using. See calibration project directory for details.") 18 | exit() 19 | else: 20 | f = open('calibration.pckl', 'rb') 21 | (cameraMatrix, distCoeffs, _, _) = pickle.load(f) 22 | f.close() 23 | if cameraMatrix is None or distCoeffs is None: 24 | print("Calibration issue. Remove ./calibration.pckl and recalibrate your camera with CalibrateCamera.py.") 25 | exit() 26 | 27 | # Constant parameters used in Aruco methods 28 | ARUCO_PARAMETERS = aruco.DetectorParameters_create() 29 | ARUCO_DICT = aruco.Dictionary_get(aruco.DICT_6X6_1000) 30 | 31 | # Create grid board object we're using in our stream 32 | board = aruco.GridBoard_create( 33 | markersX=2, 34 | markersY=2, 35 | markerLength=0.09, 36 | markerSeparation=0.01, 37 | dictionary=ARUCO_DICT) 38 | 39 | # Create vectors we'll be using for rotations and translations for postures 40 | rvecs, tvecs = None, None 41 | 42 | cam = cv2.VideoCapture('gridboardiphonetest.mp4') 43 | 44 | while(cam.isOpened()): 45 | # Capturing each frame of our video stream 46 | ret, QueryImg = cam.read() 47 | if ret == True: 48 | # grayscale image 49 | gray = cv2.cvtColor(QueryImg, cv2.COLOR_BGR2GRAY) 50 | 51 | # Detect Aruco markers 52 | corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, ARUCO_DICT, parameters=ARUCO_PARAMETERS) 53 | 54 | # Refine detected markers 55 | # Eliminates markers not part of our board, adds missing markers to the board 56 | corners, ids, rejectedImgPoints, recoveredIds = aruco.refineDetectedMarkers( 57 | image = gray, 58 | board = board, 59 | detectedCorners = corners, 60 | detectedIds = ids, 61 | rejectedCorners = rejectedImgPoints, 62 | cameraMatrix = cameraMatrix, 63 | distCoeffs = distCoeffs) 64 | 65 | ########################################################################### 66 | # TODO: Add validation here to reject IDs/corners not part of a gridboard # 67 | ########################################################################### 68 | 69 | # Outline all of the markers detected in our image 70 | QueryImg = aruco.drawDetectedMarkers(QueryImg, corners, borderColor=(0, 0, 255)) 71 | 72 | # Require 15 markers before drawing axis 73 | if ids is not None and len(ids) > 3: 74 | # Estimate the posture of the gridboard, which is a construction of 3D space based on the 2D video 75 | #pose, rvec, tvec = aruco.estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs) 76 | #if pose: 77 | # # Draw the camera posture calculated from the gridboard 78 | # QueryImg = aruco.drawAxis(QueryImg, cameraMatrix, distCoeffs, rvec, tvec, 0.3) 79 | # Estimate the posture per each Aruco marker 80 | rvecs, tvecs = aruco.estimatePoseSingleMarkers(corners, 1, cameraMatrix, distCoeffs) 81 | for rvec, tvec in zip(rvecs, tvecs): 82 | QueryImg = aruco.drawAxis(QueryImg, cameraMatrix, distCoeffs, rvec, tvec, 1) 83 | # Display our image 84 | cv2.imshow('QueryImage', QueryImg) 85 | 86 | # Exit at the end of the video on the 'q' keypress 87 | if cv2.waitKey(1) & 0xFF == ord('q'): 88 | break 89 | 90 | cv2.destroyAllWindows() 91 | -------------------------------------------------------------------------------- /PostureEstimation/EstimatePostureWithArucoGridboard.py: -------------------------------------------------------------------------------- 1 | # The following code is used to watch a video stream, detect Aruco markers, and use 2 | # a set of markers to determine the posture of the camera in relation to the plane 3 | # of markers. 4 | # 5 | # Assumes that all markers are on the same plane, for example on the same piece of paper 6 | # 7 | # Requires camera calibration (see the rest of the project for example calibration) 8 | 9 | import numpy 10 | import cv2 11 | import cv2.aruco as aruco 12 | import os 13 | import pickle 14 | 15 | # Check for camera calibration data 16 | if not os.path.exists('./calibration.pckl'): 17 | print("You need to calibrate the camera you'll be using. See calibration project directory for details.") 18 | exit() 19 | else: 20 | f = open('calibration.pckl', 'rb') 21 | (cameraMatrix, distCoeffs, _, _) = pickle.load(f) 22 | f.close() 23 | if cameraMatrix is None or distCoeffs is None: 24 | print("Calibration issue. Remove ./calibration.pckl and recalibrate your camera with CalibrateCamera.py.") 25 | exit() 26 | 27 | # Constant parameters used in Aruco methods 28 | ARUCO_PARAMETERS = aruco.DetectorParameters_create() 29 | ARUCO_DICT = aruco.Dictionary_get(aruco.DICT_5X5_50) 30 | 31 | # Create grid board object we're using in our stream 32 | board = aruco.GridBoard_create( 33 | markersX=5, 34 | markersY=7, 35 | markerLength=0.04, 36 | markerSeparation=0.01, 37 | dictionary=ARUCO_DICT) 38 | 39 | # Create vectors we'll be using for rotations and translations for postures 40 | rvecs, tvecs = None, None 41 | 42 | cam = cv2.VideoCapture('gridboard-test-at-kyles-desk2.mp4') 43 | 44 | while(cam.isOpened()): 45 | # Capturing each frame of our video stream 46 | ret, QueryImg = cam.read() 47 | if ret == True: 48 | # grayscale image 49 | gray = cv2.cvtColor(QueryImg, cv2.COLOR_BGR2GRAY) 50 | 51 | # Detect Aruco markers 52 | corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, ARUCO_DICT, parameters=ARUCO_PARAMETERS) 53 | 54 | # Refine detected markers 55 | # Eliminates markers not part of our board, adds missing markers to the board 56 | corners, ids, rejectedImgPoints, recoveredIds = aruco.refineDetectedMarkers( 57 | image = gray, 58 | board = board, 59 | detectedCorners = corners, 60 | detectedIds = ids, 61 | rejectedCorners = rejectedImgPoints, 62 | cameraMatrix = cameraMatrix, 63 | distCoeffs = distCoeffs) 64 | 65 | ########################################################################### 66 | # TODO: Add validation here to reject IDs/corners not part of a gridboard # 67 | ########################################################################### 68 | 69 | # Outline all of the markers detected in our image 70 | QueryImg = aruco.drawDetectedMarkers(QueryImg, corners, borderColor=(0, 0, 255)) 71 | 72 | # Require 15 markers before drawing axis 73 | if ids is not None and len(ids) > 15: 74 | # Estimate the posture of the gridboard, which is a construction of 3D space based on the 2D video 75 | pose, rvec, tvec = aruco.estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs) 76 | if pose: 77 | # Draw the camera posture calculated from the gridboard 78 | QueryImg = aruco.drawAxis(QueryImg, cameraMatrix, distCoeffs, rvec, tvec, 0.3) 79 | 80 | # Display our image 81 | cv2.imshow('QueryImage', QueryImg) 82 | 83 | # Exit at the end of the video on the 'q' keypress 84 | if cv2.waitKey(1) & 0xFF == ord('q'): 85 | break 86 | 87 | cv2.destroyAllWindows() 88 | -------------------------------------------------------------------------------- /PostureEstimation/EstimatePostureWithCharucoBoard.py: -------------------------------------------------------------------------------- 1 | # The following code is used to watch a video stream, detect a Charuco board, and use 2 | # it to determine the posture of the camera in relation to the plane 3 | # of markers. 4 | # 5 | # Assumes that all markers are on the same plane, for example on the same piece of paper 6 | # 7 | # Requires camera calibration (see the rest of the project for example calibration) 8 | 9 | import numpy 10 | import cv2 11 | import cv2.aruco as aruco 12 | import os 13 | import pickle 14 | 15 | # Check for camera calibration data 16 | if not os.path.exists('./calibration.pckl'): 17 | print("You need to calibrate the camera you'll be using. See calibration project directory for details.") 18 | exit() 19 | else: 20 | f = open('calibration.pckl', 'rb') 21 | (cameraMatrix, distCoeffs, _, _) = pickle.load(f) 22 | f.close() 23 | if cameraMatrix is None or distCoeffs is None: 24 | print("Calibration issue. Remove ./calibration.pckl and recalibrate your camera with CalibrateCamera.py.") 25 | exit() 26 | 27 | # Constant parameters used in Aruco methods 28 | ARUCO_PARAMETERS = aruco.DetectorParameters_create() 29 | ARUCO_DICT = aruco.Dictionary_get(aruco.DICT_5X5_50) 30 | CHARUCOBOARD_ROWCOUNT=7 31 | CHARUCOBOARD_COLCOUNT=5 32 | 33 | # Create grid board object we're using in our stream 34 | CHARUCO_BOARD = aruco.CharucoBoard_create( 35 | squaresX=CHARUCOBOARD_COLCOUNT, 36 | squaresY=CHARUCOBOARD_ROWCOUNT, 37 | squareLength=0.04, 38 | markerLength=0.02, 39 | dictionary=ARUCO_DICT) 40 | 41 | # Create vectors we'll be using for rotations and translations for postures 42 | rvecs, tvecs = None, None 43 | 44 | cam = cv2.VideoCapture('charucoboard-test-at-kyles-desk.mp4') 45 | 46 | while(cam.isOpened()): 47 | # Capturing each frame of our video stream 48 | ret, QueryImg = cam.read() 49 | if ret == True: 50 | # grayscale image 51 | gray = cv2.cvtColor(QueryImg, cv2.COLOR_BGR2GRAY) 52 | 53 | # Detect Aruco markers 54 | corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, ARUCO_DICT, parameters=ARUCO_PARAMETERS) 55 | 56 | # Refine detected markers 57 | # Eliminates markers not part of our board, adds missing markers to the board 58 | corners, ids, rejectedImgPoints, recoveredIds = aruco.refineDetectedMarkers( 59 | image = gray, 60 | board = CHARUCO_BOARD, 61 | detectedCorners = corners, 62 | detectedIds = ids, 63 | rejectedCorners = rejectedImgPoints, 64 | cameraMatrix = cameraMatrix, 65 | distCoeffs = distCoeffs) 66 | 67 | # Outline all of the markers detected in our image 68 | QueryImg = aruco.drawDetectedMarkers(QueryImg, corners, borderColor=(0, 0, 255)) 69 | 70 | # Only try to find CharucoBoard if we found markers 71 | if ids is not None and len(ids) > 10: 72 | 73 | # Get charuco corners and ids from detected aruco markers 74 | response, charuco_corners, charuco_ids = aruco.interpolateCornersCharuco( 75 | markerCorners=corners, 76 | markerIds=ids, 77 | image=gray, 78 | board=CHARUCO_BOARD) 79 | 80 | # Require more than 20 squares 81 | if response is not None and response > 20: 82 | # Estimate the posture of the charuco board, which is a construction of 3D space based on the 2D video 83 | pose, rvec, tvec = aruco.estimatePoseCharucoBoard( 84 | charucoCorners=charuco_corners, 85 | charucoIds=charuco_ids, 86 | board=CHARUCO_BOARD, 87 | cameraMatrix=cameraMatrix, 88 | distCoeffs=distCoeffs) 89 | if pose: 90 | # Draw the camera posture calculated from the gridboard 91 | QueryImg = aruco.drawAxis(QueryImg, cameraMatrix, distCoeffs, rvec, tvec, 0.3) 92 | 93 | # Display our image 94 | cv2.imshow('QueryImage', QueryImg) 95 | 96 | # Exit at the end of the video on the 'q' keypress 97 | if cv2.waitKey(1) & 0xFF == ord('q'): 98 | break 99 | 100 | cv2.destroyAllWindows() 101 | -------------------------------------------------------------------------------- /PostureEstimation/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | The code in this project is an example and test of using Aruco marker and Gridboard detection in a video stream, then creating board posture (an estimation of 3D space as constructed from a 2D video) 4 | 5 | Similarly, the same example is provided for Charuco board detection and posturing. 6 | 7 | Camera calibration is required, for an example of that check the calibration examplese in this repository. 8 | 9 | ## Systems 10 | 11 | This code in this project was tested on the following systems: 12 | - Linux Debian dist 13 | - Linux Mint 18.1 Cinnamon 64-bit 14 | - Python 2.7 with OpenCV 3.2.0 15 | - MacBook Air 16 | - macOS Sierra 10.12.4 17 | - Python 2.7 with OpenCV 3.2.0 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | The code in this project are examples and tests for using Aruco markers and OpenCV 3.2.0, for camera calibration, Aruco marker generation, and detection 4 | 5 | OpenCV 3.2.0 was run in a virtual environment. For details on setting up this work environment, use the resources linked below. 6 | 7 | ## Systems 8 | 9 | This code in this project was tested on the following systems: 10 | - Linux Debian dist 11 | - Linux Mint 18.1 Cinnamon 64-bit 12 | - Python 2.7 with OpenCV 3.2.0 13 | - MacBook Air 14 | - macOS Sierra 10.12.4 15 | - Python 2.7 with OpenCV 3.2.0 16 | 17 | ## Resources 18 | 19 | For the installation of OpenCV 3.2.0, the following tutorials were used for reference: 20 | - For Linux Mint: http://www.pyimagesearch.com/2015/06/22/install-opencv-3-0-and-python-2-7-on-ubuntu/ 21 | - For MacOSX 22 | - Sierra: http://www.pyimagesearch.com/2016/11/28/macos-install-opencv-3-and-python-2-7/ 23 | - And: http://www.pyimagesearch.com/2015/06/15/install-opencv-3-0-and-python-2-7-on-osx/ 24 | -------------------------------------------------------------------------------- /SimpleMarkerDetection/DetectMarkersAndPrint.py: -------------------------------------------------------------------------------- 1 | # The following code is used to watch a video stream, detect Aruco markers, and use 2 | # a set of markers to determine the posture of the camera in relation to the plane 3 | # of markers. 4 | # 5 | # Assumes that all markers are on the same plane, for example on the same piece of paper 6 | # 7 | # Requires camera calibration (see the rest of the project for example calibration) 8 | 9 | import numpy 10 | import cv2 11 | import cv2.aruco as aruco 12 | 13 | 14 | # Constant parameters used in Aruco methods 15 | ARUCO_PARAMETERS = aruco.DetectorParameters_create() 16 | ARUCO_DICT = aruco.Dictionary_get(aruco.DICT_6X6_1000) 17 | 18 | # Create grid board object we're using in our stream 19 | board = aruco.GridBoard_create( 20 | markersX=2, 21 | markersY=2, 22 | markerLength=0.09, 23 | markerSeparation=0.01, 24 | dictionary=ARUCO_DICT) 25 | 26 | # Create vectors we'll be using for rotations and translations for postures 27 | rvecs, tvecs = None, None 28 | 29 | cam = cv2.VideoCapture('gridboardiphonetest.mp4') 30 | 31 | while(cam.isOpened()): 32 | # Capturing each frame of our video stream 33 | ret, QueryImg = cam.read() 34 | if ret == True: 35 | # grayscale image 36 | gray = cv2.cvtColor(QueryImg, cv2.COLOR_BGR2GRAY) 37 | 38 | # Detect Aruco markers 39 | corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, ARUCO_DICT, parameters=ARUCO_PARAMETERS) 40 | 41 | # Make sure all 5 markers were detected before printing them out 42 | if ids is not None and len(ids) == 5: 43 | # Print corners and ids to the console 44 | for i, corner in zip(ids, corners): 45 | print('ID: {}; Corners: {}'.format(i, corner)) 46 | 47 | # Outline all of the markers detected in our image 48 | QueryImg = aruco.drawDetectedMarkers(QueryImg, corners, borderColor=(0, 0, 255)) 49 | 50 | # Wait on this frame 51 | if cv2.waitKey(0) & 0xFF == ord('q'): 52 | break 53 | 54 | # Display our image 55 | cv2.imshow('QueryImage', QueryImg) 56 | 57 | 58 | # Exit at the end of the video on the 'q' keypress 59 | if cv2.waitKey(1) & 0xFF == ord('q'): 60 | break 61 | 62 | cv2.destroyAllWindows() 63 | -------------------------------------------------------------------------------- /SimpleMarkerDetection/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This folder is meant for experimenting with the use of multiple sized markers on an Aruco Board 4 | 5 | 6 | --------------------------------------------------------------------------------