Skip to content

Commit 125738f

Browse files
authored
Merge pull request #15 from agfianf/claude/code-quality-review-011CURRCUCWodQXvFbAjsYY9
Review and Refactor Current Code Quality
2 parents 1c41765 + aaa1197 commit 125738f

File tree

20 files changed

+5365
-1119
lines changed

20 files changed

+5365
-1119
lines changed

.github/workflows/tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ jobs:
2424
matrix:
2525
os: [ubuntu-latest, windows-latest, macos-latest]
2626
python-version:
27-
- "3.10"
2827
- "3.11"
2928
- "3.12"
3029

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### Changed
6+
- **Python Version Requirement**: Dropped support for Python 3.10. The package now requires Python 3.11 or higher.
7+
- Updated CI/CD workflow to test only Python 3.11 and 3.12 across all platforms (Ubuntu, Windows, macOS).
8+
- Updated `pyproject.toml` to reflect `requires-python = ">=3.11"`.
9+
- Simplified dependency lock file (`uv.lock`) by removing Python 3.10-specific markers.
10+
311
## [v0.0.1-rc4] - 2025-04-11
412
**Release Candidate with MCCardDetector and Segmentation Support**
513

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ This package is designed to perform color correction on images using the Color C
2121

2222
## 📦 Installation
2323

24+
**Requirements:**
25+
- Python 3.11 or higher
26+
2427
```bash
2528
pip install color-correction
2629
```
@@ -108,6 +111,53 @@ print(eval_result)
108111

109112
</details>
110113

114+
## 🛡️ Error Handling
115+
116+
The package provides clear, actionable error messages through custom exceptions:
117+
118+
```python
119+
from color_correction import ColorCorrection
120+
from color_correction.exceptions import (
121+
UnsupportedModelError,
122+
PatchesNotSetError,
123+
ModelNotFittedError,
124+
InvalidImageError,
125+
)
126+
127+
try:
128+
# Initialize with invalid model
129+
cc = ColorCorrection(detection_model="invalid_model")
130+
except UnsupportedModelError as e:
131+
print(f"Error: {e}")
132+
# Output: "Unsupported model: 'invalid_model'. Supported models are: yolov8, mcc"
133+
134+
try:
135+
cc = ColorCorrection()
136+
# Forgot to set input patches
137+
cc.fit()
138+
except PatchesNotSetError as e:
139+
print(f"Error: {e}")
140+
# Output: "Input patches must be set before this operation. Call set_input_patches() first."
141+
142+
try:
143+
cc = ColorCorrection()
144+
# Forgot to fit the model
145+
corrected = cc.predict(image)
146+
except ModelNotFittedError as e:
147+
print(f"Error: {e}")
148+
# Output: "Model must be fitted before prediction. Call fit() first."
149+
150+
try:
151+
cc = ColorCorrection()
152+
# Invalid image format
153+
cc.set_input_patches(grayscale_image) # 2D array instead of 3D
154+
except InvalidImageError as e:
155+
print(f"Error: {e}")
156+
# Output: "Invalid image: image must have 3 dimensions (H, W, C), got 2"
157+
```
158+
159+
For more details, see the [Exception Reference](https://agfianf.github.io/color-correction/reference/exceptions/).
160+
111161
## 🔎 Reporting
112162
```python
113163
import cv2
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
"""Configuration constants for color checker card grid layout.
2+
3+
This module defines the standard layout for the X-Rite ColorChecker Classic
4+
24-patch card, which has a 6x4 grid (6 columns, 4 rows = 24 patches total).
5+
"""
6+
7+
from typing import Final
8+
9+
# ============================================================================
10+
# Grid Dimensions
11+
# ============================================================================
12+
13+
GRID_ROWS: Final[int] = 4
14+
"""Number of rows in the color checker grid."""
15+
16+
GRID_COLS: Final[int] = 6
17+
"""Number of columns in the color checker grid."""
18+
19+
TOTAL_PATCHES: Final[int] = GRID_ROWS * GRID_COLS # 24
20+
"""Total number of patches in the color checker card."""
21+
22+
23+
# ============================================================================
24+
# Grid Position Indices
25+
# ============================================================================
26+
27+
ROW_END_INDICES: Final[frozenset[int]] = frozenset([5, 11, 17, 23])
28+
"""Indices of patches at the end of each row (rightmost column)."""
29+
30+
ROW_START_INDICES: Final[frozenset[int]] = frozenset([0, 6, 12, 18])
31+
"""Indices of patches at the start of each row (leftmost column)."""
32+
33+
COL_END_INDICES: Final[frozenset[int]] = frozenset(range(18, 24))
34+
"""Indices of patches in the last row (bottom row)."""
35+
36+
COL_START_INDICES: Final[frozenset[int]] = frozenset(range(0, 6))
37+
"""Indices of patches in the first row (top row)."""
38+
39+
40+
# ============================================================================
41+
# Neighbor Offsets
42+
# ============================================================================
43+
44+
NEIGHBOR_RIGHT_OFFSET: Final[int] = 1
45+
"""Index offset to get right neighbor patch."""
46+
47+
NEIGHBOR_LEFT_OFFSET: Final[int] = -1
48+
"""Index offset to get left neighbor patch."""
49+
50+
NEIGHBOR_BOTTOM_OFFSET: Final[int] = GRID_COLS # 6
51+
"""Index offset to get bottom neighbor patch (next row)."""
52+
53+
NEIGHBOR_TOP_OFFSET: Final[int] = -GRID_COLS # -6
54+
"""Index offset to get top neighbor patch (previous row)."""
55+
56+
57+
# ============================================================================
58+
# Visualization Defaults
59+
# ============================================================================
60+
61+
DEFAULT_GRID_FIGSIZE_WIDTH: Final[int] = 15
62+
"""Default figure width for grid visualizations."""
63+
64+
DEFAULT_GRID_FIGSIZE_HEIGHT_PER_ROW: Final[int] = 4
65+
"""Default figure height per row for grid visualizations."""
66+
67+
68+
# ============================================================================
69+
# Detection Defaults
70+
# ============================================================================
71+
72+
MIN_PATCHES_REQUIRED: Final[int] = 24
73+
"""Minimum number of patches required for valid detection."""
74+
75+
DEFAULT_CONFIDENCE_THRESHOLD: Final[float] = 0.25
76+
"""Default confidence threshold for card detection."""
77+
78+
DEFAULT_IOU_THRESHOLD: Final[float] = 0.7
79+
"""Default Intersection over Union threshold for NMS."""
80+
81+
82+
# ============================================================================
83+
# Helper Functions
84+
# ============================================================================
85+
86+
87+
def is_row_end(index: int) -> bool:
88+
"""Check if patch index is at row end (rightmost column).
89+
90+
Parameters
91+
----------
92+
index : int
93+
Patch index (0-23)
94+
95+
Returns
96+
-------
97+
bool
98+
True if patch is at row end
99+
"""
100+
return index in ROW_END_INDICES
101+
102+
103+
def is_row_start(index: int) -> bool:
104+
"""Check if patch index is at row start (leftmost column).
105+
106+
Parameters
107+
----------
108+
index : int
109+
Patch index (0-23)
110+
111+
Returns
112+
-------
113+
bool
114+
True if patch is at row start
115+
"""
116+
return index in ROW_START_INDICES
117+
118+
119+
def get_row_number(index: int) -> int:
120+
"""Get row number (0-3) for a given patch index.
121+
122+
Parameters
123+
----------
124+
index : int
125+
Patch index (0-23)
126+
127+
Returns
128+
-------
129+
int
130+
Row number (0 for top row, 3 for bottom row)
131+
"""
132+
return index // GRID_COLS
133+
134+
135+
def get_col_number(index: int) -> int:
136+
"""Get column number (0-5) for a given patch index.
137+
138+
Parameters
139+
----------
140+
index : int
141+
Patch index (0-23)
142+
143+
Returns
144+
-------
145+
int
146+
Column number (0 for leftmost, 5 for rightmost)
147+
"""
148+
return index % GRID_COLS

color_correction/constant/methods.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
"affine_reg",
88
]
99

10-
LiteralModelDetection = Literal["yolov8"]
10+
LiteralModelDetection = Literal["yolov8", "mcc"]

0 commit comments

Comments
 (0)