<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Structure From Motion | Saikiran Juttu | Robotics Portfolio</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/structure-from-motion/</link><atom:link href="https://juttu-s.github.io/saikiran_juttu.github.io/tags/structure-from-motion/index.xml" rel="self" type="application/rss+xml"/><description>Structure From Motion</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Thu, 07 Nov 2024 00:00:00 +0000</lastBuildDate><image><url>https://juttu-s.github.io/saikiran_juttu.github.io/media/icon_hu7729264130191091259.png</url><title>Structure From Motion</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/structure-from-motion/</link></image><item><title>Sparse 3D Reconstruction and Bundle Adjustment</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/project/sparse-reconstruction/</link><pubDate>Thu, 07 Nov 2024 00:00:00 +0000</pubDate><guid>https://juttu-s.github.io/saikiran_juttu.github.io/project/sparse-reconstruction/</guid><description>&lt;p>This project implements a full Structure from Motion (SfM) pipeline on a &lt;strong>Buddha statue&lt;/strong> using a sequence of &lt;strong>24 grayscale images&lt;/strong>. It combines feature detection, epipolar geometry, camera pose recovery, triangulation, and bundle adjustment.&lt;/p>
&lt;hr>
&lt;h3 id="dataset">Dataset&lt;/h3>
&lt;ul>
&lt;li>24 images of a wooden Buddha statue captured at different angles&lt;/li>
&lt;li>Enhanced using &lt;strong>CLAHE (Contrast Limited Adaptive Histogram Equalization)&lt;/strong>&lt;/li>
&lt;li>Features extracted using &lt;strong>SIFT&lt;/strong> with custom parameters&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="pipeline-overview">Pipeline Overview&lt;/h3>
&lt;h4 id="1-image-preprocessing">1. Image Preprocessing&lt;/h4>
&lt;p>Using CLAHE improves contrast on low-texture surfaces like carved wood.&lt;/p>
&lt;div style="text-align: center;">
&lt;img src="processed.png" width="1000">
&lt;/div>
&lt;hr>
&lt;h4 id="2-sift-feature-detection">2. SIFT Feature Detection&lt;/h4>
&lt;ul>
&lt;li>Applied to all 24 images&lt;/li>
&lt;li>Used &lt;strong>BFMatcher&lt;/strong> with ratio test&lt;/li>
&lt;li>Matches filtered via &lt;strong>RANSAC&lt;/strong> for outlier rejection&lt;/li>
&lt;/ul>
&lt;div style="text-align: center;">
&lt;img src="features.png" width="1000">
&lt;/div>
&lt;hr>
&lt;h4 id="3-essential-matrix--pose-recovery">3. Essential Matrix &amp;amp; Pose Recovery&lt;/h4>
&lt;ul>
&lt;li>Computed Essential matrix using calibrated camera matrix&lt;/li>
&lt;li>Used &lt;code>cv2.recoverPose()&lt;/code> to derive relative rotation and translation between views&lt;/li>
&lt;li>Built a chain of camera poses from image 0 onward&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="4-triangulation">4. Triangulation&lt;/h4>
&lt;ul>
&lt;li>3D points computed from pixel correspondences using &lt;code>cv2.triangulatePoints()&lt;/code>&lt;/li>
&lt;li>All 3D points stored in homogeneous form&lt;/li>
&lt;li>Colored and visualized using Plotly&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h4 id="5-bundle-adjustment-with-gtsam">5. Bundle Adjustment with GTSAM&lt;/h4>
&lt;ul>
&lt;li>Built a factor graph with:
&lt;ul>
&lt;li>Camera pose priors&lt;/li>
&lt;li>Between factors from pose transitions&lt;/li>
&lt;li>Projection factors from 2D-3D matches&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Used &lt;code>Levenberg-MarquardtOptimizer&lt;/code> for refinement&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="results">Results&lt;/h3>
&lt;h4 id="initial-3d-trajectory">Initial 3D Trajectory&lt;/h4>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Initial Trajectory" srcset="
/saikiran_juttu.github.io/project/sparse-reconstruction/Initial_plot_hu12090084634136375331.webp 400w,
/saikiran_juttu.github.io/project/sparse-reconstruction/Initial_plot_hu6971695684859321629.webp 760w,
/saikiran_juttu.github.io/project/sparse-reconstruction/Initial_plot_hu11908849571792030370.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/sparse-reconstruction/Initial_plot_hu12090084634136375331.webp"
width="760"
height="282"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h4 id="optimized-3d-trajectory-after-bundle-adjustment">Optimized 3D Trajectory after Bundle Adjustment&lt;/h4>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Optimized Trajectory" srcset="
/saikiran_juttu.github.io/project/sparse-reconstruction/Optimized_plot_hu1365288965832748826.webp 400w,
/saikiran_juttu.github.io/project/sparse-reconstruction/Optimized_plot_hu5432368712792554619.webp 760w,
/saikiran_juttu.github.io/project/sparse-reconstruction/Optimized_plot_hu6617160073620067270.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/sparse-reconstruction/Optimized_plot_hu1365288965832748826.webp"
width="760"
height="282"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;ul>
&lt;li>Average reprojection error reduced by ~15%&lt;/li>
&lt;li>Landmark cloud tightened around object geometry&lt;/li>
&lt;li>Rotation drift corrected with global optimization&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="tools--libraries">Tools &amp;amp; Libraries&lt;/h3>
&lt;ul>
&lt;li>OpenCV (SIFT, RANSAC, triangulation)&lt;/li>
&lt;li>NumPy, Matplotlib, Plotly&lt;/li>
&lt;li>GTSAM (factor graph + BA)&lt;/li>
&lt;li>Python&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="resources">Resources&lt;/h3>
&lt;ul>
&lt;li>🔗 &lt;a href="https://github.com/juttu-s/Sparse-3D-Reconstruction" target="_blank" rel="noopener">GitHub Repo&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>This project demonstrates a scalable pipeline for SfM using minimal dependencies. It serves as a foundation for integrating real-time VIO or stereo SLAM on embedded platforms.&lt;/p></description></item></channel></rss>