Aug 24, 2026 · 5 min · Dev Guides

I used Claude Code to get a second opinion on my MRI

I used Claude Code to get a second opinion on my MRI

My MRI arrived as a ZIP archive containing hundreds of DICOM files, not a neat set of images I could drag into a chat window. The radiology report was easier to open, but it compressed a complicated scan into a few paragraphs full of phrases such as “mild signal abnormality” and “clinical correlation recommended.”

I wanted a second pass—not an AI diagnosis, and certainly not a replacement for a radiologist. I wanted to know whether the report and the visible images told a consistent story, which uncertainties mattered, and what questions I should take to my doctor.

Claude Code turned out to be useful because this was partly a medical-language problem, but mostly a data-engineering problem: inventory the scan, convert proprietary files, remove identifying information, build representative image grids, and keep the model’s conclusions tied to observable evidence.

What “second opinion” means here

A real second opinion comes from another qualified clinician with access to the complete study and clinical history. A general-purpose multimodal model cannot reproduce that process.

What it can do reasonably well is:

What it cannot reliably do is rule out subtle pathology. MRI interpretation depends on the complete sequence set, acquisition parameters, comparison studies, patient history, and interactive windowing. A montage of selected PNGs is a lossy representation of that evidence.

That distinction shaped my workflow: the model was a reviewer and question generator, not an autonomous diagnostician.

Step 1: Inventory the DICOM study locally

I started by giving Claude Code access to an isolated working directory containing the scan and a text copy of the report. Before asking it to inspect anything, I had it write a small inventory script.

DICOM directories often contain scout images, duplicate reconstructions, localizer sequences, and diagnostic series mixed together. Sending everything would be expensive and make the model less focused.

mkdir -p mri-review/{dicom,montages,notes}
unzip scan.zip -d mri-review/dicom

cd mri-review
python -m venv .venv
source .venv/bin/activate
pip install pydicom pillow numpy

This Python script groups files by series and reports how many readable images each contains:

from collections import defaultdict
from pathlib import Path

import pydicom

root = Path("dicom")
series = defaultdict(list)

for path in root.rglob("*"):
    if not path.is_file():
        continue

    try:
        ds = pydicom.dcmread(path, stop_before_pixels=True)
    except Exception:
        continue

    uid = str(getattr(ds, "SeriesInstanceUID", "unknown"))
    series[uid].append({
        "path": str(path),
        "description": str(getattr(ds, "SeriesDescription", "unnamed")),
        "instance": int(getattr(ds, "InstanceNumber", 0)),
    })

for uid, items in sorted(series.items(), key=lambda pair: -len(pair[1])):
    description = items[0]["description"]
    print(f"{len(items):4d} images | {description:40s} | {uid}")

A common gotcha is assuming file names represent slice order. They frequently do not. Sort by DICOM attributes such as InstanceNumber or, more robustly, spatial position—not lexical file name.

I also kept the raw archive outside the model’s normal working set. Claude Code is an agent capable of reading files and running commands, so I restricted the project to preprocessing scripts, sanitized output, and the report text.

Step 2: Export representative montages

Vision models work more predictably with PNG or JPEG than with raw DICOM. I exported evenly spaced slices from each relevant series and combined them into contact sheets.

The following is a simplified exporter:

from pathlib import Path
import re

import numpy as np
import pydicom
from PIL import Image, ImageDraw

files = sorted(
    Path("dicom/selected-series").glob("*.dcm"),
    key=lambda p: int(
        getattr(pydicom.dcmread(p, stop_before_pixels=True),
                "InstanceNumber", 0)
    ),
)

indexes = np.linspace(0, len(files) - 1, min(16, len(files)), dtype=int)
tiles = []

for index in indexes:
    ds = pydicom.dcmread(files[index])
    pixels = ds.pixel_array.astype(np.float32)

    slope = float(getattr(ds, "RescaleSlope", 1))
    intercept = float(getattr(ds, "RescaleIntercept", 0))
    pixels = pixels * slope + intercept

    low, high = np.percentile(pixels, (1, 99))
    pixels = np.clip((pixels - low) / max(high - low, 1e-6), 0, 1)
    image = Image.fromarray((pixels * 255).astype(np.uint8)).convert("RGB")
    image.thumbnail((384, 384))

    tile = Image.new("RGB", (400, 420), "black")
    tile.paste(image, ((400 - image.width) // 2, 10))
    ImageDraw.Draw(tile).text((10, 395), f"slice {index}", fill="white")
    tiles.append(tile)

sheet = Image.new("RGB", (1600, 1680), "black")
for position, tile in enumerate(tiles):
    sheet.paste(tile, ((position % 4) * 400, (position // 4) * 420))

safe_name = re.sub(r"[^a-z0-9_-]+", "-", "selected-series".lower())
sheet.save(Path("montages") / f"{safe_name}.png")

Percentile normalization is a practical default, not a medically correct universal window. Different MRI sequences encode tissue contrast differently, and aggressive normalization can hide or exaggerate features. I preserved the original DICOM files for clinician review and treated the PNGs only as model-friendly previews.

Before uploading any montage, I inspected it for burned-in names, dates, accession numbers, or institution labels. Exporting pixels instead of copying DICOM metadata removes many identifiers, but identifiers can also be embedded directly in the image.

Step 3: Constrain the review

My first prompt was too broad. Asking “What is wrong with this MRI?” encourages overconfident completion and gives the model no useful standard for uncertainty.

A better REVIEW.md looked like this:

You are reviewing a radiology report and selected MRI montages.

This is not a diagnosis. Do not claim that a condition is present or absent
unless the supplied report states it. Selected montages are incomplete and
may not preserve diagnostic image quality.

Tasks:
1. Extract every finding from notes/report.txt.
2. Separate explicit findings from impressions and recommendations.
3. For each finding, identify which supplied series might be relevant.
4. Describe only visible features that support, weaken, or cannot evaluate it.
5. List missing sequences, history, or views needed for greater confidence.
6. Produce questions for a radiologist or treating clinician.

For every image-related observation include:
- montage filename
- displayed slice number
- confidence: low, medium, or high
- whether the observation comes from the report, image, or both

Return no treatment recommendations.

I then launched Claude Code from the sanitized directory and asked it to read the instructions before opening the report or montages:

cd mri-review
claude
Read REVIEW.md first. Inspect notes/report.txt and the PNG files under
montages/. Do not read files outside this project. Write the structured
review to notes/model-review.md.

In practice, requiring file-and-slice references produced a more useful result than simply asking for chain-of-thought-style reasoning. References can be checked. Free-form reasoning often cannot.

What actually helped

The most valuable output was not an unexpected diagnosis. It was a three-column reconciliation:

CategoryUseful model behaviorMain limitation
Report explanationTranslated compressed radiology language into plain EnglishCan flatten important clinical nuance
Image comparisonConnected findings to visible regions and sequencesSelected slices may omit the relevant feature
Uncertainty reviewIdentified missing history and unsupported assumptionsConfidence labels are self-assessments, not calibrated probabilities
Question generationProduced focused follow-up questionsQuestions still require clinician prioritization

I also ran a second pass without the report, asking for a description of visible anatomy only. This reduced anchoring: once a model reads the radiologist’s impression, it tends to interpret every image through that conclusion. Comparing the report-blind pass with the report-aware pass made disagreements easier to spot.

Moving the workflow into Claude, GPT, or Gemini APIs

Claude Code was ideal for exploration because it could create scripts, inspect outputs, and revise the pipeline. For repeatable use, I would move the review into an API service with explicit stages:

  1. Upload already-sanitized montages.
  2. Extract the report into structured JSON.
  3. Run a report-blind image description.
  4. Run a report-aware reconciliation.
  5. Validate the response against a schema.
  6. Store prompts, hashes, model identifiers, and usage totals.

A minimal result contract might be:

{
  "findings": [
    {
      "report_text": "Exact finding from the supplied report",
      "evidence_source": ["report", "image"],
      "image_references": [
        {"file": "series-a.png", "slice": 7}
      ],
      "confidence": "low",
      "limitations": ["Only selected slices were supplied"]
    }
  ],
  "questions_for_clinician": [],
  "missing_information": []
}

Claude, GPT, and Gemini models can serve as independent reviewers, but running three models does not create medical consensus. They may share similar blind spots, and majority voting can reinforce a plausible mistake. I prefer comparing disagreements and escalating them to a human.

Cost also needs measurement rather than guesswork because providers account for images differently. As an illustrative calculation, if a run were billed at $3 per million input tokens and $15 per million output tokens, 40,000 input tokens plus 2,000 output tokens would cost:

(40,000 / 1,000,000 × $3) + (2,000 / 1,000,000 × $15)
= $0.12 + $0.03
= $0.15

Use the API’s returned usage fields for real accounting. AI Prime Tech can be useful when testing cheaper Claude, GPT, and Gemini access through one integration, especially for cross-model comparisons, but privacy terms and data-retention settings still need to satisfy the sensitivity of medical data.

Privacy and operational guardrails

Medical images deserve stricter handling than an ordinary vision demo. My minimum controls are:

For a production system, de-identification, access control, auditability, regional processing, consent, and applicable health-data agreements are architecture requirements—not a disclaimer pasted onto the interface.

Practical takeaways

MR
Marcus Reed · Senior API Engineer

Marcus has spent 9 years building LLM-backed products and integrating the Claude, GPT and Gemini APIs into production systems. He writes about API cost optimization, agent architecture, and practical model selection.

Get cheaper Claude API access

One API key for Claude Opus 4.8, Sonnet 4.6, Haiku 4.5, Fable 5, plus GPT & Gemini — up to 80% off official pricing, pay-as-you-go.

Get Your API Key →
AI Prime Tech is an independent third-party API gateway. Claude™ and Anthropic® are trademarks of Anthropic, PBC. No affiliation or endorsement is implied.