Skip to content

Imaging Bridge

Intent

Connect FHIR-based clinical systems with DICOM imaging systems through standardized web APIs, enabling seamless integration between clinical metadata and imaging data.

Forces

  • Metadata vs Payload (Imaging): Clinical data (FHIR) and imaging data (DICOM) live in separate systems with different access patterns.
  • Interactive Viewing & Context Sync: Clinical workflows require real-time coordination between multiple applications.

Structure

The Imaging Bridge pattern provides a unified interface that maps between FHIR ImagingStudy resources and DICOMweb endpoints for actual image data retrieval.

Imaging Bridge Architecture

Key Components

ImagingBridge

Main coordination component for FHIR-DICOM integration

FHIRClient

Retrieves ImagingStudy resources and clinical metadata

DICOMwebClient

Interacts with PACS/VNA via WADO-RS, QIDO-RS, STOW-RS

AuthMapper

Maps authentication between FHIR and DICOM contexts

ImageCache

Caches frequently accessed images and thumbnails

Behavior

EMR Image Display Workflow

The following sequence shows how an EMR retrieves and displays images through the bridge:

Key Integration Points

  1. Study Discovery
  2. Endpoint Resolution
  3. Authentication Mapping
  4. Image Retrieval
  5. Unified Presentation

Implementation Considerations

ImagingStudy Resource Structure

Example FHIR ImagingStudy resource showing the relationship between FHIR metadata and DICOMweb endpoints for image retrieval.

ImagingStudy Resource Structure
{
  "resourceType": "ImagingStudy",
  "id": "example-ct-chest",
  "identifier": [{
    "type": {
      "coding": [{
        "system": "http://dicom.nema.org/resources/ontology/DCM",
        "code": "110180",
        "display": "Study Instance UID"
      }]
    },
    "value": "1.2.840.113619.2.5.1762583153.215519.978957063.78"
  }],
  "status": "available",
  "subject": {
    "reference": "Patient/example"
  },
  "started": "2023-12-01T09:00:00Z",
  "endpoint": [{
    "reference": "Endpoint/dicomweb-pacs-1"
  }],
  "numberOfSeries": 1,
  "numberOfInstances": 64,
  "series": [{
    "uid": "1.2.840.113619.2.5.1762583153.215519.978957063.78.1",
    "number": 1,
    "modality": {
      "system": "http://dicom.nema.org/resources/ontology/DCM",
      "code": "CT"
    },
    "description": "Chest CT with contrast",
    "numberOfInstances": 64,
    "endpoint": [{
      "reference": "Endpoint/dicomweb-pacs-1"
    }],
    "bodySite": {
      "system": "http://snomed.info/sct",
      "code": "51185008",
      "display": "Thoracic structure"
    }
  }]
}

Endpoint Configuration

Configuration for DICOMweb endpoints (WADO-RS, QIDO-RS, STOW-RS) including authentication settings and connection parameters.

Endpoint Configuration
{
  "resourceType": "Endpoint",
  "id": "dicomweb-pacs-1", 
  "status": "active",
  "connectionType": {
    "system": "http://terminology.hl7.org/CodeSystem/endpoint-connection-type",
    "code": "dicom-wado-rs"
  },
  "name": "Hospital PACS DICOMweb Service",
  "managingOrganization": {
    "reference": "Organization/hospital"
  },
  "payloadType": [{
    "coding": [{
      "system": "http://terminology.hl7.org/CodeSystem/endpoint-payload-type",
      "code": "DICOM"
    }]
  }],
  "payloadMimeType": [
    "application/dicom",
    "image/jpeg",
    "image/png"
  ],
  "address": "https://pacs.hospital.org/dicomweb",
  "header": [
    "Authorization: Bearer {token}"
  ]
}

Bridge Implementation

Core bridge implementation that coordinates between FHIR servers and DICOMweb endpoints with study/series/instance resolution.

Bridge Implementation
class ImagingBridge:
    def __init__(self, fhir_client, dicomweb_client, auth_mapper):
        self.fhir_client = fhir_client
        self.dicomweb_client = dicomweb_client  
        self.auth_mapper = auth_mapper

    async def get_patient_studies(self, patient_id, auth_context):
        """Retrieve imaging studies for patient with unified metadata"""

        # Query FHIR for ImagingStudy resources
        studies = await self.fhir_client.search(
            'ImagingStudy',
            {'patient': patient_id, 'status': 'available'}
        )

        # Enrich with DICOMweb metadata if requested
        enriched_studies = []
        for study in studies:
            enriched_study = await self._enrich_study_metadata(study, auth_context)
            enriched_studies.append(enriched_study)

        return enriched_studies

    async def _enrich_study_metadata(self, imaging_study, auth_context):
        """Enrich FHIR study with additional DICOM metadata"""

        # Get DICOMweb endpoint
        endpoint = await self._resolve_endpoint(imaging_study.endpoint[0])

        # Convert FHIR auth to DICOM auth
        dicom_auth = self.auth_mapper.map_auth_context(auth_context, endpoint)

        # Query DICOM metadata via QIDO-RS
        study_uid = self._extract_study_uid(imaging_study)
        dicom_metadata = await self.dicomweb_client.qido_search_studies(
            endpoint.address, study_uid, dicom_auth
        )

        # Merge metadata
        return self._merge_fhir_dicom_metadata(imaging_study, dicom_metadata)

    async def get_image_data(self, study_uid, series_uid, instance_uid, 
                           accept_type="image/jpeg", auth_context=None):
        """Retrieve image data via WADO-RS"""

        # Find appropriate endpoint
        endpoint = await self._find_endpoint_for_study(study_uid)

        # Map authentication
        dicom_auth = self.auth_mapper.map_auth_context(auth_context, endpoint)

        # Retrieve image via WADO-RS
        image_data = await self.dicomweb_client.wado_retrieve_instance(
            endpoint.address, study_uid, series_uid, instance_uid,
            accept_type, dicom_auth
        )

        return image_data

Authentication Mapping

Maps authentication contexts between FHIR (OAuth2/SMART) and DICOM systems (certificates, tokens, session cookies).

Authentication Mapping
class AuthenticationMapper:
    def __init__(self):
        self.mapping_rules = {
            'smart-on-fhir': self._map_smart_to_dicom,
            'basic-auth': self._map_basic_auth,
            'mutual-tls': self._map_mtls
        }

    def map_auth_context(self, fhir_auth_context, dicom_endpoint):
        """Map FHIR auth context to DICOMweb authentication"""

        auth_type = self._detect_auth_type(dicom_endpoint)
        mapper = self.mapping_rules.get(auth_type)

        if mapper:
            return mapper(fhir_auth_context, dicom_endpoint)
        else:
            raise ValueError(f"Unsupported auth type: {auth_type}")

    def _map_smart_to_dicom(self, fhir_context, endpoint):
        """Map SMART on FHIR token to DICOM bearer token"""

        # Extract access token from FHIR context
        access_token = fhir_context.access_token

        # Map to DICOMweb authorization header
        return {
            'Authorization': f'Bearer {access_token}',
            'Accept': 'application/dicom+json'
        }

    def _map_basic_auth(self, fhir_context, endpoint):
        """Map to basic authentication"""

        # Extract credentials from endpoint configuration
        username = endpoint.extension.get('dicom-username')
        password = endpoint.extension.get('dicom-password')

        if username and password:
            credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
            return {
                'Authorization': f'Basic {credentials}'
            }
Different systems may use different authentication approaches:

Image Caching Strategy

Implements caching for DICOM images and metadata with LRU eviction, prefetching, and memory management for performance optimization.

Image Caching Strategy
class ImageCache:
    def __init__(self, cache_backend, ttl_seconds=3600):
        self.cache = cache_backend
        self.ttl = ttl_seconds

    async def get_cached_image(self, study_uid, series_uid, instance_uid, accept_type):
        """Retrieve image from cache if available"""

        cache_key = self._generate_cache_key(study_uid, series_uid, instance_uid, accept_type)

        cached_data = await self.cache.get(cache_key)
        if cached_data:
            return cached_data

        return None

    async def cache_image(self, study_uid, series_uid, instance_uid, accept_type, image_data):
        """Store image in cache"""

        cache_key = self._generate_cache_key(study_uid, series_uid, instance_uid, accept_type)

        await self.cache.set(cache_key, image_data, ttl=self.ttl)

    def _generate_cache_key(self, study_uid, series_uid, instance_uid, accept_type):
        """Generate unique cache key for image"""
        return f"img:{study_uid}:{series_uid}:{instance_uid}:{accept_type}"

EMR Integration

JavaScript client for EMR integration with the imaging bridge, handling viewer launching and image display coordination.

EMR Integration
// Example EMR-side integration
class EMRImagingComponent {
    constructor(imagingBridgeUrl) {
        this.bridgeUrl = imagingBridgeUrl;
    }

    async loadPatientImages(patientId, authToken) {
        // Get available studies
        const studies = await this.fetchStudies(patientId, authToken);

        // Render study list
        this.renderStudyList(studies);

        // Load thumbnails for first study
        if (studies.length > 0) {
            await this.loadStudyThumbnails(studies[0], authToken);
        }
    }

    async fetchStudies(patientId, authToken) {
        const response = await fetch(`${this.bridgeUrl}/patients/${patientId}/studies`, {
            headers: {
                'Authorization': `Bearer ${authToken}`,
                'Accept': 'application/fhir+json'
            }
        });

        return await response.json();
    }

    async loadImage(studyUid, seriesUid, instanceUid, authToken) {
        const response = await fetch(
            `${this.bridgeUrl}/studies/${studyUid}/series/${seriesUid}/instances/${instanceUid}`,
            {
                headers: {
                    'Authorization': `Bearer ${authToken}`,
                    'Accept': 'image/jpeg'
                }
            }
        );

        const blob = await response.blob();
        return URL.createObjectURL(blob);
    }
}

  • IID Facade: IID Facade provides simple viewer launching using Imaging Bridge metadata
  • Event Observer: Event Observer synchronizes imaging context across clinical applications
  • Security Strategy: Security Strategy maps FHIR authentication to DICOM access control
  • Audit & Provenance Chain: Image access and viewing events are logged for compliance

Benefits

  • Unified Interface: Single API for both FHIR metadata and DICOM images
  • Standards Compliance: Uses established FHIR and DICOMweb standards
  • Security Integration: Maps authentication between FHIR and DICOM contexts
  • Performance Optimization: Caching and efficient image retrieval
  • Workflow Integration: Seamless EMR-PACS integration

Trade-offs

  • Complexity: Additional layer between clinical systems and imaging
  • Performance: Network overhead for metadata enrichment
  • Security Surface: More complex authentication mapping
  • Dependency: Requires both FHIR and DICOMweb infrastructure

References


Thumbnail Generation

Consider generating and caching thumbnail images for faster study browsing. Use WADO-RS with appropriate accept headers for optimized image formats.

Large Image Handling

Implement appropriate timeouts and streaming for large image datasets. Consider progressive loading strategies for multi-frame and high-resolution studies.