Skip to content
Open
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
18 changes: 15 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,19 @@ def main(sessionName, trialName, trial_id, cameras_to_use=['all'],
cameraDirectories[camName] = os.path.join(sessionDir, 'Videos',
pathCam)
cameraModels[camName] = sessionMetadata['iphoneModel'][camName]
cameraMapping = sessionMetadata.get('cameraMapping', {})

# Get cameras' intrinsics and extrinsics.
# Load parameters if saved, compute and save them if not.
CamParamDict = {}
loadedCamParams = {}
for camName in cameraDirectories:
cameraLabel = cameraMapping.get(camName, {}).get('phone_label')
calibrationFailurePrefix = (
"Calibration failed for {}.".format(cameraLabel)
if cameraLabel else
"Calibration failed for at least one camera."
)
camDir = cameraDirectories[camName]
lidarIntrinsicPath = os.path.join(camDir, 'InputMedia', trialName,
'camera_matrix.csv')
Expand Down Expand Up @@ -254,7 +261,10 @@ def main(sessionName, trialName, trial_id, cameras_to_use=['all'],
# webapp will give you the opportunity to compute them.

else:
exception = "Intrinsics don't exist for your camera model. OpenCap supports all iOS devices released in 2018 or later: https://www.opencap.ai/get-started."
if cameraLabel:
exception = "Intrinsics don't exist for the camera model used by {}. OpenCap supports all iOS devices released in 2018 or later: https://www.opencap.ai/get-started.".format(cameraLabel)
else:
exception = "Intrinsics don't exist for your camera model. OpenCap supports all iOS devices released in 2018 or later: https://www.opencap.ai/get-started."
raise Exception(exception, exception)

# Extrinsics ##################################################
Expand All @@ -281,9 +291,11 @@ def main(sessionName, trialName, trial_id, cameras_to_use=['all'],
useSecondExtrinsicsSolution = useSecondExtrinsicsSolution)
except Exception as e:
if len(e.args) == 2: # specific exception
raise Exception(e.args[0], e.args[1])
exception = "{} {}".format(
calibrationFailurePrefix, e.args[0])
raise Exception(exception, e.args[1])
elif len(e.args) == 1: # generic exception
exception = "Camera calibration failed. Verify your setup and try again. Visit https://www.opencap.ai/best-pratices to learn more about camera calibration and https://www.opencap.ai/troubleshooting for potential causes for a failed calibration."
exception = "{} Verify your setup and try again. Visit https://www.opencap.ai/best-pratices to learn more about camera calibration and https://www.opencap.ai/troubleshooting for potential causes for a failed calibration.".format(calibrationFailurePrefix)
raise Exception(exception, traceback.format_exc())
loadedCamParams[camName] = False

Expand Down
44 changes: 38 additions & 6 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,22 @@ def downloadVideosFromServer(session_id,trial_id, isDocker=True,
os.makedirs(session_path, exist_ok=True)

trial = getTrialJson(trial_id)
session = getSessionJson(session_id)
apiCameraMap = (session.get('meta') or {}).get('camera_map') or {}

def getCameraIndex(video, fallbackIndex, usedIndices):
device_id = video["device_id"].replace('-', '').upper()
camera_label = apiCameraMap.get(device_id, {}).get('camera_label', '')
if camera_label.startswith('Cam'):
try:
camera_index = int(camera_label.replace('Cam', ''))
if camera_index not in usedIndices:
return camera_index
except ValueError:
pass
while fallbackIndex in usedIndices:
fallbackIndex += 1
return fallbackIndex

if trial_name is None:
trial_name = trial['name']
Expand All @@ -542,7 +558,10 @@ def downloadVideosFromServer(session_id,trial_id, isDocker=True,
if not benchmark:
if not os.path.exists(os.path.join(session_path, "Videos", 'mappingCamDevice.pickle')):
mappingCamDevice = {}
for k, video in enumerate(trial["videos"]):
usedIndices = set()
for i, video in enumerate(trial["videos"]):
k = getCameraIndex(video, i, usedIndices)
usedIndices.add(k)
os.makedirs(os.path.join(session_path, "Videos", "Cam{}".format(k), "InputMedia", trial_name), exist_ok=True)
video_path = os.path.join(session_path, "Videos", "Cam{}".format(k), "InputMedia", trial_name, trial_id + ".mov")
downloadVideoFile(video, video_path, trial_id,
Expand Down Expand Up @@ -584,11 +603,24 @@ def downloadVideosFromServer(session_id,trial_id, isDocker=True,
else: # subject parameters will be entered when capturing static pose
session_desc = getMetadataFromServer(session_id)

# Load iPhone models.
phoneModel= []
for i,video in enumerate(trial["videos"]):
phoneModel.append(video['parameters']['model'])
session_desc['iphoneModel'] = {'Cam' + str(i) : phoneModel[i] for i in range(len(phoneModel))}
# Load camera labels and iPhone models.
phoneModel = {}
cameraMapping = {}
for video in trial["videos"]:
device_id = video["device_id"].replace('-', '').upper()
if device_id not in mappingCamDevice:
continue
camName = 'Cam' + str(mappingCamDevice[device_id])
phoneModel[camName] = video.get('parameters', {}).get('model', 'unknown')
phone_label = apiCameraMap.get(device_id, {}).get('phone_label')
if phone_label:
cameraMapping[camName] = {
'phone_label': phone_label,
'device_id': video["device_id"],
}
session_desc['iphoneModel'] = phoneModel
if cameraMapping:
session_desc['cameraMapping'] = cameraMapping

# Save metadata.
with open(sessionYamlPath, 'w') as file:
Expand Down
15 changes: 12 additions & 3 deletions utilsChecker.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ def calcExtrinsics(imageFileName, CameraParams, CheckerBoardParams,

# 3D points real world coordinates. Assuming z=0
objectp3d = generate3Dgrid(CheckerBoardParams)
detectedCheckerBoardParams = CheckerBoardParams

# Load and resize image - remember calibration image res needs to be same as all processing
image = cv2.imread(imageFileName)
Expand Down Expand Up @@ -510,16 +511,24 @@ def calcExtrinsics(imageFileName, CameraParams, CheckerBoardParams,
# Using ACCURACY|LARGER without EXHAUSTIVE to keep the fallback reasonably fast.
corners2_from_sb = False
if not ret:
ret_sb, corners_sb, _ = cv2.findChessboardCornersSBWithMeta(
ret_sb, corners_sb, meta_sb = cv2.findChessboardCornersSBWithMeta(
grayColor, CheckerBoardParams['dimensions'],
cv2.CALIB_CB_ACCURACY | cv2.CALIB_CB_LARGER | cv2.CALIB_CB_EXHAUSTIVE)
if ret_sb:
detectedDimensions = meta_sb.shape[::-1]
checkerCopy = copy.copy(CheckerBoardParams)
checkerCopy['dimensions'] = detectedDimensions
detectedCheckerBoardParams = checkerCopy
objectp3d = generate3Dgrid(detectedCheckerBoardParams)
ret = True
corners, orderingSuccess, orderingError = ensureCornerOrdering(
grayColor, corners_sb, CheckerBoardParams['dimensions'],
grayColor, corners_sb, detectedCheckerBoardParams['dimensions'],
squareResolution=2)
if orderingSuccess:
corners2_from_sb = True
if tuple(detectedDimensions) != tuple(CheckerBoardParams['dimensions']):
print('Detected checkerboard dimensions {} instead of input dimensions {}.'.format(
detectedDimensions, CheckerBoardParams['dimensions']))
else:
print('Rejected SB checkerboard detection: ' + orderingError)
ret = False
Expand All @@ -544,7 +553,7 @@ def calcExtrinsics(imageFileName, CameraParams, CheckerBoardParams,

# For testing: Draw and display the corners
# image = cv2.drawChessboardCorners(image,
# CheckerBoardParams['dimensions'],
# detectedCheckerBoardParams['dimensions'],
# corners2, ret)
# Draw small dots instead
# Choose dot size based on size of squares in pixels
Expand Down