Skip to content

Commit e61e8d9

Browse files
committed
feat: add quantitative metrics tables with all baseline comparisons
- Add DatasetMetrics and SceneMetrics types - Include AsyncEv-Deblur (7 scenes) and Ev-DeblurBlender (4 scenes) datasets - Compare 5 methods: 3DGS, BAGS, DeblurGS, LSENeRF, Ours - Display PSNR, SSIM, LPIPS metrics with color-coded best values - Blue for best PSNR, Yellow for best SSIM, Green for best LPIPS - Include Average row for each dataset
1 parent 2cb07ee commit e61e8d9

3 files changed

Lines changed: 131 additions & 73 deletions

File tree

src/App.tsx

Lines changed: 81 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import remarkMath from 'remark-math';
55
import rehypeKatex from 'rehype-katex';
66
import 'katex/dist/katex.min.css';
77
import { RESEARCH_DATA } from './constants';
8-
import type { MetricPoint, ComparisonItem, ChatMessage } from './types';
8+
import type { ComparisonItem, ChatMessage, DatasetMetrics } from './types';
99

1010
// Import comparison images
1111
import realWorldPatio from './assets/real-world-patio.png';
@@ -241,61 +241,81 @@ const InteractiveResults: React.FC<{ comparisons: ComparisonItem[] }> = ({ compa
241241
);
242242
};
243243

244-
const MetricsChart: React.FC<{ data: MetricPoint[] }> = ({ data }) => {
245-
const maxEpoch = Math.max(...data.map(d => d.epoch));
246-
const maxPSNR = Math.max(...data.map(d => d.psnr)) * 1.1;
247-
248-
// Simple SVG Line Chart
249-
const width = 600;
250-
const height = 300;
251-
const padding = 40;
244+
const QuantitativeTable: React.FC<{ dataset: DatasetMetrics }> = ({ dataset }) => {
245+
const methods = ["3DGS", "BAGS", "DeblurGS", "LSENeRF", "Ours"];
252246

253-
const xScale = (val: number) => padding + (val / maxEpoch) * (width - 2 * padding);
254-
const yScale = (val: number) => height - padding - (val / maxPSNR) * (height - 2 * padding);
255-
256-
const points = data.map(d => `${xScale(d.epoch)},${yScale(d.psnr)}`).join(' ');
247+
const getCellClass = (scene: typeof dataset.scenes[0], method: string, metric: 'psnr' | 'ssim' | 'lpips') => {
248+
const isBest = scene.best[metric] === method;
249+
if (!isBest) return "";
250+
251+
switch (metric) {
252+
case 'psnr': return 'bg-blue-100 text-blue-800 font-bold';
253+
case 'ssim': return 'bg-yellow-100 text-yellow-800 font-bold';
254+
case 'lpips': return 'bg-green-100 text-green-800 font-bold';
255+
}
256+
};
257257

258258
return (
259-
<div className="w-full overflow-x-auto">
260-
<div className="min-w-[500px]">
261-
<svg viewBox={`0 0 ${width} ${height}`} className="w-full h-auto font-sans text-xs">
262-
{/* Grid lines */}
263-
{[0, 0.25, 0.5, 0.75, 1].map(t => (
264-
<line
265-
key={t}
266-
x1={padding}
267-
y1={height - padding - t * (height - 2 * padding)}
268-
x2={width - padding}
269-
y2={height - padding - t * (height - 2 * padding)}
270-
stroke="#e2e8f0"
271-
strokeDasharray="4 4"
272-
/>
273-
))}
274-
275-
{/* Axes */}
276-
<line x1={padding} y1={height - padding} x2={width - padding} y2={height - padding} stroke="#94a3b8" />
277-
<line x1={padding} y1={padding} x2={padding} y2={height - padding} stroke="#94a3b8" />
278-
279-
{/* Line */}
280-
<polyline points={points} fill="none" stroke="#2563eb" strokeWidth="3" />
281-
282-
{/* Points */}
283-
{data.map((d, i) => (
284-
<circle
285-
key={i}
286-
cx={xScale(d.epoch)}
287-
cy={yScale(d.psnr)}
288-
r="4"
289-
fill="white"
290-
stroke="#2563eb"
291-
strokeWidth="2"
292-
/>
293-
))}
294-
295-
{/* Labels */}
296-
<text x={width/2} y={height - 5} textAnchor="middle" fill="#64748b">Training Epochs</text>
297-
<text x={15} y={height/2} textAnchor="middle" transform={`rotate(-90 15 ${height/2})`} fill="#64748b">PSNR (dB)</text>
298-
</svg>
259+
<div className="mb-10">
260+
<h3 className="text-lg font-semibold text-slate-800 mb-2">{dataset.name}</h3>
261+
<p className="text-sm text-slate-600 mb-4">{dataset.caption}</p>
262+
<div className="overflow-x-auto">
263+
<table className="w-full text-sm border-collapse">
264+
<thead>
265+
<tr className="border-b-2 border-slate-300">
266+
<th className="text-left py-3 px-2 font-semibold text-slate-700">Scene</th>
267+
{methods.map(method => (
268+
<th key={method} colSpan={3} className="text-center py-3 px-1 font-semibold text-slate-700 border-l border-slate-200">
269+
{method === "Ours" ? <span className="text-primary">{method}</span> : method}
270+
</th>
271+
))}
272+
</tr>
273+
<tr className="border-b border-slate-200 text-xs text-slate-500">
274+
<th></th>
275+
{methods.map(method => (
276+
<React.Fragment key={method}>
277+
<th className="py-2 px-1 font-medium border-l border-slate-200">PSNR↑</th>
278+
<th className="py-2 px-1 font-medium">SSIM↑</th>
279+
<th className="py-2 px-1 font-medium">LPIPS↓</th>
280+
</React.Fragment>
281+
))}
282+
</tr>
283+
</thead>
284+
<tbody>
285+
{dataset.scenes.map((scene, idx) => (
286+
<tr
287+
key={scene.scene}
288+
className={`border-b border-slate-100 ${scene.scene === 'Average' ? 'bg-slate-50 font-medium' : ''} ${idx % 2 === 0 ? '' : 'bg-slate-50/50'}`}
289+
>
290+
<td className="py-2 px-2 text-slate-700">{scene.scene}</td>
291+
{methods.map(method => (
292+
<React.Fragment key={method}>
293+
<td className={`py-2 px-1 text-center border-l border-slate-200 ${getCellClass(scene, method, 'psnr')}`}>
294+
{scene.methods[method].psnr.toFixed(2)}
295+
</td>
296+
<td className={`py-2 px-1 text-center ${getCellClass(scene, method, 'ssim')}`}>
297+
{scene.methods[method].ssim.toFixed(3)}
298+
</td>
299+
<td className={`py-2 px-1 text-center ${getCellClass(scene, method, 'lpips')}`}>
300+
{scene.methods[method].lpips.toFixed(3)}
301+
</td>
302+
</React.Fragment>
303+
))}
304+
</tr>
305+
))}
306+
</tbody>
307+
</table>
308+
</div>
309+
<div className="flex flex-wrap gap-4 mt-3 text-xs text-slate-500">
310+
<span className="flex items-center gap-1">
311+
<span className="w-3 h-3 bg-blue-100 rounded"></span> Best PSNR
312+
</span>
313+
<span className="flex items-center gap-1">
314+
<span className="w-3 h-3 bg-yellow-100 rounded"></span> Best SSIM
315+
</span>
316+
<span className="flex items-center gap-1">
317+
<span className="w-3 h-3 bg-green-100 rounded"></span> Best LPIPS
318+
</span>
299319
</div>
300320
</div>
301321
);
@@ -434,7 +454,7 @@ const ChatWidget: React.FC = () => {
434454
// --- Main App ---
435455

436456
function App() {
437-
const { title, conference, authors, abstract, links, heroVideoUrl, methodDescription, methodImageUrl, comparisons, metrics } = RESEARCH_DATA;
457+
const { title, conference, authors, abstract, links, heroVideoUrl, methodDescription, methodImageUrl, comparisons, quantitativeResults } = RESEARCH_DATA;
438458

439459
return (
440460
<div className="min-h-screen pb-20">
@@ -582,23 +602,13 @@ function App() {
582602
{/* Metrics */}
583603
<section className="mb-20">
584604
<h2 className="font-serif text-3xl font-semibold mb-8 text-slate-900">Quantitative Metrics</h2>
585-
<div className="flex flex-col md:flex-row gap-8 items-center">
586-
<div className="flex-1 w-full bg-white p-6 rounded-2xl border border-slate-100 shadow-sm">
587-
<h3 className="text-lg font-medium mb-4 text-center">PSNR over Training Epochs</h3>
588-
<MetricsChart data={metrics} />
589-
</div>
590-
<div className="flex-1 text-slate-600 space-y-4">
591-
<p>
592-
Our model demonstrates rapid convergence, achieving a <strong>PSNR of {metrics[metrics.length-1].psnr}dB</strong> by epoch 50.
593-
The combination of our novel loss function and the initialized Gaussian field significantly accelerates the training process compared to baseline NeRF methods.
594-
</p>
595-
<ul className="list-disc list-inside space-y-2 marker:text-primary">
596-
<li>Higher PSNR indicates better reconstruction quality.</li>
597-
<li>Lower LPIPS scores (not plotted) confirm perceptual fidelity.</li>
598-
<li>Consistent performance across diverse datasets.</li>
599-
</ul>
600-
</div>
601-
</div>
605+
<p className="text-slate-600 mb-6">
606+
We compare our method against state-of-the-art approaches including Original 3D Gaussian Splatting, BAGS, DeblurringGS, and LSE-NeRF across two datasets.
607+
Our method achieves the best performance on most scenes, with significant improvements in PSNR, SSIM, and LPIPS metrics.
608+
</p>
609+
{quantitativeResults.map((dataset, idx) => (
610+
<QuantitativeTable key={idx} dataset={dataset} />
611+
))}
602612
</section>
603613

604614
{/* Citation */}

src/constants.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,32 @@ export const RESEARCH_DATA: ProjectData = {
7979
{ epoch: 30, psnr: 28.0, ssim: 0.82, lpips: 0.25 },
8080
{ epoch: 40, psnr: 30.5, ssim: 0.89, lpips: 0.15 },
8181
{ epoch: 50, psnr: 32.0, ssim: 0.93, lpips: 0.10 },
82+
],
83+
quantitativeResults: [
84+
{
85+
name: "AsyncEv-Deblur Dataset (Real-World)",
86+
caption: "Quantitative results on our AsyncEv-Deblur dataset.",
87+
scenes: [
88+
{ scene: "Patio", methods: { "3DGS": { psnr: 22.59, ssim: 0.744, lpips: 0.382 }, "BAGS": { psnr: 23.41, ssim: 0.779, lpips: 0.302 }, "DeblurGS": { psnr: 23.07, ssim: 0.628, lpips: 0.289 }, "LSENeRF": { psnr: 23.47, ssim: 0.779, lpips: 0.273 }, "Ours": { psnr: 24.45, ssim: 0.835, lpips: 0.223 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
89+
{ scene: "Bin", methods: { "3DGS": { psnr: 22.26, ssim: 0.804, lpips: 0.412 }, "BAGS": { psnr: 25.01, ssim: 0.819, lpips: 0.316 }, "DeblurGS": { psnr: 23.69, ssim: 0.633, lpips: 0.281 }, "LSENeRF": { psnr: 25.88, ssim: 0.827, lpips: 0.258 }, "Ours": { psnr: 25.67, ssim: 0.829, lpips: 0.265 } }, best: { psnr: "LSENeRF", ssim: "Ours", lpips: "LSENeRF" } },
90+
{ scene: "Lounge", methods: { "3DGS": { psnr: 22.20, ssim: 0.778, lpips: 0.434 }, "BAGS": { psnr: 24.14, ssim: 0.834, lpips: 0.347 }, "DeblurGS": { psnr: 26.34, ssim: 0.764, lpips: 0.182 }, "LSENeRF": { psnr: 25.47, ssim: 0.852, lpips: 0.256 }, "Ours": { psnr: 25.91, ssim: 0.881, lpips: 0.199 } }, best: { psnr: "DeblurGS", ssim: "Ours", lpips: "DeblurGS" } },
91+
{ scene: "Bench", methods: { "3DGS": { psnr: 22.95, ssim: 0.815, lpips: 0.373 }, "BAGS": { psnr: 23.03, ssim: 0.824, lpips: 0.326 }, "DeblurGS": { psnr: 24.19, ssim: 0.684, lpips: 0.192 }, "LSENeRF": { psnr: 24.48, ssim: 0.846, lpips: 0.217 }, "Ours": { psnr: 27.77, ssim: 0.896, lpips: 0.176 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
92+
{ scene: "Stair", methods: { "3DGS": { psnr: 24.89, ssim: 0.833, lpips: 0.376 }, "BAGS": { psnr: 26.51, ssim: 0.863, lpips: 0.294 }, "DeblurGS": { psnr: 27.95, ssim: 0.792, lpips: 0.173 }, "LSENeRF": { psnr: 26.25, ssim: 0.868, lpips: 0.202 }, "Ours": { psnr: 28.43, ssim: 0.900, lpips: 0.169 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
93+
{ scene: "Bus", methods: { "3DGS": { psnr: 20.53, ssim: 0.737, lpips: 0.466 }, "BAGS": { psnr: 22.06, ssim: 0.762, lpips: 0.403 }, "DeblurGS": { psnr: 23.43, ssim: 0.615, lpips: 0.255 }, "LSENeRF": { psnr: 22.14, ssim: 0.760, lpips: 0.295 }, "Ours": { psnr: 23.94, ssim: 0.808, lpips: 0.251 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
94+
{ scene: "Wall", methods: { "3DGS": { psnr: 23.42, ssim: 0.707, lpips: 0.466 }, "BAGS": { psnr: 24.12, ssim: 0.704, lpips: 0.242 }, "DeblurGS": { psnr: 18.01, ssim: 0.312, lpips: 0.513 }, "LSENeRF": { psnr: 25.14, ssim: 0.749, lpips: 0.225 }, "Ours": { psnr: 25.82, ssim: 0.785, lpips: 0.224 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
95+
{ scene: "Average", methods: { "3DGS": { psnr: 22.69, ssim: 0.774, lpips: 0.416 }, "BAGS": { psnr: 24.04, ssim: 0.798, lpips: 0.319 }, "DeblurGS": { psnr: 23.81, ssim: 0.633, lpips: 0.269 }, "LSENeRF": { psnr: 24.69, ssim: 0.812, lpips: 0.247 }, "Ours": { psnr: 26.00, ssim: 0.847, lpips: 0.215 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } }
96+
]
97+
},
98+
{
99+
name: "Ev-DeblurBlender Dataset (Synthetic)",
100+
caption: "Quantitative results on the Ev-DeblurBlender dataset.",
101+
scenes: [
102+
{ scene: "Factory", methods: { "3DGS": { psnr: 18.01, ssim: 0.514, lpips: 0.446 }, "BAGS": { psnr: 19.12, ssim: 0.634, lpips: 0.312 }, "DeblurGS": { psnr: 21.26, ssim: 0.620, lpips: 0.232 }, "LSENeRF": { psnr: 20.47, ssim: 0.707, lpips: 0.219 }, "Ours": { psnr: 23.18, ssim: 0.830, lpips: 0.165 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
103+
{ scene: "Pool", methods: { "3DGS": { psnr: 17.24, ssim: 0.439, lpips: 0.599 }, "BAGS": { psnr: 23.84, ssim: 0.640, lpips: 0.339 }, "DeblurGS": { psnr: 15.20, ssim: 0.015, lpips: 0.739 }, "LSENeRF": { psnr: 24.22, ssim: 0.639, lpips: 0.280 }, "Ours": { psnr: 25.16, ssim: 0.696, lpips: 0.252 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
104+
{ scene: "Tanabata", methods: { "3DGS": { psnr: 17.51, ssim: 0.517, lpips: 0.487 }, "BAGS": { psnr: 18.31, ssim: 0.596, lpips: 0.381 }, "DeblurGS": { psnr: 19.58, ssim: 0.556, lpips: 0.256 }, "LSENeRF": { psnr: 19.60, ssim: 0.659, lpips: 0.257 }, "Ours": { psnr: 20.11, ssim: 0.727, lpips: 0.221 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
105+
{ scene: "Trolley", methods: { "3DGS": { psnr: 18.52, ssim: 0.609, lpips: 0.413 }, "BAGS": { psnr: 20.25, ssim: 0.722, lpips: 0.287 }, "DeblurGS": { psnr: 21.08, ssim: 0.659, lpips: 0.204 }, "LSENeRF": { psnr: 20.75, ssim: 0.753, lpips: 0.184 }, "Ours": { psnr: 23.49, ssim: 0.854, lpips: 0.135 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } },
106+
{ scene: "Average", methods: { "3DGS": { psnr: 17.82, ssim: 0.520, lpips: 0.486 }, "BAGS": { psnr: 20.38, ssim: 0.648, lpips: 0.330 }, "DeblurGS": { psnr: 19.28, ssim: 0.463, lpips: 0.358 }, "LSENeRF": { psnr: 21.26, ssim: 0.689, lpips: 0.235 }, "Ours": { psnr: 22.99, ssim: 0.777, lpips: 0.193 } }, best: { psnr: "Ours", ssim: "Ours", lpips: "Ours" } }
107+
]
108+
}
82109
]
83110
};

src/types.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ export interface MetricPoint {
2828
lpips: number;
2929
}
3030

31+
export interface SceneMetrics {
32+
scene: string;
33+
methods: {
34+
[method: string]: {
35+
psnr: number;
36+
ssim: number;
37+
lpips: number;
38+
};
39+
};
40+
best: {
41+
psnr: string;
42+
ssim: string;
43+
lpips: string;
44+
};
45+
}
46+
47+
export interface DatasetMetrics {
48+
name: string;
49+
caption: string;
50+
scenes: SceneMetrics[];
51+
}
52+
3153
export interface ProjectData {
3254
title: string;
3355
conference?: string;
@@ -38,8 +60,7 @@ export interface ProjectData {
3860
methodDescription: string;
3961
methodImageUrl: string;
4062
comparisons: ComparisonItem[];
41-
metrics: MetricPoint[];
42-
}
63+
metrics: MetricPoint[]; quantitativeResults: DatasetMetrics[];}
4364

4465
export interface ChatMessage {
4566
role: 'user' | 'model';

0 commit comments

Comments
 (0)