Skip to content

Commit

Permalink
Merge pull request #653 from mprib/641-scale-input-boxes-to-improve-v…
Browse files Browse the repository at this point in the history
…isability-of-numbers

641 scale input boxes to improve visability of numbers
  • Loading branch information
mprib authored Oct 23, 2024
2 parents 54e4ecc + 672ebb3 commit 7116216
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 30 deletions.
53 changes: 37 additions & 16 deletions caliscope/calibration/charuco.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

INCHES_PER_CM = 0.393701


class Charuco:
"""
create a charuco board that can be printed out and used for camera
Expand Down Expand Up @@ -72,6 +71,21 @@ def board_width_cm(self):
else:
return self.board_width

def board_height_scaled(self, pixmap_scale):
if self.board_height_cm > self.board_width_cm:
scaled_height = int(pixmap_scale)
else:
scaled_height = int(pixmap_scale * (self.board_height_cm/self.board_width_cm))
return scaled_height

def board_width_scaled(self, pixmap_scale):
if self.board_height_cm > self.board_width_cm:
scaled_width = int(pixmap_scale * (self.board_width_cm/self.board_height_cm))
else:
scaled_width = int(pixmap_scale)

return scaled_width

@property
def dictionary_object(self):
# grab the dictionary from the reference info at the foot of the module
Expand Down Expand Up @@ -99,25 +113,26 @@ def board(self):
self.dictionary_object,
)

@property
def board_img(self):
"""A cv2 image (numpy array) of the board printing at 300 dpi.
Conversion to inches is strange, but done due to
ubiquity of inch measurement for familiar printing standard"""

width_inch = self.board_width_cm * INCHES_PER_CM
height_inch = self.board_height_cm * INCHES_PER_CM

img = self.board.generateImage((int(width_inch * 300), int(height_inch * 300)))
def board_img(self, pixmap_scale=1000):
"""
returns a cv2 image (numpy array) of the board
smaller scale image by default for display to GUI
provide larger max_edge_length to get printer-ready png
"""
img = self.board.generateImage((self.board_width_scaled(pixmap_scale=pixmap_scale),
self.board_height_scaled(pixmap_scale=pixmap_scale)))
if self.inverted:
img = ~img

return img

def board_pixmap(self, width, height):
"""Convert from an opencv image to QPixmap..this can be used for
creating thumbnail images"""
rgb_image = cv2.cvtColor(self.board_img, cv2.COLOR_BGR2RGB)
"""
Convert from an opencv image to QPixmap
this can be used for creating thumbnail images
"""
rgb_image = cv2.cvtColor(self.board_img(), cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
charuco_QImage = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
Expand All @@ -130,10 +145,16 @@ def board_pixmap(self, width, height):
return QPixmap.fromImage(p)

def save_image(self, path):
cv2.imwrite(path, self.board_img)
"""
Saving image at 10x higher resolution than used for GUI
"""
cv2.imwrite(path, self.board_img(pixmap_scale=10000))

def save_mirror_image(self, path):
mirror = cv2.flip(self.board_img, 1)
"""
Saving image at 10x higher resolution than used for GUI
"""
mirror = cv2.flip(self.board_img(pixmap_scale=10000), 1)
cv2.imwrite(path, mirror)

def get_connected_points(self):
Expand Down Expand Up @@ -220,7 +241,7 @@ def summary(self):
if __name__ == "__main__":
charuco = Charuco(4, 5, 4, 8.5, aruco_scale=0.75, units="inch", inverted=True, square_size_overide_cm=5.25)
charuco.save_image("test_charuco.png")
width, height = charuco.board_img.shape
width, height = charuco.board_img().shape
logger.info(f"Board width is {width}\nBoard height is {height}")

corners = charuco.board.getChessboardCorners()
Expand Down
40 changes: 27 additions & 13 deletions caliscope/gui/charuco_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path

from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (
QApplication,
QCheckBox,
Expand Down Expand Up @@ -167,10 +168,28 @@ def build_charuco(self):
charuco_height = int(charuco_width * (board_height / board_width))

logger.info("Building charuco thumbnail...")
charuco_img = self.charuco.board_pixmap(charuco_width, charuco_height)
self.charuco_display.setPixmap(charuco_img)
try:
charuco_img = self.charuco.board_pixmap(charuco_width, charuco_height)
self.charuco_display.setPixmap(charuco_img)
# Clear any previous error message
self.charuco_display.setStyleSheet("")
self.charuco_display.setToolTip("")
self.controller.update_charuco(self.charuco)
except Exception as e:
logger.error(f"Failed to create charuco board: {str(e)}")
error_msg = """Unable to create board with current dimensions.\n
The default dictionary may by too small (can be configured in config.toml file).
Alternatively, the aspect ratio may be too extreme.
"""
self.charuco_display.setPixmap(QPixmap()) # Clear the pixmap
self.charuco_display.setText(error_msg)
# Optional: Add some styling to make the error message stand out
self.charuco_display.setStyleSheet("QLabel { color: red; }")
self.charuco_display.setToolTip("Try adjusting the width and height to have a less extreme ratio")

charuco_img = self.charuco.board_pixmap(charuco_width, charuco_height)
self.charuco_display.setPixmap(charuco_img)

self.controller.update_charuco(self.charuco)


class CharucoConfigGroup(QWidget):
Expand All @@ -182,27 +201,24 @@ def __init__(self, controller: Controller):
self.column_spin = QSpinBox()
self.column_spin.setMinimum(3)
self.column_spin.setValue(self.params["columns"])
# self.column_spin.setMaximumWidth(50)

self.row_spin = QSpinBox()
self.row_spin.setMinimum(4)
self.row_spin.setValue(self.params["rows"])
# self.row_spin.setMaximumWidth(50)

self.width_spin = QDoubleSpinBox()
self.width_spin.setMinimum(1)
self.width_spin.setMaximum(10000)
self.width_spin.setValue(self.params["board_width"])
self.width_spin.setMaximumWidth(50)

self.length_spin = QDoubleSpinBox()
self.length_spin.setMaximum(10000)
self.length_spin.setMinimum(1)
self.length_spin.setValue(self.params["board_height"])
self.length_spin.setMaximumWidth(50)

self.units = QComboBox()
self.units.addItems(["cm", "inch"])
self.units.setCurrentText(self.params["units"])
self.units.setMaximumWidth(100)

self.invert_checkbox = QCheckBox("&Invert")
self.invert_checkbox.setChecked(self.params["inverted"])
Expand Down Expand Up @@ -241,18 +257,16 @@ def __init__(self, controller: Controller):


if __name__ == "__main__":
app = QApplication(sys.argv)
from caliscope import __root__
from caliscope.helper import copy_contents
from caliscope.calibration.charuco import Charuco
app = QApplication(sys.argv)

# Define the input file path here.
original_workspace_dir = Path(__root__, "tests", "sessions", "prerecorded_calibration")
# workspace_dir = Path(
# __root__, "tests", "sessions_copy_delete", "prerecorded_calibration"
# )

# copy_contents(original_workspace_dir, workspace_dir)
workspace_dir = Path(r"C:\Users\Mac Prible\OneDrive\caliscope\prerecorded_workflow")
copy_contents(original_workspace_dir, workspace_dir)
controller = Controller(workspace_dir)
charuco_page = CharucoWidget(controller)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "caliscope"
version = "0.5.1"
version = "0.5.2"
description = "GUI based multicamera calibration that integrates with 2D landmark tracking to triangulate 3D landmark positions"
authors = ["Mac Prible <[email protected]>"]
license = "BSD-2-Clause"
Expand Down

0 comments on commit 7116216

Please sign in to comment.