Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3aa2fbb
Create the point_registration module, add a homography file for compu…
RyanDoesMath Jun 10, 2025
518ab73
Implemented find_homography.
RyanDoesMath Jun 10, 2025
436bcc4
Change some of the checks for find_homography.
RyanDoesMath Jun 10, 2025
ddc1bf3
Implement transform_point.
RyanDoesMath Jun 10, 2025
6390884
update module docstring for point_registration/homography.py
RyanDoesMath Jun 10, 2025
483507b
Merge pull request #63 from Paper-Chart-Extraction-Project/add-single…
RyanDoesMath Jun 10, 2025
f573326
Stub out two methods for serializing and deserializing detections to/…
RyanDoesMath Jun 10, 2025
d13b4ed
Implement the read fn.
RyanDoesMath Jun 10, 2025
19ac78f
Implement the write fn.
RyanDoesMath Jun 10, 2025
74d0e2c
Merge pull request #64 from Paper-Chart-Extraction-Project/add-detect…
RyanDoesMath Jun 11, 2025
7a6c5b5
Stub out a generalized fn for performing tiled detection on an image.
RyanDoesMath Jun 11, 2025
afa2237
implement detect_objects_with_tiling.
RyanDoesMath Jun 11, 2025
101d7ce
Remove the detect_numbers() fn and replace with the generalized detec…
RyanDoesMath Jun 11, 2025
ecbe685
Remove the make_digit_detections fn in favor of slightly more verbose…
RyanDoesMath Jun 11, 2025
fe855ba
Fix some minor errors.
RyanDoesMath Jun 11, 2025
8d37c37
Move checkbox detection into extraction.py
RyanDoesMath Jun 11, 2025
8090e19
Add the compute_tile_size fn to reduce repetition.
RyanDoesMath Jun 11, 2025
5260622
Remove unused constant.
RyanDoesMath Jun 11, 2025
b92aaf5
Remove the make_document_landmark_detections fn and replace with call…
RyanDoesMath Jun 11, 2025
382be32
Simplify the logic of the make_bp_and_hr_detections fn.
RyanDoesMath Jun 11, 2025
8ba5834
Merge pull request #65 from Paper-Chart-Extraction-Project/add-centra…
RyanDoesMath Jun 11, 2025
b683b41
Stub out three functions that will run all of the yolo models in sequ…
RyanDoesMath Jun 11, 2025
d9dfc41
Implement run_models.
RyanDoesMath Jun 11, 2025
224f781
Implement run_intraoperative_models.
RyanDoesMath Jun 11, 2025
330ebe4
implement run_preoperative_postoperative_models.
RyanDoesMath Jun 11, 2025
6ed9c24
Stubbed out three functions that assign meaning to detections.
RyanDoesMath Jun 12, 2025
d7bbdd4
Implement assign_meaning_to_detections.
RyanDoesMath Jun 12, 2025
1e7ad34
Add functions for finding the homography matrix for both sides of the…
RyanDoesMath Jun 12, 2025
baaacf2
Add a fn to transform boxes using the homography matrix.
RyanDoesMath Jun 12, 2025
8faac0d
Add a fn to remap Keypoints.
RyanDoesMath Jun 12, 2025
fb619a8
Add a fn to interpret meaning from detections without running the mod…
RyanDoesMath Jun 13, 2025
eab6c17
Implement a fn to interpret meaning from preop postop detections.
RyanDoesMath Jun 13, 2025
5b9a562
Change key name of preoperative checkboxes.
RyanDoesMath Jun 13, 2025
9cdd79c
Merge pull request #66 from Paper-Chart-Extraction-Project/homography…
RyanDoesMath Jun 13, 2025
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
119 changes: 20 additions & 99 deletions ChartExtractor/extraction/checkboxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,22 @@


def extract_checkboxes(
image: Image.Image,
detection_model: ObjectDetectionModel,
detections: List[Detection],
side: Literal["intraoperative", "preoperative"],
slice_width: int,
slice_height: int,
horizontal_overlap_ratio: float = 0.5,
vertical_overlap_ratio: float = 0.5,
image_width: int,
image_height: int,
) -> Dict[str, str]:
"""Extracts checkbox data from an image of a chart.

Args:
`image` (Image.Image):
The image to extract checkboxes from.
`detection_model` (ObjectDetectionModel):
An object that implements the ObjectDetectionModel interface.
`slice_height` (int):
The height of each slice.
`slice_width` (int):
The width of each slice.
`horizontal_overlap_ratio` (float):
The amount of left-right overlap between slices.
`vertical_overlap_ratio` (float):
The amount of top-bottom overlap between slices.

detections (List[Detection]):
The detected checkboxes.
side (Literal["intraoperative", "preoperative"]):
The side of the chart.
image_width (int):
The original image's width.
image_height (int):
The original image's height.
Returns:
A dictionary mapping the name of checkboxes to "checked" or "unchecked".
"""
Expand All @@ -74,76 +66,21 @@ def extract_checkboxes(
f'Invalid selection for side. Must be one of ["intraoperative", "preoperative"], value supplied was {side}'
)

checkbox_bboxes: List[BoundingBox] = detect_checkboxes(
image,
detection_model,
slice_width,
slice_height,
horizontal_overlap_ratio,
vertical_overlap_ratio,
checkbox_bboxes: List[BoundingBox] = [det.annotation for det in detections]
names: Dict[str, str] = find_checkbox_names(
checkbox_bboxes,
centroids,
image_width,
image_height
)
names: Dict[str, str] = find_checkbox_names(checkbox_bboxes, centroids, image.size)
return names


def detect_checkboxes(
image: Image.Image,
detection_model: ObjectDetectionModel,
slice_width: int,
slice_height: int,
horizontal_overlap_ratio: float,
vertical_overlap_ratio: float,
) -> List[BoundingBox]:
"""Uses an object detector to detect checkboxes and their state on an image.

Args:
`image` (Image.Image):
The image to extract checkboxes from.
`detection_model` (ObjectDetectionModel):
An object that implements the ObjectDetectionModel interface.
`slice_height` (int):
The height of each slice.
`slice_width` (int):
The width of each slice.
`horizontal_overlap_ratio` (float):
The amount of left-right overlap between slices.
`vertical_overlap_ratio` (float):
The amount of top-bottom overlap between slices.

Returns:
A list of Detection objects encoding the location and state of checkboxes.
"""
image_tiles: List[List[Image.Image]] = tile_image(
image,
slice_width,
slice_height,
horizontal_overlap_ratio,
vertical_overlap_ratio,
)
detections: List[List[List[Detection]]] = [
[detection_model(pil_to_cv2(tile))[0] for tile in row]
for row in image_tiles
]
detections: List[Detection] = untile_detections(
detections,
slice_width,
slice_height,
horizontal_overlap_ratio,
vertical_overlap_ratio,
)
detections: List[Detection] = non_maximum_suppression(
detections=detections,
threshold=0.8,
overlap_comparator=intersection_over_minimum,
sorting_fn=lambda det: det.annotation.area * det.confidence,
)
return [det.annotation for det in detections]


def find_checkbox_names(
checkboxes: List[BoundingBox],
centroids: Dict[str, Tuple[float, float]],
imsize: Tuple[int, int],
image_width: int,
image_height: int,
threshold: float = 0.025,
) -> Dict[str, str]:
"""Finds the names of checkboxes.
Expand Down Expand Up @@ -175,7 +112,7 @@ def distance(p1: Tuple[float, float], p2: Tuple[float, float]) -> float:

checkbox_values: Dict[str, str] = dict()
for ckbx in checkboxes:
center = ckbx.center[0] / imsize[0], ckbx.center[1] / imsize[1]
center = ckbx.center[0] / image_width, ckbx.center[1] / image_height
distance_to_all_centroids: Dict[str, float] = {
name: distance(center, centroid) for (name, centroid) in centroids.items()
}
Expand All @@ -188,19 +125,3 @@ def distance(p1: Tuple[float, float], p2: Tuple[float, float]) -> float:
checkbox_values[closest_checkbox_centroid] = ckbx.category

return checkbox_values


def find_interaoperative_checkbox_names(
intraoperative_checkboxes: List[BoundingBox], threshold: float = 0.025
) -> Dict[str, str]:
"""Finds the names of intraoperative checkboxes."""
return find_checkbox_names(intraoperative_checkboxes, INTRAOP_CENTROIDS, threshold)


def find_preoperative_checkbox_names(
preoperative_checkboxes: List[BoundingBox], threshold: float = 0.025
) -> Dict[str, str]:
"""Finds the names of preoperative checkboxes."""
return find_checkbox_names(
preoperative_checkboxes, PREOP_POSTOP_CENTROIDS, threshold
)
Loading
Loading