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:
- Explain terminology in a radiology report.
- Organize findings by anatomy, confidence, and clinical relevance.
- Compare report statements with selected exported slices.
- Identify ambiguities or apparent inconsistencies.
- Generate specific questions for a radiologist or specialist.
- Produce a structured summary that is easier to review.
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:
| Category | Useful model behavior | Main limitation |
|---|---|---|
| Report explanation | Translated compressed radiology language into plain English | Can flatten important clinical nuance |
| Image comparison | Connected findings to visible regions and sequences | Selected slices may omit the relevant feature |
| Uncertainty review | Identified missing history and unsupported assumptions | Confidence labels are self-assessments, not calibrated probabilities |
| Question generation | Produced focused follow-up questions | Questions 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:
- Upload already-sanitized montages.
- Extract the report into structured JSON.
- Run a report-blind image description.
- Run a report-aware reconciliation.
- Validate the response against a schema.
- 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:
- Remove metadata and inspect for burned-in identifiers.
- Never commit scans, reports, or generated montages to Git.
- Keep raw DICOM data outside the agent workspace.
- Use a dedicated account or API project with appropriate retention controls.
- Encrypt local storage and delete temporary exports when finished.
- Log model versions, prompts, file hashes, and transformations.
- Treat reports and image text as untrusted input; they must not override agent instructions.
- Require human review before any output affects care.
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
- Use Claude Code to build and inspect the pipeline, not to impersonate a radiologist.
- Convert DICOM locally and send only sanitized, representative images.
- Run report-blind and report-aware passes to expose anchoring.
- Demand structured output with file and slice references.
- Preserve uncertainty and explicitly list missing evidence.
- Compare Claude, GPT, and Gemini by disagreements, not majority vote.
- Take the resulting questions—and the original complete study—to a qualified clinician.
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 →