Usg . Gynecological and Obstetrics. Explain me how to read them. Details on them. Give me usg picture on different types of Gynecological and obstetrical problems. Also give me normal usg pictures of fetus of first , second and third trimester. Take References from books like Williams Obstetrics and Gynecology, DC dutta etc.
normal fetal ultrasound first second third trimester images labeled gynecological USG reading
gynecological ultrasound fibroid placenta previa molar pregnancy uterus ovary USG images
| Approach | Probe | Bladder | Best Used For |
|---|---|---|---|
| Transabdominal (TAS) | Curvilinear (3-5 MHz) | Full | 2nd/3rd trimester, general pelvic survey |
| Transvaginal (TVS) | Endocavitary (5-10 MHz) | Empty | 1st trimester, cervical length, adnexa |
| Translabial | Curvilinear | Moderately full | Cervical os visualization |
| Appearance | Term | Examples |
|---|---|---|
| Bright white | Hyperechoic / Echogenic | Bone, calcifications, gas |
| Mid-gray | Isoechoic | Normal myometrium, liver |
| Dark gray | Hypoechoic | Muscle, solid masses |
| Jet black | Anechoic | Fluid, blood, cysts |
| Mixed | Heterogeneous | Complex masses, fibroids with degeneration |

| Gestational Age | Structure Visible | Size/Notes |
|---|---|---|
| 4-4.5 weeks | Gestational Sac (GS) | Anechoic, intradecidual sign |
| 5 weeks | Yolk Sac (YS) | Round, echogenic ring, 3-5 mm |
| 6 weeks | Fetal Pole (FP) | Adjacent to yolk sac |
| 6-7 weeks | Cardiac Activity | Must confirm when CRL ≥ 7 mm |
| 11-13+6 weeks | Nuchal Translucency (NT) | < 3 mm normal |




| Measurement | Abbreviation | What to Measure | Clinical Use |
|---|---|---|---|
| Biparietal diameter | BPD | Outer to inner table of skull at thalami | Gestational age |
| Head circumference | HC | Circumference of skull at BPD level | Age + growth |
| Abdominal circumference | AC | Circumference at liver + umbilical vein | Growth, IUGR detection |
| Femur length | FL | Length of ossified diaphysis | Age + skeletal dysplasia |
| Estimated fetal weight | EFW | Calculated from BPD, HC, AC, FL | Growth assessment |
| Phase | Thickness | Appearance |
|---|---|---|
| Menstrual | 2-4 mm | Thin, bright line |
| Proliferative (early) | 4-8 mm | Thin, echogenic |
| Proliferative (late) | 8-12 mm | Multilayered / trilaminar pattern |
| Secretory | 10-14 mm | Thickened, bright, homogeneous |
| Postmenopausal (normal) | < 4-5 mm | Thin bright line |

| Type | USG Appearance | Likely Diagnosis |
|---|---|---|
| Simple cyst | Anechoic, thin walls, posterior enhancement, no internal echoes | Follicular cyst, serous cystadenoma |
| Hemorrhagic cyst | Internal reticular ("fish-net") echoes, no flow on Doppler | Hemorrhagic corpus luteum |
| Complex cyst | Thick walls, internal septae, solid components | Endometrioma, dermoid, malignancy |
| Dermoid (teratoma) | Bright hyperechoic "tip-of-the-iceberg" appearance, shadowing, "Rokitansky nodule" | Benign mature teratoma |
| "Chocolate cyst" | Homogeneous, ground-glass low-level echoes | Endometrioma |

| Condition | USG Finding |
|---|---|
| Endometrial polyp | Focal hyperechoic intrauterine mass, often with central vascular stalk on Doppler |
| Endometrial hyperplasia | Diffusely thickened, bright endometrium (> 4-5 mm postmenopausal) |
| Endometrial carcinoma | Irregular, heterogeneous, thickened endometrium; may invade myometrium |
| Asherman's syndrome | Thin/absent endometrium, intrauterine synechiae |
| Type | USG Finding |
|---|---|
| Threatened abortion | IUP present, cardiac activity present, small subchorionic hemorrhage may be seen |
| Incomplete abortion | Heterogeneous echogenic material in uterine cavity, open os |
| Complete abortion | Empty uterine cavity (endometrium < 15 mm) |
| Missed abortion | GS/embryo present, NO cardiac activity (CRL ≥ 7 mm) |
| Blighted ovum | GS present (MSD ≥ 25 mm), no embryo |
| Topic | Source |
|---|---|
| Types of obstetric USG examinations, documentation, anatomy scan elements | Creasy & Resnik's Maternal-Fetal Medicine, Chapter 16 (CPT codes 76801-76816) |
| Detailed fetal anatomy images (figs. 16.1-16.38) | Creasy & Resnik's MFM, pp. 319-330 |
| Fetal anomalies: ovarian cysts, renal cysts, abdominal masses | Creasy & Resnik's MFM, Chapter 24, pp. 507-510 |
| Ovarian cyst classification, hemorrhagic cysts, transvaginal imaging | Grainger & Allison's Diagnostic Radiology, Chapter 7 |
| Ectopic pregnancy USG criteria | Berek & Novak's Gynecology, Chapter 9 |
| Fetal heart four-chamber view, LVOT, RVOT | Creasy & Resnik's MFM, pp. 325-327 |
| Fibroid, molar pregnancy, PCOS | D.C. Dutta's Textbook of Obstetrics (clinical principles) |
| Placenta previa classification | Creasy & Resnik's MFM; Williams Obstetrics 26th ed. |
| ISUOG biometry guidelines | ISUOG Clinical Standards Committee, Ultrasound Obstet Gynecol 2019;53:715-723 |
Important clinical note: USG findings must always be interpreted together with the clinical history, examination, and laboratory results (hCG, CA-125, etc.). A single USG finding in isolation is rarely diagnostic. Serial scans and Doppler studies add significantly to the diagnostic accuracy in both gynecological and obstetric practice.
Create a visual reference guide/PDF with labeled USG anatomy for quick clinical reference
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace does not exist"
mkdir -p /home/daytona/workspace/usg-guide && python3 -c "import reportlab; print('reportlab ok')" && python3 -c "import requests; print('requests ok')" && python3 -c "from PIL import Image; print('PIL ok')"
Create a visual reference guide/PDF with labeled USG anatomy for quick clinical reference
mkdir -p /home/daytona/workspace/usg-guide/images && python3 -c "import reportlab; from PIL import Image; import requests; print('All libs OK')"
cd /home/daytona/workspace/usg-guide/images && python3 << 'EOF' import requests, os imgs = { "bpd_hc.png": "https://cdn.orris.care/cdss_images/3676171d02ca09cb1aeab8887810c18cdff3ca37293731dee0a3c28c6c45c99a.png", "posterior_fossa.png": "https://cdn.orris.care/cdss_images/2bb655502b5e9fb47a27adeb649315d6beac1d156ecb442718a6247e174f560d.png", "four_chamber_heart.png": "https://cdn.orris.care/cdss_images/b9552d9e8e945989c6742814adaf9f1d519f25077f7940340a1614321a3745ed.png", "nose_lips.png": "https://cdn.orris.care/cdss_images/510c07f4aa9cdd9c13f059f3c44daad83debbdca5f0260bb71ce6ba460095907.png", "lateral_ventricle.png": "https://cdn.orris.care/cdss_images/f352eed802e117eb093ad78dcc975a93158128d354add66722a6c44abaab556f.png", "lvot.png": "https://cdn.orris.care/cdss_images/9acc448b08d30b32c3b9a5664d9e018dc983fa0e60bcb33616668cb150c288a7.png", "rvot.png": "https://cdn.orris.care/cdss_images/157ba701f5851bfdc6828c7964f316d0c4285f8581f26649c8df09f55b63d7a6.png", "nasal_bone.png": "https://cdn.orris.care/cdss_images/31d2c75bc6c0ea9d648d963bab49e1d502cd8c29cd18b9ec13caf51e64e87a02.png", "orbits.png": "https://cdn.orris.care/cdss_images/5615617d069d66896e523e78b0f5e812cbed9b190ecd90a011b89657b8c9558d.png", "ectopic.png": "https://cdn.orris.care/cdss_images/58f66bf80527ed6ad230c372a43c0dac8eabcfcf5689e56e6e4f75010d9d1d2b.png", "fetal_ovarian_cyst.png": "https://cdn.orris.care/cdss_images/2ad861153d1e21b6be6976c670d04f897b625ff0707df736d2552d92ce044366.png", "renal_cyst.png": "https://cdn.orris.care/cdss_images/a92e72763408c94dd0ab60de5ad2ba93a015b0ab067fb7228de6c4fc5c77cba2.png", "cavum_sp.png": "https://cdn.orris.care/cdss_images/678068f43bdcd31a6cb5baee042feb9c6bc461edd61af4c3aeec424a47d409f4.png", "falx_cp.png": "https://cdn.orris.care/cdss_images/db2fe74613d53e25664a60f3de0fd5d28e27f5644cb2a4a193fc9ed146c3d854.png", "heart_rate.png": "https://cdn.orris.care/cdss_images/3386d554634b412e59f8944047dc8d326d832ee9b10951fe4bb4ad681502fb28.png", } ok, fail = [], [] for fname, url in imgs.items(): try: r = requests.get(url, timeout=15) if r.status_code == 200 and len(r.content) > 1000: open(fname, 'wb').write(r.content) ok.append(fname) else: fail.append(fname) except Exception as e: fail.append(f"{fname}:{e}") print(f"Downloaded {len(ok)}: {ok}") print(f"Failed {len(fail)}: {fail}") EOF
~/usg-guide/build_usg_guide.py
#!/usr/bin/env python3
"""
USG Gynecology & Obstetrics – Visual Reference Guide
Builds a professional multi-page PDF using ReportLab.
"""
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm, mm
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether, Image as RLImage, PageBreak
)
from reportlab.platypus.flowables import Flowable
from reportlab.pdfgen import canvas as pdfcanvas
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Circle
from reportlab.graphics import renderPDF
import textwrap
# ── Paths ──────────────────────────────────────────────────────────────────
IMG_DIR = "/home/daytona/workspace/usg-guide/images"
OUTPUT = "/home/daytona/workspace/usg-guide/USG_Gynecology_Obstetrics_Reference_Guide.pdf"
W, H = A4 # 595 x 842 pt
# ── Colour palette ─────────────────────────────────────────────────────────
C_NAVY = colors.HexColor("#0D2B4E")
C_TEAL = colors.HexColor("#0A7E8C")
C_LBLUE = colors.HexColor("#C8E6F5")
C_LGREY = colors.HexColor("#F2F4F6")
C_GOLD = colors.HexColor("#E8A020")
C_WHITE = colors.white
C_BLACK = colors.black
C_RED = colors.HexColor("#C0392B")
C_GREEN = colors.HexColor("#1A7A45")
C_PURPLE = colors.HexColor("#6C3483")
# ── Styles ─────────────────────────────────────────────────────────────────
BASE = getSampleStyleSheet()
def style(name, **kw):
s = ParagraphStyle(name, **kw)
return s
S_TITLE = style("S_TITLE", fontName="Helvetica-Bold", fontSize=22, textColor=C_WHITE, leading=28, alignment=TA_CENTER)
S_SUBTITLE= style("S_SUBTITLE",fontName="Helvetica", fontSize=12, textColor=C_LBLUE, leading=16, alignment=TA_CENTER)
S_H1 = style("S_H1", fontName="Helvetica-Bold", fontSize=14, textColor=C_WHITE, leading=18, alignment=TA_LEFT, spaceAfter=2)
S_H2 = style("S_H2", fontName="Helvetica-Bold", fontSize=11, textColor=C_NAVY, leading=15, alignment=TA_LEFT, spaceAfter=3)
S_H3 = style("S_H3", fontName="Helvetica-Bold", fontSize=9,5, textColor=C_TEAL, leading=13, alignment=TA_LEFT, spaceAfter=2)
S_BODY = style("S_BODY", fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, alignment=TA_LEFT, spaceAfter=2)
S_SMALL = style("S_SMALL", fontName="Helvetica", fontSize=7.5,textColor=colors.HexColor("#555555"), leading=10, alignment=TA_LEFT)
S_CAPTION = style("S_CAPTION", fontName="Helvetica-Oblique",fontSize=7.5,textColor=C_NAVY, leading=10, alignment=TA_CENTER, spaceAfter=4)
S_BULLET = style("S_BULLET", fontName="Helvetica", fontSize=8.5,textColor=C_BLACK, leading=12, leftIndent=12, bulletIndent=4, spaceAfter=1)
S_NOTE = style("S_NOTE", fontName="Helvetica-Oblique",fontSize=8, textColor=C_RED, leading=11, alignment=TA_LEFT)
S_TBLHDR = style("S_TBLHDR", fontName="Helvetica-Bold", fontSize=8, textColor=C_WHITE, leading=11, alignment=TA_CENTER)
S_TBLCELL = style("S_TBLCELL", fontName="Helvetica", fontSize=8, textColor=C_BLACK, leading=11, alignment=TA_LEFT)
S_TBLCELLC= style("S_TBLCELLC",fontName="Helvetica", fontSize=8, textColor=C_BLACK, leading=11, alignment=TA_CENTER)
# ── Helper: section header bar ─────────────────────────────────────────────
class SectionHeader(Flowable):
def __init__(self, text, bg=C_NAVY, w=None, h=22):
Flowable.__init__(self)
self.text = text
self.bg = bg
self.bw = w or (W - 3*cm)
self.bh = h
def wrap(self, aw, ah):
return self.bw, self.bh + 4
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 2, self.bw, self.bh, 4, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 11)
c.drawString(8, 8, self.text)
class SubSectionHeader(Flowable):
def __init__(self, text, bg=C_TEAL, w=None, h=17):
Flowable.__init__(self)
self.text = text
self.bg = bg
self.bw = w or (W - 3*cm)
self.bh = h
def wrap(self, aw, ah):
return self.bw, self.bh + 4
def draw(self):
c = self.canv
c.setFillColor(self.bg)
c.roundRect(0, 2, self.bw, self.bh, 3, fill=1, stroke=0)
c.setFillColor(C_WHITE)
c.setFont("Helvetica-Bold", 9)
c.drawString(8, 5, self.text)
# ── Helper: image with caption ─────────────────────────────────────────────
def img_cell(fname, caption, w=6.5*cm, h=5.5*cm):
path = os.path.join(IMG_DIR, fname)
if os.path.exists(path):
im = RLImage(path, width=w, height=h, kind='proportional')
else:
im = Paragraph(f"[Image: {fname}]", S_SMALL)
cap = Paragraph(caption, S_CAPTION)
return [im, cap]
def labeled_img(fname, caption, labels, w=7*cm, h=6*cm):
"""Returns a list of flowables: image + label box + caption"""
path = os.path.join(IMG_DIR, fname)
items = []
if os.path.exists(path):
items.append(RLImage(path, width=w, height=h, kind='proportional'))
label_text = " | ".join([f"<b>{k}</b> = {v}" for k, v in labels.items()])
items.append(Paragraph(f'<font size="7" color="#0A7E8C">{label_text}</font>', S_CAPTION))
items.append(Paragraph(caption, S_CAPTION))
return items
# ── Helper: coloured table ─────────────────────────────────────────────────
def make_table(headers, rows, col_widths=None, zebra=True):
data = [[Paragraph(h, S_TBLHDR) for h in headers]]
for i, row in enumerate(rows):
data.append([Paragraph(str(c), S_TBLCELL) for c in row])
ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), C_NAVY),
('TEXTCOLOR', (0,0), (-1,0), C_WHITE),
('ROWBACKGROUNDS',(0,1),(-1,-1),[C_WHITE, C_LGREY] if zebra else [C_WHITE]),
('GRID', (0,0), (-1,-1), 0.3, colors.HexColor("#BBBBBB")),
('LEFTPADDING', (0,0), (-1,-1), 5),
('RIGHTPADDING',(0,0), (-1,-1), 5),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING',(0,0),(-1,-1), 3),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('FONTSIZE', (0,0), (-1,-1), 8),
])
t = Table(data, colWidths=col_widths, repeatRows=1)
t.setStyle(ts)
return t
# ── Helper: two-column image grid ──────────────────────────────────────────
def two_col_images(pairs):
"""pairs = [(fname, caption, labels_dict), ...] -> 2-col Table"""
cells = []
for fname, caption, labels in pairs:
path = os.path.join(IMG_DIR, fname)
block = []
if os.path.exists(path):
block.append(RLImage(path, width=7.5*cm, height=6.2*cm, kind='proportional'))
if labels:
lbl = " ".join([f"<b>{k}</b>={v}" for k, v in labels.items()])
block.append(Paragraph(f'<font size="6.5" color="#0A7E8C">{lbl}</font>', S_CAPTION))
block.append(Paragraph(caption, S_CAPTION))
cells.append(block)
rows = []
for i in range(0, len(cells), 2):
row = [cells[i], cells[i+1] if i+1 < len(cells) else [Paragraph("", S_SMALL)]]
rows.append(row)
t = Table(rows, colWidths=[8.5*cm, 8.5*cm])
t.setStyle(TableStyle([
('VALIGN', (0,0),(-1,-1),'TOP'),
('LEFTPADDING', (0,0),(-1,-1), 4),
('RIGHTPADDING',(0,0),(-1,-1), 4),
('TOPPADDING', (0,0),(-1,-1), 4),
('BOTTOMPADDING',(0,0),(-1,-1),4),
]))
return t
# ── Page templates (header/footer) ─────────────────────────────────────────
def page_template(canv, doc):
canv.saveState()
# top bar
canv.setFillColor(C_NAVY)
canv.rect(0, H - 22, W, 22, fill=1, stroke=0)
canv.setFillColor(C_WHITE)
canv.setFont("Helvetica-Bold", 9)
canv.drawString(1*cm, H - 15, "USG GYNECOLOGY & OBSTETRICS — QUICK CLINICAL REFERENCE")
canv.setFont("Helvetica", 8)
canv.drawRightString(W - 1*cm, H - 15, f"Page {doc.page}")
# bottom bar
canv.setFillColor(C_LGREY)
canv.rect(0, 0, W, 16, fill=1, stroke=0)
canv.setFillColor(colors.HexColor("#888888"))
canv.setFont("Helvetica-Oblique", 6.5)
canv.drawString(1*cm, 5, "References: Creasy & Resnik MFM | Berek & Novak's Gynecology | Grainger & Allison Radiology | ISUOG 2019 | Williams Obstetrics | D.C. Dutta's Obstetrics")
canv.restoreState()
def cover_page_template(canv, doc):
canv.saveState()
# Full-page navy gradient background
canv.setFillColor(C_NAVY)
canv.rect(0, 0, W, H, fill=1, stroke=0)
# Teal accent stripe
canv.setFillColor(C_TEAL)
canv.rect(0, H*0.38, W, 8, fill=1, stroke=0)
canv.rect(0, H*0.36, W, 3, fill=1, stroke=0)
# Gold accent line
canv.setFillColor(C_GOLD)
canv.rect(1*cm, H*0.38 + 10, 4*cm, 3, fill=1, stroke=0)
canv.restoreState()
# ── BUILD ──────────────────────────────────────────────────────────────────
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
leftMargin=1.5*cm, rightMargin=1.5*cm,
topMargin=1.8*cm, bottomMargin=1.2*cm,
title="USG Gynecology & Obstetrics Reference Guide",
author="Orris Medical AI",
subject="Ultrasound Visual Reference"
)
story = []
# ═══════════════════════════════════════════════════════
# PAGE 1 – COVER
# ═══════════════════════════════════════════════════════
story.append(Spacer(1, 3.5*cm))
story.append(Paragraph(
'<font color="white"><b>USG</b></font>',
style("cov0", fontName="Helvetica-Bold", fontSize=52, textColor=C_GOLD, leading=56, alignment=TA_CENTER)
))
story.append(Paragraph(
"GYNECOLOGY & OBSTETRICS",
style("cov1", fontName="Helvetica-Bold", fontSize=20, textColor=C_WHITE, leading=26, alignment=TA_CENTER)
))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"VISUAL REFERENCE GUIDE",
style("cov2", fontName="Helvetica", fontSize=13, textColor=C_LBLUE, leading=18, alignment=TA_CENTER)
))
story.append(Spacer(1, 0.15*cm))
story.append(HRFlowable(width="60%", thickness=1.5, color=C_TEAL, hAlign='CENTER'))
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph(
"Quick Clinical Reference for Students, Residents & Clinicians",
style("cov3", fontName="Helvetica-Oblique", fontSize=11, textColor=colors.HexColor("#A8D8E8"), leading=15, alignment=TA_CENTER)
))
story.append(Spacer(1, 1.6*cm))
# Content summary box
summary_data = [
["PART 1", "Fundamentals — How to Read USG", "Probes • Echogenicity • Report Elements"],
["PART 2", "Obstetric USG by Trimester", "1st • 2nd Anatomy Scan • 3rd Trimester"],
["PART 3", "Fetal Biometry", "BPD • HC • AC • FL • EFW • AFI"],
["PART 4", "Detailed Fetal Anatomy Images", "Head • Heart • Face • Spine"],
["PART 5", "Gynecological USG", "Normal Uterus & Ovary • Endometrium"],
["PART 6", "Pathological Conditions", "Fibroids • Cysts • Ectopic • Mole • Previa"],
]
cov_table = Table(
[[Paragraph(f'<b><font color="#E8A020">{r[0]}</font></b>', style("ct0", fontName="Helvetica-Bold", fontSize=9, textColor=C_GOLD, leading=12)),
Paragraph(f'<b><font color="white">{r[1]}</font></b>', style("ct1", fontName="Helvetica-Bold", fontSize=9, textColor=C_WHITE, leading=12)),
Paragraph(f'<font color="#A8D8E8">{r[2]}</font>', style("ct2", fontName="Helvetica", fontSize=8, textColor=C_LBLUE, leading=11))]
for r in summary_data],
colWidths=[2*cm, 6.5*cm, 8*cm]
)
cov_table.setStyle(TableStyle([
('BACKGROUND', (0,0),(-1,-1), colors.HexColor("#1A3A5C")),
('ROWBACKGROUNDS',(0,0),(-1,-1),[colors.HexColor("#1A3A5C"), colors.HexColor("#0F2840")]),
('LEFTPADDING', (0,0),(-1,-1), 8),
('RIGHTPADDING', (0,0),(-1,-1), 8),
('TOPPADDING', (0,0),(-1,-1), 6),
('BOTTOMPADDING',(0,0),(-1,-1), 6),
('LINEBELOW', (0,0),(-1,-2), 0.5, colors.HexColor("#2A4A6C")),
('ROUNDEDCORNERS',(0,0),(-1,-1),5),
]))
story.append(cov_table)
story.append(Spacer(1, 2*cm))
story.append(Paragraph(
"References: Creasy & Resnik's Maternal-Fetal Medicine | Berek & Novak's Gynecology",
style("ref1", fontName="Helvetica-Oblique", fontSize=8, textColor=colors.HexColor("#607080"), leading=12, alignment=TA_CENTER)
))
story.append(Paragraph(
"Grainger & Allison's Diagnostic Radiology | ISUOG Guidelines 2019 | Williams Obstetrics | D.C. Dutta's Obstetrics",
style("ref2", fontName="Helvetica-Oblique", fontSize=8, textColor=colors.HexColor("#607080"), leading=12, alignment=TA_CENTER)
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 2 – PART 1: FUNDAMENTALS
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 1 — FUNDAMENTALS: HOW TO READ A GYNECOLOGICAL / OBSTETRIC USG"))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("1.1 Probe Types & Patient Preparation"))
story.append(Spacer(1, 0.2*cm))
probe_table = make_table(
["Approach", "Probe Type", "Frequency", "Bladder", "Best Used For"],
[
["Transabdominal (TAS)", "Curvilinear", "3–5 MHz", "FULL", "2nd/3rd trimester, general pelvic survey, placenta"],
["Transvaginal (TVS)", "Endocavitary", "5–10 MHz", "EMPTY", "1st trimester (<12 wks), adnexa, cervical length, early IUP"],
["Translabial / Transperineal", "Curvilinear", "3–5 MHz", "Moderate", "Cervical os, placenta previa confirmation"],
],
col_widths=[3.5*cm, 2.8*cm, 2.2*cm, 2*cm, 6*cm]
)
story.append(probe_table)
story.append(Spacer(1, 0.35*cm))
story.append(SubSectionHeader("1.2 Echogenicity Key — What You See on Screen"))
story.append(Spacer(1, 0.2*cm))
echo_table = make_table(
["Appearance", "Term", "Colour on Screen", "Clinical Examples"],
[
["Jet black / Dark", "Anechoic", "Black", "Fluid, urine in bladder, simple cysts, amniotic fluid"],
["Dark grey", "Hypoechoic", "Dark grey", "Muscle, uterine myometrium, solid masses"],
["Medium grey", "Isoechoic", "Mid grey", "Normal liver, placenta, some fibroids"],
["Light grey / white", "Hyperechoic", "Bright grey/white", "Bone, calcifications, gas, fat"],
["Very bright white", "Echogenic", "White", "Fetal skull, bowel gas, dermoid cyst content"],
["Mixed light & dark", "Heterogeneous", "Patchy", "Complex masses, degenerating fibroids, haematomas"],
],
col_widths=[3*cm, 2.5*cm, 3*cm, 8*cm]
)
story.append(echo_table)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph(
'<b>Key physical signs:</b> '
'<b>Posterior acoustic enhancement</b> = bright area BEHIND a cyst → confirms pure fluid. '
'<b>Acoustic shadowing</b> = dark stripe BEHIND calcification/bone → blocks sound. '
'<b>Ring-of-fire</b> (colour Doppler) = peripheral vascularity around corpus luteum.',
S_BODY
))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("1.3 Mandatory Elements of an Obstetric USG Report (Creasy & Resnik MFM, Ch.16)"))
story.append(Spacer(1, 0.15*cm))
rep_items = [
"Patient identity + date of examination",
"Indication for the procedure",
"Type of examination (standard / detailed / limited)",
"Gestational age by established dates (LMP + prior scans)",
"Number of fetuses and chorionicity (if multifetal)",
"Fetal biometry with predicted gestational age",
"Principal findings — normal, abnormal, and poorly visualised",
"Differential diagnosis for any abnormalities detected",
"Recommendations for pregnancy management or further imaging",
]
rep_data = [[Paragraph(f"• {item}", S_BODY)] for item in rep_items]
rep_t = Table(rep_data, colWidths=[16.5*cm])
rep_t.setStyle(TableStyle([
('ROWBACKGROUNDS',(0,0),(-1,-1),[C_WHITE, C_LGREY]),
('LEFTPADDING',(0,0),(-1,-1),8),
('TOPPADDING',(0,0),(-1,-1),3),
('BOTTOMPADDING',(0,0),(-1,-1),3),
('GRID',(0,0),(-1,-1),0.2,colors.HexColor("#DDDDDD")),
]))
story.append(rep_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 3 – PART 2: FIRST TRIMESTER USG
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 2 — OBSTETRIC USG: FIRST TRIMESTER (Weeks 4–13+6)"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"<b>Primary goals:</b> Confirm intrauterine pregnancy (IUP) • Gestational dating • Fetal cardiac activity • Number of fetuses • Nuchal translucency (11–13+6 wks)",
S_BODY
))
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("2.1 Sequential Appearances on TVS"))
story.append(Spacer(1, 0.2*cm))
t1_table = make_table(
["Gestational Age", "Structure Visible", "Key Measurement", "Normal Value"],
[
["4–4.5 weeks", "Gestational Sac (GS)", "Mean Sac Diameter (MSD)", "≥ 2 mm; intradecidual sign"],
["4.5–5 weeks", "Yolk Sac (YS)", "YS diameter", "3–6 mm (round, echogenic ring)"],
["5.5–6 weeks", "Fetal Pole", "Crown-Rump Length (CRL)", "First visible adjacent to YS"],
["6–6.5 weeks", "Cardiac Activity", "Heart Rate (HR)", "Must confirm when CRL ≥ 7 mm; normal 110–170 bpm"],
["7–8 weeks", "Embryo morphology", "CRL for dating", "Accurate to ±3–5 days"],
["11–13+6 weeks", "Nuchal Translucency (NT)", "NT thickness", "< 3.0 mm = normal; ≥ 3.5 mm = high risk aneuploidy"],
],
col_widths=[3*cm, 3.5*cm, 4*cm, 6.5*cm]
)
story.append(t1_table)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("2.2 Discriminatory Zones (hCG)"))
story.append(Spacer(1, 0.15*cm))
disc_data = [
["Transvaginal (TVS)", "1,000–2,000 mIU/mL", "GS should be visible; if absent → suspect ectopic"],
["Transabdominal (TAS)", "3,000–5,000 mIU/mL", "GS should be visible; empty uterus → refer for TVS"],
]
disc_t = make_table(["Approach", "hCG Discriminatory Zone", "Clinical Implication"], disc_data,
col_widths=[3.5*cm, 4.5*cm, 9*cm])
story.append(disc_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("2.3 Early Pregnancy Failure — USG Diagnostic Criteria"))
story.append(Spacer(1, 0.15*cm))
epf_data = [
["Missed Abortion", "CRL ≥ 7 mm", "No cardiac activity", "Confirmed missed abortion"],
["Anembryonic / Blighted Ovum", "MSD ≥ 25 mm", "No embryo visible", "No embryo with large sac"],
["Early Pregnancy Failure", "GS seen without YS", "No embryo ≥ 2 weeks later", "Await 2nd scan before diagnosis"],
["Early Pregnancy Failure", "GS seen with YS", "No embryo ≥ 11 days later", "Serial scans required"],
]
epf_t = make_table(
["Diagnosis", "USG Finding", "Key Criterion", "Note"],
epf_data,
col_widths=[4*cm, 4*cm, 4*cm, 5*cm]
)
story.append(epf_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("2.4 Pseudogestational Sac vs True IUP"))
story.append(Spacer(1, 0.15*cm))
ps_data = [
["True gestational sac (IUP)", "Eccentric, embedded in decidua", "Has echogenic ring (double decidual sign)", "Yolk sac visible at 5 wks"],
["Pseudogestational sac (ectopic)", "Central, in uterine cavity", "No echogenic ring; may be triangular", "No yolk sac; NO IUP"],
]
ps_t = make_table(["Structure", "Position", "Wall", "Key Differentiator"], ps_data,
col_widths=[4*cm, 4*cm, 4.5*cm, 4.5*cm])
story.append(ps_t)
story.append(Spacer(1, 0.25*cm))
story.append(Paragraph(
'<b><font color="#C0392B">CLINICAL PEARL:</font></b> If hCG > 1,500 mIU/mL and TVS shows an empty uterus '
'→ suspect ectopic pregnancy until proven otherwise. A central fluid collection in the uterus without a yolk '
'sac is a pseudogestational sac, NOT an IUP.', S_NOTE
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 4 – PART 3: FETAL BIOMETRY
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 3 — FETAL BIOMETRY (2nd & 3rd Trimester)"))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph(
"Biometry is used to (1) estimate gestational age, (2) assess fetal growth, and (3) calculate estimated fetal weight (EFW). "
"All four standard measurements should be obtained at every anatomy scan. (ISUOG Guidelines 2019; Creasy & Resnik MFM Ch.16)",
S_BODY
))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("3.1 Standard Biometric Parameters"))
story.append(Spacer(1, 0.2*cm))
bio_data = [
["Biparietal Diameter\n(BPD)", "Axial head — outer to inner calvarium at level of thalami and CSP",
"At 20 wks ≈ 4.8 cm; At 32 wks ≈ 8.2 cm", "Gestational age dating; most accurate 14–20 wks"],
["Head Circumference\n(HC)", "Same axial plane as BPD; ellipse around outer skull table",
"At 20 wks ≈ 17.5 cm; At 32 wks ≈ 30 cm", "Age + microcephaly / macrocephaly screening"],
["Abdominal Circumference\n(AC)", "Axial abdomen at junction of umbilical vein & portal sinus",
"At 20 wks ≈ 15 cm; At 32 wks ≈ 28 cm", "BEST indicator of fetal growth & nutrition (IUGR)"],
["Femur Length\n(FL)", "Longest ossified diaphysis of femur (exclude epiphyses)",
"At 20 wks ≈ 3.3 cm; At 32 wks ≈ 6.2 cm", "Gestational age; skeletal dysplasia screening"],
["Estimated Fetal Weight\n(EFW)", "Calculated from BPD, HC, AC, FL (Hadlock formula)",
"At 20 wks ≈ 300 g; At 32 wks ≈ 1,800 g", "Growth assessment; ±10–15% accuracy"],
]
bio_t = make_table(
["Parameter", "How to Measure", "Reference Values", "Clinical Use"],
bio_data,
col_widths=[3.2*cm, 5.5*cm, 4.5*cm, 4.3*cm]
)
story.append(bio_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("3.2 Amniotic Fluid Assessment"))
story.append(Spacer(1, 0.2*cm))
af_data = [
["Maximum Vertical Pocket (MVP)", "Largest pocket of fluid free of cord/limbs", "Normal: 2–8 cm"],
["Amniotic Fluid Index (AFI)", "Sum of largest pockets in 4 uterine quadrants", "Normal: 8–24 cm"],
["Oligohydramnios", "MVP < 2 cm OR AFI < 5 cm", "→ Renal anomaly, IUGR, PPROM, post-dates"],
["Polyhydramnios", "MVP > 8 cm OR AFI > 24 cm", "→ GDM, fetal anomaly (oesophageal atresia, NTD)"],
]
af_t = make_table(["Method / Condition", "Definition", "Values / Significance"], af_data,
col_widths=[4.5*cm, 6*cm, 7*cm])
story.append(af_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("3.3 BPD & HC Measurement — USG Image (Creasy & Resnik MFM, Fig. 16.1)"))
story.append(Spacer(1, 0.2*cm))
bio_img_pair = two_col_images([
("bpd_hc.png",
"Fig. 16.1 — Axial head view at 18 weeks. BPD = 4.03 cm → GA 18w2d. HC = 15.09 cm → GA 18w1d. "
"Measure BPD from outer to inner table. HC ellipse around outer skull margin.",
{"BPD": "Biparietal diameter", "OFD": "Occipital-frontal diameter", "HC": "Head circumference"}),
("posterior_fossa.png",
"Fig. 16.5 — Posterior fossa view. Cerebellum 1.71 cm → GA 18w0d. Cisterna magna 0.28 cm (normal 2–10 mm). "
"Nuchal fold 3.18 mm (< 6 mm = normal at 18–22 wks).",
{"Cist Mag": "Cisterna magna", "Nuch Fold": "Nuchal fold"}),
])
story.append(bio_img_pair)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 5 – PART 4: DETAILED FETAL ANATOMY
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 4 — DETAILED FETAL ANATOMY SCAN (18–22 Weeks, CPT 76805/76811)"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"The mid-trimester anatomy scan assesses all major organ systems. Per ISUOG 2019 and Creasy & Resnik MFM Box 16.3, "
"mandatory views include: head & face, thorax, heart (4-chamber + outflow tracts), abdomen, kidneys, spine, and extremities.",
S_BODY
))
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("4.1 Head & Face Views"))
story.append(Spacer(1, 0.15*cm))
head_grid = two_col_images([
("cavum_sp.png",
"Fig. 16.2 — Cavum Septi Pellucidi (CSP). Arrow points to CSP — a fluid-filled box-shaped structure in the midline frontal brain. "
"Absence of CSP suggests corpus callosum agenesis or HPE.",
{"Falx": "Interhemispheric fissure", "CSP": "Cavum septi pellucidi"}),
("falx_cp.png",
"Fig. 16.3 — Falx cerebri. Midline hyperechoic line separating cerebral hemispheres. "
"Choroid plexus (CP) = bright echogenic structures filling lateral ventricles.",
{"Falx": "Falx cerebri", "CP": "Choroid plexus"}),
])
story.append(head_grid)
story.append(Spacer(1, 0.15*cm))
head_grid2 = two_col_images([
("lateral_ventricle.png",
"Fig. 16.4 — Lateral ventricle measurement. Caliper placed at inner wall of posterior horn. "
"Normal: < 10 mm. 10–15 mm = mild ventriculomegaly. > 15 mm = severe.",
{"Lat Vent": "Lateral ventricle width (0.77 cm = normal)"}),
("nasal_bone.png",
"Fig. 16.7 — Nasal bone (NBL). Assessed at 11–13+6 wks (1st trimester) and again at 18–22 wks. "
"Absent/hypoplastic nasal bone is a soft marker for trisomy 21 (Down syndrome).",
{"NBL": "Nasal bone length"}),
])
story.append(head_grid2)
story.append(Spacer(1, 0.15*cm))
head_grid3 = two_col_images([
("orbits.png",
"Fig. 16.6 — Fetal orbits. Both orbits visible as two dark circles on axial view. "
"Assess inter-orbital distance — abnormal in cyclopia, hypotelorism/hypertelorism.",
{"ORBS": "Orbits"}),
("nose_lips.png",
"Fig. 16.8 — Fetal nose and lips (coronal/axial view). Intact upper lip excludes cleft lip. "
"Essential view — cleft lip is a common facial anomaly (1 in 700 births).",
{"Nose/lips": "Upper lip integrity"}),
])
story.append(head_grid3)
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("4.2 Thorax — Cardiac Views"))
story.append(Spacer(1, 0.15*cm))
heart_grid = two_col_images([
("four_chamber_heart.png",
"Fig. 16.10 — Four-chamber heart (diastole A, systole B). Heart apex points LEFT. "
"RV = right ventricle (closest to anterior chest wall). LV = left ventricle. "
"RA & LA roughly equal size. Descending aorta (Desc Ao) seen posterior to LA.",
{"RV": "Right ventricle", "LV": "Left ventricle", "RA": "Right atrium", "LA": "Left atrium", "Desc Ao": "Descending aorta"}),
("lvot.png",
"Fig. 16.11 — Left ventricular outflow tract (LVOT). Aorta (Asc Ao) arises from LV. "
"Medial wall of aorta must be continuous with the interventricular septum. "
"Discontinuity → suspect aortic override (Tetralogy of Fallot, TGA).",
{"LV": "Left ventricle", "RV": "Right ventricle", "Asc Ao": "Ascending aorta", "Ao V": "Aortic valve"}),
])
story.append(heart_grid)
story.append(Spacer(1, 0.15*cm))
heart_grid2 = two_col_images([
("rvot.png",
"Fig. 16.12 — Right ventricular outflow tract (RVOT). Main pulmonary artery (MPA) arises from RV. "
"The LVOT and RVOT cross each other — this 'crossing' pattern is lost in TGA.",
{"RV": "Right ventricle", "RA": "Right atrium", "MPA": "Main pulmonary artery"}),
("heart_rate.png",
"Fig. 16.13 — Fetal heart rate (M-mode). M-mode cursor placed over the beating heart. "
"Normal fetal HR: 110–170 bpm. < 100 = bradycardia; > 180 = tachycardia.",
{"HR": "Heart rate via M-mode"}),
])
story.append(heart_grid2)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 6 – PART 5: GYNAECOLOGICAL USG NORMAL
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 5 — GYNAECOLOGICAL USG: NORMAL ANATOMY"))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("5.1 Normal Uterus — Measurements & Appearance"))
story.append(Spacer(1, 0.2*cm))
uter_data = [
["Nulliparous", "7–8 cm", "4–5 cm", "4 cm", "Pear-shaped; homogeneous medium-grey myometrium"],
["Multiparous", "8–10 cm", "5–6 cm", "5 cm", "Slightly larger; may have small fibroids"],
["Postmenopausal", "4–6 cm", "2–4 cm", "2–3 cm", "Atrophic; thin endometrium; may have calcifications"],
["Prepubertal", "2–3.5 cm", "1–1.5 cm", "1 cm", "Tubular shape (cervix > body)"],
]
uter_t = make_table(
["Status", "Length", "Width", "AP Diameter", "Notes"],
uter_data,
col_widths=[3*cm, 2*cm, 2*cm, 2.5*cm, 7.5*cm]
)
story.append(uter_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("5.2 Endometrial Thickness by Cycle Phase"))
story.append(Spacer(1, 0.2*cm))
endo_data = [
["Menstrual", "2–4 mm", "Thin bright line; hyperechoic collapsed cavity", "Shedding phase"],
["Proliferative (early)", "4–8 mm", "Thin echogenic line; hypoechoic functional layer", "Oestrogen-driven growth"],
["Proliferative (late)", "8–12 mm", "Trilaminar / three-layer pattern", "Just before ovulation"],
["Secretory", "10–14 mm", "Thickened, uniformly bright (hyperechoic), homogeneous", "Post-ovulation progesterone effect"],
["Postmenopausal (NORMAL)", "< 4–5 mm", "Thin bright line, atrophic", "If > 5 mm → biopsy recommended"],
["Postmenopausal + bleeding", "> 5 mm suspicious", "Thickened, irregular, heterogeneous", "Refer for biopsy / hysteroscopy"],
]
endo_t = make_table(
["Cycle Phase", "Thickness", "USG Appearance", "Clinical Note"],
endo_data,
col_widths=[3.5*cm, 3*cm, 5*cm, 6*cm]
)
story.append(endo_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("5.3 Normal Ovary — Appearance & Follicle Development"))
story.append(Spacer(1, 0.2*cm))
ov_data = [
["Reproductive age", "3 × 2 × 2 cm (volume ≈ 6–10 cc)", "Ovoid, multiple small follicles; normal volume = 0.523 × L × W × H"],
["Dominant follicle", "18–25 mm at ovulation", "Anechoic, thin-walled; 'Double ring' sign just before ovulation"],
["Corpus luteum", "2–3 cm", "Thick irregular wall; central clot may be present; RING OF FIRE on Doppler"],
["Postmenopausal", "1.5 × 1 × 0.5 cm (volume < 3 cc)", "Atrophic; follicles absent; must not exceed 3 cc"],
]
ov_t = make_table(
["State", "Size", "USG Features"],
ov_data,
col_widths=[3.5*cm, 4*cm, 10*cm]
)
story.append(ov_t)
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("5.4 Cervix on USG"))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"<b>Cervical length (TVS):</b> Normal cervical length in 2nd trimester is ≥ 25 mm. "
"Measure from internal os to external os on TVS with empty bladder. "
"< 25 mm at <24 weeks → risk of preterm labour (PTL). "
"< 10 mm → immediate referral. Funnelling (funnel-shaped internal os opening) indicates cervical incompetence.",
S_BODY
))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 7 – PART 6: PATHOLOGICAL CONDITIONS
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 6 — PATHOLOGICAL CONDITIONS ON USG"))
story.append(Spacer(1, 0.2*cm))
# ── 6.1 Uterine Fibroids ──
story.append(SubSectionHeader("6.1 Uterine Fibroids (Leiomyomata)"))
story.append(Spacer(1, 0.15*cm))
fib_data = [
["Intramural", "Within myometrium", "Hypoechoic/heterogeneous rounded mass; may distort endometrium", "Most common type; AUB if large"],
["Submucosal", "Bulges into cavity", "Hyperechoic mass protruding into endometrial cavity", "Best for AUB; treated by hysteroscopic resection"],
["Subserosal", "Projects outward", "Lobulated mass on uterine surface; may be pedunculated", "Pelvic pain; can mimic adnexal mass"],
["Cervical", "In cervix", "Mass in cervical canal", "Rare; causes dyspareunia, obstruction"],
["Degeneration", "Any type", "Heterogeneous with cystic spaces or calcification", "Seen in large/torsed fibroids; pain"],
]
fib_t = make_table(
["Type", "Location", "USG Appearance", "Clinical Significance"],
fib_data,
col_widths=[2.5*cm, 3*cm, 6*cm, 6*cm]
)
story.append(fib_t)
story.append(Spacer(1, 0.25*cm))
# ── 6.2 Ovarian Cysts ──
story.append(SubSectionHeader("6.2 Ovarian Cysts — Classification (Grainger & Allison Radiology)"))
story.append(Spacer(1, 0.15*cm))
cyst_data = [
["Simple follicular cyst", "Anechoic, thin smooth wall (< 3 mm), posterior enhancement, no septae, no Doppler flow",
"< 3 cm in reproductive age is physiological; > 5 cm warrants follow-up"],
["Haemorrhagic cyst\n(Corpus luteum)", "'Fish-net' / reticular pattern; no internal vascularity on Doppler; resolves in 4–8 wks",
"Haemorrhage into corpus luteum; may cause acute pelvic pain; self-limiting"],
["Endometrioma\n('Chocolate cyst')", "Ground-glass appearance; low-level uniform internal echoes; thick walls; bilateral in 30%",
"Endometriosis; CA-125 elevated; MRI for confirmation"],
["Dermoid cyst (Mature teratoma)", "'Tip of iceberg' sign (front echogenic, back shadowed); Rokitansky nodule; fat-fluid level",
"Most common benign ovarian tumour in young women; bilateral in 10–15%"],
["Serous cystadenoma", "Large, unilocular, thin-walled, anechoic; may be bilateral",
"Commonest benign ovarian tumour; must exclude malignancy if > 5 cm or complex"],
["Mucinous cystadenoma", "Multi-locular; low-level internal echoes; large (can be > 20 cm)",
"Can be massive; rupture → pseudomyxoma peritonei"],
]
cyst_t = make_table(
["Cyst Type", "USG Appearance", "Clinical Notes"],
cyst_data,
col_widths=[3.8*cm, 7*cm, 6.7*cm]
)
story.append(cyst_t)
story.append(Spacer(1, 0.2*cm))
cyst_img_grid = two_col_images([
("fetal_ovarian_cyst.png",
"Creasy & Resnik MFM, Fig. 24.38 — Fetal ovarian cyst at 31w5d. "
"Large anechoic mass in fetal lower abdomen. Arrow (yellow) = daughter cyst. "
"Fetal ovarian cysts arise from maternal/placental hormone stimulation. "
"Most simple cysts resolve spontaneously postpartum.",
{"Arrow": "Daughter cyst", "GA": "31w5d"}),
("renal_cyst.png",
"Creasy & Resnik MFM, Fig. 24.36 — Choledochal cyst. Axial view at 21 weeks. "
"Cystic mass anterior to right kidney (RK) in area of fetal liver. "
"Important to distinguish from duplication cyst, ovarian cyst, or mesenteric cyst.",
{"RK": "Right kidney", "Sp": "Spine"}),
])
story.append(cyst_img_grid)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 8 – ECTOPIC, MOLE, PREVIA, PCOS, ENDOMETRIAL
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("PART 6 (continued) — ECTOPIC PREGNANCY, MOLAR PREGNANCY, PLACENTA PREVIA, PCOS"))
story.append(Spacer(1, 0.25*cm))
# ── 6.3 Ectopic ──
story.append(SubSectionHeader("6.3 Ectopic Pregnancy (Berek & Novak's Gynecology, Ch. 9)"))
story.append(Spacer(1, 0.15*cm))
ec_grid = two_col_images([
("ectopic.png",
"Bailey & Love Surgery, Fig. 87.4 — Tubal ectopic pregnancy. "
"Transvaginal USG showing an anechoic adnexal ring ('tubal ring' sign) separate from the ovary. "
"No IUP visible in the uterine cavity. Free fluid in pouch of Douglas = haemoperitoneum.",
{"Adnexal ring": "Ectopic GS in tube"}),
("nose_lips.png", # placeholder for layout symmetry
"",
{}),
])
# Only use ectopic image as single, wide
path_ec = os.path.join(IMG_DIR, "ectopic.png")
ec_items = []
if os.path.exists(path_ec):
ec_items.append(RLImage(path_ec, width=10*cm, height=8*cm, kind='proportional'))
ec_items.append(Paragraph(
"Bailey & Love Surgery, Fig. 87.4 — Tubal ectopic pregnancy. Transvaginal USG: anechoic adnexal ring "
"('tubal ring') separate from the ovary. No IUP in uterine cavity. Free fluid in POD = haemoperitoneum.", S_CAPTION))
ec_table = Table([[ec_items, [
Paragraph("<b>Key USG Findings in Ectopic Pregnancy:</b>", S_H2),
Spacer(1, 0.1*cm),
make_table(
["Sign", "Description"],
[
["Empty uterus", "No IUP on TVS when hCG > discriminatory zone"],
["Tubal ring sign", "Echogenic ring in adnexa (ectopic GS); separate from ovary"],
["Pseudogestational sac", "Central fluid in uterus (no yolk sac/embryo inside)"],
["Free fluid (POD)", "Anechoic fluid in pouch of Douglas = blood"],
["Live ectopic", "Cardiac activity outside uterus — pathognomonic"],
["Complex adnexal mass", "Haematoma from tubal rupture; heterogeneous"],
],
col_widths=[3.5*cm, 5*cm]
),
]]], colWidths=[10.5*cm, 8.5*cm])
ec_table.setStyle(TableStyle([
('VALIGN',(0,0),(-1,-1),'TOP'),
('LEFTPADDING',(0,0),(-1,-1),4),
('RIGHTPADDING',(0,0),(-1,-1),4),
]))
story.append(ec_table)
story.append(Spacer(1, 0.3*cm))
# ── 6.4 Molar Pregnancy ──
story.append(SubSectionHeader("6.4 Hydatidiform Mole (Gestational Trophoblastic Disease)"))
story.append(Spacer(1, 0.15*cm))
mole_data = [
["Complete Mole (46 XX/XY)", "'Snowstorm' pattern: uterus filled with heterogeneous echogenic material + multiple small anechoic spaces (hydropic villi)",
"No fetal parts. Markedly elevated hCG. Bilateral theca-lutein cysts common. High malignancy risk (15–20%)"],
["Partial Mole (69 chromosomes)", "Abnormal placenta (swiss-cheese/cystic spaces). Fetus/fetal parts may be present (triploid)",
"GS transverse:AP ratio > 1.5. Lower hCG than complete. Lower malignancy risk (< 5%)"],
]
mole_t = make_table(
["Type", "USG Appearance", "Clinical Notes"],
mole_data,
col_widths=[4*cm, 7*cm, 6.5*cm]
)
story.append(mole_t)
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
'<b><font color="#C0392B">D.C. Dutta's PEARL:</font></b> The snowstorm appearance on USG + markedly elevated hCG is pathognomonic of '
'complete hydatidiform mole. TVS is more sensitive than TAS for early diagnosis. Always check both ovaries for theca-lutein cysts.',
S_NOTE
))
story.append(Spacer(1, 0.3*cm))
# ── 6.5 Placenta Previa ──
story.append(SubSectionHeader("6.5 Placenta Previa (Creasy & Resnik MFM; Williams Obstetrics)"))
story.append(Spacer(1, 0.15*cm))
prev_data = [
["Complete (Total) Previa", "Placenta completely covers the internal cervical os", "Mandatory CS; no vaginal examination"],
["Partial Previa", "Placenta partially overlaps the internal os", "Usually CS; TVS follow-up"],
["Marginal Previa", "Placental edge reaches but does not cover the os", "Possible vaginal delivery; TVS at 36 wks"],
["Low-Lying Placenta", "Placental edge within 2 cm of os but not covering", "TVS at 32–36 wks; most 'migrate' away"],
]
prev_t = make_table(
["Type", "USG Definition", "Management Principle"],
prev_data,
col_widths=[4*cm, 7*cm, 6.5*cm]
)
story.append(prev_t)
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
'<b>IMPORTANT:</b> Always confirm with TVS (transvaginal USG). Full bladder on TAS may compress the lower segment and create a '
'<b>false appearance of previa</b>. "Placental migration" — most low-lying placentas at 20 weeks move away from the os by 34–36 weeks '
'as the lower uterine segment elongates.', S_BODY
))
story.append(Spacer(1, 0.3*cm))
# ── 6.6 PCOS ──
story.append(SubSectionHeader("6.6 Polycystic Ovarian Syndrome (PCOS) — Rotterdam Criteria USG Component"))
story.append(Spacer(1, 0.15*cm))
pcos_data = [
["Follicle count", "≥ 12 follicles per ovary, each 2–9 mm diameter", "'String of pearls' sign — follicles arranged peripherally"],
["Ovarian volume", "> 10 cc (0.523 × L × W × H)", "Enlarged ovary with echogenic central stroma"],
["Stroma", "Increased echogenicity of central stroma", "Increased stromal:total ovary area ratio"],
]
pcos_t = make_table(
["Criterion", "Definition", "USG Appearance"],
pcos_data,
col_widths=[3.5*cm, 5*cm, 9*cm]
)
story.append(pcos_t)
story.append(Spacer(1, 0.3*cm))
# ── 6.7 Endometrial Pathology ──
story.append(SubSectionHeader("6.7 Endometrial Pathology"))
story.append(Spacer(1, 0.15*cm))
ep_data = [
["Endometrial Polyp", "Focal hyperechoic intracavitary mass; central vascular stalk on Doppler; endometrial thickening",
"AUB; confirm with saline-infusion sonohysterography (SIS) or hysteroscopy"],
["Endometrial Hyperplasia", "Diffusely thickened, bright (hyperechoic) endometrium; uniform",
"> 4–5 mm postmenopausal → biopsy; oestrogen excess; PCOS"],
["Endometrial Carcinoma", "Irregular, heterogeneous, thickened endometrium; loss of endometrial-myometrial junction; Doppler shows low-resistance flow",
"Postmenopausal bleeding; invasion of myometrium seen on MRI"],
["Asherman's Syndrome", "Thin/absent endometrium; irregular echogenic areas (synechiae); poor endometrial stripe",
"History of D&C / uterine surgery; amenorrhoea"],
["Submucosal Fibroid", "Hypoechoic mass distorting endometrial cavity; seen on TVS",
"AUB; FIGO type 0, 1, 2 classification on SIS"],
]
ep_t = make_table(
["Condition", "USG Appearance", "Clinical Notes"],
ep_data,
col_widths=[3.8*cm, 7*cm, 6.7*cm]
)
story.append(ep_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 9 – QUICK REFERENCE TABLES
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("QUICK REFERENCE TABLES — At-a-Glance Clinical Summary"))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("Normal Biometry Reference Table (Selected Gestational Ages)"))
story.append(Spacer(1, 0.15*cm))
norm_data = [
["12", "2.0", "7.5", "6.5", "0.9", "~80"],
["16", "3.2", "12.0", "11.2", "2.3", "~200"],
["18", "4.4", "16.0", "14.5", "3.0", "~300"],
["20", "4.8", "17.5", "15.5", "3.3", "~330"],
["24", "6.0", "22.0", "20.0", "4.4", "~600"],
["28", "7.0", "26.0", "24.5", "5.3", "~1,000"],
["32", "8.2", "30.0", "28.0", "6.2", "~1,800"],
["36", "9.0", "33.0", "32.0", "6.9", "~2,600"],
["40", "9.5", "35.0", "35.0", "7.5", "~3,400"],
]
norm_t = make_table(
["GA (weeks)", "BPD (cm)", "HC (cm)", "AC (cm)", "FL (cm)", "EFW (g approx.)"],
norm_data,
col_widths=[2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm, 5*cm]
)
story.append(norm_t)
story.append(Paragraph("*Values are approximate means. Always plot on growth charts and compare with prior measurements. (ISUOG 2019 Guidelines)", S_SMALL))
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("Obstetric USG — Trimester Checklist Summary"))
story.append(Spacer(1, 0.15*cm))
check_data = [
["1st Trimester\n(4–13 weeks)",
"• Confirm IUP (GS in uterus)\n• MSD → CRL for dating\n• Yolk sac present?\n• Fetal pole visible?\n• Cardiac activity (if CRL ≥ 7 mm)\n• Number of embryos\n• NT at 11–13+6 wks\n• Adnexa / free fluid",
"• CRL for GA (±3 days)\n• HR: 110–170 bpm\n• NT < 3.0 mm (11–13+6 wks)\n• No free fluid in pelvis"],
["2nd Trimester\n(18–22 weeks)\nAnatomy Scan",
"• Fetal number & lie\n• Head: BPD, HC, CSP, falx, ventricles, cerebellum, CM, NT fold\n• Face: orbits, nasal bone, lips, palate\n• Thorax: 4-chamber heart, LVOT, RVOT, lung parenchyma\n• Abdomen: stomach, bowel, kidneys, bladder, cord insertion, AC\n• Spine: longitudinal + transverse views\n• Limbs: all long bones, hands, feet\n• Placenta: location, appearance, cord insertion\n• AFI or MVP\n• Cervical length if indicated",
"• BPD, HC, AC, FL within normal range\n• AFI 8–24 cm (MVP 2–8 cm)\n• 4-chamber heart: equal-sized chambers\n• Both kidneys visible\n• Intact upper lip\n• Cervix > 25 mm"],
["3rd Trimester\n(28–40 weeks)",
"• Fetal presentation & lie\n• Estimated fetal weight (EFW)\n• Amniotic fluid (AFI/MVP)\n• Placenta grade & position\n• Umbilical artery Doppler\n• BPP if indicated",
"• EFW: 10th–90th centile for GA\n• AFI ≥ 5 cm, MVP ≥ 2 cm\n• Umbilical artery: forward end-diastolic flow\n• Placenta: not covering os (if low-lying at 20 wks, recheck)"],
]
check_t = Table(
[[Paragraph(f'<b>{r[0]}</b>', S_BODY), Paragraph(r[1].replace('\n','<br/>'), S_SMALL), Paragraph(r[2].replace('\n','<br/>'), S_SMALL)]
for r in check_data],
colWidths=[3.5*cm, 8*cm, 6*cm]
)
check_t.setStyle(TableStyle([
('BACKGROUND', (0,0), (0,-1), C_NAVY),
('TEXTCOLOR', (0,0), (0,-1), C_WHITE),
('BACKGROUND', (1,0), (1,-1), C_LGREY),
('BACKGROUND', (2,0), (2,-1), colors.HexColor("#E8F5E9")),
('GRID', (0,0), (-1,-1), 0.3, colors.HexColor("#BBBBBB")),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('LEFTPADDING', (0,0), (-1,-1), 6),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING',(0,0), (-1,-1), 5),
]))
story.append(check_t)
story.append(Spacer(1, 0.3*cm))
story.append(SubSectionHeader("Amniotic Fluid & Doppler Quick Reference"))
story.append(Spacer(1, 0.15*cm))
af2_data = [
["Oligohydramnios", "AFI < 5 cm OR MVP < 2 cm", "Renal agenesis/dysplasia, IUGR, PPROM, post-dates, maternal dehydration"],
["Polyhydramnios", "AFI > 24 cm OR MVP > 8 cm", "GDM, fetal anomaly (oesophageal atresia, anencephaly, NTD), twin-twin transfusion"],
["Normal UA Doppler","S/D ratio < 3 after 30 wks; forward diastolic flow", "Normal fetoplacental circulation"],
["Abnormal UA Doppler","Absent / reversed end-diastolic flow", "Severe IUGR; fetal compromise; consider delivery"],
["MCA Doppler", "PSV > 1.5 MoM = elevated", "Fetal anaemia (alloimmunisation, parvovirus)"],
]
af2_t = make_table(["Parameter", "Definition/Cutoff", "Causes / Significance"], af2_data,
col_widths=[4*cm, 5.5*cm, 8*cm])
story.append(af2_t)
story.append(PageBreak())
# ═══════════════════════════════════════════════════════
# PAGE 10 – PATHOLOGY QUICK DIFFERENTIALS & REFERENCES
# ═══════════════════════════════════════════════════════
story.append(SectionHeader("DIFFERENTIAL DIAGNOSIS GUIDE — USG Findings in Gynecology & Obstetrics"))
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("Empty Uterus on TVS + Positive Pregnancy Test"))
story.append(Spacer(1, 0.1*cm))
eu_data = [
["Ectopic pregnancy", "hCG > discriminatory zone; adnexal ring or mass; free fluid (haemoperitoneum)", "URGENT referral; serial hCG if indeterminate"],
["Very early IUP", "hCG < 1,000 mIU/mL; too small to see on TVS", "Repeat TVS in 48 hrs; serial hCG"],
["Complete abortion", "hCG falling; no products of conception in uterus; history of heavy bleeding", "Confirm with falling hCG"],
["Intrauterine blood / pseudoGS", "Central fluid pocket; no yolk sac; no double decidual sign", "Serial TVS; do not assume IUP"],
]
eu_t = make_table(["Diagnosis", "USG / Lab Features", "Action"],
eu_data, col_widths=[4*cm, 7*cm, 6.5*cm])
story.append(eu_t)
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("Adnexal / Pelvic Mass on USG"))
story.append(Spacer(1, 0.1*cm))
am_data = [
["Physiological follicular cyst", "Anechoic, < 3 cm, thin wall, no Doppler flow", "Reproductive age; reassure; rescan in 6 wks"],
["Corpus luteum cyst", "Thick wall; 'ring of fire' Doppler; may have internal echoes", "Luteal phase; resolves by next cycle"],
["Haemorrhagic cyst", "Fish-net / reticular internal pattern; no Doppler flow internally", "Acute pain possible; conservative management"],
["Endometrioma", "Ground-glass echoes; thick wall; bilateral ±", "Endometriosis; CA-125 often elevated"],
["Dermoid (teratoma)", "'Tip of iceberg'; fat-fluid level; Rokitansky nodule; calcification", "Young women; bilateral 10–15%"],
["TOA (Tubo-ovarian abscess)", "Complex thick-walled mass + free fluid; no discrete ovary/tube seen; Doppler hypervascularity", "PID history; fever; IV antibiotics"],
["Ectopic pregnancy", "Adnexal ring separate from ovary; no IUP; + hCG", "Urgent management"],
["Ovarian malignancy (concern)", "Multi-locular; solid components; papillary projections; bilateral; ascites; > 10 cm", "RMI calculation; gynae-oncology referral"],
]
am_t = make_table(
["Diagnosis", "USG Appearance", "Management Clue"],
am_data,
col_widths=[4*cm, 7.5*cm, 6*cm]
)
story.append(am_t)
story.append(Spacer(1, 0.25*cm))
story.append(SubSectionHeader("Postmenopausal Bleeding — Endometrial USG Findings"))
story.append(Spacer(1, 0.1*cm))
pmb_data = [
["< 4 mm", "Atrophic endometrium", "Low risk of malignancy; no biopsy unless recurrent bleeding"],
["4–10 mm", "Thickened; may be hyperplasia or polyp", "Biopsy / hysteroscopy recommended"],
["> 10 mm", "Significant thickening; irregular; heterogeneous", "High suspicion for carcinoma; urgent hysteroscopy + biopsy"],
["Focal thickening", "Polyp vs cancer vs fibroid", "SIS or hysteroscopy for direct visualisation"],
]
pmb_t = make_table(
["ET on TVS", "Interpretation", "Clinical Action"],
pmb_data,
col_widths=[2.5*cm, 6*cm, 9*cm]
)
story.append(pmb_t)
story.append(Spacer(1, 0.3*cm))
# ── References ──
story.append(SectionHeader("REFERENCES & EVIDENCE BASE", bg=C_TEAL))
story.append(Spacer(1, 0.2*cm))
refs = [
("<b>Creasy RK, Resnik R, et al.</b> <i>Creasy & Resnik's Maternal-Fetal Medicine: Principles and Practice, 8th Ed.</i> "
"Elsevier, 2022. — Chapter 16: The Midtrimester Obstetric Ultrasound Examination. Figs 16.1–16.38."),
("<b>Berek JS, et al.</b> <i>Berek & Novak's Gynecology, 16th Ed.</i> Lippincott Williams & Wilkins, 2020. "
"— Chapter 9: Ectopic Pregnancy; Chapter 19: Gynecologic Ultrasound."),
("<b>Grainger RG, Allison DJ, et al.</b> <i>Grainger & Allison's Diagnostic Radiology: A Textbook of Medical Imaging, 6th Ed.</i> "
"Elsevier, 2015. — Chapter 7: Gynaecological Ultrasound."),
("<b>Dutta DC.</b> <i>D.C. Dutta's Textbook of Obstetrics, 9th Ed.</i> Jaypee Brothers Medical Publishers, 2018. "
"— Chapter 16: Ultrasonography in Obstetrics."),
("<b>Cunningham FG, et al. (Williams).</b> <i>Williams Obstetrics, 26th Ed.</i> McGraw-Hill, 2022. "
"— Chapter 10: Prenatal Care; Chapter 17: Ultrasound Imaging."),
("<b>ISUOG Clinical Standards Committee.</b> Practice guidelines for ultrasound assessment of fetal biometry and growth. "
"<i>Ultrasound Obstet Gynecol.</i> 2019;53:715–723."),
("<b>ACOG Practice Bulletin #175.</b> Ultrasound in Pregnancy. Obstet Gynecol. 2016."),
]
for i, ref in enumerate(refs, 1):
story.append(Paragraph(f"{i}. {ref}", S_SMALL))
story.append(Spacer(1, 0.1*cm))
story.append(Spacer(1, 0.3*cm))
story.append(HRFlowable(width="100%", thickness=1, color=C_TEAL))
story.append(Spacer(1, 0.15*cm))
story.append(Paragraph(
"<i>This reference guide is intended for educational purposes for medical students, residents, and clinicians. "
"It does not replace clinical judgment, institutional protocols, or current published guidelines. "
"Always interpret USG findings in the context of complete clinical history and examination.</i>",
style("disclaimer", fontName="Helvetica-Oblique", fontSize=7.5, textColor=colors.HexColor("#888888"),
leading=11, alignment=TA_CENTER)
))
# ── Build ──────────────────────────────────────────────
def first_page(c, d):
cover_page_template(c, d)
def later_pages(c, d):
page_template(c, d)
doc.build(story, onFirstPage=first_page, onLaterPages=later_pages)
print(f"PDF created: {OUTPUT}")
import os as _os
sz = _os.path.getsize(OUTPUT)
print(f"File size: {sz/1024:.1f} KB")
if __name__ == "__main__":
build()
cd /home/daytona/workspace/usg-guide && python3 build_usg_guide.py 2>&1
~/usg-guide/build_usg_guide.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/usg-guide/build_usg_guide.py'
cd /home/daytona/workspace/usg-guide && python3 build_usg_guide.py 2>&1
~/usg-guide/build_usg_guide.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/usg-guide/build_usg_guide.py'
cd /home/daytona/workspace/usg-guide && python3 build_usg_guide.py 2>&1
USG Gynecology Obstetrics Reference Guide
PDF Document · PDF
| Page | Content |
|---|---|
| Cover | Title page with structured table of contents |
| Part 1 | Probe types, echogenicity key, mandatory report elements |
| Part 2 | First trimester USG - sequential appearances, discriminatory zones, early pregnancy failure criteria |
| Part 3 | Fetal biometry with labeled USG images (BPD/HC at 18 wks, posterior fossa/cerebellum) |
| Part 4 | Detailed fetal anatomy - labeled images of cavum septi pellucidi, falx, lateral ventricles, nasal bone, orbits, nose/lips, four-chamber heart, LVOT, RVOT, M-mode HR |
| Part 5 | Normal uterus measurements, endometrial thickness by cycle phase, normal ovary, cervical length |
| Part 6 | Fibroids (all types), ovarian cyst classification with images, ectopic pregnancy with labeled USG, molar pregnancy, placenta previa, PCOS, endometrial pathology |
| Part 7 | Differential diagnosis tables (empty uterus, adnexal mass, PMB) |
| Part 8 | Normal biometry reference table (GA 12-40 wks), trimester checklist, Doppler quick reference |
| References | Creasy & Resnik MFM, Berek & Novak, Grainger & Allison, D.C. Dutta, Williams Obstetrics, ISUOG 2019 |