Agent Skillsmaziyarpanahi/openmed › extracting-lab-tables

extracting-lab-tables

GitHub

从PDF、扫描件或图片中检测并提取实验室面板表格,通过OCR解析和PHI去标识化,输出包含测试名称、值、单位及异常标志的结构化行数据,供后续LOINC映射和FHIR转换使用。

skills/extracting-lab-tables/SKILL.md maziyarpanahi/openmed

Trigger Scenarios

用户有CBC、CMP等化验报告扫描件或PDF需要提取结构化数据 需要将CSV/TSV导出的化验表分类列并去除敏感信息 需要为下游临床工具准备机器可读的实验室结果行

Install

npx skills add maziyarpanahi/openmed --skill extracting-lab-tables -g -y
More Options

Use without installing

npx skills use maziyarpanahi/openmed@extracting-lab-tables

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill extracting-lab-tables -a claude-code -g -y

安装 repo 全部 skill

npx skills add maziyarpanahi/openmed --all -g -y

预览 repo 内 skill

npx skills add maziyarpanahi/openmed --list

SKILL.md

Frontmatter
{
    "name": "extracting-lab-tables",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "before",
        "project": "OpenMed",
        "version": "1.0",
        "category": "imaging-ocr"
    },
    "description": "Detects and extracts tabular laboratory panels from PDFs, scans, and images into structured rows ready for OpenMed and FHIR. Use when the user has a CBC, CMP, lipid panel, or other lab report as a scanned image \/ PDF \/ spreadsheet and needs the test name, value, unit, reference range, and abnormal flag as clean rows. Trigger keywords: lab table extraction, lab panel, OCR labs, table detection, layout analysis, header detection, reference range column, abnormal flag column, LOINC, UCUM, CBC, CMP, structured labs. Pairs before OpenMed: OCR\/parse the table on-device (openmed.multimodal.ocr.ocr, read_table), de-identify embedded PHI with openmed.deidentify, then hand structured rows to LOINC\/UCUM mapping and openmed.clinical lab flagging. Image\/CSV\/TSV intake is supported; PDF\/DOCX raise UnsupportedDocumentError — render those to images or text first."
}

Extracting lab tables from documents and scans

Lab results arrive as tables: a column of test names, a value column, units, a reference range, and an abnormal flag (H/L/Crit). To use them downstream you must recover that grid from a PDF, scan, or spreadsheet into clean rows — then code each test to LOINC, normalize units with UCUM, and flag abnormals.

This skill is the intake step: it OCRs/parses the table on-device with openmed.multimodal, de-identifies any embedded PHI, and emits structured rows. It pairs before OpenMed's clinical helpers — the LOINC/UCUM coding and the high/low/critical flag are downstream (see parsing-lab-values).

When to use

  • You have a lab report as a scanned image / photo / PDF page and need the panel as rows, not pixels.
  • The source is a CSV/TSV export and you need columns classified (which is the value, the unit, the range, the flag) and PHI columns redacted.
  • You need machine-readable rows to feed LOINC mapping and a FHIR Observation/DiagnosticReport.

What OpenMed gives you here

openmed.multimodal ships the intake primitives (no heavy deps at import; the OCR backend loads lazily):

  • openmed.multimodal.ocr.ocr(image, engine=...) → an OcrResult whose .words are OcrWord(text, bbox, confidence, page) and .text is the joined string. OcrResult.to_document() bridges each word (with its pixel bbox) into an ExtractedDocument so detected PHI can project back to the source location.
  • read_table(...) → a TableView (headers, rows, delimiter, has_header, columns) for delimited text; classify_columns(...) labels each column; redact_table(...) → a RedactedTable with a PHI-safe manifest.

Engines: Tesseract (pip install "openmed[multimodal]" + the system binary) or PaddleOCR (pip install "openmed[ocr-paddle]"). ocr() auto-selects the first installed backend.

Quick start

from openmed.multimodal.ocr import ocr
from openmed.multimodal import read_table, classify_columns, redact_table

# A) Scanned / image lab report -> words with pixel boxes.
result = ocr("cbc_report.png")               # OcrResult
for w in result.words[:5]:
    print(repr(w.text), w.bbox, round(w.confidence, 2), "p", w.page)

doc = result.to_document()                   # ExtractedDocument; bbox preserved

# B) Delimited lab export (CSV/TSV) -> classified, PHI-redacted rows.
csv_text = (
    "PatientName,Test,Value,Unit,RefRange,Flag\n"
    "Jane Roe,Hemoglobin,9.1,g/dL,12.0-15.5,L\n"
    "Jane Roe,Glucose,148,mg/dL,70-99,H\n"
)
view = read_table(csv_text)                  # TableView
view = classify_columns(view)                # tag PHI vs data columns
redacted = redact_table(view)                # RedactedTable: PatientName redacted

for row in redacted.rows:
    print(row)                               # name column masked; lab data intact
for col in redacted.manifest:                # PHI-safe per-column audit manifest
    print(col["column_name"], col["assigned_class"], col["action"])

For an OCR'd (image) table, you reconstruct the grid yourself from word boxes (next section) — OCR yields positioned words, not a delimited table.

Workflow

  1. Detect the source type. CSV/TSV → read_table. Image/scan → ocr(). PDF/DOCX are not directly parseable (they raise UnsupportedDocumentError); render PDF pages to images first, or extract their text layer, then OCR.
  2. OCR with positions. ocr() returns OcrWords carrying bbox and page. Keep the boxes — they let you cluster words into rows/columns and project PHI redaction back to pixels.
  3. Reconstruct the grid. Cluster words by their bbox y into rows, by x into columns. The header row names the columns; align body cells to those x bands. Confidence (OcrWord.confidence) flags shaky cells for review.
  4. Identify the lab columns. Map headers to roles: test name, value, unit, reference range, flag. For delimited input, classify_columns tags PHI columns (name/MRN/DOB) so redact_table masks them.
  5. De-identify embedded PHI. Patient name/MRN often sit in the table header or a leading column. Redact those columns (redact_table) and run free-text cells through openmed.deidentify before the rows leave the device.
  6. Emit structured rows {test, value, unit, ref_range, flag} per result and hand off to LOINC/UCUM coding and parsing-lab-values.

Hand-off to / from OpenMed

  • To parsing-lab-values (openmed.clinical.parse_reference_range, derive_abnormal_flag): pass the parsed value + ref_range (+ any explicit lab flag) to get a structured low/normal/high/critical signal.
  • To mapping-loinc: code each test name to a LOINC code; normalize the unit with UCUM. OpenMed emits the row; the terminology binding is out-of-process.
  • To FHIR (exporting-to-fhir): each row becomes an Observation (code=LOINC, valueQuantity with UCUM unit, referenceRange, interpretation) grouped under a DiagnosticReport.
  • De-identify with deidentifying-clinical-text (openmed.deidentify) before export. OCR words carry pixel boxes so redaction maps back to the image.
  • Everything here runs on-device; no scan or row leaves the process un-de-identified.

Edge cases & gotchas

  • PDF/DOCX raise UnsupportedDocumentError. The multimodal dispatcher has no PDF/DOCX handler — rasterize PDF pages to PNG (or pull the text layer) before calling ocr(). Image formats (PNG/JPG/TIFF/…) and CSV/TSV are handled.
  • OCR returns words, not a table. You must reconstruct rows/columns from bbox geometry. Multi-line cells, wrapped test names, and merged header cells break naive x/y bucketing — tune the clustering tolerance per template.
  • Reference ranges are easy to mis-split. "12.0-15.5", "<5", "70 - 99", and en/em dashes must survive OCR and tokenization as one cell. Don't let a space or a misread dash fracture the range — parse_reference_range downstream expects it whole.
  • Units belong to the value, not the range. Keep "9.1 g/dL" and the range "12.0-15.5" in separate fields; the value's unit must match the range's unit or the abnormal flag will be wrong (the flag helper is unit-agnostic).
  • Low-confidence cells. Gate on OcrWord.confidence; a 0.4-confidence value in a lab table is a patient-safety risk — route it to human review, don't silently accept it.
  • PHI hides in tables. Patient name, MRN, DOB, and accession numbers commonly occupy the header or first column. Classify and redact them; never log the raw table.
  • Engine availability. ocr() raises a clear MissingDependencyError if no backend is installed — install Tesseract or PaddleOCR per the extras.

Standards & references

Version History

  • f213557 Current 2026-07-23 00:44

Same Skill Collection

skills/building-with-openmed/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/annotating-variants/SKILL.md
skills/assembling-fhir-bundles/SKILL.md
skills/auditing-deid-leakage/SKILL.md
skills/auditing-deidentification-runs/SKILL.md
skills/auditing-part11-trails/SKILL.md
skills/auditing-safe-harbor-checklist/SKILL.md
skills/auditing-subgroup-fairness/SKILL.md
skills/authoring-model-cards/SKILL.md
skills/batch-processing-clinical-text/SKILL.md
skills/benchmarking-clinical-ner/SKILL.md
skills/bridging-presidio-and-spacy/SKILL.md
skills/building-gold-corpus/SKILL.md
skills/building-patient-timelines/SKILL.md
skills/checking-hipaa-compliance/SKILL.md
skills/choosing-openmed-models/SKILL.md
skills/coding-hcc-risk-adjustment/SKILL.md
skills/coding-icd10/SKILL.md
skills/computing-ecqms/SKILL.md
skills/configuring-privacy-policies/SKILL.md
skills/defining-cohort-phenotypes/SKILL.md
skills/deidentifying-clinical-text/SKILL.md
skills/deidentifying-multilingual-text/SKILL.md
skills/deploying-openmed-mcp/SKILL.md
skills/detecting-pv-signals/SKILL.md
skills/enforcing-nophi-logging/SKILL.md
skills/etl-to-omop-cdm/SKILL.md
skills/evaluating-with-leakage-gates/SKILL.md
skills/exporting-bulk-fhir/SKILL.md
skills/exporting-to-fhir/SKILL.md
skills/extracting-clinical-entities/SKILL.md
skills/extracting-dicom-metadata/SKILL.md
skills/extracting-pii-entities/SKILL.md
skills/extracting-sdoh/SKILL.md
skills/fetching-fhir-resources/SKILL.md
skills/gating-deid-leakage/SKILL.md
skills/generating-synthea-data/SKILL.md
skills/generating-synthetic-surrogates/SKILL.md
skills/ingesting-clinical-documents/SKILL.md
skills/linking-umls-concepts/SKILL.md
skills/mapping-loinc/SKILL.md
skills/mapping-to-snomed/SKILL.md
skills/mining-pubmed-literature/SKILL.md
skills/normalizing-rxnorm/SKILL.md
skills/parsing-ccda-documents/SKILL.md
skills/parsing-hl7v2-messages/SKILL.md
skills/parsing-lab-values/SKILL.md
skills/parsing-trial-eligibility/SKILL.md

Metadata

Files
0
Version
f213557
Hash
231ad52c
Indexed
2026-07-23 00:44

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-29 13:11
浙ICP备14020137号-1 $お客様$