Skip to content

Conversation

@zgypa
Copy link
Member

@zgypa zgypa commented Oct 11, 2025

Adds a Django idiomatic model to the bfd9000_dicom package. Major refactoring and re-organization.

@zgypa zgypa self-assigned this Oct 11, 2025
@zgypa zgypa requested a review from Copilot October 11, 2025 04:00
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a Django idiomatic DTO (Data Transfer Object) architecture to the bfd9000_dicom package, with major refactoring and reorganization of the codebase. The changes introduce a clean separation of concerns with specialized converter classes, core utilities, and Django-style metadata models for various imaging modalities.

Key changes:

  • Introduced Django-style DTO models for DICOM metadata with multiple imaging modalities support
  • Restructured the package into logical modules: converters/, core/, and models.py
  • Added comprehensive test coverage and documentation for the new architecture

Reviewed Changes

Copilot reviewed 28 out of 35 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
bfd9000_dicom/bfd9000_dicom/models.py Implements Django-style DTO classes for DICOM metadata across multiple modalities
bfd9000_dicom/bfd9000_dicom/converters/ New package containing specialized converters for different imaging types
bfd9000_dicom/bfd9000_dicom/core/ Core utilities for DICOM building and compression, refactored from existing modules
bfd9000_dicom/tests/ Comprehensive test suite for the new architecture and existing functionality
bfd9000_dicom/examples/basic_usage.py Example code demonstrating the new DTO and converter APIs
bfd9000_dicom/docs/ Architecture documentation and planning documents
bfd9000_dicom/pyproject.toml Project configuration with updated dependencies and metadata

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 1 to 5
import os
import json
import pydicom
import argparse
from pydicom.dataset import Dataset
from pydicom.uid import SecondaryCaptureImageStorage, generate_uid
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the import pydicom line may indicate incomplete refactoring. Verify that all pydicom functionality is accessed through specific imports rather than the general module import.

Copilot uses AI. Check for mistakes.
f"{self.nominal_scanned_pixel_spacing[0]}",
f"{self.nominal_scanned_pixel_spacing[1]}"
]
ds.PixelSpacing No newline at end of file
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete code line - the assignment to ds.PixelSpacing is missing its value. This appears to be truncated code that should be completed or removed.

Suggested change
ds.PixelSpacing
ds.PixelSpacing = [
f"{self.nominal_scanned_pixel_spacing[0]}",
f"{self.nominal_scanned_pixel_spacing[1]}"
]

Copilot uses AI. Check for mistakes.
f"{self.nominal_scanned_pixel_spacing[0]}",
f"{self.nominal_scanned_pixel_spacing[1]}"
]
ds.PixelSpacing No newline at end of file
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate incomplete code line - the assignment to ds.PixelSpacing is missing its value. This appears to be duplicated truncated code that should be completed or removed.

Suggested change
ds.PixelSpacing
ds.PixelSpacing = [
f"{self.nominal_scanned_pixel_spacing[0]}",
f"{self.nominal_scanned_pixel_spacing[1]}"
]

Copilot uses AI. Check for mistakes.
zgypa added 12 commits October 11, 2025 00:51
- Remove obsolete DocumentConverter and Converter classes.
- Introduce new JPEGConverter, PNGConverter, PDFConverter, STLConverter, and TIFFConverter classes for handling respective formats.
- Implement a router system to automatically select the appropriate converter based on file type.
- Add example usage scripts demonstrating the new converter architecture and functionality.
- Ensure proper handling of metadata and pixel data for each converter.
Relocated compression.py → compression.py
Updated all import statements across the codebase (TIFF, JPEG, PNG converters, tests, etc.)
Integrated DICOM tags logic from dicom_tags.py

Added Bolton Brush specific attributes to RadiographMetadata class:
is_bolton_brush_study flag
Automatic setting of Bolton Brush device information when enabled
Added orientation methods: set_orientation_ll(), set_orientation_pa(), set_orientation_hand()
Integrated common Bolton Brush tags into the metadata DTO
Integrated TIFF conversion logic from tiff2dcm.py

Created utility functions in converters/utils.py:
extract_bolton_brush_data_from_filename() - parses Bolton Brush filename format
load_radiograph_metadata_from_json() - backward compatibility for JSON metadata
Exported these utilities in the main package API
Updated all imports and references

Updated main package __init__.py to export new utility functions
All compression imports now point to the new location
No remaining active references to old modules
📁 File Changes:
Moved: compression.py → compression.py
Modified: models.py - Added Bolton Brush support to RadiographMetadata
Created: converters/utils.py - Bolton Brush utilities
Updated: All converter files, main __init__.py, test files
🗂️ Remaining Action:
The old/ folder can now be safely removed since all its logic has been integrated into the new architecture:
- Moved exception imports to the base converter module.
- Updated import paths in JPEG converter.
- Removed unused compression imports from core module.
- Improved README test structure and added categories.
- Added unit tests for Bolton Brush utilities and DICOM metadata models.
- Created integration tests for converter router functionality.
- Enhanced TIFF converter tests and added edge case handling.
…ion and update filename parsing to include image type
@zgypa zgypa requested a review from Copilot October 11, 2025 22:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 38 out of 43 changed files in this pull request and generated 5 comments.


Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

# Calculate PixelAspectRatio using original dpi values to avoid rounding errors
if dpi_horizontal == dpi_vertical:
pixel_aspect_ratio = [1, 1]
pixel_aspect_ratio = ["1", "1"]
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent return type for pixel_aspect_ratio. The function returns a list [\"1\", \"1\"] for equal DPI but a list [f\"{int(dpi_vertical / gcd_ratio)}\", f\"{int(dpi_horizontal / gcd_ratio)}\"] for unequal DPI. The original function returned tuples but this has been changed to lists for string formatting, which should be consistent throughout.

Copilot uses AI. Check for mistakes.
class ConversionType(Enum):
"""DICOM Conversion Type values (0008,0064)."""
DF = "DF" # Digitized Film
SI = "SI" # Digital Interface
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected 'DI' to 'SI' in the enum value comment. The enum value 'SI' stands for 'Synthetic Image' but the comment incorrectly references 'Digital Interface'.

Suggested change
SI = "SI" # Digital Interface
SI = "SI" # Synthetic Image

Copilot uses AI. Check for mistakes.
Comment on lines 136 to 140
# Create metadata
metadata = RadiographMetadata(
patient_id=patient_id,
patient_sex=PatientSex[sex],
patient_age=age_months, # This might not be the correct format for the DTO.
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment indicates uncertainty about the correct format for patient_age. Based on the DTO definition, patient_age should be a string in DICOM format (e.g., '217M' for months), not the raw age_months value returned from extract_metadata_from_filename.

Suggested change
# Create metadata
metadata = RadiographMetadata(
patient_id=patient_id,
patient_sex=PatientSex[sex],
patient_age=age_months, # This might not be the correct format for the DTO.
def months_to_dicom_age(months):
"""Convert integer months to DICOM age string (e.g., '217M')."""
return f"{int(months):03d}M"
# Create metadata
metadata = RadiographMetadata(
patient_id=patient_id,
patient_sex=PatientSex[sex],
patient_age=months_to_dicom_age(age_months),

Copilot uses AI. Check for mistakes.
from pydicom.uid import ExplicitVRLittleEndian, JPEG2000Lossless

from bfd9000_dicom.models import BaseDICOMMetadata
from .compression import get_encapsulated_jpeg2k_pixel_data
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect relative import path. Should import from bfd9000_dicom.converters.compression instead of .compression since the compression module is in the same converters package.

Suggested change
from .compression import get_encapsulated_jpeg2k_pixel_data
from bfd9000_dicom.converters.compression import get_encapsulated_jpeg2k_pixel_data

Copilot uses AI. Check for mistakes.
class ConversionType(Enum):
"""DICOM Conversion Type values (0008,0064)."""
DF = "DF" # Digitized Film
SI = "SI" # Digital Interface
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect comment for enum value. 'SI' in DICOM Conversion Type should be 'Synthetic Image', not 'Digital Interface'. The correct value for Digital Interface would be 'DI'.

Suggested change
SI = "SI" # Digital Interface
SI = "SI" # Synthetic Image

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants