<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Levenberg-Marquardt | Saikiran Juttu | Robotics Portfolio</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/levenberg-marquardt/</link><atom:link href="https://juttu-s.github.io/saikiran_juttu.github.io/tags/levenberg-marquardt/index.xml" rel="self" type="application/rss+xml"/><description>Levenberg-Marquardt</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sat, 05 Oct 2024 00:00:00 +0000</lastBuildDate><image><url>https://juttu-s.github.io/saikiran_juttu.github.io/media/icon_hu7729264130191091259.png</url><title>Levenberg-Marquardt</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/levenberg-marquardt/</link></image><item><title>Photo Mosaicking of Low-Contrast Underwater Images</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/project/photo-mosaicking/</link><pubDate>Sat, 05 Oct 2024 00:00:00 +0000</pubDate><guid>https://juttu-s.github.io/saikiran_juttu.github.io/project/photo-mosaicking/</guid><description>&lt;p>This project implements a full photo mosaicking and optimization pipeline using low-contrast underwater images from the &lt;strong>Skerki Bank Roman shipwreck&lt;/strong> dataset. The approach registers both sequential and non-sequential images using SIFT and RANSAC, computes affine transformations, and optimizes a global trajectory using GTSAM.&lt;/p>
&lt;hr>
&lt;h3 id="pipeline-breakdown">Pipeline Breakdown&lt;/h3>
&lt;h4 id="clahe-image-enhancement">CLAHE Image Enhancement&lt;/h4>
&lt;ul>
&lt;li>Applies histogram equalization to improve contrast and enhance keypoints.&lt;/li>
&lt;li>OpenCV CLAHE was used on each grayscale frame.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">clahe&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cv2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">createCLAHE&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">clipLimit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tileGridSize&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">clahe_image&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">clahe&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">gray_image&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h4 id="sift-feature-detection">SIFT Feature Detection&lt;/h4>
&lt;ul>
&lt;li>Detected keypoints using tuned SIFT settings:
&lt;ul>
&lt;li>&lt;code>nfeatures=5000&lt;/code>, &lt;code>contrastThreshold=0.025&lt;/code>, &lt;code>nOctaveLayers=8&lt;/code>, &lt;code>sigma=1.5&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sift&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cv2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">SIFT_create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">kp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">desc&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sift&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">detectAndCompute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">image&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h4 id="feature-matching--ransac-filtering">Feature Matching + RANSAC Filtering&lt;/h4>
&lt;ul>
&lt;li>Matched descriptors using Brute-Force Matcher + Lowe’s ratio test.&lt;/li>
&lt;li>Applied &lt;code>cv2.estimateAffine2D&lt;/code> with RANSAC to compute and refine transformation.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">matches&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">bf&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">knnMatch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">des1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">des2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">good&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">m&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">matches&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">distance&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mf">0.75&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">distance&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">H&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">mask&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">cv2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">estimateAffine2D&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pts1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">pts2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">method&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">cv2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">RANSAC&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h4 id="pose-graph-construction-gtsam">Pose Graph Construction (GTSAM)&lt;/h4>
&lt;ul>
&lt;li>Built a factor graph using all non-repeating image pairs.&lt;/li>
&lt;li>Relative poses (affine transforms) were added as edges.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">graph&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BetweenFactorPose2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">i1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">T_ij&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">noise_model&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="initial-trajectoryplot_beforepng">
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Initial Trajectory" srcset="
/saikiran_juttu.github.io/project/photo-mosaicking/plot_before_hu6875028771095386571.webp 400w,
/saikiran_juttu.github.io/project/photo-mosaicking/plot_before_hu3546410195309766098.webp 760w,
/saikiran_juttu.github.io/project/photo-mosaicking/plot_before_hu3825931163024726418.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/photo-mosaicking/plot_before_hu6875028771095386571.webp"
width="571"
height="455"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/h2>
&lt;h4 id="global-bundle-adjustment">Global Bundle Adjustment&lt;/h4>
&lt;ul>
&lt;li>Used GTSAM’s Levenberg-Marquardt optimizer to refine global poses.&lt;/li>
&lt;li>Corrects drift and adjusts poses to minimize total residual error.&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">optimizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gtsam&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LevenbergMarquardtOptimizer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">graph&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">initial_estimate&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">optimizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">optimize&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&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/photo-mosaicking/plot_after_hu16779151673749428898.webp 400w,
/saikiran_juttu.github.io/project/photo-mosaicking/plot_after_hu14280678253068865284.webp 760w,
/saikiran_juttu.github.io/project/photo-mosaicking/plot_after_hu13790384701387224375.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/photo-mosaicking/plot_after_hu16779151673749428898.webp"
width="580"
height="455"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;hr>
&lt;h3 id="techniques-used">Techniques Used&lt;/h3>
&lt;ul>
&lt;li>Image normalization + CLAHE&lt;/li>
&lt;li>SIFT feature detection and matching&lt;/li>
&lt;li>RANSAC for outlier rejection&lt;/li>
&lt;li>Homography estimation using Levenberg–Marquardt&lt;/li>
&lt;li>Graph construction (GTSAM)&lt;/li>
&lt;li>Loop closure detection&lt;/li>
&lt;li>Pose optimization&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="results">Results&lt;/h3>
&lt;ul>
&lt;li>Successfully registered both sequential and non-sequential image pairs&lt;/li>
&lt;li>Constructed optimized pose graphs for 6 and 29 image subsets&lt;/li>
&lt;li>Achieved a ~20% improvement in alignment after bundle adjustment&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="-related-files">📁 Related Files&lt;/h3>
&lt;ul>
&lt;li>🔗 &lt;a href="https://github.com/juttu-s/photo-mosaicking-skerki" target="_blank" rel="noopener">GitHub Repository&lt;/a>&lt;/li>
&lt;li>📁 &lt;a href="https://drive.google.com/drive/folders/1AtvT65txGIgAG23NRs3EkvDET036a81O" target="_blank" rel="noopener">Skerki Dataset Reference (Google Drive)&lt;/a>&lt;/li>
&lt;li>📓 &lt;a href="https://juttu-s.github.io/saikiran_juttu.github.io/files/Part1_and_2.ipynb">Project Notebook&lt;/a>&lt;/li>
&lt;li>📓 &lt;a href="https://juttu-s.github.io/saikiran_juttu.github.io/files/Part_3.ipynb">Extended Analysis&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="references">References&lt;/h3>
&lt;ul>
&lt;li>Pizarro &amp;amp; Singh (2003): &lt;em>Toward large-area mosaicing for underwater scientific applications.&lt;/em>&lt;/li>
&lt;li>Ballard et al. (1998, 2000): &lt;em>Roman shipwreck discovery using submersible tech.&lt;/em>&lt;/li>
&lt;/ul></description></item></channel></rss>