Download docs/presentation/build_from_template.py from kimjunhan/vkgs-sim: direct link, hf CLI and curl.
- Browser
- Download file 82.8 kB
-
https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/docs/presentation/build_from_template.py
- Command line
-
hf download hf://kimjunhan/vkgs-sim/docs/presentation/build_from_template.py
-
curl -L -o build_from_template.py https://huggingface.co/kimjunhan/vkgs-sim/resolve/main/docs/presentation/build_from_template.py
82.8 kB
import copy
import os
import json
from PIL import Image
from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.dml.color import RGBColor
from pptx.enum.chart import XL_CHART_TYPE, XL_LABEL_POSITION
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.oxml.ns import qn
from pptx.util import Inches, Pt
A = "/tmp/claude-1000/-home-mm-Downloads-vkgs-sim/8bf0e66c-975d-4257-af27-61bc25ee4316/scratchpad/deck/"
NAVY, BLUE, LIGHT, PALE, GRAY, ORANGE, WHITE = (RGBColor(0x1F, 0x3B, 0x70), RGBColor(0x44, 0x72, 0xC4), RGBColor(0xDC, 0xE6, 0xF4),
RGBColor(0xF2, 0xF5, 0xFA), RGBColor(0x40, 0x40, 0x40), RGBColor(0xED, 0x7D, 0x31),
RGBColor(0xFF, 0xFF, 0xFF))
FONT = "๋ง์ ๊ณ ๋"
KEEP = {"์ฌ๋ผ์ด๋ ๋ฒํธ ๊ฐ์ฒด ํ 1", "์ ๋ชฉ 1", "๊ทธ๋ฃน 6", "TextBox 9", "TextBox 4"}
def shape(sl, name):
for sh in sl.shapes:
if sh.name == name:
return sh
raise KeyError(name)
def set_runs_text(tf, text):
"""์ฒซ ๋ฌธ๋จ ์ฒซ run ์ ์์์ผ๋ก text ๋ง ๋จ๊ธด๋ค."""
p0 = tf.paragraphs[0]
for p in tf.paragraphs[1:]:
p._p.getparent().remove(p._p)
runs = p0.runs
if not runs:
p0.text = text
return
runs[0].text = text
for r in runs[1:]:
r._r.getparent().remove(r._r)
def set_paragraphs(tf, items):
"""์ฒซ ๋ฌธ๋จ์ ๋ณธ์ผ๋ก ๋ฌธ๋จ๋ง๋ค ๋ณต์ฌ (๊ธ๋จธ๋ฆฌํยท๊ฐ๊ฒฉ ์ ์ง)."""
p0 = tf.paragraphs[0]._p
for p in tf.paragraphs[1:]:
p._p.getparent().remove(p._p)
parent = p0.getparent()
proto = copy.deepcopy(p0)
parent.remove(p0)
for it in items:
p = copy.deepcopy(proto)
rs = p.findall(qn("a:r"))
for r in rs[1:]:
p.remove(r)
if rs:
rs[0].find(qn("a:t")).text = it
parent.append(p)
def body(sl, tab, heading, bullets):
for sh in list(sl.shapes):
if sh.name not in KEEP:
sh._element.getparent().remove(sh._element)
set_runs_text(shape(sl, "์ ๋ชฉ 1").text_frame, "VKGS-Sim")
set_runs_text(shape(sl, "TextBox 4").text_frame, tab)
grp = shape(sl, "๊ทธ๋ฃน 6")
for c in grp.shapes:
if c.has_text_frame and c.text_frame.text.strip():
set_runs_text(c.text_frame, heading)
set_paragraphs(shape(sl, "TextBox 9").text_frame, bullets)
return 1.82 + 0.28 * sum(1 + len(b) // 95 for b in bullets) + 0.15 # ๋ณธ๋ฌธ ๋ค์ y (12pt, ์ค๊ฐ๊ฒฉ 150%)
def notes(sl, text):
sl.notes_slide.notes_text_frame.text = text
def tb(sl, x, y, w, h, text, size=12, bold=False, color=GRAY, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, font=FONT):
t = sl.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = t.text_frame
tf.word_wrap = True
tf.margin_left = tf.margin_right = Inches(0.04)
tf.margin_top = tf.margin_bottom = Inches(0.02)
tf.vertical_anchor = anchor
for i, line in enumerate(text.split("\n")):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = align
r = p.add_run()
r.text = line
r.font.size, r.font.bold, r.font.color.rgb, r.font.name = Pt(size), bold, color, font
return t
def box(sl, x, y, w, h, text, fill=LIGHT, color=GRAY, size=12, bold=False, line=None, align=PP_ALIGN.CENTER, title=None):
s = sl.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h))
s.adjustments[0] = 0.08
s.fill.solid()
s.fill.fore_color.rgb = fill
if line:
s.line.color.rgb = line
s.line.width = Pt(1.25)
else:
s.line.fill.background()
s.shadow.inherit = False
tf = s.text_frame
tf.word_wrap = True
tf.margin_left = tf.margin_right = Inches(0.1)
tf.margin_top = tf.margin_bottom = Inches(0.06)
tf.vertical_anchor = MSO_ANCHOR.MIDDLE if title is None else MSO_ANCHOR.TOP
lines = ([(title, True, size + 1)] if title else []) + [(l, bold, size) for l in text.split("\n") if l]
for i, (l, b, sz) in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = PP_ALIGN.CENTER if (title and i == 0) else align
p.space_after = Pt(3)
r = p.add_run()
r.text = l
r.font.size, r.font.bold, r.font.color.rgb, r.font.name = Pt(sz), b, color, FONT
return s
def arrow(sl, x, y, w=0.36, h=0.24, color=BLUE):
s = sl.shapes.add_shape(MSO_SHAPE.RIGHT_ARROW, Inches(x), Inches(y), Inches(w), Inches(h))
s.fill.solid()
s.fill.fore_color.rgb = color
s.line.fill.background()
s.shadow.inherit = False
return s
def image(sl, path, x, y, w=None, h=None):
iw, ih = Image.open(path).size
if w and h: # ์์ ์์ ๋ง์ถ๋ค (contain), ๊ฐ์ด๋ฐ
s = min(w / iw, h / ih)
ww, hh = iw * s, ih * s
return sl.shapes.add_picture(path, Inches(x + (w - ww) / 2), Inches(y + (h - hh) / 2), Inches(ww), Inches(hh))
if w:
return sl.shapes.add_picture(path, Inches(x), Inches(y), Inches(w), Inches(w * ih / iw))
return sl.shapes.add_picture(path, Inches(x), Inches(y), Inches(h * iw / ih), Inches(h))
def table(sl, x, y, w, rows, colw, size=11, rowh=0.3, align_right=()):
t = sl.shapes.add_table(len(rows), len(rows[0]), Inches(x), Inches(y), Inches(w), Inches(rowh * len(rows))).table
for j, cw in enumerate(colw):
t.columns[j].width = Inches(w * cw)
for i, row in enumerate(rows):
t.rows[i].height = Inches(rowh)
for j, v in enumerate(row):
c = t.cell(i, j)
c.margin_left = c.margin_right = Inches(0.08)
c.margin_top = c.margin_bottom = Inches(0.03)
c.vertical_anchor = MSO_ANCHOR.MIDDLE
c.fill.solid()
c.fill.fore_color.rgb = NAVY if i == 0 else (PALE if i % 2 == 0 else WHITE)
tf = c.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.text = ""
p.alignment = PP_ALIGN.RIGHT if (j in align_right and i > 0) else PP_ALIGN.LEFT
r = p.add_run()
r.text = str(v)
r.font.size, r.font.name = Pt(size), FONT
r.font.bold = i == 0
r.font.color.rgb = WHITE if i == 0 else GRAY
return t
def kpi(sl, x, y, w, num, label, color=NAVY):
s = box(sl, x, y, w, 1.05, "", fill=PALE, line=LIGHT)
tb(sl, x + 0.1, y + 0.08, w - 0.2, 0.55, num, size=26, bold=True, color=color, align=PP_ALIGN.CENTER)
tb(sl, x + 0.1, y + 0.64, w - 0.2, 0.35, label, size=11, color=GRAY, align=PP_ALIGN.CENTER)
return s
def caption(sl, x, y, w, text):
return tb(sl, x, y, w, 0.32, text, size=12, bold=True, color=GRAY, align=PP_ALIGN.CENTER)
import sys
prs = Presentation(sys.argv[1])
slides = list(prs.slides)
# ------------------------------------------------------------------ 1 ํ์ง
s = slides[0]
for sh in s.shapes:
if sh.name == "์ ๋ชฉ 1":
set_runs_text(sh.text_frame, "VKGS-Sim: 3D Gaussian Splatting ๊ธฐ๋ฐ Vulkan ์ฃผํ ์๋ฎฌ๋ ์ดํฐ")
elif sh.name == "๋ถ์ ๋ชฉ 2":
sh.text_frame.text = "nuScenes ์ฑ๊ฐํฌ๋ฅด ์ค์ฃผํ ๋ก๊ทธ๋ก ๋ง๋ closed-loop ์๋ฎฌ๋ ์ดํฐ"
for r in sh.text_frame.paragraphs[0].runs:
r.font.size = Pt(16)
elif sh.name == "ํ
์คํธ ๊ฐ์ฒด ํ 3":
set_runs_text(sh.text_frame, "2026. 10. 12.")
elif sh.name == "ํ
์คํธ ๊ฐ์ฒด ํ 6":
set_paragraphs(sh.text_frame, ["๊ตญ๋ฏผ๋ํ๊ต ์ฐจ๋์ง๋ฅ์ฐ๊ตฌ์ค", "kimjunhan"])
notes(s, "VKGS-Sim ์งํ ๋ณด๊ณ . ์ค์ ์ฃผํ ๋ก๊ทธ๋ก ๋ง๋ 3D ์ฅ๋ฉด ์์์ ์ฃผํ ๋ชจ๋ธ์ด ์ด์ ํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ ๋ค์ ๊ด์ธก์ ๋ฐ๊พธ๋ ์๋ฎฌ๋ ์ดํฐ๋ฅผ ์๊ฐํ๋ค.")
# ------------------------------------------------------------------ 2 ๋ชฉ์ฐจ
s = slides[1]
for sh in s.shapes:
if sh.name == "ํ
์คํธ ๊ฐ์ฒด ํ 2":
set_paragraphs(sh.text_frame, ["์ฐ๊ตฌ ๋ฐฐ๊ฒฝ ๋ฐ ๋ชฉํ", "์๋ฎฌ๋ ์ด์
์์ง ์ํคํ
์ฒ", "๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ ์ํคํ
์ฒ", "๋ฐ์ดํฐ ๋ฐ ํ์ต", "์๋ฎฌ๋ ์ด์
๊ฒฐ๊ณผ", "์งํ ํํฉ ๋ฐ ๊ณํ"])
notes(s, "๋ค์ฏ ๋ถ๋ถ์ผ๋ก ๋ฐํํ๋ค.")
def divider(sl, title, note):
for sh in sl.shapes:
if sh.name == "์ ๋ชฉ 1":
set_runs_text(sh.text_frame, title)
notes(sl, note)
divider(slides[2], "์ฐ๊ตฌ ๋ฐฐ๊ฒฝ ๋ฐ ๋ชฉํ", "๋จผ์ ์ closed-loop ์๋ฎฌ๋ ์ดํฐ๊ฐ ํ์ํ์ง์ 3DGS ๋ฅผ ์ค๋ช
ํ๋ค.")
# ------------------------------------------------------------------ 4 ์ฐ๊ตฌ ๋ฐฐ๊ฒฝ
s = slides[3]
y = body(s, "์ฐ๊ตฌ ๋ฐฐ๊ฒฝ", "์ฐ๊ตฌ ๋ฐฐ๊ฒฝ โ open-loop ํ๊ฐ์ ํ๊ณ์ closed-loop ์๋ฎฌ๋ ์ด์
", [
"๊ธฐ์กด ์ฃผํ ๋ชจ๋ธ ํ๊ฐ๋ ๊ธฐ๋ก๋ ์์์ ์
๋ ฅํ๊ณ ์ ๋ต ๊ถค์ ๊ณผ ๋น๊ตํ๋ open-loop ๋ฐฉ์์",
"๋ชจ๋ธ์ด ๋ค๋ฅด๊ฒ ์ด์ ํด๋ ๋ค์ ์์์ ๋ฐ๋์ง ์์ผ๋ฏ๋ก, ์ค์๊ฐ ๋์ ๋๋ ์ํฉ์ ํ๊ฐํ ์ ์์",
"๋ณธ ์ฐ๊ตฌ๋ ์ค์ฃผํ ๋ก๊ทธ๋ก 3D ์ฅ๋ฉด์ ์ฌ๊ตฌ์ฑํ๊ณ , ๋ชจ๋ธ์ ์ ์ด๋ก ์์ง์ธ ์์ฐจ ์์น์์ ์ 6์บ ์์์ ๋ ๋๋งํ๋ closed-loop ์๋ฎฌ๋ ์ดํฐ๋ฅผ ๊ฐ๋ฐํจ",
"๋ชฉํ: ๋จ์ผ RTX 3060 Ti (8 GB) ์์ ์ฑ๊ฐํฌ๋ฅด ๋ฎ ๋งต ์ ์ฒด (284์ฌ, 30 km) ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ ๋๋ง",
])
y = max(y, 3.55)
labels = ["6์บ ๊ด์ธก", "VLM / VLA", "์กฐํฅ ยท ๊ฐ์", "์์ฐจ ์ ๋ถ ยท ์ถฉ๋", "3DGS ๋ ๋"]
bw, gap, x0 = 2.0, 0.55, 0.85
for i, l in enumerate(labels):
x = x0 + i * (bw + gap)
box(s, x, y + 0.35, bw, 0.75, l, fill=NAVY if i == 4 else LIGHT, color=WHITE if i == 4 else NAVY, size=14, bold=True)
if i < 4:
arrow(s, x + bw + 0.1, y + 0.6)
back = s.shapes.add_shape(MSO_SHAPE.U_TURN_ARROW, Inches(x0 + 0.3), Inches(y + 1.25), Inches(4 * (bw + gap) + bw - 0.6), Inches(0.55))
back.rotation = 180
back.fill.solid()
back.fill.fore_color.rgb = LIGHT
back.line.fill.background()
back.shadow.inherit = False
tb(s, x0, y + 1.95, 4 * (bw + gap) + bw, 0.32, "๋ ๋ ๊ฒฐ๊ณผ๊ฐ ๋ค์ ๊ด์ธก์ด ๋๋ค โ ์ ์ด๊ฐ ์ฅ๋ฉด์ ๋ฐ๊พธ๋ ๋ฃจํ", size=12, bold=True, color=NAVY, align=PP_ALIGN.CENTER)
box(s, 0.85, y + 2.45, 5.6, 0.95, "๊ธฐ๋ก ์์์ ์ฌ์ โ ์ ๋ต ๊ถค์ ๊ณผ ๋น๊ต\n๋ชจ๋ธ์ด ๋ฒ์ด๋๋ ์์์ ๊ทธ๋๋ก", title="open-loop (๊ธฐ์กด)", fill=PALE, line=LIGHT, size=11)
box(s, 6.9, y + 2.45, 5.6, 0.95, "๋ชจ๋ธ์ ์กฐํฅ ยท ๊ฐ์์ผ๋ก ์์ฐจ ์ด๋\n๊ทธ ์์น์์ 6์บ ์์์ ์๋ก ๋ ๋", title="closed-loop (VKGS-Sim)", fill=PALE, line=BLUE, size=11)
notes(s, "ํต์ฌ ๋์ ์ ์๋ ๊ถค์ ์์ ๋ฒ์ด๋๋ฉด ํ์ต ์นด๋ฉ๋ผ๊ฐ ๋ณธ ์ ์๋ ์์ ์ด ๋๋ค๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ์์ ๋ณํ ์ฆ๊ฐ๊ณผ ๊ตฌ๊ฐ ๋ถํ ๊ฐ์ ์์
์ด ์ด์ด์ง๋ค.")
# ------------------------------------------------------------------ 5 3DGS
s = slides[4]
y = body(s, "์ฐ๊ตฌ ๋ฐฐ๊ฒฝ", "3D Gaussian Splatting ๊ฐ์", [
"์ฅ๋ฉด์ ์๋ฐฑ๋ง ๊ฐ์ 3D ๊ฐ์ฐ์์ (์์น ยท ๊ณต๋ถ์ฐ ยท ๋ถํฌ๋ช
๋ ยท ๊ตฌ๋ฉด์กฐํ ์) ์ผ๋ก ํํํ๋ ๋ช
์์ ์ฅ๋ฉด ํํ",
"์นด๋ฉ๋ผ๋ก ํฌ์ โ ๊น์ด์ ์ ๋ ฌ โ ์์์๋ถํฐ ์ํ ๋ธ๋ ๋ฉํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์์ฑ: C = ฮฃ cแตข ฮฑแตข ฮ (1 โ ฮฑโฑผ)",
"๋ฏธ๋ถ ๊ฐ๋ฅํ์ฌ ์ค์ ์ฌ์ง๊ณผ์ ์ค์ฐจ๋ก ํ๋ผ๋ฏธํฐ๋ฅผ ํ์ตํ๊ณ , ํ์ต ํ์๋ ๋์คํฐํ๋ก ์ค์๊ฐ ๋ ๋๋ง์ด ๊ฐ๋ฅํจ",
])
table(s, 0.85, y + 0.2, 6.1, [
["ํ๋ผ๋ฏธํฐ", "์๋ฏธ", "๋ฐ์ดํธ"],
["์์น ฮผ (xyz)", "๊ฐ์ฐ์์ ์ค์ฌ", "12"],
["์ค์ผ์ผ + ํ์ (์ฟผํฐ๋์ธ)", "๊ณต๋ถ์ฐ ฮฃ = R S Sแต Rแต", "28"],
["๋ถํฌ๋ช
๋ ฮฑ", "์ผ๋ง๋ ๊ฐ๋ฆฌ๋๊ฐ", "4"],
["๊ตฌ๋ฉด์กฐํ ๊ณ์ (3์ฐจ, 48๊ฐ)", "๋ณด๋ ๋ฐฉํฅ์ ๋ฐ๋ฅธ ์", "192"],
["ํฉ๊ณ", "๊ตฌ๊ฐ ๋ชจ๋ธ๋น 200๋ง ๊ฐ โ 0.5 GB", "236"],
], [0.38, 0.47, 0.15], size=12, rowh=0.38, align_right=(2,))
steps = [("โ ํฌ์", "ฮฃ โ ํ๋ฉด 2D ๊ณต๋ถ์ฐ\n๋ณด๋ ๋ฐฉํฅ์ SH ์"), ("โก ์ ๋ ฌ", "๋ณด์ด๋ ๊ฐ์ฐ์์๋ง\nGPU radix ์ ๋ ฌ"), ("โข ๋ธ๋ ๋ฉ", "์์์๋ถํฐ ๋์ \n๊ฐ๊น์ด ๊ฒ์ด ๊ฐ๋ฆผ")]
for i, (t, d) in enumerate(steps):
x = 7.35 + i * 1.85
box(s, x, y + 0.2, 1.55, 2.25, d, title=t, fill=PALE, line=BLUE, size=11)
if i < 2:
arrow(s, x + 1.57, y + 1.2, w=0.26, h=0.2)
tb(s, 7.35, y + 2.6, 5.3, 0.6, "ํ์ต: PyTorch + gsplat (CUDA) / ์๋ฎฌ๋ ์ดํฐ: Vulkan ์ผ๋ก ๊ฐ์ ์์ ์ฌ๊ตฌํ โ ๋ ๊ฒฐ๊ณผ๊ฐ PSNR 56 dB ๋ก ์ผ์น", size=11, bold=True, color=NAVY)
notes(s, "NeRF ์ฒ๋ผ ์ ๊ฒฝ๋ง์ด ์๋๋ผ ๋ช
์์ ์ธ ๊ฐ์ฐ์์ ์งํฉ์ด๋ค. 2D ๊ณต๋ถ์ฐ์ ฮฃ' = J W ฮฃ Wแต Jแต. ๋ธ๋ ๋ฉ ์์๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ํ๋ฏ๋ก ์ ๋ ฌ์ด ํต์ฌ ๋น์ฉ์ด๋ค.")
# ------------------------------------------------------------------ 7 ์ ์ฒด ์ํคํ
์ฒ
s = slides[5]
y = body(s, "์ฐ๊ตฌ ๋ฐฐ๊ฒฝ", "์ ์ฒด ์์คํ
์ํคํ
์ฒ", [
"๋ฐ์ดํฐ ๊ณ์ธต โ ์ฌ๊ตฌ์ฑ (CUDA) โ ๋ ๋๋ง (Vulkan) โ closed-loop ์๋ฎฌ๋ ์ด์
์ 4๋จ๊ณ๋ก ๊ตฌ์ฑ๋จ",
"ํ์ต์ ๋ฏธ๋ถ์ด ํ์ํ์ฌ PyTorch + gsplat ์, ์๋ฎฌ๋ ์ดํฐ๋ ๋ฉ์ ยท ์กฐ๋ช
ยท ํ์ฒ๋ฆฌ๋ฅผ ํ ํ๋ ์์ ์๊ธฐ ์ํด Vulkan ์ ์ฌ์ฉํจ",
"๋ชจ๋ ๋จ๊ณ๊ฐ ๋จ์ผ RTX 3060 Ti 8 GB ์์ ๋์ํ๋ฉฐ, ์กฐ์ ๊ฐ์ configs/ (sim.json, ํ์ต ํ๋ฆฌ์
, ์์
JSON) ์ ๋ ",
])
stages = [("โ ๋ฐ์ดํฐ ๊ณ์ธต", "NFS ์ nuScenes ๋ฅผ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก\nํ ๋ฒ ํ์ด ์ฌ ์ธ๋ฑ์ค ์บ์\n(6์บ ยท ํฌ์ฆ ยท ์บ๋ฆฌ๋ธ ยท ๋ผ์ด๋ค ยท ๋ฐ์ค)\n์ธ๋ฑ์ค 35.8์ด ยท ์ฌ ๋ก๋ 7 ms"),
("โก ์ฌ๊ตฌ์ฑ (CUDA)", "PyTorch + gsplat 3DGS ํ์ต\n๋ผ์ด๋ค ์ด๊ธฐํ ยท ๊น์ด ๊ฐ๋
\n์ฐจ๋ยท์ฌ๋ ๊ฐ๋ฆผ ยท ํ๋ ํ๋ธ๋งต\n60 m ๊ตฌ๊ฐ ๋จ์"),
("โข ๋ ๋๋ง (Vulkan)", "vkgs_viewer: bindless\n+ ๋ ๋ ๊ทธ๋ํ (JSON)\nGPU radix ์ ๋ ฌ ยท 6์บ ยท BEV\n๊ตฌ๊ฐ ์คํธ๋ฆฌ๋ฐ ยท ์คํ์คํฌ๋ฆฐ"),
("โฃ ์๋ฎฌ๋ ์ด์
", "์์ ๊ฑฐ ๋ชจ๋ธ ์์ฐจ\n์ฅ์ ๋ฌผ ยท ์ฐ์ ์ถฉ๋\n๋ผ์ด๋ค ยท ๋ ์ด๋ ๋ ์ด์บ์คํธ\n์คํฌ๋ฆฝํธ ์ ์ด โ ๊ด์ธก ์ ์ฅ")]
bw = 2.75
for i, (t, d) in enumerate(stages):
x = 0.85 + i * (bw + 0.38)
box(s, x, y + 0.25, bw, 1.75, d, title=t, fill=NAVY if i == 3 else PALE, color=WHITE if i == 3 else GRAY, line=None if i == 3 else BLUE, size=11)
if i < 3:
arrow(s, x + bw + 0.04, y + 1.01, w=0.3, h=0.22)
tb(s, 0.85, y + 2.15, 11.8, 0.32, "๊ฒฐ๊ณผ๋ฌผ: outputs/gs_day/<scene>/seg<k> (๊ตฌ๊ฐ ๋ชจ๋ธ) โ ๋ ๋ / ์ฆ๊ฐ (outputs/aug/map ยท outputs/aug/aug_artfixer) / ์๋ฎฌ๋ ์ดํฐ", size=11, bold=True, color=NAVY, align=PP_ALIGN.CENTER)
notes(s, "ํ์ต VRAM ์ฝ 2.3~3 GB. ์ฌ๋ฌ ๋จ๊ณ ์์
์ configs/jobs/<์ด๋ฆ>.json + nusim run ์ผ๋ก ๋๋ฆฐ๋ค.")
# ------------------------------------------------------------------ 9 ๋ ๋๋ฌ ์ฑ๋ฅ
s = slides[11]
y = body(s, "์์ง ๊ตฌ์กฐ", "Vulkan ๋ ๋๋ฌ ์ฑ๋ฅ", [
"gsplat 1.4.0 ๊ณผ ๊ฐ์ ์
ฐ์ด๋ ์์์ Vulkan ์ผ๋ก ๊ตฌํํ์ฌ ํ์ต๊ธฐ ๋ ๋์ PSNR 56 dB ๋ก ์ผ์นํจ",
"์ ๋ ฌ์ด ํ๋ ์์ 58% ๋ฅผ ์ฐจ์งํ์ฌ, ๋ณด์ด๋ ๊ฐ์ฐ์์๋ง ์์ถํ ๋ค GPU radix ์ ๋ ฌ๋ก ๊ต์ฒดํจ",
])
for i, (n, l) in enumerate([("56 dB", "ํ์ต๊ธฐ ๋ ๋์์ PSNR"), ("13ร", "์ ๋ ฌ 31~35 ms โ 2.7 ms"), ("16 ms", "1600ร900 ํ ์ฅ (์คํ์คํฌ๋ฆฐ)"), ("0.19 s", "๊ตฌ๊ฐ ๋ชจ๋ธ ๊ต์ฒด (200๋ง ๊ฐ)")]):
kpi(s, 0.85 + i * 3.0, y + 0.2, 2.75, n, l)
table(s, 0.85, y + 1.55, 11.75, [
["๊ตฌ์ฑ", "๋ด์ฉ"],
["bindless ๋ฆฌ์์ค", "์
ฐ์ด๋๊ฐ ์ฌ๋กฏ ๋ฒํธ๋ก ๋ฒํผ ยท ์ด๋ฏธ์ง๋ฅผ ๊ณ ๋ฅธ๋ค โ ์ ํจ์ค์ ๋์คํฌ๋ฆฝํฐ ์ฝ๋๊ฐ ํ์ ์์"],
["๋ ๋ ๊ทธ๋ํ", "ํ๋ ์ ๊ตฌ์ฑ์ JSON ์ด ์ ํ๊ณ ๋ฐฐ๋ฆฌ์ด๋ ๊ทธ๋ํ๊ฐ ์๋์ผ๋ก ์ฝ์
(๊ฒ์ฆ ๋ ์ด์ด ๋๊ธฐํ ๊ฒ์ฆ)"],
["์ ํ๋", "RGBA16F ๋์คํฐ (32๋นํธ ๋๋น 64 dB), ๊ฑฐ๋ฆฌ ๋์ r32f, ํ์ต๊ธฐ ๋น๊ต ์ FXAA ๋"],
["๋ ๋ ํ๊ฒ ยท ์ ๋ ฌ", "16/32๋นํธ ยท radix/bitonic ยท FXAA ๋ฅผ ๊ทธ๋ํ JSON ๊ณผ sim.json ์ผ๋ก ์ ํ"],
], [0.22, 0.78], size=12, rowh=0.4)
tb(s, 0.85, y + 3.7, 11.75, 0.3, "* ์์น๋ ํ์ต๊ณผ GPU ๋ฅผ ํจ๊ป ์ฐ๋ ์ํ์์ ์ธก์ ", size=10, color=GRAY)
notes(s, "56 dB ๋ nusim render compare ๋ก ๊ฐ์ ์นด๋ฉ๋ผ์์ ํ์ต๊ธฐ ๋ ๋์ ๋น๊ตํ ๊ฐ. 800ร450 ์์๋ ์ฅ๋น 6.8 ms.")
divider(slides[18], "๋ฐ์ดํฐ ๋ฐ ํ์ต", "nuScenes ๋ฐ์ดํฐ, ํ์ต ๋ฐฉ๋ฒ, ์ฌ๊ตฌ์ฑ ๊ฒฐ๊ณผ, ์ฆ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ค๋ช
ํ๋ค.")
# ------------------------------------------------------------------ 12 ๋ฐ์ดํฐ์
s = slides[19]
y = body(s, "๋ฐ์ดํฐ", "nuScenes ์ฑ๊ฐํฌ๋ฅด ๋ฐ์ดํฐ์
", [
"nuScenes 850์ฌ ์ค ์ฑ๊ฐํฌ๋ฅด 383์ฌ์ ์ฌ์ฉ (๋ณด์คํด 467์ฌ ์ ์ธ) โ 6์บ 1600ร900 ์ฝ 11.7 Hz, ์ด๋ฏธ์ง 532,157์ฅ, 32์ฑ๋ ๋ผ์ด๋ค + ๋ ์ด๋ 5๋",
"๋ฐค ์์์ ๋๋ฌด ์ด๋์ ์ฌ๊ตฌ์ฑ ํ์ง์ด ๋ฎ์ผ๋ฏ๋ก ๋ฎ 284์ฌ (์ฃผํ ๊ฒฝ๋ก 30 km) ์ผ๋ก ๋งต์ ๊ตฌ์ฑํจ โ ๊ทธ์ค 77% ๊ฐ 3 m/s ์ด์์ ๋น ๋ฅธ ์ฃผํ",
])
table(s, 0.85, y + 0.2, 3.9, [["์ง์ญ", "์ ์ฒด", "๋ฎ"], ["one-north", "183", "183"], ["queenstown", "115", "82"],
["holland village", "85", "19"], ["ํฉ๊ณ", "383", "284"]], [0.52, 0.24, 0.24], size=12, rowh=0.4, align_right=(1, 2))
tb(s, 0.85, y + 2.35, 3.9, 0.9, "ํคํ๋ ์ (์ด๋
ธํ
์ด์
) 2 Hz, ๊ทธ ์ฌ์ด sweep ๊น์ง ํ์ต์ ์ฌ์ฉ. ์๋ณธ์ NFS ๊ณต์ฉ ๋ณผ๋ฅจ์์ ์ฝ๊ธฐ ์ ์ฉ.", size=11, color=GRAY)
image(s, A + "gt_6cam.jpg", 5.05, y + 0.2, w=7.6, h=2.85)
caption(s, 5.05, y + 3.1, 7.6, "์ค์ 6์บ ์ฌ์ง (scene-0402) โ ์: ์์ผ์ชฝ ยท ์ ยท ์์ค๋ฅธ์ชฝ / ์๋: ๋ค์ค๋ฅธ์ชฝ ยท ๋ค ยท ๋ค์ผ์ชฝ")
notes(s, "CAM_BACK ๋ง HFOV 89ยฐ (fx 809), ๋๋จธ์ง 5๋๋ ์ฝ 64ยฐ (fx ์ฝ 1260). ๋ฐค โ ๋ฎ ๋ณํ (CycleGAN-Turbo) ์ ์ผ์ ์ก์์ ํค์ ์ธ ์ ์์๋ค.")
# ------------------------------------------------------------------ 13 ํ์ต ๋ฐฉ๋ฒ
s = slides[20]
y = body(s, "ํ์ต", "ํ์ต ๋ฐฉ๋ฒ ๋ฐ ๊ตฌ๊ฐ ๋ถํ ", [
"๋ผ์ด๋ค ๋์ ์ผ๋ก ๊ฐ์ฐ์์์ ์ด๊ธฐํํ๊ณ ๊น์ด ๊ฐ๋
(ฮป = 0.1), gsplat MCMC ๋ฐ๋ ์ ์ด (์ต๋ 200๋ง ๊ฐ), ํ๋ ํ๋ธ๋งต ๋ถ๋ฆฌ๋ฅผ ์ ์ฉํจ",
"์ฐจ๋ ยท ์ฌ๋์ 3D ๋ฐ์ค๋ก ๊ฐ๋ ค ํ๊ฒฝ ์ ์ฉ ๋งต์ ํ์ตํ๊ณ , ์นด๋ฉ๋ผ๋ณ ์ ์ํ ยท ์ธ๋ถ ํ๋ผ๋ฏธํฐ๋ฅผ ํจ๊ป ๋ณด์ ํจ โ ๊ตฌ๊ฐ๋น 15k ์คํ
, ์ฝ 20๋ถ",
"๋น ๋ฅธ ์ฌ์ ํต์งธ๋ก ํ์ตํ๋ฉด ์ ํฉ ์์ฒด๊ฐ ์คํจํ์ฌ 60 m ๊ตฌ๊ฐ (10 m ๊ฒน์นจ) ์ผ๋ก ๋๋ ํ์ตํจ โ 284์ฌ โ 696 ํ์ต ๋จ์",
])
cd = CategoryChartData()
cd.categories = ["์ฌ ํต์งธ", "๊ตฌ๊ฐ 1", "๊ตฌ๊ฐ 2", "๊ตฌ๊ฐ 3", "๊ตฌ๊ฐ 4", "๊ตฌ๊ฐ 5"]
cd.add_series("์ ์ PSNR (dB)", (16.23, 23.78, 22.76, 23.04, 23.02, 22.70))
gf = s.shapes.add_chart(XL_CHART_TYPE.COLUMN_CLUSTERED, Inches(0.85), Inches(y + 0.1), Inches(7.2), Inches(3.3), cd)
ch = gf.chart
ch.has_legend = False
ch.has_title = True
ch.chart_title.text_frame.text = "scene-0402 (11.9 m/s, 235 m) ์ ์ PSNR (dB)"
ch.chart_title.text_frame.paragraphs[0].runs[0].font.size = Pt(12)
ch.chart_title.text_frame.paragraphs[0].runs[0].font.bold = True
pl = ch.plots[0]
pl.gap_width = 60
pl.has_data_labels = True
pl.data_labels.font.size = Pt(11)
pl.data_labels.number_format = "0.00"
pl.data_labels.number_format_is_linked = False
pl.data_labels.position = XL_LABEL_POSITION.OUTSIDE_END
ser = pl.series[0]
ser.format.fill.solid()
ser.format.fill.fore_color.rgb = BLUE
pt0 = ser.points[0]
pt0.format.fill.solid()
pt0.format.fill.fore_color.rgb = RGBColor(0xA5, 0xA5, 0xA5)
va = ch.value_axis
va.minimum_scale, va.maximum_scale = 0, 30
va.has_major_gridlines = True
va.major_gridlines.format.line.color.rgb = RGBColor(0xE0, 0xE0, 0xE0)
va.tick_labels.font.size = Pt(10)
ch.category_axis.tick_labels.font.size = Pt(11)
box(s, 8.35, y + 0.15, 4.3, 3.2, "ํต์งธ ํ์ต์ ํ์ต ์์ค๋ถํฐ ๋์๋ค\n(L1 0.135 vs 0.05) โ ์ผ๋ฐํ๊ฐ ์๋๋ผ ์ ํฉ ์คํจ\n\n์์ธ์ ์ฅ๋ฉด ๊ธธ์ด\n(์ ๋ต ยท ๊น์ด ๊ฐ๋
ยท ์นด๋ฉ๋ผ ๋ณด์ ์ ์์ธ ์๋)\n\n๊ตฌ๊ฐ ๊ฒฝ๊ณ ํ๋ ์ 4์์์\n์ ยท ๊ธฐํ ์ด์๋งค ์์",
title="+7.5 dB (16.23 โ 23.78)", fill=PALE, line=BLUE, size=11)
notes(s, "๋ฎ 284์ฌ ์ค 77% (218์ฌ) ๊ฐ 3 m/s ๋ฅผ ๋์ด ๊ตฌ๊ฐ ๋ถํ ์ด ํ์๋ค. ๊ตฌ๊ฐ์ ๊ฐ์ ๊ธธ์ด๋ก ๋๋๋ 60 m ์ดํ, ์ด์ 10 m ๊ฒน์นจ. 1๋จ๊ณ ๊ธฐ์ค์ ์ scene-0003 6๋ง ์คํ
PSNR 25.62 / SSIM 0.804.")
# ------------------------------------------------------------------ 14 ์ฌ๊ตฌ์ฑ ๊ฒฐ๊ณผ
s = slides[21]
y = body(s, "ํ์ต", "์ฌ๊ตฌ์ฑ ๊ฒฐ๊ณผ", [
"ํ์ต ์์ ์ฌํ: ๊ฐ์ ์นด๋ฉ๋ผ ยท ๊ฐ์ ์๊ฐ์ ์ค์ ์ฌ์ง๊ณผ ์ฌ๊ตฌ์ฑ ๋ ๋๋ฅผ ๋น๊ต (scene-0008) โ ๋ ๋์์๋ ์ฃผ์ฐจ ์ฐจ๋์ด ์ ๊ฑฐ๋จ (ํ๊ฒฝ ์ ์ฉ ๋งต)",
"๊ตฌ๊ฐ ์ ์ PSNR ์ค์๊ฐ 24.7 dB (84 ๋จ์), ํ์ 10% 22.1 dB, ํ์ต ์คํจ 0๊ฑด",
])
image(s, A + "recon_vs_gt.jpg", 0.85, y + 0.15, w=11.8, h=3.3)
caption(s, 0.85, y + 3.5, 5.9, "์ค์ ์ฌ์ง โ")
caption(s, 6.75, y + 3.5, 5.9, "3DGS ๋ ๋ (์ฐจ๋ ์ ๊ฑฐ) โ")
notes(s, "์ด ๊ทธ๋ฆผ์ ํ์ต์ ์ด ์์ ์ ์ฌํ์ด๋ค. ํ์ต์์ ๋บ ์ ์ฐจ์ ์ฃผํ์ ์ค์ ์ฌ์ง์ผ๋ก ์ฌ๋ฉด ์ฝ 16.5 dB ๋ก ํฌ๊ฒ ๋จ์ด์ง๋ค โ ์ ์์ ํ์ง์ด ๋จ์ ํต์ฌ ๊ณผ์ ๋ค.")
# ------------------------------------------------------------------ 15 ์ฆ๊ฐ ๊ฒฐ๊ณผ
s = slides[22]
y = body(s, "์ฆ๊ฐ", "์์ ๋ณํ ๋ฐ์ดํฐ ์ฆ๊ฐ ๊ฒฐ๊ณผ", [
"๋ณํ 9์ข
: ์ข์ฐ 0.5 ยท 1 m ์ด๋, ๋์ด +0.4 / โ0.3 m, ์๋๋ก 3ยฐ, ์ข์ฐ 4ยฐ ํ์ โ ํคํ๋ ์ 2 Hz, ์ฐจ๋ ๋ฏธํฌํจ (ํ๊ฒฝ ์ ์ฉ ๋งต)",
"ํ์ฌ 32์ฌ ์๋ฃ: 70,824์ฅ (14 GB) โ 284์ฌ ์๋ฃ ์ ์ฝ 61๋ง ์ฅ์ผ๋ก ๋ฎ ๋ฐ์ดํฐ๊ฐ 9๋ฐฐ๊ฐ ๋จ",
])
pic = image(s, A + "aug_grid.jpg", 0.85, y + 0.15, w=11.8)
gh = pic.height / 914400
names = ["์๋ณธ (์ค์ )", "left 1 m", "left 0.5 m", "right 0.5 m", "right 1 m", "high 0.4 m", "low 0.3 m", "pitch down 3ยฐ", "yaw left 4ยฐ", "yaw right 4ยฐ"]
cw = 11.8 / 5
for i, n in enumerate(names):
r, c = divmod(i, 5)
t = tb(s, 0.85 + c * cw + 0.05, y + 0.15 + r * gh / 2 + 0.04, 1.3, 0.26, n, size=10, bold=True, color=WHITE)
t.fill.solid()
t.fill.fore_color.rgb = ORANGE if i == 0 else NAVY
table(s, 0.85, y + 0.3 + gh, 11.8, [["ํญ๋ชฉ", "๋ด์ฉ"], ["๊ฒฐ๊ณผ ๊ฒฝ๋ก", "outputs/aug/map/<scene>/<variant>/<CAM>/<์๋ณธ ํ์ผ๋ช
>.jpg + meta.json (๋ฐ๋ calibrated_sensor, ์๋ณธ ํ์ผ ยท ํฌ์ฆ)"],
["ํ๊ณ", "์ 1 m ์์ ๋
ธ๋ฉด ๋ฒ์ง ยท ์ง์ด ์ฐจ๋ ์๋ฆฌ (์ค๋ฅธ์ชฝ ์นํฉ์ฐจ) ๊ฐ ํ๋ฆฟํ๊ฒ ๋จ์"]], [0.15, 0.85], size=11, rowh=0.34)
notes(s, "์ ์ฌ์ด ๋์ด๋๋ ๊ฒ์ด ์๋๋ผ ๊ฐ์ ์ฌ์ '๋ค๋ฅธ ์นด๋ฉ๋ผ ๋ฐฐ์น' ๋ฒ์ ์ด 9๊ฐ ์๊ธด๋ค. ํ์ต์ด ์ฌ์ ๋๋ด๋ฉด ๋ฐ๋ก ์ด์ด์ ์ฆ๊ฐํ๋ค (nusim run day_map).")
divider(slides[23], "์๋ฎฌ๋ ์ด์
๊ฒฐ๊ณผ", "์๋ฎฌ๋ ์ดํฐ ๊ตฌ์ฑ, ๊ตฌ๊ฐ ์คํธ๋ฆฌ๋ฐ๊ณผ ์ถฉ๋, ์ผ์, ์๊ฐํ๋ฅผ ๋ณด์ธ๋ค.")
# ------------------------------------------------------------------ 17 ์๋ฎฌ๋ ์ด์
๊ตฌ์ฑ
s = slides[24]
y = body(s, "์๋ฎฌ๋ ์ด์
", "์๋ฎฌ๋ ์ด์
๊ตฌ์ฑ", [
"์ฌ๊ตฌ์ฑ ์ฅ๋ฉด ์์ ์์ฐจ ยท ๋ฌผ๋ฆฌ ยท ์ผ์๋ฅผ ์น์ด, ๋ชจ๋ธ์ ์ ์ด โ ๋ค์ ๊ด์ธก์ ๋ฃจํ๋ฅผ ๊ตฌ์ฑํจ",
])
table(s, 0.85, y + 0.15, 11.8, [
["๊ตฌ์ฑ ์์", "๊ตฌํ"],
["์์ฐจ", "ํค๋ค๋งํฑ ์์ ๊ฑฐ ๋ชจ๋ธ (์กฐํฅ ยท ๊ฐ์ ยท ํ์ง), glTF ์ฐจ๋ (Suzuki Carry) ๋ฐํด ๊ตฌ๋ฆ ยท ์์คํ์
, ์ ์ง ์ํ๋ก ์์"],
["์ถฉ๋", "์ ์ ๋ผ์ด๋ค๋ก ๋ง๋ ์ฅ์ ๋ฌผ ์ง๋ (0.2 m) + ์ฃผํ๊ฐ๋ฅ์์ญ ๊ฒฝ๊ณ (์ฐ์). ์ค์นจ (2์ ์ดํ) ๊ณผ ๋น ์ ธ๋๊ฐ๋ ์์ง์์ ํ์ฉ"],
["๋งต ๋ก๋", "๊ตฌ๊ฐ ๋ชจ๋ธ ์คํธ๋ฆฌ๋ฐ โ ์์ฐจ ์์น์ ๊ตฌ๊ฐ์ ๊ทธ๋ฆฌ๊ณ ์ด์ ๊ตฌ๊ฐ์ ๋ฏธ๋ฆฌ ์ฝ์ด ๊ฒฝ๊ณ์์ 0.19์ด ๋ง์ ๊ต์ฒด"],
["์ผ์", "6์บ (ํ์ต๊ณผ ๊ฐ์ ์บ๋ฆฌ๋ธ) + ๋ ์ด์บ์คํธ ๋ผ์ด๋ค 1๋ ยท ๋ ์ด๋ 5๋, ํจ๋์์ ๋ณด๊ธฐ ์ผ๊ธฐ"],
["์ ์ด ์ธํฐํ์ด์ค", "ํค๋ณด๋ ๋๋ ์คํฌ๋ฆฝํธ (--controls, 50 ms ๊ณ ์ ์คํ
) โ ๊ตฌ๊ฐ๋ง๋ค 6์บ ยท ์ผ์ ๊ด์ธก ์ ์ฅ (VLA ์ฐ๊ฒฐ ์๋ฆฌ)"],
["๊ธฐ๋ก", "drive_log.csv: ์์น ยท ์๋ ยท ๋๋ก ์ดํ ยท ์๋ ๊ถค์ ์์ ๋ฒ์ด๋ ๊ฑฐ๋ฆฌ ยท ์ถฉ๋ ์ข
๋ฅ"],
], [0.18, 0.82], size=12, rowh=0.52)
notes(s, "ํฉ์ฑ ๋ ์จ (๋น ยท ์๊ฐ ยท ๋ฐค, ์ฌ๋ผ์ด๋ UI) ๋ ๊ตฌํ๋ผ ์์ง๋ง ๋
ผ๋ฌธ ๋ฒ์์์ ๋บ๋ค. ๋ค๋ฅธ ๊ตํต ์ฐธ๊ฐ์๋ ์์ง ์๋ค.")
# ------------------------------------------------------------------ 18 ์คํธ๋ฆฌ๋ฐ ยท ์ถฉ๋
s = slides[25]
y = body(s, "์๋ฎฌ๋ ์ด์
", "๊ตฌ๊ฐ ์คํธ๋ฆฌ๋ฐ ๋ฐ ์ถฉ๋ ํ์ ๊ฐ์ ", [
"๊ตฌ๊ฐ ๋ชจ๋ธ ์คํธ๋ฆฌ๋ฐ: ๋ฒํผ๋ฅผ ๊ฐ์ฅ ํฐ ๊ตฌ๊ฐ ํฌ๊ธฐ๋ก ํ ๋ฒ ์ก๊ณ ๊ฒฝ๊ณ์์ ๋ด์ฉ๋ง ๊ต์ฒด, 3 m ํ์คํ
๋ฆฌ์์ค๋ก ๊น๋นก์ ๋ฐฉ์ง",
"์ฅ์ ๋ฌผ ์ง๋ ๊ฐ์ : ๊ธด ์ฌ์ ๋ผ์ด๋ค ๋ฒ์ง์ผ๋ก ์ง๋ฉด์ด ๋ฎ๊ฒ ์กํ๊ณ ๊ฐ๋ก์ ์๋ ๋
ธ๋ฉด์ด '๊ตฌ์กฐ๋ฌผ' ๋ก ๋จ๋ ๋ฌธ์ ์์ โ ๋
ธ๋ฉด ์ ์นธ 11,091 โ 83",
])
image(s, A + "segrun_seams.jpg", 0.85, y + 0.15, w=6.2, h=3.2)
caption(s, 0.85, y + 3.38, 6.2, "๊ตฌ๊ฐ ๊ฒฝ๊ณ 4๊ณณ (ํ) ์ ๊ฒฝ๊ณ ์ ํ ํ๋ ์ โ ์ด์๋งค ์์")
image(s, A + "obst_cmp.png", 7.35, y + 0.15, w=5.3, h=3.2)
caption(s, 7.35, y + 3.38, 5.3, "์ฅ์ ๋ฌผ ์ง๋ ๊ฐ์ ์ / ํ (ํ๋ ์๋ ๊ฒฝ๋ก, ๋นจ๊ฐ ์ถฉ๋ ์ง์ )")
notes(s, "์ง๋ฉด = ์ฒซ ๋นฝ๋นฝํ 10 cm ์ธต, ๋
ธ๋ฉด์์ ๋จ๊ธฐ๋ ์นธ = ์ง๋ฉด ์ 2~3 m ์ ์ ์ด ์๋ ์นธ (๊ธฐ๋ฅ ยท ์ค๊ธฐ ยท ๋ฒฝ). ์ค์นจ ํ์ ๊ณผ ๋น ์ ธ๋๊ฐ๊ธฐ ํ์ ์ผ๋ก '๋ณด์ด์ง ์๋ ๋ฌผ์ฒด์ ๊ฐํ๋' ๋ฌธ์ ๋ ํด๊ฒฐํ๋ค.")
# ------------------------------------------------------------------ 19 ์ผ์
s = slides[26]
y = body(s, "์ผ์", "๋ ์ด์บ์คํธ ๋ผ์ด๋ค ยท ๋ ์ด๋ ์ผ์", [
"์นด๋ฉ๋ผ์ฒ๋ผ ์์ฐจ์ ์ฅ์ฐฉํ๋ ์ผ์ (CARLA ray-cast ๋ฐฉ์) โ 3DGS ๊น์ด๊ฐ ์๋๋ผ ์ค์ ๋ผ์ด๋ค ๋์ ๋ณต์
์๋ (์ง๋ฉด 0.5 m ๋์ด ์ง๋) ์ ๊ด์ ์ ์จ",
"๋น์ด ๋ ์ง๋๊ฐ๋ ์นธ์ ์ง์ฐ๋ ๋น ๊ณต๊ฐ ๊น๊ธฐ๋ก ์ง์ด ์ฐจ๋์ ์ํด๋ฅผ ์ ๊ฑฐ โ ์ค์ ๋ผ์ด๋ค ๋๋น ๊ฐ์ ๋ฐฉํฅ ๊ฑฐ๋ฆฌ ์ค์ฐจ ์ค์๊ฐ 24% โ 3.9~5.9%",
])
image(s, A + "sensors_sim.png", 0.85, y + 0.15, w=4.3, h=3.2)
caption(s, 0.85, y + 3.38, 4.3, "์๋ฎฌ ๋ผ์ด๋ค + ๋ ์ด๋ 5๋ (10 m/s ์ฃผํ)")
image(s, A + "sensors_real.png", 5.35, y + 0.15, w=4.3, h=3.2)
caption(s, 5.35, y + 3.38, 4.3, "์ค์ nuScenes ๋ผ์ด๋ค (๊ฐ์ ์๊ฐ)")
table(s, 9.9, y + 0.15, 2.75, [["๊ฑฐ๋ฆฌ ์ค์ฐจ", "์ค์๊ฐ"], ["์ฒ์", "24%"], ["scene-0402", "5.9%"], ["scene-0003", "3.9%"]], [0.6, 0.4], size=11, rowh=0.38, align_right=(1,))
tb(s, 9.9, y + 1.8, 2.75, 1.6, "๋ผ์ด๋ค 32์ฑ๋ ํ ๋ฐํด 4 ms\n๋ ์ด๋: ๋ํ๋ฌ vr ยท ๋ณด์ ์๋\n๋
ธ๋ฉด ๋ฐ์ฌ ์ ๊ฑฐ\nO ํค๋ก nuScenes ํ์ .bin ์ ์ฅ\n\n๋ ์ด๋ ์: ๋นจ๊ฐ ๋ค๊ฐ์ด ยท ํ๋ ๋ฉ์ด์ง ยท ๋
ธ๋ ์ ์ง", size=10, color=GRAY)
notes(s, "์ค์ ์ sim.json sensors (HDL-32E ๊ทผ์ฌ, ARS 408 ๊ทผ์ฌ, nuScenes ์ฅ์ฐฉ ์์น ๊ทผ์ฌ). ์ค์ ์ชฝ ๊ฐ๊น์ด ๋ฉ์ด๋ฆฌ๋ ๊ทธ ์๊ฐ์ ์ค์ ์ฐจ ยท ์ฌ๋์ผ๋ก ํ๊ฒฝ ์ ์ฉ ๋งต์๋ ์๋ค. ๋จ์ ๊ฒ: ๋ค๋ฅธ ์ฐจ๋์ ์ค์ ๋์ด ยท ์๋, ๋ผ์ด๋ค ์ธ๊ธฐ.")
# ------------------------------------------------------------------ 20 ์๊ฐํ
s = slides[27]
y = body(s, "์๊ฐํ", "์๋ฎฌ๋ ์ดํฐ ์๊ฐํ โ ์ค์ 6์บ vs ์ฌ๊ตฌ์ฑ 6์บ ", [
"scene-0402 (235 m) ๋ฅผ ๊ตฌ๊ฐ 5๊ฐ๋ก ์ด์ด 6์บ ์ผ๋ก ๋ ๋ โ 238ํ๋ ์ ร 6์บ ์ 13์ด์ ๋ ๋๋ง (์ฅ๋น 6.8 ms, 800ร450), ๊ตฌ๊ฐ ๊ต์ฒด 4ํ",
])
image(s, A + "gt_6cam.jpg", 0.85, y + 0.15, w=5.85, h=2.25)
caption(s, 0.85, y + 2.45, 5.85, "์ค์ nuScenes 6์บ โ")
vw, vh = 5.85, 5.85 * 720 / 1920 # ์์ 1920ร720 โ ์ ์ฌ์ง๊ณผ ๊ฐ์ ๋๋น
import os
if os.environ.get("NOVIDEO"):
image(s, A + "drive_6cam_still.jpg", 6.8, y + 0.15, w=5.85, h=2.25)
else:
mv = s.shapes.add_movie(A + "drive_6cam.mp4", Inches(6.8), Inches(y + 0.15 + (2.25 - vh) / 2), Inches(vw), Inches(vh),
poster_frame_image=A + "drive_6cam_still.jpg", mime_type="video/mp4")
mv.name = "์ฃผํ ์์"
caption(s, 6.8, y + 2.45, 5.85, "VKGS-Sim ์ฌ๊ตฌ์ฑ ์ฃผํ ์์ (ํด๋ฆญํ๋ฉด ์ฌ์) โ")
box(s, 0.85, y + 2.95, 11.8, 0.75, "์ฃผํ ์์: 20์ด, 12 fps, 6์บ ๋ชจ์์ดํฌ โ ์: ์์ผ์ชฝ ยท ์ ยท ์์ค๋ฅธ์ชฝ / ์๋: ๋ค์ค๋ฅธ์ชฝ ยท ๋ค ยท ๋ค์ผ์ชฝ\n์๋ฎฌ๋ ์ดํฐ์์ ์ง์ ์ฃผํ: nusim render view scene-0402 --model outputs/gs_day/scene-0402", fill=PALE, line=LIGHT, size=11)
notes(s, "์ค๋ฅธ์ชฝ ์์์ ํด๋ฆญํ๋ฉด ์ฌ์๋๋ค. ์ฌ์ ์ ํ์ ํ๋ฉด์ ์ผ์ชฝ ์ค์ ์ฌ์ง๊ณผ ๊ฐ์ ์๊ฐ(120๋ฒ์งธ ํ๋ ์)์ด๋ค. ์ฐจ๋ ยท ์ฌ๋์ ์ง์ด ํ๊ฒฝ ์ ์ฉ ๋งต์ด๋ค.")
divider(slides[34], "์งํ ํํฉ ๋ฐ ๊ณํ", "์ฑ๊ฐํฌ๋ฅด ๋ฎ ๋งต ๊ตฌ์ถ ํํฉ๊ณผ ํฅํ ๊ณํ.")
# ------------------------------------------------------------------ 22 ์งํ ํํฉ
s = slides[36]
y = body(s, "์งํ ํํฉ", "์ฑ๊ฐํฌ๋ฅด ๋ฎ ๋งต ๊ตฌ์ถ ํํฉ (2026-10-12)", [
"ํ์ต ๋จ์ 696๊ฐ ์ค 253๊ฐ (36%) ์๋ฃ โ ์ ๋๋ก๋ฅผ ๋ง์ด ๋ฎ๋ ์ฌ ์์๋ก ํ์ต ์ค, ์ ์ PSNR ์ค์๊ฐ 24.67 dB",
"์ต๊ทผ 48์๊ฐ ์๋ (์๊ฐ๋น ์ฝ 2.6 ๋จ์) ๊ธฐ์ค ๋จ์ 443๋จ์์ ์ฝ 7์ผ โ 10์ 19์ผ ๋ฌด๋ ต ์๋ฃ ์์",
])
for i, (n, l) in enumerate([("253 / 696", "ํ์ต ๋จ์ (36%)"), ("75", "์ฆ๊ฐ์ด ๋๋ ์ฌ (๋ณํ 9์ข
)"), ("161k", "์ฆ๊ฐ ์ด๋ฏธ์ง (32 GB)"), ("51์ฌ", "one-north ์ง์ญ ๋งต (๊ตฌ๊ฐ 149๊ฐ)")]):
kpi(s, 0.85 + i * 3.0, y + 0.15, 2.75, n, l)
table(s, 0.85, y + 1.5, 11.75, [["ํญ๋ชฉ", "10์ 10์ผ", "10์ 12์ผ"], ["์๋ฃ ํ์ต ๋จ์", "84", "253"], ["์ฆ๊ฐ ์ฌ ยท ์ด๋ฏธ์ง", "32์ฌ ยท 70.8k", "75์ฌ ยท 160.9k"],
["์ง์ญ ๋งต", "์ฌ ํ๋ ์์ ๊ตฌ๊ฐ๋ง", "one-north 51์ฌ ยท ๊ตฌ๊ฐ 149๊ฐ ยท ์ผ์ 51/51"],
["๋ค์ ํ์ตํ ๋จ์", "0", "72 (NAS ์ฅ์ ๋ ์คํจ โ ๋ค์ ํ์ฐจ์ ์๋ ์ฌํ์ต)"]], [0.3, 0.25, 0.45], size=12, rowh=0.4)
notes(s, "์คํจ 72๊ฐ๋ 10์ 10์ผ ์ ๋
NAS ์ฅ์ (์ฝ 40๋ถ) ๋์ ๋ฐ์ดํฐ์
์ ๋ชป ์ฝ์ ๊ฒ์ผ๋ก, ๋๊ธฐ ยท ์ฌ์๋ ๋ก์ง์ ๋ฃ์ ๋ค๋ก ์ ์คํจ๋ ์๋ค. ๋์คํฌ ์ฌ์ 641 GB.")
# ------------------------------------------------------------------ 21b ์ง์ญ ๋งต (์)
s = slides[28]
y = body(s, "์๋ฎฌ๋ ์ด์
", "์ง์ญ ๋งต โ ์ฌ ์ฌ์ด๋ฅผ ์ด์ด ๋ฌ๋ฆฌ๊ธฐ (one-north)", [
"ํ์ต๋ 60๊ฐ ์ฌ ยท 179๊ฐ ๊ตฌ๊ฐ์ ๊ณตํต ์์ ํ๋๋ก ๋ฌถ์ โ ์์ฐจ์ ๊ฐ์ฅ ๊ฐ๊น์ด ๊ตฌ๊ฐ์ ๊ทธ๋ฆฌ๊ณ ๊ฐ๊น์ด 3๊ฐ๋ฅผ ๋ฏธ๋ฆฌ ์ฝ์ด ์ฌ ๊ฒฝ๊ณ๋ฅผ ๋์ด ๊ณ์ ์ฃผํ",
"๋ผ์ด๋ค ยท ๋ ์ด๋ ๋ณต์
์๋๋ ์ฌ๋ง๋ค ๋ฐ๋ก ๋๊ณ (์ง์ญ ์ ์ฒด ํ ๊ฒฉ์๋ 1 GB ์ด๊ณผ) ๋ฌ๋ฆฌ๋ ๊ตฌ๊ฐ์ ์ฌ ๊ฒ์ผ๋ก ๊ต์ฒด โ 179๊ฐ ๊ตฌ๊ฐ ๋ชจ๋ ์ผ์ ๋ฐ์ดํฐ ํ์ธ",
])
image(s, A + "region_onenorth.png", 0.85, y + 0.15, h=3.3)
caption(s, 0.85, y + 3.48, 3.4, "one-north ์ง์ญ ๋งต: ํ์ = ๋ณต์
์๋, ์ ์ = ๊ตฌ๊ฐ, โ
์ถ๋ฐ")
image(s, A + "strip_all.png", 4.45, y + 0.15, w=5.87, h=3.3)
caption(s, 4.45, y + 3.48, 5.87, "์ฃผํ ํ๋ฉด โ ์ ๋ฐฉ ์นด๋ฉ๋ผ 3๋ ยท BEV ๋ฅผ ํ๋ฉด ์์ชฝ ํ ์ค์ (V ยท N)")
table(s, 10.5, y + 0.15, 2.15, [["ํญ๋ชฉ", "๊ฐ"], ["์ฌ", "60"], ["๊ตฌ๊ฐ", "179"], ["๋ณต์
์๋", "60 / 60"], ["์ถ๋ฐ", "0042"]], [0.55, 0.45], size=11, rowh=0.38, align_right=(1,))
tb(s, 10.5, y + 2.2, 2.15, 1.4, "ํ ยท ๊ฐ์ด๋ฐ ๋ฒํผ ๋๋๊ทธ๋ก ์ฐจ ๋ค ์์ ๊ฑฐ๋ฆฌ 0.4~5๋ฐฐ\n\n์ถฉ๋์ ์์ง ์ฐ์๋ง (์ง์ญ ๋จ์ ์ฅ์ ๋ฌผ ์ง๋๋ ๋ค์ ๋จ๊ณ)", size=10, color=GRAY)
notes(s, "nusim render map singapore-onenorth. ์ผ์๊ฐ ์ผ๋ถ ๊ตฌ๊ฐ์์ ๊บผ์ง๋ ์์ธ: ์ฌ์ ๊ตฌ๊ฐ์ด ํ๋ ๋ ํ์ต๋ ๋๋ง๋ค ๋ณต์
์๋๋ฅผ '๋ก์' ์ผ๋ก ๋ณด๊ณ ๊ป๋ค. ๋ณต์
์ ์ฌ ์ ์ฒด ๋ผ์ด๋ค๋ก ๋ง๋ค์ด ๊ธฐํ๊ฐ ๊ทธ๋๋ก์ด๋ฏ๋ก, ๋ง๋ ์์ ์ ๊ธฐ๋กํด ๊ทธ๋๋ก ์ฐ๊ฒ ๊ณ ์ณค๋ค.")
# ------------------------------------------------------------------ 21d ์ผ์ ์ฃผํ ์์ (์)
V = "/home/mm/Downloads/vkgs-sim/outputs/videos/"
def movie(sl, name, x, y, w, h):
"""์์ (NOVIDEO=1 ์ด๋ฉด ํ์ง ํ๋ฉด๋ง โ PDF ์ฉ). 1280ร720 ์ ์์ ์์ ๋ง์ถ๋ค."""
vh = min(h, w * 9 / 16)
vw = vh * 16 / 9
xx, yy = x + (w - vw) / 2, y + (h - vh) / 2
if os.environ.get("NOVIDEO"):
return image(sl, V + name + "_poster.jpg", xx, yy, w=vw, h=vh)
mv = sl.shapes.add_movie(V + name + ".mp4", Inches(xx), Inches(yy), Inches(vw), Inches(vh),
poster_frame_image=V + name + "_poster.jpg", mime_type="video/mp4")
mv.name = name
return mv
s = slides[29]
y = body(s, "์๋ฎฌ๋ ์ด์
", "์ฃผํ ์์ โ ์นด๋ฉ๋ผ ยท BEV ยท ๋ผ์ด๋ค ยท ๋ ์ด๋๋ฅผ ๋ชจ๋ ์ผ ์๋ ์ฃผํ", [
"์๋ ์ฃผํ (T ํค โ ๊ธฐ๋ก ๊ถค์ ์ pure pursuit ๋ก ๋ฐ๋ผ๊ฐ๋ฉฐ 20 km/h) ์ผ๋ก one-north ์ง์ญ ๋งต์ ๋ฌ๋ฆฌ๋ฉฐ ์ฐฝ ํ๋ฉด ๊ทธ๋๋ก ๋
นํ",
"์์ชฝ ์ค = ์ ๋ฐฉ ์นด๋ฉ๋ผ 3๋ ยท BEV (V ยท N), ์ฅ๋ฉด ์ = ๋ผ์ด๋ค 32์ฑ๋ (๋์ด๋ณ ์) ยท ๋ ์ด๋ 5๋ (๋นจ๊ฐ ๋ค๊ฐ์ด ยท ํ๋ ๋ฉ์ด์ง ยท ๋
ธ๋ ์ ์ง)",
])
movie(s, "sensors_all", 0.85, y + 0.12, 8.6, 4.0)
caption(s, 0.85, y + 4.15, 8.6, "ํด๋ฆญํ๋ฉด ์ฌ์ (20์ด) โ nusim run demo_videos")
table(s, 9.7, y + 0.15, 2.95, [["ํญ๋ชฉ", "๊ฐ"], ["๋
นํ", "20 fps ๊ณ ์ ์คํ
"], ["๊ธธ์ด", "400ํ๋ ์ ยท 20์ด"], ["๋ผ์ด๋ค", "HDL-32E ๊ทผ์ฌ"], ["๋ ์ด๋", "ARS 408 ๊ทผ์ฌ ร 5"], ["์ผ์ 1ํ", "์ฝ 4 ms (CPU)"]],
[0.42, 0.58], size=10, rowh=0.34)
tb(s, 9.7, y + 2.35, 2.95, 1.7, "์ฐฝ ํ๋ฉด ๋
นํ: --record-screen DIR\n(UI ยท ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค ํฌํจ)\n\n์๋ ์ฃผํ: --autopilot ๋๋ T,\nํ์ดํ๋ฅผ ๋๋ฅด๋ฉด ์์ผ๋ก", size=10, color=GRAY)
notes(s, "์ผ์๋ 3DGS ๊น์ด๊ฐ ์๋๋ผ ๋ผ์ด๋ค ๋์ ๋ณต์
์๋์ ๋ ์ด์บ์คํธํ๋ค. ์ง์ญ ๋งต์์๋ ๋ฌ๋ฆฌ๋ ๊ตฌ๊ฐ์ ์ฌ ๋ณต์
์๋๋ก ๋ฐ๊ฟ ๋ผ์ด๋ค.")
# ------------------------------------------------------------------ 21e ๋ ์จ ์์ (์)
s = slides[30]
y = body(s, "์๋ฎฌ๋ ์ด์
", "๋ ์จ ์ฃผํ ์์ โ ์์นจ ยท ๋น ยท ๋", [
"๊ฐ์ ์๋ ์ฃผํ ๊ฒฝ๋ก๋ฅผ ๋ ์จ ํ๋ฆฌ์
๋ง ๋ฐ๊ฟ ๋
นํ โ ๋ ์จ๋ 3DGS ๋ ๋ ๋ค ํ์ฒ๋ฆฌ (weather.comp) ์ ์์ฐจ ์ฃผ๋ณ ์๋ ๊ณต๊ฐ ๊ฐ์ ์
์ (precip)",
])
for i, (nm, t) in enumerate([("weather_morning", "์์นจ โ ์กฐ๋ 0.6 ยท ์
์ ์๊ฐ"), ("weather_rain", "๋น โ ๊ฐ์ 0.5 ยท ์ ์ ๋
ธ๋ฉด"), ("weather_snow", "๋ โ ๊ฐ์ค 0.5 ยท ์์ธ ๋")]):
movie(s, nm, 0.85 + i * 3.97, y + 0.15, 3.85, 2.17)
caption(s, 0.85 + i * 3.97, y + 2.35, 3.85, t)
table(s, 0.85, y + 2.85, 11.75, [["ํ๋ฆฌ์
", "์กฐ๋", "๊ตฌ๋ฆ", "๋น", "๋", "์๊ฐ", "ํจ๊ณผ"],
["์์นจ (morning)", "0.6", "0.15", "-", "-", "0.15", "๋ฎ์ ํด ยท ์์นจ ์๊ฐ"],
["๋น (rain)", "0.75", "0.8", "0.5", "-", "-", "๋น์ค๊ธฐ ๋ชจ์
๋ธ๋ฌ ยท ์ ์ ๋
ธ๋ฉด ๋ฐ์ฌ ยท ๋ ์ฆ ๋ฌผ๋ฐฉ์ธ"],
["๋ (snow)", "0.8", "-", "-", "0.5", "-", "๋์ก์ด ์ด์ ํ๋ฆผ ยท ๋
ธ๋ฉด ๋ ๋ฎ์ 0.4"]],
[0.16, 0.08, 0.08, 0.08, 0.08, 0.08, 0.44], size=10, rowh=0.32)
notes(s, "์ธ ์์์ ๊ฐ๊ฐ ํด๋ฆญํด ์ฌ์. ๋ ์จ ์กฐ์ ๊ฐ์ configs/sim.json weather (ํ๋ฆฌ์
11๊ฐ, ์ฐฝ์ ๋ ์จ ํจ๋์์ ๋ฐ๋ก ๋ฐ๊ฟ).")
# ------------------------------------------------------------------ 21f ์นด๋ฉ๋ผ ์ข
๋ฅ (์)
s = slides[31]
y = body(s, "์ผ์", "์นด๋ฉ๋ผ ์ผ์ ์ข
๋ฅ โ RGB ยท ๊น์ด ยท ์๋งจํฑ ์ธ๊ทธ๋ฉํ
์ด์
ยท ํ๋ฐฑ", [
"๋ ์จ ํจ๋์ '์นด๋ฉ๋ผ' ๋ฒํผ (๋๋ F3) ์ผ๋ก ๋ฐ๊ฟ โ ํ๋ฉด ยท ์ ๋ฐฉ 3๋ ยท BEV ๋ฏธ๋ฆฌ๋ณด๊ธฐ ยท ๋
นํ์ ํจ๊ป ์ ์ฉ, 6์บ ๊ด์ธก ์ ์ฅ(O)์ ๋ RGB",
])
image(s, A + "camera_modes.jpg", 0.85, y + 0.12, w=7.4, h=4.2)
rows = [("๊น์ด", "๋ ๋ํ ๋ ์๋ ๊ฑฐ๋ฆฌ ๋ฒํผ (ฮฃzฮฑ / ฮฃฮฑ) ์ ํ๋ฉด ๊ฑฐ๋ฆฌ๋ฅผ ๋ก๊ทธ ๋๊ธ ์์ผ๋ก โ ์ถ๊ฐ ๋ ๋ ์์"),
("์๋งจํฑ", "๊ฐ์ฐ์์๋ง๋ค ๊ฐ๊น์ด lidarseg ๋ผ์ด๋ค ์ ์ ๋ค์๊ฒฐ ๋ผ๋ฒจ (11์ข
, Cityscapes ์) โ SH ์ ๋์ ๋ผ๋ฒจ ์์ผ๋ก ์คํ๋ซ"),
("ํ๋ฐฑ", "๋ ์จ ยท ISP ๋ฅผ ๊ฑฐ์น ์ต์ข
์์์ ๋ฃจ๋ง"),
("๊ตฌํ", "๋ ๋ ๊ทธ๋ํ camera_mode ํจ์ค 1๊ฐ + ์ ์ฒ๋ฆฌ ์
ฐ์ด๋ ๋ถ๊ธฐ โ ๊ฐ์ ํ๋ ์์์ ๋ฐ๊ฟ, ๋ค์ ํ์ต ์์")]
for i, (t, d) in enumerate(rows):
box(s, 8.45, y + 0.12 + i * 1.06, 4.2, 0.96, d, title=t, fill=PALE, line=BLUE, size=10)
notes(s, "์๋งจํฑ ๋ผ๋ฒจ: nusim recon semantic (๋ชจ๋ธ ์ semantic.rgba). ๋ผ์ด๋ค๊ฐ ์ ๋ฟ๋ ๋์ ๊ฑด๋ฌผ ์๋ถ๋ถ์ ์ด์ ๋ผ๋ฒจ์์ ๋ฒ์ง๊ณ , ๊ทธ๋๋ ์์ผ๋ฉด ๊ฑด๋ฌผ, ํ๋ ๊ตฌ๋ ํ๋๋ก ์น ํ๋ค. ๋ฐํฌ๋ช
ํ์ฌ๋(์ฐฝ๋ฌธ)๋ ๋ฎ์์ผ๋ก ๋๋ ๋ผ๋ฒจ ์ ๊ทธ๋๋ก ๋๋ค.")
# ------------------------------------------------------------------ 21g ์ฑ๋ฅ ๋น๊ต โ ํ์ง (์)
def highlight(t, rows):
"""ํ์์ ์ฐ๋ฆฌ ํ์ ๊ฐ์กฐ (์ฐํ ํ๋ ๋ฐฐ๊ฒฝ ยท ๊ตต๊ฒ ยท ๋จ์ ๊ธ์)."""
for i in rows:
for j in range(len(t.columns)):
c = t.cell(i, j)
c.fill.solid()
c.fill.fore_color.rgb = LIGHT
for r in c.text_frame.paragraphs[0].runs:
r.font.bold, r.font.color.rgb = True, NAVY
def metric_boxes(sl, y, items):
w = (11.8 - 0.15 * (len(items) - 1)) / len(items)
for i, (t, d) in enumerate(items):
box(sl, 0.85 + i * (w + 0.15), y, w, 0.76, d, title=t, fill=PALE, line=BLUE, size=9)
s = slides[32]
y = body(s, "์ฑ๋ฅ ๋น๊ต", "nuScenes ๋ ๋๋ง ํ์ง ๋น๊ต โ ๊ด๋ จ ๋
ผ๋ฌธ์ด nuScenes ์์ ๋ณด๊ณ ํ ๊ฐ", [
"๋
ผ๋ฌธ๋ง๋ค ์ฅ๋ฉด ยท ํด์๋ ยท ํ๊ฐ ๋ถํ ์ด ๋ฌ๋ผ ๋ฌถ์(ํ๊ฐ ์กฐ๊ฑด)๋ผ๋ฆฌ๋ ์ง์ ๋น๊ตํ ์ ์์ โ ๊ฐ์ ๋ฌถ์ ์์์๋ง ์์๊ฐ ์๋ฏธ ์์",
])
metric_boxes(s, y + 0.05, [
("PSNR (dB) โ", "๋ ๋ ์์๊ณผ ์ค์ ์ฌ์ง์ ํฝ์
์ค์ฐจ๋ฅผ ๋ก๊ทธ๋ก ์ฐ ๊ฐ.\n1 dB ์ค๋ฅด๋ฉด RMS ์ค์ฐจ๊ฐ ์ฝ 11% ์ค์ด๋ ๋ค"),
("SSIM (0~1) โ", "๋ฐ๊ธฐ ยท ๋๋น ยท ๊ตฌ์กฐ์ ์ง์ญ ์ ์ฌ๋.\n์ค๊ณฝ๊ณผ ์ง๊ฐ์ด ์ผ๋ง๋ ๋ณด์กด๋๋์ง"),
("LPIPS (0~1) โ", "๋ฅ๋ฌ๋ ํน์ง ๊ณต๊ฐ์ ๊ฑฐ๋ฆฌ.\n์ฌ๋์ด ๋๋ผ๋ ํ๋ฆผ ยท ์๊ณก์ ๊ฐ์ฅ ๊ฐ๊น๋ค"),
])
rows = [["ํ๊ฐ ์กฐ๊ฑด (์ถ์ฒ)", "๋ฐฉ๋ฒ", "PSNR โ", "SSIM โ", "LPIPS โ"],
["SplatAD ํ 1 โ 10์ฅ๋ฉด, 1600ร900, ํ ์ฅ ๊ฑธ๋ฌ ํ๊ฐ, ํ๋ฉด ์ ์ฒด", "UniSim", "22.66", "0.743", "0.414"],
["", "PVG", "24.94", "0.768", "0.497"],
["", "OmniRe", "25.50", "0.798", "0.386"],
["", "Street Gaussians", "25.54", "0.799", "0.375"],
["", "NeuRAD", "26.17", "0.790", "0.312"],
["", "SplatAD", "27.54", "0.849", "0.302"],
["NeuRAD ํ 1 โ 4์ฅ๋ฉด, 4์ฅ๋ง๋ค ํ๊ฐ", "S-NeRF", "26.21", "0.831", "0.228"],
["", "NeuRAD-2x", "27.13", "0.820", "0.205"],
["DrivingGaussian ํ 1 โ 6์ฅ๋ฉด, 1600ร900, 5์ฅ๋ง๋ค", "3D-GS", "26.08", "0.717", "0.298"],
["", "EmerNeRF", "26.75", "0.760", "0.311"],
["", "DrivingGaussian-L", "28.74", "0.865", "0.237"],
["HUGSIM ํ V โ Waymo 2 + nuScenes 2 ์ํ์ค", "HUGSIM", "25.36", "0.776", "0.171"],
["VKGS-Sim (์ฐ๋ฆฌ) โ 800ร450, 8์ฅ๋ง๋ค, ์ ์ ์์ญ *", "ํ์ต ๋จ์ 258๊ฐ ์ค์๊ฐ", "24.65", "0.766", "๋ฏธ์ธก์ "],
["", "scene-0039 (SplatAD ์ฅ๋ฉด)", "24.86", "0.799", "๋ฏธ์ธก์ "]]
t = table(s, 0.85, y + 0.92, 11.8, rows, [0.40, 0.24, 0.12, 0.12, 0.12], size=9, rowh=0.22, align_right=(2, 3, 4))
highlight(t, [13, 14])
tb(s, 0.85, y + 0.96 + 0.22 * len(rows), 11.8, 0.3,
"* ์ฐจ๋ ยท ์ฌ๋์ ์ง์ด ํ๊ฒฝ ์ ์ฉ ๋ชจ๋ธ์ด๋ผ ์ ์ ์์ญ๋ง ์ผ (ํ๋ฉด ์ ์ฒด 23.41 dB). ์ถ์ฒ ํ๋ 2026-10-12 arXiv ์๋ฌธ์์ ํ์ธ.", size=9, color=GRAY)
notes(s, "๊ฐ์ ๋ฌถ์ ์์์๋ง ๋น๊ตํ๋ค. ์ฐ๋ฆฌ ํ์ ํ๋กํ ์ฝ์ด ๋ฌ๋ผ ์ฐธ๊ณ ๊ฐ์ด๋ค. ๊ณต์ ๋น๊ต๋ SplatAD ํ๋กํ ์ฝ(10์ฅ๋ฉด, ์ ํด์๋, ํ๋ฉด ์ ์ฒด, LPIPS) ์ฌํ์ด ๋จ์ ์ผ โ docs/paper/nuscenes_comparison.md.")
# ------------------------------------------------------------------ 21h ์ฑ๋ฅ ๋น๊ต โ ์๋ ร ํ์ง (์)
s = slides[33]
y = body(s, "์ฑ๋ฅ ๋น๊ต", "๋ ๋๋ง ์๋ ร ํ์ง โ ๊ฐ์ ํ์ ๋ ๋ค ๋ณด๊ณ ํ ๋
ผ๋ฌธ", [
"VKGS-Sim ์ 2026-10-12 ์ธก์ (scene-0039, 6์บ 240์ฅ ํ๊ท , GPU ๋จ๋
). 1600ร900 ํ ์ฅ 15.5 ms ์ค 86% ๊ฐ ์คํ๋ซ ๋์คํฐ",
])
metric_boxes(s, y + 0.05, [
("FPS โ", "์ด๋น ๋ ๋ํ๋ ์์ ์ฅ์.\nํด์๋ ยท GPU ์ ๋ฐ๋ผ ํฌ๊ฒ ๋ฌ๋ผ์ง๋ค"),
("MP/s โ", "์ด๋น ๋ ๋ํ๋ ํฝ์
์ (๋ฐฑ๋ง) = FPS ร ๊ฐ๋ก ร ์ธ๋ก.\nํด์๋๊ฐ ๋ฌ๋ผ๋ ๋น๊ตํ ์ ์๋ค"),
("PSNR โ", "ํ์ง (์ ์ฅ). ์๋์ ํจ๊ป ๋ด์ผ ํ๋ค โ\n๊ฐ์ฐ์์ ์๋ฅผ ์ค์ด๋ฉด ๋นจ๋ผ์ง๊ณ ํ์ง์ด ๋จ์ด์ง๋ค"),
])
rows = [["์ถ์ฒ", "๋ฐฉ๋ฒ", "PSNR โ", "์๋ โ", "ํ๋์จ์ด ยท ๋น๊ณ "],
["SplatAD ํ 1 (nuScenes 10์ฅ๋ฉด)", "UniSim", "22.66", "13.3 MP/s", "GPU ํ๊ธฐ ์์ (ํ์ต์ A100)"],
["", "NeuRAD", "26.17", "11.8 MP/s", ""],
["", "PVG", "24.94", "18.8 MP/s", ""],
["", "Street Gaussians", "25.54", "21.5 MP/s", ""],
["", "OmniRe", "25.50", "16.3 MP/s", ""],
["", "SplatAD", "27.54", "106.1 MP/s", ""],
["HUGSIM ํ V (Waymo 2 + nuScenes 2)", "NeuRAD", "24.49", "2.61 FPS", "RTX 3090, ํด์๋ ํ๊ธฐ ์์"],
["", "Street Gaussians", "โ", "66.5 FPS", "๊ฐ์ฐ์์ 685๋ง"],
["", "HUGSIM", "25.36", "89.15 FPS", "๊ฐ์ฐ์์ 445๋ง"],
["VKGS-Sim (์ฐ๋ฆฌ, Vulkan)", "1600ร900", "24.65 *", "64 FPS ยท 93 MP/s", "RTX 3060 Ti 8 GB, ๊ฐ์ฐ์์ 200๋ง"],
["", "800ร450", "24.65 *", "188 FPS ยท 68 MP/s", "๊ฐ์ ์กฐ๊ฑด"]]
t = table(s, 0.85, y + 0.92, 11.8, rows, [0.27, 0.17, 0.1, 0.18, 0.28], size=9.5, rowh=0.25, align_right=(2, 3))
highlight(t, [10, 11])
tb(s, 0.85, y + 0.96 + 0.25 * len(rows), 11.8, 0.5,
"* PSNR ์ ์ฐ๋ฆฌ ํ๋กํ ์ฝ (800ร450 ยท 8์ฅ๋ง๋ค ยท ์ ์ ์์ญ, ์ ์ฅ). 1600ร900 ํ ์ฅ = ์ ์ฒ๋ฆฌ 1.23 ยท ์ ๋ ฌ 0.63 ยท ๋์คํฐ 13.38 ms. "
"ํ์ต๊ณผ GPU ๋ฅผ ๊ฐ์ด ์ฐ๋ฉด 17.1 ms.", size=9, color=GRAY)
notes(s, "SplatAD ๋ MP/s ๋ก, HUGSIM ์ FPS ๋ก ๋๋ค. ์ฐ๋ฆฌ GPU(RTX 3060 Ti) ๋ HUGSIM ์ RTX 3090 ๋ณด๋ค ์ฝํ๋ค. ๊ณ ํด์๋์์๋ ๋ธ๋ ๋ฉ ์ฑ์๋ฅ ์ด ๋ณ๋ชฉ์ด๋ผ 800ร450 ์์๋ ๋์คํฐ๊ฐ 3.5 ms ๋ก ์ค๋ค.")
# ------------------------------------------------------------------ 21c ์์ ์ฑ ๊ฐ์ (์)
s = slides[35]
y = body(s, "์งํ ํํฉ", "์์ ์ฑ ๊ฐ์ โ 10์ 10์ผ ~ 12์ผ์ ์ฐพ์ ๋ฌธ์ ์ ํด๊ฒฐ", [
"์ฌํ์งธ ๋๋ ์ผ๊ด ํ์ต์์ ๋๋ฌ๋ ์คํจ๋ฅผ ์์ธ๊น์ง ์ฐพ์ ๊ณ ์นจ โ ๊ฐ์ ์ผ์ด ๋ค์ ์๊ฒจ๋ ์ฌ๋ ์ ์์ด ์ด์ด์ง๋๋ก ํจ",
])
table(s, 0.85, y + 0.2, 11.8, [["๋ฌธ์ ", "์์ธ", "ํด๊ฒฐ"],
["ํ์ต ๋จ์ 79๊ฐ ์คํจ", "NAS ์ผ์ ์ฅ์ (10/10 18:44โ19:25, ์
์ถ๋ ฅ ์ค๋ฅ)", "๋ฐ์ดํฐ์
์ด ๋์์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ ๋ค ๋ค์ ์๋, ์ต๋ 3ํ์ฐจ ์ฌํ์ต"],
["์ฆ๊ฐ 2์ฌ ์คํจ (PNG ์์)", "๋ฉ๋ชจ๋ฆฌ ๋นํธ 1๊ฐ ๋ค์งํ (ECC ์์) โ ๋ค์ ๋ ๋ํ ๊ฒ๊ณผ 1๋นํธ ์ฐจ์ด", "PNG ๋ฅผ ๋ชจ๋ ์ด์ด ๊ฒ์ฌํ๊ณ ๊นจ์ก์ผ๋ฉด ๊ทธ ๊ตฌ๊ฐ์ ๋ค์ ๋ ๋"],
["์ง์ญ ๋งต ์ผ๋ถ์์ ๋ผ์ด๋ค ยท ๋ ์ด๋ ๊บผ์ง", "๋ณต์
์๋๊ฐ ์๊ฑฐ๋, ๊ตฌ๊ฐ์ด ํ๋ ๋ ํ์ต๋๋ฉด '๋ก์' ์ผ๋ก ๋ณด๊ณ ๊บผ ๋ฒ๋ฆผ", "์ฌ๋ณ ๋ณต์
์๋ ๊ต์ฒด ยท ๊ธฐํ๊ฐ ๊ฐ์ผ๋ฉด ๊ทธ๋๋ก ์ฌ์ฉ ยท ์๋ ์ฌ์ ๋งต์ ์ด ๋ ์์ฑ"],
["์ฐจ๊ฐ ์์ง์ด์ง ์์", "์ฐฝ์ด ํค๋ณด๋ ํฌ์ปค์ค๋ฅผ ๋ชป ๋ฐ์ ยท ํ๊ธ ์
๋ ฅ๊ธฐ (ibus) ๊ฐ ํค ์ด๋ฒคํธ๋ฅผ ๊ฐ๋ก์ฑ", "ํฌ์ปค์ค ์์ฒญ + ํ๋ฉด ๊ฒฝ๊ณ , ๋ทฐ์ด์์ ์
๋ ฅ๊ธฐ๋ฅผ ๋"],
["์ง๋ฉด ๋ชจ๋ธ (HUGSIM ๋ค์ค ํ๋ฉด) ์คํ", "์ฐจ์ ๋ณ๊ฒฝ ์์ PSNR +0.08 dB โ ํจ๊ณผ ๋ฏธ๋ฏธ", "๋งต ๋ฐฐ์น์๋ ๋ฃ์ง ์์"]],
[0.22, 0.4, 0.38], size=11, rowh=0.55)
notes(s, "PNG ์์: ๋ ๋๋ ๊ฒฐ์ ์ ์ด๋ผ ์ธ ๋ฒ ๋ค์ ๋ ๋ํด๋ ๊ฐ์ ํ์ผ์ด ๋์๊ณ , ๊นจ์ง ํ์ผ์ ๊ทธ๊ฒ๊ณผ ์ ํํ 1๋นํธ ๋ฌ๋๋ค. ECC ์๋ ๋ฉ๋ชจ๋ฆฌ์ ์ผ์ ์ค๋ฅ๋ก ๋ณด๋ฉฐ memtest86 ์ ๊ฒ์ ๊ถํ๋ค.")
# ------------------------------------------------------------------ 23 ํฅํ ๊ณํ
s = slides[37]
y = body(s, "ํฅํ ๊ณํ", "ํฅํ ์ฐ๊ตฌ ๊ณํ", [
"์ง์ญ ๋งต์ ์์ฑํ๊ณ , ์ฃผํ ๋ชจ๋ธ์ ํ์ฐ๊ณ , ์ ์์ ํ์ง์ ๊ฐ์ ํ๋ ์์๋ก ์งํํจ",
])
plans = [("์ง์ญ ๋จ์ ์ฅ์ ๋ฌผ ์ง๋", "์ง์ญ ๋งต์ ์์ง ์ฐ์ ์ถฉ๋๋ง โ ์ผ์์ฒ๋ผ ์ฌ๋ณ ์ฅ์ ๋ฌผ ์ง๋๋ฅผ ๋ฐ๊ฟ ๋ผ์ ๊ฑด๋ฌผ ยท ๊ธฐ๋ฅ๊ณผ์ ์ถฉ๋๊น์ง"),
("VLA ์ฐ๊ฒฐ ยท ํ๊ฐ", "closed-loop ์ฐ๊ฒฐ (--serve + Gym) ๊ณผ HD-Score ์งํ๋ ๊ตฌํ๋จ โ VLM/VLA ์ ์ฑ
์ ์ง์ญ ๋งต ์์์ ํ๊ฐ"),
("์ ์์ ํ์ง (ํต์ฌ ๊ณผ์ )", "์ ์ฐจ์ ์ค์ ์ฌ์ง ๊ธฐ์ค ์ฝ 16.5 dB (์๊ธฐ ๊ฒฝ๋ก ์ฝ 23 dB) โ ์ง๋ฉด ๋ชจ๋ธ์ +0.08 dB ๋ก ํจ๊ณผ ๋ฏธ๋ฏธ, ๋ค๋ฅธ ๋ฐฉ๋ฒ ๊ฒํ "),
("๊ตํต ์ฐธ๊ฐ์", "3DRealCar ์ฐจ๋ ์์
์ฝ์
(๋์ด ยท ์๋ โ ๋ ์ด๋ ๋ํ๋ฌ), queenstown ยท holland village ์ง์ญ ๋งต")]
for i, (t, d) in enumerate(plans):
r, c = divmod(i, 2)
box(s, 0.85 + c * 6.0, y + 0.2 + r * 1.75, 5.75, 1.55, d, title=t, fill=NAVY if i == 2 else PALE, color=WHITE if i == 2 else GRAY,
line=None if i == 2 else BLUE, size=12)
notes(s, "์ฌ๋ฌ ์ฃผํ ํฉ์น๊ธฐ (ํ์ผ): ๊ฐ์ ๊ธธ์ ๋ค๋ฅธ ์ฐจ์ ์ผ๋ก ์ง๋๊ฐ ์ฃผํ์ ํจ๊ป ํ์ตํ๋ฉด ์ ์ฐจ์ ์ด ์ค์ ์ฌ์ง์ผ๋ก ๊ฐ๋
๋๋ค. ์ฃผํ 1~2๊ฐ๋ ์ ์, 6๊ฐ์์ 3k ์คํ
์ดํ ๋ฌด๋์ง๋ค.")
for sh in slides[38].shapes:
if sh.name == "ํ
์คํธ ๊ฐ์ฒด ํ 6":
for para in sh.text_frame.paragraphs:
rs = para.runs
if not rs:
continue
if "์ค ์ฌ ์ฐ" in rs[0].text:
rs[0].text = "kimjunhan"
if rs[0].text == "Email":
rs[1].text = " : kimjunhan1605@gmail.com"
notes(slides[38], "์ง์์๋ต.")
notes(slides[39], "๊ฐ์ฌํฉ๋๋ค.")
# ================================================================== โ
ก. ์๋ฎฌ๋ ์ด์
์์ง ์ํคํ
์ฒ
divider(slides[6], "์๋ฎฌ๋ ์ด์
์์ง ์ํคํ
์ฒ", "Vulkan ๊ธฐ๋ฐ ์๋ฎฌ๋ ์ด์
์์ง์ ์ ์ฒด ๊ตฌ์กฐ, ํ ํ๋ ์์ ๋ ๋ ๊ทธ๋ํ, ์๋ฎฌ๋ ์ด์
๋ฃจํ, Python ๊ณผ์ ๋ฐ์ดํฐ ์ธํฐํ์ด์ค๋ฅผ ์ค๋ช
ํ๋ค.")
def module(sl, x, y, w, h, title, desc, fill=WHITE, line=LIGHT, tcolor=NAVY, dcolor=GRAY, size=10):
box(sl, x, y, w, h, "", fill=fill, line=line)
tb(sl, x + 0.06, y + 0.04, w - 0.12, 0.26, title, size=size + 1, bold=True, color=tcolor)
tb(sl, x + 0.06, y + 0.3, w - 0.12, h - 0.32, desc, size=size, color=dcolor)
def figure(sl, path, y, w=11.8, h=4.4, x=0.85):
im = Image.open(path)
s_ = min(w / im.width, h / im.height)
ww, hh = im.width * s_, im.height * s_
return sl.shapes.add_picture(path, Inches(x + (w - ww) / 2), Inches(y), Inches(ww), Inches(hh))
def down_arrow(sl, x, y, w=0.26, h=0.26, color=BLUE):
s_ = sl.shapes.add_shape(MSO_SHAPE.DOWN_ARROW, Inches(x), Inches(y), Inches(w), Inches(h))
s_.fill.solid()
s_.fill.fore_color.rgb = color
s_.line.fill.background()
s_.shadow.inherit = False
# ------------------------------------------------------------------ 8 ์์ง ์ ์ฒด ๊ตฌ์กฐ๋
s = slides[7]
y = body(s, "์์ง ๊ตฌ์กฐ", "์๋ฎฌ๋ ์ด์
์์ง ์ ์ฒด ๊ตฌ์กฐ๋", [
"(a) CPU ์๋ฎฌ๋ ์ด์
๋ฃจํ๊ฐ ๋งค ํ๋ ์ ์ ์ด ยท ์์ฐจ ๋์ญํ ยท ์ถฉ๋ ยท ๊ตฌ๊ฐ ์คํธ๋ฆฌ๋ฐ ยท ์ผ์ ยท ๊ธฐ๋ก์ ์ฒ๋ฆฌํ๊ณ , (b) GPU ๋ ๋ ๊ทธ๋ํ๊ฐ ๊ฐ์ฐ์์ โ ์ ๋ ฌ โ ๋์คํฐ โ ํ์ฒ๋ฆฌ๋ก ์์์ ๋ง๋ฆ (๊ทธ๋ฆผ์ ๊ฐ ๋จ๊ณ๋ scene-0402 ์ค์ ๋ฐ์ดํฐ)",
])
figure(s, "/home/mm/Downloads/vkgs-sim/docs/presentation/figures/out/fig_engine_pipeline.png", y + 0.02, h=6.98 - (y + 0.02))
notes(s, "์ฐธ๊ณ ํ ๋์ ํ์: 3DGS (Kerbl 2023) ์ต์ ํ ํ์ดํ๋ผ์ธ, HUGSIM ยท OmniRe ๊ฐ์๋ โ ๋จ๊ณ๋ง๋ค ์ค์ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฌ ์ค๋ค. (a) ์ ์ฅ์ ๋ฌผ ์ง๋ ยท ๊ตฌ๊ฐ ยท ๋ผ์ด๋ค ยท ์๋ ๊ธฐ๋ก, (b) ์ ๊ฐ์ฐ์์ ยท ํ๋ฉด ํ์ ยท ์ ๋ ฌ ์์ ยท ํ๋ ยท ์ ยท ๊ฑฐ๋ฆฌ๋ ๋ชจ๋ scene-0402 ๊ตฌ๊ฐ 1 ๋ชจ๋ธ๊ณผ ์ค์ ์ฃผํ ๋ก๊ทธ์์ ๋ง๋ ๊ทธ๋ฆผ์ด๋ค. ์์ง์ ํ๋์ ์คํ ํ์ผ(vkgs_viewer)์ด๊ณ , ์ฐฝ ๋ชจ๋(์๋ฎฌ๋ ์ดํฐ)์ ์คํ์คํฌ๋ฆฐ ๋ชจ๋(๋ฐ์ดํฐ ๋ ๋ ยท ์ฆ๊ฐ)๊ฐ ๊ฐ์ ๋ ๋๋ฌ๋ฅผ ์ด๋ค.")
# ------------------------------------------------------------------ 9 ๋ ๋ ๊ทธ๋ํ ํ์ดํ๋ผ์ธ
s = slides[8]
y = body(s, "์์ง ๊ตฌ์กฐ", "๋ ๋ ๊ทธ๋ํ โ ํ ํ๋ ์์ ํจ์ค ํ์ดํ๋ผ์ธ", [
"ํ๋ ์ ๊ตฌ์ฑ์ configs/render_graph.json ์ด ์ ํจ โ ํจ์ค๋ง๋ค ์ฐ๋ ์์๊ณผ ์ฉ๋ (uses) ๋ฅผ ์ ์ธํ๋ฉด ๊ทธ๋ํ๊ฐ ๋ฐฐ๋ฆฌ์ด ยท ๋ ์ด์์ ์ ํ์ ์๋์ผ๋ก ์ฝ์
ํจ",
"๊ฐ์ฐ์์ SSBO โ preprocess (ํฌ์ ยท SH ยท ๋ณด์ด๋ ๊ฒ๋ง ์์ถ) โ GPU radix ์ ๋ ฌ โ ํ๋ ๋ฐฐ๊ฒฝ โ ์คํ๋ซ ๋์คํฐ (RGBA16F ์ + r32f ๊ฑฐ๋ฆฌ) โ ํ์ฒ๋ฆฌ โ 800ร450 ์ฅ๋น ์ฝ 6.8 ms",
])
figure(s, "/home/mm/Downloads/vkgs-sim/docs/presentation/figures/out/fig_engine_pipeline_b.png", y + 0.1, h=6.95 - (y + 0.1))
notes(s, "์ค์ ํจ์ค ์์: clear_draw_args โ preprocess โ sort โ readback_count โ background โ scene โ precip โ weather โ fxaa โ fxaa_resolve โ to_present (camera_isp ๊บผ์ง). ์ธก์ (800ร450): preprocess 2.02 ms, sort 0.44 ms (์ด์ bitonic 31~35 ms ๋๋น 13๋ฐฐ), scene 4.38 ms. preprocess ๊ฐ 200๋ง ๊ฐ ์ค ๋ณด์ด๋ ์ฝ 25~46๋ง ๊ฐ๋ง ์์ถํด ์ ๋ ฌ ๋์์ ์ค์ธ๋ค. RGBA16F ๋ธ๋ ๋ฉ์ 32๋นํธ ๋๋น 64 dB, ๊ฑฐ๋ฆฌ ๋์ ์ ์ผ์ ยท ๋ ์จ ยท ๋ฐ์ฌ์ ์ด๋ค.")
# ------------------------------------------------------------------ 10 ์๋ฎฌ๋ ์ด์
๋ฃจํ
s = slides[9]
y = body(s, "์์ง ๊ตฌ์กฐ", "์๋ฎฌ๋ ์ด์
๋ฃจํ โ ํ ํ๋ ์์ ์ผ์ด๋๋ ์ผ", [
"์ ์ด ์
๋ ฅ โ ์์ฐจ ์ ๋ถ ยท ์ถฉ๋ โ ๊ตฌ๊ฐ ์ ํ โ ์ผ์ โ ๋ ๋ โ ๊ธฐ๋ก์ ์์๋ก ๋งค ํ๋ ์์ ์ฒ๋ฆฌํ๋ฉฐ, ์คํฌ๋ฆฝํธ ์ ์ด๋ 50 ms ๊ณ ์ ์คํ
์ด๋ผ ์ฌํ ๊ฐ๋ฅํจ",
"VLA ๋ชจ๋ธ์ '์ ์ด ์
๋ ฅ' ์๋ฆฌ์ ๋ค์ด์ 6์บ (+ ์ผ์) ๊ด์ธก์ ๋ฐ๊ณ ์กฐํฅ ยท ๊ฐ์์ ๋๋ ค์ฃผ๋ ๊ตฌ์กฐ โ ๊ธฐ๋ก๋ ์ ์ด๋ drive_log.csv ๋ก ๋จ์ (์ค๋ฅธ์ชฝ: ์ค์ ์ํ ์ฃผํ์ ์๋)",
])
pic = figure(s, "/home/mm/Downloads/vkgs-sim/docs/presentation/figures/out/fig_engine_pipeline_a.png", y + 0.05, h=2.75)
yy = y + 0.2 + pic.height / 914400
table(s, 0.85, yy, 11.8, [["๋จ๊ณ", "ํต์ฌ ์ฒ๋ฆฌ"],
["โข ์ถฉ๋", "์ฐจ์ฒด ์ํ 0.1 m ๊ฒฉ์ ยท ๊น์ด = ๋ฟ์ ์ โ ์ค์นจ (2) ยท ๊ฐ์ ๋ฐฉํฅ 0.3 m ์์ด ๋ ๊น์ง ์์ผ๋ฉด ํ์ฉ (๊ฐํ ๋ฐฉ์ง)"],
["โฃ ๊ตฌ๊ฐ", "๋ด๋น ๊ถค์ ์ด ๊ฐ์ฅ ๊ฐ๊น์ด ๊ตฌ๊ฐ ยท 3 m ํ์คํ
๋ฆฌ์์ค ยท ๊ฐ๊น์ด 3๊ตฌ๊ฐ ๋น๋๊ธฐ ๋ก๋ ยท ๊ต์ฒด 0.19์ด"],
["โค ์ผ์", "๋ค ๋ฐํด ์๋ฆฌ ์ง๋ฉด ๋์ด๋ก z ยท pitch ยท roll โ ๋ผ์ด๋ค 32 ร 1,091 ๊ด์ DDA 4 ms ยท ๋ ์ด๋ 5๋ ๋ํ๋ฌ"]],
[0.1, 0.9], size=10, rowh=0.29)
notes(s, "โข ์ฅ์ ๋ฌผ ์ง๋์ ์ธํจ์ด ์นธ์ด๋ ํ๋จ ๊ฐ์ฅ์๋ฆฌ ํ ์นธ์ ์ฐจ์ฒด ์์ด ์ค์น๊ธฐ๋ง ํด๋ ๋งํ ๊ฐํ๋ ๋ฌธ์ ๋ฅผ ์ค์นจ ํ์ฉ๊ณผ ํ์ถ ํ์ ์ผ๋ก ํด๊ฒฐํ๋ค. โค ๊ธฐ์ธ์ด์ง ๊ธธ์ ๋ฌด์ํ๋ฉด ๋ฎ์ ๋น์ ๋
ธ๋ฉด ๊ฑฐ๋ฆฌ๊ฐ 20% ๋๊ฒ ์งง์์ ธ ๋
ธ๋ฉด์ ์ํ๋ค.")
# ------------------------------------------------------------------ 11 ๋ฐ์ดํฐ ์ธํฐํ์ด์ค
s = slides[10]
y = body(s, "์์ง ๊ตฌ์กฐ", "Python โ ์์ง ๋ฐ์ดํฐ ์ธํฐํ์ด์ค", [
"์์ง๊ณผ Python ์ ์ฌ๋์ด ์ฝ์ ์ ์๋ ํ์ผ๋ก๋ง ์ฐ๊ฒฐ๋จ โ ๊ฐ ํ์ผ์ ๋ฌด์์ผ๋ก ๋ง๋ค์๋์ง export.json ์ ๋จ๊ธฐ๊ณ , ๋ชจ๋ธ ยท ์๊ณ ๋ฆฌ์ฆ์ด ๋ฐ๋๋ฉด ์๋์ผ๋ก ๋ค์ ๋ง๋ฆ",
])
table(s, 0.85, y + 0.15, 11.8, [
["ํ์ผ", "๋ง๋๋ ๊ณณ (Python)", "๋ด์ฉ", "์์ง์์ ์ฐ๋ ๊ณณ"],
["point_cloud.ply (๊ตฌ๊ฐ๋ง๋ค)", "recon train", "๊ฐ์ฐ์์ + ์์ ์ฃผ์ (nusim_origin)", "๋ ๋๋ฌ ยท SegmentStreamer"],
["segments.txt", "render/segmap.py", "๊ตฌ๊ฐ ์์ ์ฐจ ยท ๋ด๋น ๊ถค์ ์ ", "SegmentMap (๊ตฌ๊ฐ ์ ํ)"],
["rig.txt", "render/export.py", "ํ๋ ์๋ณ 6์บ w2c ยท ์์ฐจ ํฌ์ฆ ยท ๊ฐ์ฒด ๋ฐ์ค", "์ฌ์ ยท ์ด์ ์นด๋ฉ๋ผ ยท ์ฆ๊ฐ"],
["map.txt ยท drivable.txt", "render/export.py", "๋งต ์ ยท ์ฃผํ๊ฐ๋ฅ์์ญ ํด๋ฆฌ๊ณค", "์ค๋ฒ๋ ์ด ยท ์ฐ์ ํ์ "],
["obstacles.pgm", "sim/obstacles.py", "0.2 m ์ฅ์ ๋ฌผ ๊ฒฉ์ (์ ์ ๋ผ์ด๋ค)", "์ถฉ๋ ํ์ "],
["world.vox", "sim/voxels.py + vkgs_voxcarve", "0.2 m ๋ณต์
+ 0.5 m ์ง๋ฉด ๋์ด ์ง๋", "๋ผ์ด๋ค ยท ๋ ์ด๋ ยท ๋
ธ๋ฉด ์ ์ฐฉ"],
["sky.ktx2 ยท IBL", "recon/sky.py ยท render/ibl.py", "ํ์ต ํ๋ ํ๋ธ๋งต ยท ํ๊ฒฝ๊ด (BC6H)", "background ยท glTF ์กฐ๋ช
"],
["sim.json ยท render_graph.json", "configs/", "๋ ์จ ยท ์ผ์ ยท ์ถฉ๋ ยท ์นด๋ฉ๋ผ ยท ํจ์ค ๊ตฌ์ฑ", "์์ง ์ ์ฒด ์ค์ "],
], [0.22, 0.24, 0.32, 0.22], size=10, rowh=0.42)
notes(s, "ํ๋์ฝ๋ฉ์ ์ค์ด๊ธฐ ์ํด ์กฐ์ ๊ฐ์ ๋ชจ๋ configs/ ์ ์๋ค. ์ขํ๊ณ๋ nusim/data/rig.py ์ docstring ์ด ์ ์ผํ ์ถ์ฒ๋ค. ๋ชจ๋ ํ์ผ์ ๊ทธ ๋ชจ๋ธ์ ์์ ๊ธฐ์ค ์ขํ๋ฅผ ์ด๋ค.")
# ================================================================== โ
ข. ๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ ์ํคํ
์ฒ
divider(slides[12], "๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ ์ํคํ
์ฒ", "6์บ ๋ฉํฐ๋ทฐ ์์์ ์๋ก์ด ์นด๋ฉ๋ผ ๋ฐฐ์น๋ก ๋ณํํ๋ ๋ชจ๋ธ โ ๊ตฌ๊ฐ๋ณ 3DGS ์ฌ๊ตฌ์ฑ ๋ชจ๋ธ์ ๊ตฌ์กฐ, ๋ชจ๋, ์์ค ํจ์, ๋ฆฌ๊ทธ ๋ณํ์ ์ค๋ช
ํ๋ค.")
# ------------------------------------------------------------------ 14 ๋ชจ๋ธ ์ ์ฒด ๊ตฌ์กฐ๋
s = slides[13]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ ์ ์ฒด ๊ตฌ์กฐ๋", [
"๊ตฌ๊ฐ๋ง๋ค ๋ฉํฐ๋ทฐ ์ฌ์ง ยท ๋ผ์ด๋ค๋ก 3DGS ์ฅ๋ฉด์ ํ์ต: ๋ผ์ด๋ค ์ด๊ธฐํ โ 3D ๊ฐ์ฐ์์ โ ๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ โ ๋ ๋ (์ ยท ๊น์ด) โ ์ฌ์ง ยท ๋ผ์ด๋ค ยท ๋ง์คํฌ ๊ฐ๋
โ ์ญ์ ํ",
"ํ์ต๋ ์ฅ๋ฉด์ ๋ฆฌ๊ทธ ๋ณํ T ๋ฅผ ์ค 6์บ ์ผ๋ก ๋ค์ ๋ ๋๋งํด ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์์ฑ (๊ทธ๋ฆผ์ ๊ฐ ๋จ๊ณ๋ scene-0402 ์ค์ ๋ฐ์ดํฐ)",
])
figure(s, "/home/mm/Downloads/vkgs-sim/docs/presentation/figures/out/fig_viewpoint_model_a.png", y + 0.15, h=6.9 - (y + 0.15))
notes(s, "์ฐธ๊ณ ํ ๋์ ํ์: 3DGS (Kerbl 2023) Fig. 2 ์ต์ ํ ํ์ดํ๋ผ์ธ โ ์ด๊ธฐ ์ โ 3D ๊ฐ์ฐ์์ โ ํฌ์ ยท ํ์ผ ๋์คํฐ โ ์ด๋ฏธ์ง, ๊ทธ๋ฆฌ๊ณ gradient ๋๋๋ฆผ. ์ฌ๊ธฐ์๋ SfM ์ ๋์ ๋ผ์ด๋ค ๋์ ์ผ๋ก ์ด๊ธฐํํ๊ณ , ์ฌ์ง ์์ค์ ๋ผ์ด๋ค ๊น์ด ยท ํ๋ ยท ์ ๊ทํ๋ฅผ ๋ํ๋ค. (b) ๋ ์์ ๋ณํ์ด ํ์ต์ด ์๋๋ผ '์ ์นด๋ฉ๋ผ ๋ฐฐ์น๋ก ๋ค์ ์ฐ๊ธฐ' ์์ ๋ณด์ธ๋ค. ์ค๋ฅธ์ชฝ 9์ฅ์ ๊ฐ์ ์๊ฐ์ ์ ์นด๋ฉ๋ผ ๋ณํ 9์ข
์ด๋ค.")
# ------------------------------------------------------------------ 15 ์ฅ๋ฉด ํํ ยท ๋ฏธ๋ถ ๋ ๋๋ฌ
s = slides[14]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โ ์ฅ๋ฉด ํํ ๋ฐ ๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ ", [
"์ฅ๋ฉด ๋ชจ๋ธ์ ์ ๊ฒฝ๋ง์ด ์๋ ๋ช
์์ ๊ฐ์ฐ์์ ์งํฉ์ด๋ฉฐ, ๋ผ์ด๋ค๋ก ์ด๊ธฐํํ๊ณ 3DGS-MCMC ๋ก ๊ฐ์ (์ต๋ 200๋ง) ๋ฅผ ์ ์งํ๋ฉฐ ์์น๋ฅผ ์ฌ๋ฐฐ์นํจ",
"๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ (gsplat 1.4.0) ๊ฐ ์ ยท ๋ถํฌ๋ช
๋ ยท ๊น์ด๋ฅผ ํจ๊ป ๋ ๋๋งํ๊ณ , ๊ทธ gradient ๋ก ๋ชจ๋ ๊ฐ์ฐ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐฑ์ ํจ",
])
box(s, 0.85, y + 0.15, 5.75, 3.55, "", fill=PALE, line=BLUE)
tb(s, 0.95, y + 0.2, 5.5, 0.3, "๊ฐ์ฐ์์ ์ฅ๋ฉด G", size=13, bold=True, color=NAVY)
table(s, 1.0, y + 0.58, 5.45, [["ํญ๋ชฉ", "์ค์ "], ["์ด๊ธฐํ", "์ ์ ๋ผ์ด๋ค ๋์ (์ฝ 400 sweep) โ ๋ณต์
โ ์ฌ์ง ํฌ์ ์"],
["ํ๋ผ๋ฏธํฐ", "ฮผ ยท ์ค์ผ์ผ ยท ์ฟผํฐ๋์ธ ยท ฮฑ ยท SH (3์ฐจ, 1,000 ์คํ
๋ง๋ค ์ฐจ์ ์ฆ๊ฐ)"],
["๋ฐ๋ ์ ์ด", "MCMC: ์ํ 200๋ง, ๋ฎ์ ฮฑ ์ฌ๋ฐฐ์น, ์์น ์ก์ (lr 5e5)"],
["์ ๊ทํ", "๋ถํฌ๋ช
๋ ยท ์ค์ผ์ผ ํ๊ท ๊ฐ 0.01 (๋ณด์ด๋ ๊ฒ๋ง ์ต์
)"],
["๊ฐ๋ฆผ", "์ฐจ๋ ยท ์ฌ๋ 3D ๋ฐ์ค โ ์ฌ์ง ยท ๋ผ์ด๋ค์์ ์ ์ธ"]], [0.25, 0.75], size=10, rowh=0.44)
box(s, 6.9, y + 0.15, 5.75, 3.55, "", fill=PALE, line=BLUE)
tb(s, 7.0, y + 0.2, 5.5, 0.3, "๋ฏธ๋ถ ๋์คํฐ๋ผ์ด์ (gsplat)", size=13, bold=True, color=NAVY)
rs = [("ํฌ์", "ฮฃโฒ = J W ฮฃ Wแต Jแต, ๋ณด๋ ๋ฐฉํฅ์ผ๋ก SH ์ ๊ณ์ฐ"), ("ํ์ผ ์ ๋ ฌ", "16ร16 ํ์ผ๋ง๋ค ๊ฒน์น๋ ๊ฐ์ฐ์์์ ๊น์ด์ ์ ๋ ฌ"),
("์ํ ๋ธ๋ ๋ฉ", "C = ฮฃ cแตข ฮฑแตข ฮ (1 โ ฮฑโฑผ), ฮฑ ๋์ ยท ๊ธฐ๋ ๊น์ด D"), ("์ญ์ ํ", "ฮผ ยท ฮฃ ยท ฮฑ ยท SH ๋ก gradient (packed ๋ชจ๋)"),
("์นด๋ฉ๋ผ ํ๋ ฌ", "view gradient ๋ (2.2๋ฐฐ ๋๋ ค์ง) โ ฮ ๋ ๋ณ๋ ๋ชจ๋")]
for k, (t, d) in enumerate(rs):
box(s, 7.05, y + 0.6 + k * 0.6, 1.5, 0.5, t, fill=NAVY, color=WHITE, size=10, bold=True)
tb(s, 8.62, y + 0.62 + k * 0.6, 3.95, 0.48, d, size=10, color=GRAY, anchor=MSO_ANCHOR.MIDDLE)
notes(s, "Vulkan ๋ ๋๋ฌ๋ ์ด ๋์คํฐ๋ผ์ด์ ์ ๊ฐ์ ์์(gs_common.glsl)์ ์ฐ๊ณ , ํ์ต๊ธฐ ๋ ๋์ PSNR 56 dB ๋ก ์ผ์นํ๋ค. ํ์ต์ 2๋ฐฐ ๋ค์ด์ค์ผ์ผ(800ร450)์์ ํ๋ค.")
# ------------------------------------------------------------------ 16 ๋ณด์ ยท ํ๋
s = slides[15]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โก ์นด๋ฉ๋ผ ๋ณด์ ๋ฐ ํ๋ ๋ชจ๋ธ", [
"6๋ ์นด๋ฉ๋ผ์ ์ ยท ์ฅ์ฐฉ ์ค์ฐจ์ ํ๋์ ๋ณ๋ ๋ชจ๋๋ก ๋ถ๋ฆฌํ์ฌ, ๊ฐ์ฐ์์์ด ์นด๋ฉ๋ผ ์ฐจ์ด๋ ํ๋์ ํก์ํด ์๊ธฐ๋ floater ๋ฅผ ๋ง์",
])
cards = [("์ ๋ณด์ (ColorCorrection)", "์นด๋ฉ๋ผ๋ณ 3ร4 ์ํ + ํ๋ ์๋ณ RGB log ๊ฒ์ธ\n\naffine_c = [I|0] + d_c โ mean(d)\nlog_gain_v = g_v โ mean(g)\n\n์ค์ฌํ โ ๋ณด์ ์์ด ๊ทธ๋ฆฐ ply ๊ฐ ๊ณง\nํ๊ท ์นด๋ฉ๋ผ ์ (์ฆ๊ฐ ์์์ ์ ๊ธฐ์ค)"),
("์ธ๋ถ ํ๋ผ๋ฏธํฐ ๋ณด์ (CameraAdjust)", "์นด๋ฉ๋ผ๋ณ SE(3) ฮ (ํ์ ๋ฒกํฐ 3 + ์ด๋ 3)\n\nw2cโฒ = ฮ ยท w2c\ncamโegoโฒ = camโego ยท ฮโปยน\n\nlr 1e-4, 4 ์คํ
๋ง๋ค, 3๋ง ์คํ
๊น์ง\n์ฌ์ ์ ๊ทํ 5e-4\n๊ฒฐ๊ณผ: ํ์ 0.1~0.4ยฐ, ์ด๋ ์ฝ 1 cm"),
("ํ๋ ๋ชจ๋ธ (SkyCube)", "ํ์ต ํ๋ธ๋งต 256ยฒ (lr 0.01)\n\nร_final = ร + (1 โ ฮฑ) ยท S(๊ด์ ๋ฐฉํฅ)\n\nBCE: ํ๋ ํฝ์
ฮฑ โ 0,\n๋ผ์ด๋ค ํ๋ฉด ํฝ์
ฮฑ โ 1 (ฮป 0.05)\n\n์ ์ฅ: sky.ktx2 (RGBA16F ์ ํ)\nโ Vulkan background ํจ์ค")]
for k, (t, d) in enumerate(cards):
box(s, 0.85 + k * 4.0, y + 0.2, 3.8, 2.45, d, title=t, fill=PALE, line=BLUE, size=11, align=PP_ALIGN.LEFT)
why = [("๋ถ๋ฆฌํ์ง ์์ผ๋ฉด", "์นด๋ฉ๋ผ๋ง๋ค ๋ค๋ฅธ ์ ยท ๋
ธ์ถ์ ๊ฐ์ฐ์์ ์์ด ํก์ โ ์ ์์ ์์ ์ผ๋ฃฉ"),
("๋ถ๋ฆฌํ์ง ์์ผ๋ฉด", "์ฅ์ฐฉ ์ค์ฐจ (0.1~0.4ยฐ) ๋งํผ ๊ฐ์ ๋ฌผ์ฒด๊ฐ ๊ฒน์ณ ํ๋ ค์ง"),
("๋ถ๋ฆฌํ์ง ์์ผ๋ฉด", "ํ๋์ด 9 m ๊ฑฐ๋ฆฌ์ ๋ฐ์ ๊ฐ์ฐ์์ ๋ฉ์ด๋ฆฌ๋ก ๊ตฌ์์ ธ floater ๊ฐ ๋จ")]
for k, (t, d) in enumerate(why):
x = 0.85 + k * 4.0
down_arrow(s, x + 1.77, y + 2.72, h=0.24, color=ORANGE)
box(s, x, y + 3.02, 3.8, 0.85, d, title=t, fill=WHITE, line=ORANGE, size=10)
notes(s, "ํ๋์ ๋ถ๋ฆฌํ์ง ์์ผ๋ฉด ํ๋ ์ผ๋ถ๊ฐ ๊ฐ๊น์ด ๋ถํฌ๋ช
๊ฐ์ฐ์์์ผ๋ก ๊ตฌ์์ ธ(9 m ๊ฑฐ๋ฆฌ์ ๋ฐ์ ๋ฉ์ด๋ฆฌ) ์ ์์ ์์ ๋ ๋ค๋๋ค. 'ํ๋ ์๋' ์ ์ฒด์ ฮฑโ1 ์ ๊ฑธ๋ฉด ๋๋ญ์ ์ฌ์ด๋ก floater ๊ฐ ์๊ฒจ ๋ผ์ด๋ค๊ฐ ํ๋ฉด์ ํ์ธํ ํฝ์
์๋ง ๊ฑด๋ค.")
# ------------------------------------------------------------------ 17 ์์ค ยท ํ์ต ์ค์
s = slides[16]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "์์ค ํจ์ ๋ฐ ํ์ต ์ค์ ", [
"์ฌ์ง ์ฌ๊ตฌ์ฑ ์์ค์ ๋ผ์ด๋ค ๊น์ด ยท ํ๋ ๋ถ๋ฆฌ ยท MCMC ์ ๊ทํ ยท ์นด๋ฉ๋ผ ๋ณด์ ์ฌ์ ์ ๋ํด ํ์ตํจ โ ์ฌ์ง ์์ค์ ์ฐจ๋ ยท ์ฌ๋ ๋ง์คํฌ ๋ฐ ํฝ์
์์๋ง ๊ณ์ฐ",
])
box(s, 0.85, y + 0.15, 11.8, 0.62, "L = 0.8 ยท L1 + 0.2 ยท (1 โ SSIM) + 0.1 ยท L_depth + 0.05 ยท (L_sky + L_surf) + 0.01 ยท mean(ฮฑ) + 0.01 ยท mean(s) + 5ยท10โปโด ยท R(ฮ)",
fill=NAVY, color=WHITE, size=14, bold=True)
table(s, 0.85, y + 0.95, 6.3, [["ํญ", "์ ์"], ["L1 ยท D-SSIM", "๋ ๋ ร ์ ์ค์ ์ฌ์ง, ๊ฐ์ฒด ๋ง์คํฌ ๋ฐ ํฝ์
(SSIM ฮป 0.2)"],
["L_depth", "|D โ D_lidar| / D_lidar, 1/4 ํด์๋, ์ฐจ๋ ํฝ์
์ ์ธ"],
["L_sky ยท L_surf", "ํ๋ ํฝ์
โlog(1โฮฑ), ๋ผ์ด๋ค ํ๋ฉด ํฝ์
โlog ฮฑ"],
["mean(ฮฑ) ยท mean(s)", "MCMC ๋ถํฌ๋ช
๋ ยท ์ค์ผ์ผ ์ ๊ทํ"],
["R(ฮ)", "์นด๋ฉ๋ผ ์ธ๋ถ ํ๋ผ๋ฏธํฐ ๋ณด์ ์ ํฌ๊ธฐ ์ฌ์ "]], [0.3, 0.7], size=10, rowh=0.44)
table(s, 7.4, y + 0.95, 5.25, [["ํ์ต ์ค์ (day_map)", "๊ฐ"], ["์คํ
/ ๊ตฌ๊ฐ", "15,000 (์ฝ 20๋ถ)"], ["ํด์๋", "800ร450 (2๋ฐฐ ์ถ์)"],
["๊ฐ์ฐ์์ ์ํ", "2,000,000"], ["lr ์์น / ์ค์ผ์ผ", "1.6e-4 (โ ร0.01) / 5e-3"],
["lr ํ์ / ๋ถํฌ๋ช
๋ / ์", "1e-3 / 5e-2 / 1e-3"], ["์ฌ๋ฐฐ์น ๊ตฌ๊ฐ", "500 ~ 15,000 ์คํ
"]],
[0.55, 0.45], size=10, rowh=0.37)
notes(s, "L_depth ๋ ๊ฐ์ ์ ์ ๋ผ์ด๋ค๋ฅผ ๊ทธ ์นด๋ฉ๋ผ์ ํฌ์ํ ๊น์ด ์ง๋์์ ์๋ ์ค์ฐจ๋ค. ์ฐจ๋ ํฝ์
์ ๋ผ์ด๋ค ๊น์ด๋ ์ฐจ ๋ค ๋ฐฐ๊ฒฝ์ด๋ผ ๋บ๋ค. GPU ํ
์ ๊ฐ์ ํ์ด์ฌ if ๋ก ๊ฒ์ฌํ๋ฉด ๋งค ์คํ
๋๊ธฐํ๊ฐ ๊ฑธ๋ ค ํ์ต ๋ฃจํ์์ ํผํ๋ค.")
# ------------------------------------------------------------------ 18 ๋ฆฌ๊ทธ ๋ณํ
s = slides[17]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โข ๋ฉํฐ๋ทฐ ๋ฆฌ๊ทธ ๋ณํ ๋ฐ ๋ ๋๋ง", [
"6๋ ์นด๋ฉ๋ผ ์ ์ฒด์ ๊ฐ์ ๋ณํ T ๋ฅผ ์ฃผ์ด ๋ฆฌ๊ทธ ๊ธฐํ๋ฅผ ์ ์งํ ์ฑ '๋ค๋ฅธ ์ฐจ์ ๋จ ์นด๋ฉ๋ผ' ๋ฅผ ๋ง๋ฆ โ ์์ฐจ ๊ถค์ ยท ์๊ฐ์ ์๋ณธ ๊ทธ๋๋ก",
"ํ๋ ์๋ง๋ค ๊ทธ ์๊ฐ์ ๋งก์ ๊ตฌ๊ฐ ๋ชจ๋ธ๋ก ๋ ๋๋งํ์ฌ ๊ตฌ๊ฐ ๊ฒฝ๊ณ์์๋ ์ ยท ๊ธฐํ ์ด์๋งค ์์ด ์ด์ด์ง (scene-0402: ๊ตฌ๊ฐ 5๊ฐ)",
])
pic = figure(s, "/home/mm/Downloads/vkgs-sim/docs/presentation/figures/out/fig_viewpoint_model_b.png", y + 0.1, h=2.9)
yy = y + 0.2 + pic.height / 914400
table(s, 0.85, yy, 11.8, [["๋จ๊ณ", "๋ด์ฉ"],
["1 ยท ๋ณํ ์ ์", "shift [x ์, y ์ผ์ชฝ, z ์] m ยท rot [roll, pitch, yaw]ยฐ โ configs/aug/rig_variants.json (9์ข
)"],
["2 ยท ์บ๋ฆฌ๋ธ ๋ณํ", "Rโฒ = Rz(yaw) ยท R ยท Rx(โpitch) ยท Rz(roll), tโฒ = t + shift โ w2cโฒ = (ego โ world ยท cam โ egoโฒ)โปยน ยท ฮ"],
["3 ยท ๋ด๋น ๊ตฌ๊ฐ", "CAM_FRONT ์๊ฐ โ [own0, own1) ์ธ ๊ตฌ๊ฐ ๋ชจ๋ธ (๊ฒน์นจ 10 m ์ ๊ฐ์ด๋ฐ์์ ์๋ฆ)"],
["4 ยท ๋ ๋ ยท ์ถ๋ ฅ", "๊ตฌ๊ฐ๋ง๋ค rig.txt โ ์คํ์คํฌ๋ฆฐ 6์บ (FXAA ๋, ํ๋ ํ๋ธ๋งต) โ <variant>/<CAM>/*.jpg + meta.json"]],
[0.16, 0.84], size=10, rowh=0.31)
notes(s, "๋ณํ ๊ณต์์ nusim/aug/rig_aug.py transform_calib ๊ทธ๋๋ก๋ค. pitch + ๋ ์นด๋ฉ๋ผ๊ฐ ์๋๋ก ์์ด๋ ๋ฐฉํฅ, yaw + ๋ ์ผ์ชฝ์ผ๋ก ๋๋ฆฌ๋ ๋ฐฉํฅ. ๋ฆฌ๊ทธ ์ ์ฒด์ ๊ฐ์ T ๋ฅผ ์ฃผ๋ฏ๋ก 6์บ ์ฌ์ด์ ์๋ ๊ธฐํ๊ฐ ์ค์ ์ฐจ๋์ฒ๋ผ ์ผ๊ด๋๋ค.")
# ================================================================== 10-14 ์ถ๊ฐ: ArtiFixer ยท ์ฐจ์ ํ์ฒ๋ฆฌ ยท ๋๋จน์ ยท ์์ธ ๋ถ์ ยท ๋
ธ๋ฉด ํ
์ค์ฒ
from pptx.chart.data import CategoryChartData as _CCD
from pptx.enum.chart import XL_LEGEND_POSITION
for sh in slides[0].shapes:
if sh.name == "ํ
์คํธ ๊ฐ์ฒด ํ 3":
set_runs_text(sh.text_frame, "2026. 10. 14.")
divider(slides[12], "๋ฉํฐ๋ทฐ ์์ ๋ณํ ๋ชจ๋ธ ์ํคํ
์ฒ", "6์บ ๋ฉํฐ๋ทฐ ์์์ ์๋ก์ด ์นด๋ฉ๋ผ ๋ฐฐ์น๋ก ๋ณํํ๋ ๋ชจ๋ธ โ ๊ตฌ๊ฐ๋ณ 3DGS ์ฌ๊ตฌ์ฑ ๋ชจ๋ธ์ ๊ตฌ์กฐ, ๋ชจ๋, ์์ค, ๋ฆฌ๊ทธ ๋ณํ, "
"๊ทธ๋ฆฌ๊ณ ๋ ๋๋ฅผ ๊ณ ์น๋ ArtiFixer ํ์ฐ ๋ณด์ ยท ๋
ธ๋ฉด ์ฐจ์ ํ์ฒ๋ฆฌ ยท 3DGS ๋๋จน์ ๋ฏธ์ธ์กฐ์ ์ ์ค๋ช
ํ๋ค.")
def line_chart(sl, x, y, w, h, cats, series, title, colors, ymin=None, ymax=None, fmt='0.0'):
cd = _CCD()
cd.categories = cats
for n, v in series:
cd.add_series(n, v)
gf = sl.shapes.add_chart(XL_CHART_TYPE.LINE_MARKERS, Inches(x), Inches(y), Inches(w), Inches(h), cd)
ch = gf.chart
ch.has_title = True
ch.chart_title.text_frame.text = title
tp = ch.chart_title.text_frame.paragraphs[0]
tp.runs[0].font.size, tp.runs[0].font.bold, tp.runs[0].font.name, tp.runs[0].font.color.rgb = Pt(11), True, FONT, NAVY
ch.has_legend = True
ch.legend.position = XL_LEGEND_POSITION.BOTTOM
ch.legend.include_in_layout = False
ch.legend.font.size, ch.legend.font.name = Pt(9), FONT
va = ch.value_axis
if ymin is not None:
va.minimum_scale = ymin
if ymax is not None:
va.maximum_scale = ymax
va.has_major_gridlines = True
va.major_gridlines.format.line.color.rgb = LIGHT
va.tick_labels.font.size = Pt(9)
va.format.line.fill.background()
ch.category_axis.tick_labels.font.size = Pt(9)
ch.category_axis.tick_labels.font.name = FONT
for k, s_ in enumerate(ch.plots[0].series):
s_.format.line.color.rgb = colors[k]
s_.format.line.width = Pt(2.25)
s_.marker.format.fill.solid()
s_.marker.format.fill.fore_color.rgb = colors[k]
s_.marker.format.line.color.rgb = colors[k]
s_.smooth = False
pl = ch.plots[0]
pl.has_data_labels = True
dl = pl.data_labels
dl.number_format, dl.number_format_is_linked = fmt, False
dl.position = XL_LABEL_POSITION.ABOVE
dl.font.size, dl.font.name = Pt(8), FONT
return ch
def flow(sl, y, steps, h=0.95, fills=None, size=10):
"""๊ฐ๋ก ๋จ๊ณ ์์ + ํ์ดํ."""
n = len(steps)
aw = 0.3
w = (11.8 - aw * (n - 1) - 0.06 * 2 * (n - 1)) / n
for i, (t, d) in enumerate(steps):
x = 0.85 + i * (w + aw + 0.12)
f = (fills or {}).get(i)
box(sl, x, y, w, h, d, title=t, fill=f or PALE, color=WHITE if f == NAVY else GRAY, line=None if f == NAVY else BLUE, size=size)
if i < n - 1:
arrow(sl, x + w + 0.06, y + h / 2 - 0.12, w=aw)
# ------------------------------------------------------------------ ๋ชจ๋ โฃ ArtiFixer (์)
s = slides[40]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โฃ ArtiFixer ํ์ฐ ๋ณด์ โ ์ ์์ ๋ ๋์ ๊ฒฐํจ ๋ณต์", [
"์ ์์ (์ 1 m ๋ฑ) ์์ 3DGS ๋ ๋๋ ํ๋ฆผ ยท floater ยท ๋น ๊ณณ์ด ์๊น โ ๋น๋์ค ํ์ฐ ๋ชจ๋ธ์ด ๊ฐ์ ์๊ฐ์ ์ค์ ์ฌ์ง์ ์ฐธ์กฐํด ๊ฒฐํจ์ ๊ณ ์น ์์์ ์์ฑํจ",
"ArtiFixer (NVIDIA, SIGGRAPH 2026) ์ฌ์ ํ์ต 1.3B ๋ชจ๋ธ์ ๊ทธ๋๋ก ์ฌ์ฉ โ ํ์ต ์์ด ์ถ๋ก ๋ง, ์ ๋ฉด ์นด๋ฉ๋ผ ยท ๋ฆฌ๊ทธ ๋ณํ 9์ข
ยท ํคํ๋ ์",
])
flow(s, y + 0.15, [
("์
๋ ฅ โ 3DGS ๋ ๋", "๊ตฌ๊ฐ ๋ชจ๋ธ ร ๋ณํ ์์ธ\n640ร360 ์ฐ์ ํ๋ ์\n+ ๋ถํฌ๋ช
๋ ์ง๋ (๋น ๊ณณ ํ์)"),
("์
๋ ฅ โก ์ฐธ์กฐ ๋ทฐ", "๊ฐ์ ์๊ฐ์ ์๋ ์นด๋ฉ๋ผ\n์ค์ ์ฌ์ง + ์์ธ\n(transforms.json)"),
("ArtiFixer 1.3B", "Wan2.1-T2V-1.3B ๊ธฐ๋ฐ\n์๊ธฐํ๊ท ๋น๋์ค ํ์ฐ\n์ฐธ์กฐ ๋ทฐ 3์ฅ ยท ๊ตญ์ ์ฃผ์ 14"),
("์ถ๋ ฅ", "๋ณด์ ์์ (ํคํ๋ ์)\nโ ๋ชจ๋ โค ์ฐจ์ ํ์ฒ๋ฆฌ\nโ ๋ชจ๋ โฅ 3DGS ๋๋จน์"),
], h=1.25, fills={2: NAVY})
table(s, 0.85, y + 1.65, 7.1, [["์ค์ ", "๊ฐ (configs/aug/artifixer.json)"],
["์ฒดํฌํฌ์ธํธ", "artifixer-1.3b.pt (Wan-AI/Wan2.1-T2V-1.3B-Diffusers)"],
["์ถ๋ก ์ธ์", "--num_views 3 ยท --max_neighbors_per_encode 1 ยท --local_attn_size 14"],
["๊ถค์ ", "--render_trajectory trajectory (๋ณํ ์์ธ ์์๋๋ก)"],
["์คํ ํ๊ฒฝ", "๋ณ๋ artifixer ํ๊ฒฝ ํ์ ํ๋ก์ธ์ค (torch ๋ฒ์ ๋ค๋ฆ), ์ฌ๋น ๋ชจ๋ธ 1ํ ๋ก๋"],
["VRAM ยท ์๊ฐ", "์ฝ 7.7 GB (8 GB ๊ฑฐ์ ์ ๋ถ) ยท ์ฌ๋น 26~38๋ถ (์ถ๋ก ์ฝ 25๋ถ)"]],
[0.32, 0.68], size=10, rowh=0.36)
box(s, 8.15, y + 1.65, 4.5, 2.16, "โข 3DGS ๋ ํ์ต ๊ถค์ ๊ทผ์ฒ์์๋ง ์ ๋ช
โ ์ ์ฐจ์ ์ ๊ฐ๋
์ด ์๋ค\nโข ํ์ฐ ๋ชจ๋ธ์ '๊ทธ๋ด๋ฏํ' ์ง๊ฐ์ ์ฑ์ฐ์ง๋ง ์ฐจ์ ๊ฐ์ ๊ธฐํ ์ ๋ณด๋ ํ๋ ค์ง๊ฑฐ๋ ๋๊น\n"
"โ ์ฐจ์ ์ ๋ชจ๋ โค ์์ ์ค์ ์ฌ์ง์ผ๋ก ๋๋๋ฆฐ๋ค", title="์ ํ์ํ๊ฐ ยท ํ๊ณ", fill=WHITE, line=ORANGE, size=10, align=PP_ALIGN.LEFT)
notes(s, "์ฐธ๊ณ : ArtiFixer (de Lutio et al., SIGGRAPH 2026, nv-tlabs/ArtiFixer), Difix3D+ (Wu et al., CVPR 2025) โ ๋ ๋ค 3D ์ฌ๊ตฌ์ฑ ๋ ๋๋ฅผ ํ์ฐ ๋ชจ๋ธ๋ก ๊ณ ์น๊ณ , ๊ณ ์น ์์์ ๋ค์ 3D ์ ์ฆ๋ฅํ๋ ๋ฐฉ์. "
"GPU ๊ฐ 8 GB ๋ผ ArtiFixer ๋ฅผ ๋๋ฆฌ๋ ๋์ ๋ทฐ์ด ยท ํ์ต์ ํจ๊ป ๋๋ฆด ์ ์๋ค.")
# ------------------------------------------------------------------ ๋ชจ๋ โค ์ฐจ์ ํ์ฒ๋ฆฌ (์)
s = slides[41]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โค ๋
ธ๋ฉด ํ๋ฉด ํธ๋ชจ๊ทธ๋ํผ ์ฐจ์ ํ์ฒ๋ฆฌ", [
"๊ฐ์ ์๊ฐ ยท ๊ฐ์ ์์ฐจ์์ ์นด๋ฉ๋ผ๋ง ์ฎ๊ธด ๊ฒ์ด๋ฏ๋ก, ๋
ธ๋ฉด์ ํ๋ฉด (์์ฐจ z = 0) ์ผ๋ก ๋ณด๋ฉด ๋ณํ ์นด๋ฉ๋ผ ํฝ์
์ ์๋ ์นด๋ฉ๋ผ์ ์ค์ ์ฌ์ง (1600ร900) ์ ์ ํํ ๋์์ํฌ ์ ์์ (์ญ์๊ทผ ๋ณํ, IPM)",
"๋
ธ๋ฉด๋ง ์ค์ ์ฌ์ง ํฝ์
๋ก ๋ฐ๊พธ๊ณ ๋๋จธ์ง๋ ArtiFixer ๊ฒฐ๊ณผ๋ฅผ ์ ์ง โ ์ฐจ์ ์ ์ ๊ฐ๊ฒฉ ยท ํญ ยท ์์ด ์ค์ ์ ๊ฐ์",
])
box(s, 0.85, y + 0.12, 11.8, 0.55, "x_o โ K_o (R โ t nแต / d) K_vโปยน x_v (n, d: ์์ฐจ ๋
ธ๋ฉด ํ๋ฉด, R, t: ๋ณํ โ ์๋ ์นด๋ฉ๋ผ)",
fill=NAVY, color=WHITE, size=14, bold=True)
flow(s, y + 0.85, [
("1 ยท ๊ด์ โ ๋
ธ๋ฉด", "๋ณํ ์นด๋ฉ๋ผ ํฝ์
๋ง๋ค\n๋
ธ๋ฉด ํ๋ฉด ๊ต์ X\n(35 m ๋์ผ๋ฉด ์ ์ธ)"),
("2 ยท ์๋ ์นด๋ฉ๋ผ๋ก", "X ๋ฅผ ์ค์ ์ฌ์ง์ ํฌ์\n์์ ํ ์ํ\n(์ฌ์ง ๋ฐ์ด๋ฉด ์ ์ธ)"),
("3 ยท ๋ง์คํฌ", "SegFormer-B5 (Cityscapes)\n์ฐจ๋๋ง ยท ์ฐจ๋ ยท ์ฌ๋\n9 px ํฝ์ฐฝํด ์ ์ธ"),
("4 ยท ์ ๋ง์ถค", "์ฐจ๋ (๋ฐ์ ์์ 20% ์ ์ธ)\nํ๊ท ยท ํ์คํธ์ฐจ๋ฅผ\nArtiFixer ์ชฝ์ผ๋ก (๋๋น 0.75)"),
("5 ยท ํฉ์ฑ", "์์ญ ์์ชฝ 12 px\n๊ฑฐ๋ฆฌ ๊ธฐ๋ฐ ํ๋\n+ ๊ฐ์ฐ์์ ๋ธ๋ฌ 1.5"),
], h=1.25)
table(s, 0.85, y + 2.3, 11.8, [["ํญ๋ชฉ", "๋ด์ฉ"],
["๋ชจ๋", "road (๊ถ์ฅ) = ์ฐจ๋ ์ ์ฒด๋ฅผ ์ค์ ์ฌ์ง์ผ๋ก ยท band = HD ๋งต ์ฐจ์ (lane ยท road divider, ํก๋จ๋ณด๋, ์ ์ง์ ) ยฑ0.6 m ๋ ๋ง"],
["๋ณด๋๋ฅผ ๋นผ๋ ์ด์ ", "๋ณด๋๋ ์ฝ 15 cm ๋์ ํ๋ฉด ๊ฐ์ ์ด ๊นจ์ง โ ์ 1 m ์์ ์์ ๋ช ํฝ์
์ฉ ์ด๊ธ๋จ"],
["๋งต์ ์ง์ ๊ทธ๋ฆฌ์ง ์๋ ์ด์ ", "HD ๋งต์๋ ์ ์ ๊ฐ๊ฒฉ ยท ํญ์ด ์๊ณ ์์๊ณผ 10~30 cm ์ด๊ธ๋จ โ ๋งต์ '์ด๋์' ๋ง, ๋ชจ์์ ์ค์ ์ฌ์ง์์"],
["๊ตฌํ", "nusim/aug/lane_fix.py (LaneFixConfig), nusim aug artifixer ์ lanefix ๋จ๊ณ"]],
[0.2, 0.8], size=10, rowh=0.34)
notes(s, "์ฐธ๊ณ : ์ญ์๊ทผ ๋ณํ(IPM) โ Mallot et al. 1991, Bertozzi & Broggi GOLD 1998. ์ธ๊ทธ๋ฉํ
์ด์
โ SegFormer (Xie et al., NeurIPS 2021), Cityscapes (Cordts et al., CVPR 2016). "
"ํ๋ฉด ํธ๋ชจ๊ทธ๋ํผ๋ ํํํ ๋
ธ๋ฉด์์ ๊ธฐํ๊ฐ ์ ํํ๋ฏ๋ก ํ์ต ์์ด ์ค์ ์ฌ์ง์ ํด์๋๋ฅผ ๊ทธ๋๋ก ๊ฐ์ ธ์จ๋ค.")
# ------------------------------------------------------------------ ๋ชจ๋ โฅ 3DGS ๋๋จน์ (์)
s = slides[42]
y = body(s, "๋ชจ๋ธ ๊ตฌ์กฐ", "๋ชจ๋ โฅ 3DGS ๋๋จน์ ๋ฏธ์ธ์กฐ์ (ArtiFixer3D ์ ์ฆ๋ฅ)", [
"๋ณด์ ์์์ ๋ณํ ์์ธ์ ์์ฌ ์ ๋ต์ผ๋ก ์ผ์ ๊ตฌ๊ฐ 3DGS ๋ชจ๋ธ์ ์ด์ด ํ์ต โ ์๋ฎฌ๋ ์ดํฐ๊ฐ ์ค์๊ฐ ๋ ๋ํ๋ 3D ๋ชจ๋ธ ์์ฒด๋ฅผ ๊ณ ์นจ",
"์ค์ ๋ทฐ ๊ฐ๋
(์ฌ์ง ยท ๋ผ์ด๋ค ๊น์ด ยท ํ๋ ๋ง์คํฌ) ์ ๊ทธ๋๋ก ๋๊ณ , ์์ฌ ๋ทฐ๋ฅผ 30% ํ๋ฅ ยท ๊ฐ์ค 0.5 ๋ก ์์",
])
table(s, 0.85, y + 0.15, 5.6, [["์ค์ (scripts/artifixer_distill.py)", "๊ฐ"],
["์์์ ", "๊ตฌ๊ฐ ๋ชจ๋ธ (ํ๋ ยท ์ ๋ณด์ ยท ์ธ๋ถ ๋ณด์ ์ด์ด๋ฐ์)"],
["์์ฌ ๋ทฐ", "lanefix ํคํ๋ ์ 640ร360 โ ํ์ต ํด์๋๋ก ์
์ค์ผ์ผ"],
["์คํ
ยท ํ๋ฅ ยท ๊ฐ์ค", "3,000 ยท 0.3 ยท 0.5"],
["lr ์์น", "1.6e-4 (๊ธฐํ๋ ์์ง์ด๋๋ก)"],
["์ฌ๋ฐฐ์น", "500 ~ 1,500 ์คํ
, ์ํ 200๋ง ์ ์ง"],
["๊ฒฐ๊ณผ", "7์ฌ 18๊ตฌ๊ฐ โ outputs/gs_day_afx"],
["์๊ฐ ยท VRAM", "๊ตฌ๊ฐ๋น ์ฝ 3.7๋ถ ยท 2.3 GB"],
["์ ์ PSNR (์ค์๊ฐ)", "23.92 โ 23.65 dB (์๋ ๊ถค์ , โ0.27)"]],
[0.42, 0.58], size=10, rowh=0.36)
image(s, A + "afx_distill.jpg", 6.65, y + 0.15, w=6.0, h=3.4)
caption(s, 6.65, y + 3.6, 6.0, "์ 1 m ์์ โ ์: ์๋ ๋ชจ๋ธ, ์๋: ๋๋จน์ ํ (scene-0001)")
notes(s, "์๋ ๊ถค์ PSNR ์ 0.27 dB ๋ด๋ ค๊ฐ์ง๋ง ์ ์ฐจ์ ์์ ์์ ์ฐจ ์์ ยท floater ๊ฐ ์ฌ๋ผ์ง๋ค. ๋ค๋ง ์ฐจ์ ์ ๋ช
๋๋ ๊ฑฐ์ ๊ทธ๋๋ก โ ์์ธ ๋ถ์์ ์งํ ํํฉ์ '์ฐจ์ ํ์ง ์์ธ ๋ถ์' ์ฅ.")
# ------------------------------------------------------------------ ArtiFixer ์ฆ๊ฐ ๊ฒฐ๊ณผ (์)
s = slides[43]
y = body(s, "์ฆ๊ฐ", "ArtiFixer + ์ฐจ์ ํ์ฒ๋ฆฌ ์ฆ๊ฐ ๊ฒฐ๊ณผ", [
"์ 1 m ๋ณํ ์์ (scene-0001) โ ๊ธฐ์กด 3DGS ์ฆ๊ฐ์ ๋ฒ์ง ยท ์ฐจ ์์ ยท ๋๊ธด ์ฐจ์ ์ด ArtiFixer ๋ก ์ ๋ฆฌ๋๊ณ , ๋
ธ๋ฉด์ ์ค์ ์ฌ์ง์ ์ฐจ์ ์ผ๋ก ๋ฐ๋",
])
pic = image(s, A + "afx_compare.jpg", 0.85, y + 0.12, h=3.2)
pw = pic.width / 914400
for k, n in enumerate(["๊ธฐ์กด 3DGS ์ฆ๊ฐ", "ArtiFixer", "ArtiFixer + ์ฐจ์ ํ์ฒ๋ฆฌ"]):
caption(s, 0.85 + k * pw / 3, y + 3.35, pw / 3, n + " โ")
bx = 0.85 + pw + 0.2
bw = 12.65 - bx
for k, (t, d) in enumerate([("์งํ", "10์ฌ ์๋ฃ ยท 3,584์ฅ\n์ ๋ฉด ์นด๋ฉ๋ผ ยท ๋ณํ 9์ข
ยท ํคํ๋ ์\n๋จ์ ์ฝ 84์ฌ (์ฝ 2์ผ)"),
("๊ฒฐ๊ณผ ๊ฒฝ๋ก", "outputs/aug/aug_artfixer/\n<scene>_lanefix/<variant>/CAM_FRONT/"),
("ํ๊ณ", "์ง์ด ์ฐจ๋ ์๋ฆฌ์ ํ์ ์๊ฐ (์๋ ์ค)\n์ ๋ฉด ์นด๋ฉ๋ผ๋ง (6์บ ์ ์๊ฐ 6๋ฐฐ)")]):
box(s, bx, y + 0.12 + k * 1.1, bw, 1.0, d, title=t, fill=PALE if k < 2 else WHITE, line=BLUE if k < 2 else ORANGE, size=10)
notes(s, "๊ธฐ์กด ์ฆ๊ฐ(outputs/aug/map, 94์ฌ ยท 20๋ง ์ฅ)์ ๊ทธ๋๋ก ๋๊ณ , ArtiFixer ์ฆ๊ฐ์ ๋ณ๋ ๊ฒฝ๋ก์ ๋ง๋ ๋ค. ๋๋ ์ฌ์ done.json ์ผ๋ก ํ์ํด ๋์๋ค ๋ค์ ๋๋ ค๋ ์ด์ด์ง๋ค.")
# ------------------------------------------------------------------ ์ฐจ์ ํ์ง ์์ธ ๋ถ์ (์)
s = slides[44]
y = body(s, "์งํ ํํฉ", "์ฐจ์ ํ์ง ์์ธ ๋ถ์ โ ์๋ฎฌ ๋ ๋๊ฐ 2D ํ์ฒ๋ฆฌ๋ณด๋ค ํ๋ฆฐ ์ด์ ", [
"2D ํ์ฒ๋ฆฌ๋ ์ค์ ์ฌ์ง ํฝ์
(1600ร900) ์ ์ ํํ ๋
ธ๋ฉด ํ๋ฉด์ผ๋ก ์ฎ๊ธฐ์ง๋ง, ์๋ฎฌ์ 3DGS ๊ฐ์ฐ์์์ด ๊ทธ๋ฆฐ ๋
ธ๋ฉด์ ๋ ๋ โ ํ์ต ์์ธ์์๋ ๋
ธ๋ฉด ๊ณ ์ฃผํ๊ฐ ์ฌ์ง์ 17~18% ๋ฟ",
])
fx = [("85 cm", "๋
ธ๋ฉด ํฝ์
์ ๊ทธ๋ฆฌ๋ ๊ฐ์ฐ์์\nํฐ์ถ (๊ฐ์ค ์ค์๊ฐ)"), ("3.8%", "200๋ง ๊ฐ ์ค ๋
ธ๋ฉด ๋ชซ\n(๊ฑด๋ฌผ 51 ยท ํ๋ 19 ยท ์์ 18%)"),
("โ45 cm", "๋
ธ๋ฉด ๊ฐ์ฐ์์ ์ค์ฌ ๋์ด\n(์ค์ ๋
ธ๋ฉด โ0.6 cm)"), ("0.17", "๋
ธ๋ฉด ์ ๋ช
๋ ๋ ๋/์ฌ์ง\n(ํ์ต ์์ธ์์๋)")]
for i, (n, l) in enumerate(fx):
kpi(s, 0.85 + i * 3.0, y + 0.12, 2.75, n, l, color=ORANGE if i == 0 else NAVY)
table(s, 0.85, y + 1.38, 6.0, [["๊ด์ฐฐ (scene-0001 seg0)", "์๋ฏธ"],
["30 cm ๋๋ ๊ฐ์ฐ์์์ด ๋
ธ๋ฉด ๊ธฐ์ฌ 95~96%", "10~15 cm ํญ ์ฐจ์ ์ ํํ ๋ชป ํจ"],
["|cos(์งง์์ถ, ๋ฒ์ )| 0.46~0.52", "๋
ธ๋ฉด์ ๋ฉ์ํ์ง ์๊ณ ๊ธฐ์ธ์ด์ง ๋ฉ์ด๋ฆฌ"],
["์ค์ฌ โ45 cm ์ธ๋ฐ ๊น์ด๋ ํ๋ฉด๊ณผ 1~2% ์ผ์น", "์ฌ๋ฌ ๋ฉ์ด๋ฆฌ ํฉ์ผ๋ก 'ํ๊ท ๊น์ด' ๋ง ๋ง์ถค"],
["์ ์ฐจ์ ์ฝ 25๊ฐ/mยฒ", "3 cm ํด์๋ (1,100๊ฐ/mยฒ) ์ 2%"],
["๋๋จน์ ๋ฏธ์ธ์กฐ์ ์ผ๋ก ์ ๊ณ ์ณ์ง", "์ํ์ด ์ด๋ฏธ ์ฐจ ์๊ณ 3k ์คํ
ยท 640ร360 ๋ชฉํ"]],
[0.55, 0.45], size=9.5, rowh=0.36)
line_chart(s, 7.05, y + 1.38, 5.6, 2.6, ["โ1.0 m", "0 m", "+0.5 m", "+1.0 m", "+1.5 m"],
[("์๋ ๋ชจ๋ธ", (24.46, 26.73, 25.81, 25.14, 24.86)), ("๋๋จน์ ํ (afx)", (25.47, 27.63, 26.94, 26.22, 25.76))],
"๋
ธ๋ฉด PSNR (dB) vs ์ ์ด๋ โ ์ค์ ์ฌ์ง ํ๋ฉด ์ํ ๊ธฐ์ค", [BLUE, ORANGE], ymin=23.5, ymax=28.5, fmt='0.0')
notes(s, "์ธก์ : ํคํ๋ ์ 8์ฅ, ์ฐจ๋(SegFormer) ์ค ํ๋ฉด ์ํ๊ฐ ์ ํจํ ํฝ์
๋ง. ๋๋จน์์ PSNR ์ ์ฝ 1 dB ์ฌ๋ฆฌ์ง๋ง ์ ๋ช
๋(๋ผํ๋ผ์์ ๋น)๋ 0.15~0.17 ๋ก ๊ทธ๋๋ก๋ค โ ์์ ๋ง์ถ์ง๋ง ์ฐจ์ ๋ชจ์์ ๋ชป ๋ง๋ ๋ค. "
"๊ฒฐ๋ก : ๋
ธ๋ฉด์ ๊ฐ์ฐ์์์ ๋งก๊ธฐ์ง ๋ง๊ณ ๋ฐ๋ก ํํํด์ผ ํ๋ค (๋ค์ ์ฅ).")
# ------------------------------------------------------------------ ๋
ธ๋ฉด ํ
์ค์ฒ ๋ ์ด์ด ์ํ (์)
s = slides[45]
y = body(s, "์งํ ํํฉ", "ํด๊ฒฐ ๋ฐฉํฅ โ ๋
ธ๋ฉด ํ
์ค์ฒ ๋ ์ด์ด ์ํ (scene-0001 seg0)", [
"์ ๋ฉด ์นด๋ฉ๋ผ 142์ฅ (์ค์ ํฌํจ) ์ ํ๋ฉด ํธ๋ชจ๊ทธ๋ํผ๋ก ๋
ธ๋ฉด ์ ์ฌ์์ (3 cm/px, 2,257 mยฒ) ์ ๋ชจ์ผ๊ณ , ๋
ธ๋ฉด ยท ๋
์ ๊ฐ์ฐ์์์ ๋นผ๊ณ ๊ทธ ์๋ ํ
์ค์ฒ ํ๋ฉด์ ๊น์ ๋ ๋",
])
image(s, A + "roadtex_bev.jpg", 0.85, y + 0.1, w=4.6, h=1.75)
caption(s, 0.85, y + 1.86, 4.6, "๋
ธ๋ฉด ํ
์ค์ฒ (BEV, ์
๋ง๋ค ๊ฐ์ฅ ๊ฐ๊น์ด์ ๋ณธ ์ฌ์ง)")
pp_ = image(s, A + "roadtex_panel.jpg", 5.6, y + 0.35, w=7.05)
cw3 = 7.05 / 3
for k, n in enumerate(["3DGS (+1 m)", "3DGS + ๋
ธ๋ฉด ํ
์ค์ฒ (+1 m)", "์ค์ ์ฌ์ง ํ๋ฉด ์ํ"]):
caption(s, 5.6 + k * cw3, y + 0.38 + pp_.height / 914400, cw3, n)
line_chart(s, 0.85, y + 2.25, 5.85, 2.15, ["โ1.0 m", "0 m", "+0.5 m", "+1.0 m", "+1.5 m"],
[("3DGS", (0.17, 0.18, 0.17, 0.16, 0.16)), ("3DGS + ๋
ธ๋ฉด ํ
์ค์ฒ", (0.96, 1.02, 1.00, 0.93, 0.89))],
"๋
ธ๋ฉด ์ ๋ช
๋ (๋ ๋ / ์ฌ์ง) vs ์ ์ด๋", [BLUE, ORANGE], ymin=0, ymax=1.2, fmt='0.00')
table(s, 6.85, y + 2.3, 5.8, [["", "3DGS", "+ ๋
ธ๋ฉด ํ
์ค์ฒ"],
["๋
ธ๋ฉด PSNR, โ1 m", "24.46", "25.63"],
["๋
ธ๋ฉด PSNR, 0 m", "26.73", "25.87"],
["๋
ธ๋ฉด PSNR, +1 m", "25.14", "26.13"],
["๋บ ๊ฐ์ฐ์์", "โ", "67๋ง (34%)"],
[" ๊ทธ์ค ๋
์ 1.5 m ์๋", "โ", "43๋ง (22%)"]],
[0.46, 0.24, 0.3], size=10, rowh=0.32, align_right=(1, 2))
notes(s, "๊ฐ์ฐ์์์ ๋นผ๋ ๊ธฐ์ค: ํ
์ค์ฒ ์ ๋
ธ๋ฉด๋ณด๋ค 0.3 m ์๋, ์ฐจ๋ ์
์ 2 m ์๋, ํ
์ค์ฒ ๋๋ 15 m ์ 0.5 m ์๋, ๊ทธ๋ฆฌ๊ณ ๊ฐ์ฅ ๊ฐ๊น์ด ์์ฐจ ๋
ธ๋ฉด๋ณด๋ค 1.5 m ๋๊ฒ ์๋. "
"๋
์ ๊ฐ์ฐ์์ 43๋ง ๊ฐ(์์ฐ์ 22%)๋ ๋
ธ๋ฉด์ ์๋์์ ๋ฎ์ด ์ฐจ์ ์ ํ๋ฆฌ๋ ๊ฒ์ด๋ค โ ์์ง์์๋ ๊น์ด ํ
์คํธํ๋ ๋
ธ๋ฉด ๋ฉ์๊ฐ ๊ฐ๋ฆฐ๋ค. "
"0 m ์์ PSNR ์ด 0.9 dB ๋ฎ์ ๊ฒ์ ํ๋ ์ ์ฌ์ด ๋
ธ์ถ ์ด์๋งค ยท 1~2 px ์ ๋ ฌ ์ค์ฐจ. ๋ค์: ์์ง ๋ฉ์ ํจ์ค๋ก ์ด์, 6์บ ยท ์ ์ฌ ํ
์ค์ฒ.")
# ------------------------------------------------------------------ ๊ธฐ์กด ์ฅ ๊ฐฑ์
s = slides[22]
for gf in s.shapes:
if gf.has_table:
c = gf.table.cell(2, 1)
c.text_frame.paragraphs[0].runs[0].text = "์ 1 m ์์ ๋
ธ๋ฉด ๋ฒ์ง ยท ์ง์ด ์ฐจ๋ ์๋ฆฌ๊ฐ ํ๋ฆฟํ๊ฒ ๋จ์ โ ArtiFixer + ์ฐจ์ ํ์ฒ๋ฆฌ ์ฆ๊ฐ์ผ๋ก ๋ณด์ (๋ค์ ์ฅ)"
s = slides[22]
for sh in s.shapes:
if sh.name == "TextBox 9":
for para in sh.text_frame.paragraphs:
if para.runs and "32์ฌ" in "".join(r.text for r in para.runs):
para.runs[0].text = "ํ์ฌ 94์ฌ ์๋ฃ: 205,331์ฅ (40 GB) โ 284์ฌ ์๋ฃ ์ ์ฝ 61๋ง ์ฅ์ผ๋ก ๋ฎ ๋ฐ์ดํฐ๊ฐ 9๋ฐฐ๊ฐ ๋จ"
for r in para.runs[1:]:
r.text = ""
s = slides[36]
for sh in list(s.shapes):
if sh.name not in KEEP:
sh._element.getparent().remove(sh._element)
y = body(s, "์งํ ํํฉ", "์ฑ๊ฐํฌ๋ฅด ๋ฎ ๋งต ๊ตฌ์ถ ํํฉ (2026-10-14)", [
"ํ์ต ๋จ์ 696๊ฐ ์ค 313๊ฐ (45%) ์๋ฃ โ 10์ 13์ผ๋ถํฐ ์ผ๊ด ํ์ต์ ์ ์ ๋ฉ์ถ๊ณ ArtiFixer ์ฆ๊ฐ์ ๋จผ์ ์งํ (GPU 8 GB ๋ฅผ ํจ๊ป ๋ชป ์)",
"ArtiFixer ์ฆ๊ฐ์ด ๋๋ ์ฌ๊น์ง ๋ง์น๋ฉด ๊ฐ์ ์์
์ด day_map ์ผ๊ด ํ์ต์ ์๋ ์ฌ๊ฐํจ (nusim run aug_artifixer) โ ์ ์ฒด ๋งต ํ์ต์ ๊ณ์",
])
for i, (n, l) in enumerate([("313 / 696", "ํ์ต ๋จ์ (45%)"), ("94", "3DGS ์ฆ๊ฐ ์ฌ (205k์ฅ ยท 40 GB)"), ("10์ฌ", "ArtiFixer + ์ฐจ์ ํ์ฒ๋ฆฌ (3.6k์ฅ)"), ("313", "์๋งจํฑ ๋ผ๋ฒจ (๋ชจ๋ ๊ตฌ๊ฐ)")]):
kpi(s, 0.85 + i * 3.0, y + 0.15, 2.75, n, l)
table(s, 0.85, y + 1.5, 11.75, [["ํญ๋ชฉ", "10์ 12์ผ", "10์ 14์ผ"], ["์๋ฃ ํ์ต ๋จ์", "253", "313"], ["3DGS ์ฆ๊ฐ ์ฌ ยท ์ด๋ฏธ์ง", "75์ฌ ยท 160.9k", "94์ฌ ยท 205.3k"],
["ArtiFixer ์ฆ๊ฐ ยท ๋๋จน์", "โ", "10์ฌ 3,584์ฅ ยท 7์ฌ 18๊ตฌ๊ฐ ๋ฏธ์ธ์กฐ์ (gs_day_afx)"],
["์๋งจํฑ ์นด๋ฉ๋ผ", "์ผ๋ถ ๊ตฌ๊ฐ๋ง ๋ผ๋ฒจ (๋๋จธ์ง ๊ฒ๊ฒ ๋ณด์)", "๋ชจ๋ ๊ตฌ๊ฐ ๋ผ๋ฒจ ยท render view/map ์ด ์์ผ๋ฉด ์๋ ์์ฑ"]],
[0.3, 0.3, 0.4], size=12, rowh=0.4)
notes(s, "์๋งจํฑ ์นด๋ฉ๋ผ๊ฐ ํ๋ฐฑ์ผ๋ก ๋ณด์ด๋ ๊ฒ์ 313๊ฐ ์ค 170๊ฐ ๊ตฌ๊ฐ์ semantic.rgba ๊ฐ ์์ด์์๋ค (๋ผ๋ฒจ์ด ์์ผ๋ฉด ํ๋๋ง ํ๋๊ณ ๋๋จธ์ง๊ฐ ๊ฒ๋ค). ์ง๊ธ์ ๋ชจ๋ ์ฑ์ ๋ค.")
s = slides[37]
for sh in list(s.shapes):
if sh.name not in KEEP:
sh._element.getparent().remove(sh._element)
y = body(s, "ํฅํ ๊ณํ", "ํฅํ ์ฐ๊ตฌ ๊ณํ", [
"๋
ธ๋ฉด ํ
์ค์ฒ ๋ ์ด์ด๋ฅผ ์์ง์ ๋ฃ์ด ์ฐจ์ ํ์ง์ ์๋ฎฌ์์๋ ํ๋ณดํ๊ณ , ์ง์ญ ๋งต์ ์์ฑํ ๋ค ์ฃผํ ๋ชจ๋ธ์ ํ์ฐ๋ ์์๋ก ์งํํจ",
])
plans = [("๋
ธ๋ฉด ํ
์ค์ฒ ๋ ์ด์ด (ํต์ฌ ๊ณผ์ )", "์ํ์์ ์ฐจ์ ์ ๋ช
๋ 0.16 โ 0.93 (์ 1 m) โ ๋ ๋ ๊ทธ๋ํ์ ๋
ธ๋ฉด ๋ฉ์ ํจ์ค ์ถ๊ฐ, 6์บ ยท ์ ์ฌ ํ
์ค์ฒ, ๋
์ ๊ฐ์ฐ์์ ์ ๋ฆฌ"),
("ArtiFixer ์ฆ๊ฐ ยท ๋งต ์์ฑ", "๋จ์ ์ฝ 84์ฌ ArtiFixer ์ฆ๊ฐ (์ฝ 2์ผ) โ day_map ์ผ๊ด ํ์ต ์ฌ๊ฐ (383๋จ์ ๋จ์)"),
("VLA ์ฐ๊ฒฐ ยท ํ๊ฐ", "closed-loop ์ฐ๊ฒฐ (--serve + Gym) ๊ณผ HD-Score ์งํ๋ ๊ตฌํ๋จ โ VLM/VLA ์ ์ฑ
์ ์ง์ญ ๋งต ์์์ ํ๊ฐ"),
("๊ตํต ์ฐธ๊ฐ์ ยท ์ฅ์ ๋ฌผ", "3DRealCar ์ฐจ๋ ์์
์ฝ์
, ์ง์ญ ๋จ์ ์ฅ์ ๋ฌผ ์ง๋ (๊ฑด๋ฌผ ยท ๊ธฐ๋ฅ ์ถฉ๋), queenstown ยท holland village ์ง์ญ ๋งต")]
for i, (t, d) in enumerate(plans):
r, c = divmod(i, 2)
box(s, 0.85 + c * 6.0, y + 0.2 + r * 1.75, 5.75, 1.55, d, title=t, fill=NAVY if i == 0 else PALE, color=WHITE if i == 0 else GRAY,
line=None if i == 0 else BLUE, size=12)
notes(s, "๋
ธ๋ฉด ํ
์ค์ฒ๋ ํ๋ ์ ์ฌ์ด ๋
ธ์ถ ์ด์๋งค์ ์ฐจ๋ ๊ฐ๋ฆผ ๊ตฌ๋ฉ ์ฒ๋ฆฌ๊ฐ ๋จ์๋ค. ๋์์ผ๋ก๋ ๋ผ์ด๋ค ์ง๋ฉด์ ๋ฉ์ํ ๋
ธ๋ฉด ๊ฐ์ฐ์์์ ๋ฐ๋ก ๋๊ณ ๋ค์ ํ์ตํ๋ ๋ฐฉ๋ฒ(2DGS ยท RoGS ์)์ด ์๋ค.")
# ------------------------------------------------------------------ ์์: ์ ์ฅ์ ์ ์๋ฆฌ๋ก
lst = prs.slides._sldIdLst
ids = list(lst)
order = list(range(0, 18)) + [40, 41, 42] + list(range(18, 23)) + [43] + list(range(23, 37)) + [44, 45] + list(range(37, 40))
assert sorted(order) == list(range(len(ids)))
for e in ids:
lst.remove(e)
for k in order:
lst.append(ids[k])
prs.save(sys.argv[2])
print("saved", sys.argv[2], len(prs.slides))
import copy
import os
import json
from PIL import Image
from pptx import Presentation
from pptx.chart.data import CategoryChartData
from pptx.dml.color import RGBColor
from pptx.enum.chart import XL_CHART_TYPE, XL_LABEL_POSITION
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.oxml.ns import qn
from pptx.util import Inches, Pt
A = "/tmp/claude-1000/-home-mm-Downloads-vkgs-sim/8bf0e66c-975d-4257-af27-61bc25ee4316/scratchpad/deck/"
NAVY, BLUE, LIGHT, PALE, GRAY, ORANGE, WHITE = (RGBColor(0x1F, 0x3B, 0x70), RGBColor(0x44, 0x72, 0xC4), RGBColor(0xDC, 0xE6, 0xF4),
RGBColor(0xF2, 0xF5, 0xFA), RGBColor(0x40, 0x40, 0x40), RGBColor(0xED, 0x7D, 0x31),
RGBColor(0xFF, 0xFF, 0xFF))
FONT = "๋ง์ ๊ณ ๋"
KEEP = {"์ฌ๋ผ์ด๋ ๋ฒํธ ๊ฐ์ฒด ํ 1", "์ ๋ชฉ 1", "๊ทธ๋ฃน 6", "TextBox 9", "TextBox 4"}
def shape(sl, name):
for sh in sl.shapes:
if sh.name == name:
return sh
raise KeyError(name)
def set_runs_text(tf, text):
"""์ฒซ ๋ฌธ๋จ ์ฒซ run ์ ์์์ผ๋ก text ๋ง ๋จ๊ธด๋ค."""
p0 = tf.paragraphs[0]
for p in tf.paragraphs[1:]:
p._p.getparent().remove(p._p)
runs = p0.runs
if not runs:
p0.text = text
return
runs[0].text = text
for r in runs[1:]:
r._r.getparent().remove(r._r)
def set_paragraphs(tf, items):
"""์ฒซ ๋ฌธ๋จ์ ๋ณธ์ผ๋ก ๋ฌธ๋จ๋ง๋ค ๋ณต์ฌ (๊ธ๋จธ๋ฆฌํยท๊ฐ๊ฒฉ ์ ์ง)."""
p0 = tf.paragraphs[0]._p
for p in tf.paragraphs[1:]:
p._p.getparent().remove(p._p)
parent = p0.getparent()
proto = copy.deepcopy(p0)
parent.remove(p0)
for it in items:
p = copy.deepcopy(proto)
rs = p.findall(qn("a:r"))
for r in rs[1:]:
p.remove(r)
if rs:
rs[0].find(qn("a:t")).text = it
parent.append(p)
def body(sl, tab, heading, bullets):
for sh in list(sl.shapes):
if sh.name not in KEEP:
sh._element.getparent().remove(sh._element)
set_runs_text(shape(sl, "์ ๋ชฉ 1").text_frame, "VKGS-Sim")
set_runs_text(shape(sl, "TextBox 4").text_frame, tab)
grp = shape(sl, "๊ทธ๋ฃน 6")
for c in grp.shapes:
if c.has_text_frame and c.text_frame.text.strip():
set_runs_text(c.text_frame, heading)
set_paragraphs(shape(sl, "TextBox 9").text_frame, bullets)
return 1.82 + 0.28 * sum(1 + len(b) // 95 for b in bullets) + 0.15 # ๋ณธ๋ฌธ ๋ค์ y (12pt, ์ค๊ฐ๊ฒฉ 150%)
def notes(sl, text):
sl.notes_slide.notes_text_frame.text = text
def tb(sl, x, y, w, h, text, size=12, bold=False, color=GRAY, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, font=FONT):
t = sl.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = t.text_frame
tf.word_wrap = True
tf.margin_left = tf.margin_right = Inches(0.04)
tf.margin_top = tf.margin_bottom = Inches(0.02)
tf.vertical_anchor = anchor
for i, line in enumerate(text.split("\n")):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = align
r = p.add_run()
r.text = line
r.font.size, r.font.bold, r.font.color.rgb, r.font.name = Pt(size), bold, color, font
return t
def box(sl, x, y, w, h, text, fill=LIGHT, color=GRAY, size=12, bold=False, line=None, align=PP_ALIGN.CENTER, title=None):
s = sl.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h))
s.adjustments[0] = 0.08
s.fill.solid()