در بینایی ماشین سنتی، درک فاصلهی اشیا نیازمند حسگرهای گرانقیمتی مثل لیدار (LiDAR) یا جفتدوربینهای استریو بود. برای توسعهدهندگان ایرانی، دسترسی فیزیکی یا واردات حسگرهای سختافزاری دقیق اغلب پرهزینه و چالشبرانگیز است. اما ظهور انکودرهای بینایی خودنظارتی (Self-Supervised) مانند DINOv2 معادله را تغییر داده و این امکان را فراهم کرده است که تنها با یک فریم RGB ساده، نقشههای عمق بسیار دقیقی به دست آورید.
این درس به شما نشان میدهد چطور بدون نیاز به دادهبرداری پیچیده، از مدلهای خطمقدمی مانند Depth Anything V3 و Marigold برای تخمین عمق صحنه استفاده کنید، تفاوت اساسی میان عمق نسبی و عمق متری را بشناسید و خروجی مدل را به یک ابر نقطهی سهبعدی تبدیل نمایید.
خوشبختانه اجرای استنتاج مدلهای بهینهشدهی عمق مانند نسخههای Small نیازی به پردازشهای ابری سنگین ندارد و روی سختافزارهای استاندارد یا حتی CPU نیز قابل بررسی است. با این حال، به دلیل ناپایداریهای معمول در دسترسی به مخازن خارجی مانند Hugging Face، بهتر است وزنهای ازپیشآموزشدیده را از قبل ذخیره کنید یا از میرورهای پایدار برای دانلود استفاده نمایید.
نقشهی عمق (depth map) تصویری تککاناله است که در آن، مقدار هر پیکسل فاصلهی آن نقطه از دوربین را نشان میدهد. در گذشته، پیشبینی این نقشه تنها از روی یک فریم RGB بدون دوربین استریو یا لیدار (LiDAR) غیرممکن بود. اما در سال 2026، یک انکودر منجمد ViT بههمراه یک هد سبک به اختلافی در حد چند درصد نسبت به دادهی مرجع واقعی (ground truth) میرسد.
اهداف یادگیری
- تمایز قائل شدن بین عمق نسبی (relative depth) و عمق متری (metric depth) و تشخیص اینکه مدلهای عملیاتی مطرح (MiDaS، Marigold، Depth Anything V3 و ZoeDepth) هرکدام کدام مسئله را حل میکنند
- استفاده از Depth Anything V3 (با ستون فقرات DINOv2) برای پیشبینی عمق روی تکتصاویر دلخواه و بدون نیاز به کالیبراسیون
- توضیح اینکه چرا تخمین عمق تکتصویری (monocular depth) اصلاً از روی یک تصویر کار میکند (نشانههای پرسپکتیو، گرادیانهای بافت، پیشینهای آموختهشده) و چه چیزهایی را نمیتواند بازیابی کند (مقیاس مطلق، هندسهی پنهان در اثر انسداد)
- تبدیل تشخیصهای دوبعدی به نقاط سهبعدی با استفاده از نقشهی عمق و پارامترهای ذاتی دوربین پینهول (pinhole camera intrinsics)
صورت مسئله
عمق همان محور گمشده در بینایی ماشین دوبعدی است. با یک تصویر RGB، میدانید هر شیء در کجای صفحهی تصویر قرار دارد؛ اما نمیدانید چقدر از شما دور است. حسگرهای عمق (سامانههای استریو، لیدار و زمانپرواز یا ToF) این مسئله را مستقیماً حل میکنند، اما گرانقیمت، آسیبپذیر و دارای برد محدودی هستند.
تخمین عمق تکتصویری — یعنی پیشبینی عمق تنها از روی یک فریم RGB — در گذشته خروجیهایی تار و نامطمئن میداد. تا سال 2026، انکودرهای بزرگِ ازپیشآموزشدیده بازی را عوض کردند: Depth Anything V3 از ستون فقرات منجمد DINOv2 بهره میبرد و نقشههای عمقی میسازد که روی محیطهای داخلی، فضای باز، دادههای پزشکی و تصاویر ماهوارهای تعمیمپذیرند. مدل Marigold عمق را بهشکل یک مسئلهی دیفیوژن شرطی (conditional diffusion) بازتعریف میکند؛ و ZoeDepth فواصل متری واقعی را رگرسیون مینماید.
عمق همچنین پلی میان تشخیص دوبعدی و درک سهبعدی است: کافی است پیکسلهای یک باکس تشخیصدادهشده را در عمق ضرب کنید تا شیء دوبعدی به یک ابر نقطه (point cloud) سهبعدی تبدیل شود. این فرایند هستهی اصلی سیستمهای انسداد در واقعیت افزوده (AR occlusion)، پایپلاینهای جلوگیری از برخورد با مانع، و رباتهای «برداشتن فنجان» است.
مفاهیم پایه
عمق نسبی در برابر عمق متری
- عمق نسبی — مقادیر مرتبشدهی
zبدون واحد در دنیای واقعی. «پیکسل A از پیکسل B نزدیکتر است، اما نسبت فواصل بر حسب متر مشخص نیست.» - عمق متری — فاصلهی مطلق از دوربین بر حسب متر. به این نیاز دارد که مدل، رابطهی آماریِ میان نشانههای درون تصویر و فاصلهی واقعی را یاد گرفته باشد.
مدلهای MiDaS و Depth Anything V3 عمق نسبی تولید میکنند. Marigold هم عمق نسبی میدهد. اما ZoeDepth، UniDepth و Metric3D عمق متری تولید میکنند. مدلهای متری به پارامترهای ذاتی دوربین حساساند؛ در حالی که مدلهای نسبی چنین حساسیتی ندارند.
الگوی انکودر-دیکودر
مدل Depth Anything V3 انکودر را منجمد نگه میدارد و فقط دیکودر نوع DPT را آموزش میدهد. انکودر ویژگیهای غنی و عمیقی را فراهم میکند؛ دیکودر هم این ویژگیها را دوباره به رزولوشن تصویر درونیابی کرده و عمق را رگرسیون میکند.
چرا یک تصویر تکی اصلاً اطلاعات عمق را نشان میدهد؟
یک تصویر دوبعدی نشانههای تکچشمی (monocular cues) متعددی دارد که با عمق همبستگی دارند:
- پرسپکتیو — خطوط موازی در دنیای سهبعدی، در فضای دوبعدی همگرا میشوند.
- گرادیان بافت — سطوح دورتر بافتی متراکمتر و ریزتر دارند.
- ترتیب انسداد — اشیای نزدیکتر، اشیای دورتر را میپوشانند.
- ثبات اندازه — اشیای آشنا (خودروها، انسانها) مقیاس تقریبی صحنه را نشان میدهند.
- پرسپکتیو جوی — در فضاهای باز، اشیای دورتر تارتر و متمایل به آبی دیده میشوند.
یک مدل ViT که روی میلیاردها تصویر آموزش دیده، این نشانهها را در خود نهادینه میکند. با دادههای کافی و یک ستون فقرات قدرتمند، عمق تکتصویری حتی بدون نظارت مستقیم سهبعدی به دقتی معقول میرسد.
محدودیتهای عمق تکتصویری
- مقیاس متری مطلق بدون پارامترهای ذاتی دوربین یا وجود شیئی با اندازهی مشخص در صحنه قابل بازیابی نیست. شبکه میتواند بگوید «فاصلهی فنجان دو برابر قاشق است»، بدون اینکه بداند فنجان در فاصلهی 1 متری قرار دارد یا 10 متری.
- هندسهی پنهان در اثر انسداد — پشت صندلی دیده نمیشود و نمیتوان آن را با اطمینان استنتاج کرد.
- سطوح واقعاً بدون بافت یا بازتابنده — آینهها، شیشهها یا دیوارهای یکدست. شبکه در این شرایط عمقی بهظاهر باورپذیر ولی اشتباه تحویل میدهد.
مدل Depth Anything V3 در سال 2026
- انکودر استاندارد DINOv2 ViT-L/14 بهصورت منجمد.
- دیکودر DPT.
- آموزشدیده روی جفتتصاویر با پوز مشخص (posed image pairs) از منابع متنوع (بدون نیاز به نظارت مستقیم عمق، فراتر از سازگاری نورسنجی یا photometric consistency).
- پیشبینی هندسهی سازگار از نظر مکانی بر اساس تعداد دلخواهی از ورودیهای بصری، با یا بدون پوزهای مشخص دوربین.
- پیشتاز (SOTA) در عمق تکتصویری، هندسهی چندنما (any-view geometry)، رندرینگ بصری و تخمین پوز دوربین.
در سال 2026، هر زمان به عمق نیاز داشتید این مدل انتخاب اول و آمادهبهکار شماست.
مدل Marigold — دیفیوژن برای تخمین عمق
مدل Marigold (ارائهشده توسط Ke و همکاران، CVPR 2024) مسئلهی تخمین عمق را در قالب یک دیفیوژن تصویر-به-تصویر شرطی بازتعریف میکند. ورودی شرطی: تصویر RGB؛ خروجی هدف: نقشهی عمق. این مدل از شبکهی U-Net ازپیشآموزشدیدهی Stable Diffusion 2 بهعنوان ستون فقرات استفاده میکند. نقشههای عمق خروجی روی مرز اشیاء وضوح خیرهکنندهای دارند. عیب آن: سرعت استنتاج پایینتر در مقایسه با مدلهای مستقیم و پیشخور (feed-forward) بهدلیل نیاز به 10 تا 50 گام حذف نویز.
پارامترهای ذاتی و دوربین پینهول
برای تبدیل یک پیکسل (u, v) با عمق d به یک نقطهی سهبعدی (X, Y, Z) در مختصات دوربین:
پارامترهای ذاتی را میتوان از متادیتاهای EXIF، الگوهای کالیبراسیون یا تخمینزنندههای تکتصویری پارامترهای ذاتی (مثل Perspective Fields یا UniDepth) استخراج کرد. اگر این پارامترها در دسترس نبودند، میتوانید با فرض میدان دید (FOV) حدود 60 تا 70 درجه و در نظر گرفتن نقطهی اصلی در مرکز تصویر، ابر نقطه را بسازید. این کار برای مصورسازی خوب است، اما به درد اندازهگیری دقیق نمیخورد.
ارزیابی
دو معیار استاندارد در این زمینه وجود دارد:
- AbsRel (خطای نسبی مطلق):
mean(|d_pred - d_gt| / d_gt). هرچه کمتر باشد بهتر است؛ برای مدلهای عملیاتی بین 0.05 تا 0.1 قرار دارد. - delta < 1.25 (دقت آستانهای): کسری از پیکسلها که در آنها شرط
max(d_pred/d_gt, d_gt/d_pred) < 1.25برقرار است. هرچه بیشتر باشد بهتر است؛ برای مدلهای SOTA بالای 0.9 است.
برای عمق نسبی (مثل Depth Anything V3 و MiDaS)، ارزیابی با نسخههای ناوردا نسبت به مقیاس و جابهجایی (scale-and-shift invariant) در هر دو معیار انجام میشود.
پیادهسازی عملی
گام 1: معیارهای ارزیابی عمق
import torch
def abs_rel_error(pred, target, mask=None):
if mask is not None:
pred = pred[mask]
target = target[mask]
return (torch.abs(pred - target) / target.clamp(min=1e-6)).mean().item()
def delta_accuracy(pred, target, threshold=1.25, mask=None):
if mask is not None:
pred = pred[mask]
target = target[mask]
ratio = torch.maximum(pred / target.clamp(min=1e-6), target / pred.clamp(min=1e-6))
return (ratio < threshold).float().mean().item()
همیشه قبل از ارزیابی، پیکسلهای نامعتبر عمق (صفر، NaN، مقادیر اشباعشده) را ماسک کنید.
گام 2: تراز مقیاس و جابهجایی
در مدلهای عمق نسبی، پیش از محاسبهی معیارها باید پیشبینی را با دادهی واقعی تراز کنید. این کار با برازش کمترین مربعات روی رابطهی a * pred + b = target انجام میشود:
def align_scale_shift(pred, target, mask=None):
if mask is not None:
p = pred[mask]
t = target[mask]
else:
p = pred.flatten()
t = target.flatten()
A = torch.stack([p, torch.ones_like(p)], dim=1)
coeffs, *_ = torch.linalg.lstsq(A, t.unsqueeze(-1))
a, b = coeffs[:2, 0]
return a * pred + b
هنگام ارزیابی MiDaS یا Depth Anything، تابع align_scale_shift را حتماً قبل از abs_rel_error صدا بزنید.
گام 3: تبدیل عمق به ابر نقطه
import numpy as np
def depth_to_point_cloud(depth, intrinsics):
H, W = depth.shape
fx, fy, cx, cy = intrinsics
v, u = np.meshgrid(np.arange(H), np.arange(W), indexing="ij")
z = depth
x = (u - cx) * z / fx
y = (v - cy) * z / fy
return np.stack([x, y, z], axis=-1)
depth = np.random.uniform(0.5, 4.0, (240, 320))
intr = (320.0, 320.0, 160.0, 120.0)
pc = depth_to_point_cloud(depth, intr)
print(f"point cloud shape: {pc.shape} (H, W, 3)")
همین یک تابع برای تمام کاربردهای تبدیل به سهبعدی کفایت میکند. ابر نقطهی خروجی را با فرمت .ply ذخیره کنید و در MeshLab یا CloudCompare ببینید.
گام 4: تست صحت عملکرد با صحنهی عمق ساختگی
def synthetic_depth(size=96):
yy, xx = np.meshgrid(np.arange(size), np.arange(size), indexing="ij")
# کف: گرادیان خطی از نزدیک (بالا) به دور (پایین)
depth = 1.0 + (yy / size) * 4.0
# جعبه وسط: نزدیکتر
mask = (np.abs(xx - size / 2) < size / 6) & (np.abs(yy - size * 0.6) < size / 6)
depth[mask] = 2.0
return depth.astype(np.float32)
gt = torch.from_numpy(synthetic_depth(96))
pred = gt + 0.3 * torch.randn_like(gt) # simulated prediction
aligned = align_scale_shift(pred, gt)
print(f"before align absRel = {abs_rel_error(pred, gt):.3f}")
print(f"after align absRel = {abs_rel_error(aligned, gt):.3f}")
گام 5: نحوهی استفاده از Depth Anything V2 (کد مرجع)
import numpy as np
from transformers import pipeline
from PIL import Image
pipe = pipeline(task="depth-estimation", model="depth-anything/Depth-Anything-V2-Large-hf")
image = Image.open("street.jpg").convert("RGB")
out = pipe(image)
depth_np = np.array(out["depth"])
در سه خط. خروجی out["depth"] یک تصویر خاکستری با فرمت PIL است؛ برای انجام محاسبات ریاضی آن را به آرایهی numpy تبدیل کنید. نسخهی Depth Anything 3 (نوامبر 2025) با این پایپلاین بارگذاری نمیشود و پکیج اختصاصی خودش به نام depth_anything_3 را دارد: با دستور DepthAnything3.from_pretrained("depth-anything/DA3MONO-LARGE") مدل مونوکولار نسبی لود میشود و model.inference(images).depth آرایهی عمق را در ابعاد [N, H, W] برمیگرداند.
استفادهی عملی
- Depth Anything V3 (محصول مشترک Meta AI و ByteDance، سال 2024 تا 2026) — گزینهی پیشفرض برای عمق نسبی. سریعترین مدل عملیاتی با ستون فقرات ViT-large.
- Marigold (دانشگاه ETH، 2024) — بالاترین کیفیت بصری، اما استنتاج کند.
- UniDepth (دانشگاه ETH، 2024) — عمق متری همراه با تخمین پارامترهای ذاتی دوربین.
- ZoeDepth (اینتل، 2023) — عمق متری؛ قدیمیتر اما هنوز قابل اعتماد.
- MiDaS v3.1 — مدلی قدیمی ولی پایدار؛ گزینهای عالی برای مقایسه.
الگوی معمول یکپارچهسازی:
- فریم RGB دریافت میشود.
- مدل عمق، نقشهی عمق را میسازد.
- دیتکتور باکسها را شناسایی میکند.
- مرکز خوشه (centroid) باکسها با عمق به فضای سهبعدی منتقل میشود و در صورت وجود، با ابر نقطه merge میگردد.
- تسکهای پاییندستی: انسداد در واقعیت افزوده، برنامهریزی مسیر، تخمین اندازهی شیء و جایگزینی با سیستم استریو.
برای کاربردهای بلادرنگ، مدل Depth Anything V2 Small با کوانتیزاسیون INT8 روی یک GPU معمولی با رزولوشن 518x518 به حدود 30 فریم بر ثانیه میرسد.
خروجی این درس
این درس این خروجیها را تولید میکند:
outputs/prompt-depth-model-picker.md— پرامپتی برای انتخاب میان Depth Anything V3، Marigold، UniDepth و MiDaS بر اساس تأخیر مجاز، نیاز به عمق متری یا نسبی، و نوع صحنه.outputs/skill-depth-to-pointcloud.md— قابلیتی که با مدیریت درست پارامترهای ذاتی و ذخیره با فرمت.ply، از روی نقشهی عمق ابر نقطه میسازد.
تمرینها
- (ساده) مدل Depth Anything V2 را روی 10 تصویر مختلف از میز کار خود اجرا کنید. نقشههای عمق را بهصورت فایلهای PNG خاکستری ذخیره و بررسی کنید. شیئی را پیدا کنید که عمق آن اشتباه تخمین زده شده است و بگویید چرا نشانههای تکچشمی در آن صحنه جواب ندادهاند.
- (متوسط) با ورودی RGB و نقشهی عمق Depth Anything V2، ابر نقطه را بسازید و آن را با
open3dرندر کنید. دو صحنهی مختلف (داخلی و باز) را با هم مقایسه کنید و ببینید کدامیک خروجی باورپذیرتری دارد. - (سخت) پنج جفت تصویر بگیرید که در هر جفت فقط جای یک شیء مشخص عوض شده باشد (مثلاً یک بطری 30 سانتیمتر نزدیکتر شده باشد). با UniDepth عمق متری را در هر دو تصویر پیشبینی کنید. اختلاف فاصلهی پیشبینیشده را با جابهجایی واقعی (30 سانتیمتر) مقایسه کرده و گزارش دهید.
اصطلاحات کلیدی
| اصطلاح | در گفتگوها چه میگویند | معنای دقیق فنی |
|---|---|---|
| عمق تکتصویری (Monocular depth) | «عمق از یک تصویر» | تخمین عمق فقط از روی یک فریم RGB، بدون استریو یا لیدار |
| عمق نسبی (Relative depth) | «عمق ترتیبی» | مقادیر مرتبشدهی z بدون واحد اندازهگیری در دنیای واقعی |
| عمق متری (Metric depth) | «فاصلهی مطلق» | عمق بر حسب متر؛ نیازمند کالیبراسیون یا مدلی آموزشدیده با نظارت متری |
| معیار AbsRel | «خطای نسبی مطلق» | میانگین ؛ معیار استاندارد ارزیابی عمق |
| دقت دلتا (Delta accuracy) | «دلتا کمتر از 1.25» | کسری از پیکسلها که مقدار پیشبینی آنها حداکثر 25 درصد با واقعیت اختلاف دارد |
| دوربین پینهول (Pinhole camera) | «fx, fy, cx, cy» | مدل دوربینی که برای تبدیل (u, v, d) به مختصات (X, Y, Z) به کار میرود |
| مدل DPT | «ترنسفورمر پیشبینی متراکم» | دیکودر مبتنی بر کانولوشن که روی انکودرهای منجمد ViT برای تخمین عمق سوار میشود |
| ستون فقرات DINOv2 | «دلیل اصلی کارکرد مدل» | ویژگیهای خودنظارتی (self-supervised) که بدون نیاز به برچسبهای عمق، روی دامنههای مختلف تعمیم مییابند |
برای مطالعهی بیشتر
- صفحهی مقالهی Depth Anything V3 — پیشرفتهترین روش عمق تکتصویری با انکودر DINOv2
- مقالهی Marigold (ارائهشده توسط Ke و همکاران، CVPR 2024) — تخمین عمق مبتنی بر مدلهای دیفیوژن
- مقالهی UniDepth (ارائهشده توسط Piccinelli و همکاران، 2024) — تخمین عمق متری بههمراه پارامترهای ذاتی دوربین
- مخزن MiDaS v3.1 (گروه ISL اینتل) — بیسلاین مرجع و استاندارد برای عمق نسبی
- پست وبلاگی DINOv3 (متا) — خانوادهی انکودرهایی که دقت تخمین عمق را ارتقا دادند
