<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Computer Vision | Saikiran Juttu | Robotics Portfolio</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/computer-vision/</link><atom:link href="https://juttu-s.github.io/saikiran_juttu.github.io/tags/computer-vision/index.xml" rel="self" type="application/rss+xml"/><description>Computer Vision</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Mon, 15 Apr 2024 00:00:00 +0000</lastBuildDate><image><url>https://juttu-s.github.io/saikiran_juttu.github.io/media/icon_hu7729264130191091259.png</url><title>Computer Vision</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/tags/computer-vision/</link></image><item><title>Automated Insect Leg Labeling using DeepLabCut</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/</link><pubDate>Mon, 15 Apr 2024 00:00:00 +0000</pubDate><guid>https://juttu-s.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/</guid><description>&lt;p>This project proposes a robust and scalable method for automating insect leg labeling using &lt;strong>image processing, feature detection, and clustering&lt;/strong>, enabling seamless integration with &lt;strong>DeepLabCut&lt;/strong> for behavioral analysis.&lt;/p>
&lt;hr>
&lt;h2 id="methodology-overview">Methodology Overview&lt;/h2>
&lt;h3 id="1-data-collection">1. Data Collection&lt;/h3>
&lt;ul>
&lt;li>Captured insect locomotion data using a &lt;strong>ServoSphere&lt;/strong> robot equipped with omni-wheels and a high-speed camera.&lt;/li>
&lt;li>The camera tracked an insect (ant) placed atop the rotating sphere.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="2-preprocessing-pipeline">2. Preprocessing Pipeline&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Grayscale conversion&lt;/strong> and &lt;strong>Gaussian blur&lt;/strong> for noise reduction&lt;/li>
&lt;li>&lt;strong>Canny Edge Detection&lt;/strong> for edge enhancement&lt;/li>
&lt;li>&lt;strong>Binary thresholding&lt;/strong> and &lt;strong>morphological operations&lt;/strong> for skeletonization&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Canny Edge Result" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/canny_hu11275747406885085122.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/canny_hu15745542599272552929.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/canny_hu3473078471050911037.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/canny_hu11275747406885085122.webp"
width="555"
height="350"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Output after applying Canny edge detection.&lt;/em>&lt;/p>
&lt;hr>
&lt;h3 id="3-feature-extraction">3. Feature Extraction&lt;/h3>
&lt;ul>
&lt;li>Applied &lt;strong>Shi-Tomasi Corner Detection&lt;/strong> on Canny edges for precise joint detection&lt;/li>
&lt;li>Robust to noise and sensitive to detailed motion features&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Shi-Tomasi Detection" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/shi_tomasi_hu3655572418342755069.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/shi_tomasi_hu14103565545081466617.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/shi_tomasi_hu4890327641649225453.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/shi_tomasi_hu3655572418342755069.webp"
width="555"
height="350"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Shi-Tomasi corner detection highlights potential joint features.&lt;/em>&lt;/p>
&lt;hr>
&lt;h3 id="4-body-removal">4. Body Removal&lt;/h3>
&lt;ul>
&lt;li>Used &lt;strong>Zhang-Suen thinning&lt;/strong> for skeleton extraction&lt;/li>
&lt;li>Applied &lt;strong>connected component labeling&lt;/strong> to segment body parts&lt;/li>
&lt;li>Removed body via &lt;strong>template matching&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Skeleton Extraction" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/skeleton_extraction_hu7723478630954022702.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/skeleton_extraction_hu1654188756838549732.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/skeleton_extraction_hu4799263873215453537.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/skeleton_extraction_hu7723478630954022702.webp"
width="553"
height="355"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Skeleton representation using Zhang-Suen thinning.&lt;/em>&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Connected Components" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/connected_components_hu7217986797033856015.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/connected_components_hu12195037151038958192.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/connected_components_hu4918036970471170597.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/connected_components_hu7217986797033856015.webp"
width="545"
height="378"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Connected component labeling for body part isolation.&lt;/em>&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Body Template" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/template_hu11659726123555705027.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/template_hu18209107862982516437.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/template_hu2884419823242467532.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/template_hu11659726123555705027.webp"
width="499"
height="353"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Template matching used to isolate and remove the body region.&lt;/em>&lt;/p>
&lt;hr>
&lt;h3 id="5-leg-detection">5. Leg Detection&lt;/h3>
&lt;ul>
&lt;li>Remaining features correspond to legs&lt;/li>
&lt;li>Calculated angles of features w.r.t. body centroid&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Detected Leg Features" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/leg_features_hu7341448728120080587.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/leg_features_hu18101909398949920466.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/leg_features_hu14108854493791996505.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/leg_features_hu7341448728120080587.webp"
width="489"
height="320"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Extracted leg features post body removal.&lt;/em>&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="Feature Angles" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/angles_hu911305775039293742.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/angles_hu16264059692635278634.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/angles_hu12389778951175088630.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/angles_hu911305775039293742.webp"
width="496"
height="338"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Angle estimation of each leg with respect to the centroid.&lt;/em>&lt;/p>
&lt;hr>
&lt;h3 id="6-clustering--tip-detection">6. Clustering &amp;amp; Tip Detection&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>KMeans (K=6)&lt;/strong> clusters features into 6 legs&lt;/li>
&lt;li>Furthest feature in each cluster = leg tip&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="KMeans Clustering" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/kmeans_hu2991777993052901984.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/kmeans_hu1537055730035741828.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/kmeans_hu8003083638116927705.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/kmeans_hu2991777993052901984.webp"
width="556"
height="406"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: KMeans clustering of features into 6 leg regions.&lt;/em>&lt;/p>
&lt;hr>
&lt;h3 id="7-integration-with-deeplabcut">7. Integration with DeepLabCut&lt;/h3>
&lt;ul>
&lt;li>Created &lt;code>.h5&lt;/code> files with clustered keypoints&lt;/li>
&lt;li>Trained DeepLabCut on auto-labeled dataset&lt;/li>
&lt;li>Achieved performance near manual labeling&lt;/li>
&lt;/ul>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="DLC Integration" srcset="
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/integration_hu13320621738235640093.webp 400w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/integration_hu5511305675759056958.webp 760w,
/saikiran_juttu.github.io/project/automated-insect-leg-labeling/integration_hu10805202269737531730.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/automated-insect-leg-labeling/integration_hu13320621738235640093.webp"
width="671"
height="615"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;br>
&lt;em>Figure: Final annotated labels used with DeepLabCut.&lt;/em>&lt;/p>
&lt;hr>
&lt;h2 id="experimental-results">Experimental Results&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Leg&lt;/th>
&lt;th>TP (Auto)&lt;/th>
&lt;th>FP (Auto)&lt;/th>
&lt;th>TP (Manual)&lt;/th>
&lt;th>FP (Manual)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>95&lt;/td>
&lt;td>2&lt;/td>
&lt;td>98&lt;/td>
&lt;td>1&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>90&lt;/td>
&lt;td>3&lt;/td>
&lt;td>95&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>85&lt;/td>
&lt;td>4&lt;/td>
&lt;td>90&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>80&lt;/td>
&lt;td>3&lt;/td>
&lt;td>85&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>75&lt;/td>
&lt;td>5&lt;/td>
&lt;td>80&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>70&lt;/td>
&lt;td>3&lt;/td>
&lt;td>75&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;em>Confusion matrix comparing auto-labeled vs manually labeled results. Accuracy slightly lower, but performance is consistent and scalable.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="key-techniques">Key Techniques&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Canny Edge Detection&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Shi-Tomasi GFTT&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Template Matching&lt;/strong>&lt;/li>
&lt;li>&lt;strong>KMeans Clustering&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Zhang-Suen Thinning&lt;/strong>&lt;/li>
&lt;li>&lt;strong>DeepLabCut integration&lt;/strong>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="insights--future-work">Insights &amp;amp; Future Work&lt;/h2>
&lt;ul>
&lt;li>Automation significantly reduced manual effort&lt;/li>
&lt;li>High reproducibility across ant datasets&lt;/li>
&lt;li>KMeans produced sharper clusters than Ensemble KMeans&lt;/li>
&lt;li>Future work may explore deep learning-based leg segmentation and adaptive clustering strategies&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="resources">Resources&lt;/h2>
&lt;ul>
&lt;li>📄 &lt;a href="report.pdf">Project Report (PDF)&lt;/a>&lt;/li>
&lt;li>🔗 &lt;a href="https://github.com/juttu-s/Pattern-Recognition-and-Computer-Vision/tree/main/Automated%20Insect%20Leg%20Labeling" target="_blank" rel="noopener">GitHub Repository&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;p>This approach provides a &lt;strong>generalizable and scalable method&lt;/strong> for anatomical labeling in biological research and can be extended to other multi-limbed species or anatomical joints.&lt;/p></description></item><item><title>Real-Time 2D Object Recognition with Feature Matching</title><link>https://juttu-s.github.io/saikiran_juttu.github.io/project/object-recognition/</link><pubDate>Sat, 30 Mar 2024 00:00:00 +0000</pubDate><guid>https://juttu-s.github.io/saikiran_juttu.github.io/project/object-recognition/</guid><description>&lt;p>Recognise objects on a tabletop from a live webcam, using classical computer vision and nothing else — no learned features, no pretrained backbone. Camera overhead, dark objects on a white surface, everything computed per frame in C++.&lt;/p>
&lt;p>The constraint that made this interesting: most of the pipeline had to be written from scratch. Two of the first four stages were required to be; three ended up that way. The only OpenCV algorithm doing real work is connected-component labelling.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="flex justify-center ">
&lt;div class="w-100" >&lt;img alt="A watch and a pen segmented with oriented bounding boxes, axis-of-least-central-moment arrows, and live feature values overlaid" srcset="
/saikiran_juttu.github.io/project/object-recognition/features-annotated_hu1285270646848479672.webp 400w,
/saikiran_juttu.github.io/project/object-recognition/features-annotated_hu4246342232475753791.webp 760w,
/saikiran_juttu.github.io/project/object-recognition/features-annotated_hu5357358603646478662.webp 1200w"
src="https://juttu-s.github.io/saikiran_juttu.github.io/saikiran_juttu.github.io/project/object-recognition/features-annotated_hu1285270646848479672.webp"
width="640"
height="480"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;em>Two objects at once. Blue boxes are the oriented bounding boxes, red arrows the axis of least central moment, cyan text the live feature values.&lt;/em>&lt;/p>
&lt;hr>
&lt;h2 id="pipeline">Pipeline&lt;/h2>
&lt;h3 id="thresholding-without-otsu">Thresholding, without Otsu&lt;/h3>
&lt;p>Rather than call a threshold function, the threshold is found by &lt;strong>2-means clustering on sampled pixel values&lt;/strong>. Sample the frame, converge two centroids — one settles on the dark object population, one on the light background — and put the threshold at their midpoint.&lt;/p>
&lt;p>The appeal is that it&amp;rsquo;s &lt;em>adaptive by construction&lt;/em>. As the lighting shifts, both centroids move and the threshold tracks them, without a hand-tuned constant anywhere. It&amp;rsquo;s a genuinely better fit for a live feed than a fixed cut, and it&amp;rsquo;s about fifteen lines of code.&lt;/p>
&lt;h3 id="morphological-cleanup">Morphological cleanup&lt;/h3>
&lt;p>The thresholded feed had holes in it — printed text and specular highlights on dark objects read as background. So: &lt;strong>dilation first to close the gaps, then erosion to remove the speckle&lt;/strong> the dilation amplified. Written by hand rather than called, and the ordering was driven by looking at the actual defect rather than reaching for a default.&lt;/p>
&lt;h3 id="segmentation">Segmentation&lt;/h3>
&lt;p>&lt;code>cv::connectedComponentsWithStats&lt;/code> labels the regions; components below a size threshold are dropped as noise. Survivors get distinct colours for display.&lt;/p>
&lt;h3 id="features-from-moments-up">Features, from moments up&lt;/h3>
&lt;p>Raw and central moments computed directly, then five descriptors per region:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>What it captures&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Centroid (x, y)&lt;/td>
&lt;td>Region position&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>θ&lt;/td>
&lt;td>Angle of the axis of least central moment — the object&amp;rsquo;s orientation&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Percent filled&lt;/td>
&lt;td>Region area ÷ oriented bounding box area&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bounding box ratio&lt;/td>
&lt;td>Oriented box aspect ratio&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Stored to CSV alongside a label typed at capture time, which makes the training set inspectable — you can open it and see why the classifier does what it does.&lt;/p>
&lt;h2 id="classification">Classification&lt;/h2>
&lt;p>Two classifiers over the same features:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Nearest neighbour&lt;/strong> on cumulative scaled Euclidean distance — closest labelled example wins.&lt;/li>
&lt;li>&lt;strong>k-NN with k = 4&lt;/strong> — take the four nearest, majority vote.&lt;/li>
&lt;/ul>
&lt;p>The k-NN version is the more robust of the two, and the reason is visible in the failure mode of the first. Nearest neighbour commits to a single best match, so when two classes differ only marginally in feature space, one noisy frame is enough to flip the decision. Requiring agreement among four neighbours means a single outlier can&amp;rsquo;t carry the vote.&lt;/p>
&lt;hr>
&lt;h2 id="results">Results&lt;/h2>
&lt;p>&lt;strong>11 object classes&lt;/strong>, roughly 30 labelled samples captured at varying positions and orientations: watch, pen, mobile, spoon, bracelet, earbuds box, pendrive, statue, controller, star, clutch. Over 15 trials across five classes, classification accuracy ran &lt;strong>93.33–100%&lt;/strong>.&lt;/p>
&lt;p>The more informative result is how well the shape features separate the classes:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Range across the 11 classes&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Percent filled&lt;/td>
&lt;td>0.34 (bracelet — a hollow loop) → 0.97 (phone — a filled rectangle)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bounding box ratio&lt;/td>
&lt;td>1.04 (near-square box) → 8.88 (pen)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Those two numbers do most of the discriminating, and they&amp;rsquo;re both scale- and rotation-invariant, which is the whole reason for computing orientation first and measuring the box &lt;em>after&lt;/em> aligning to it. Deliberately including several elongated objects — pen at 8.88, watch strap at 5.31, spoon at 3.99 — was what stress-tested it; anything can separate a pen from a phone, but separating a pen from a watch strap needs the percent-filled term to pull its weight.&lt;/p>
&lt;p>An extension pushed it to &lt;strong>multiple objects simultaneously&lt;/strong>, segmenting and classifying every region in the frame rather than assuming one object at a time.&lt;/p>
&lt;h2 id="honest-limitations">Honest limitations&lt;/h2>
&lt;p>&lt;strong>The feature vector includes absolute centroid position.&lt;/strong> Centroid x and y range from 165 to 484 px across the dataset, and feeding those into a scaled-Euclidean distance means &lt;em>where the object sits in frame&lt;/em> contributes to the class decision — in a system whose stated goal is translation invariance. The three shape descriptors are the invariant ones and are doing the real work; the centroid terms are a liability I&amp;rsquo;d drop.&lt;/p>
&lt;p>&lt;strong>Lighting drives everything.&lt;/strong> The 2-means threshold adapts, but it can only adapt to a bimodal scene. Introduce a shadow gradient across the white surface, or a mid-grey object, and the two-cluster assumption stops holding.&lt;/p>
&lt;p>&lt;strong>No timing was measured.&lt;/strong> The system runs interactively on a live feed, but there&amp;rsquo;s no frame-rate figure behind that, so I won&amp;rsquo;t claim one.&lt;/p>
&lt;h2 id="stack">Stack&lt;/h2>
&lt;p>C++, OpenCV 4, CMake. Thresholding, morphology and the entire moment/feature pipeline hand-written; &lt;code>connectedComponentsWithStats&lt;/code> for labelling. Training data self-collected via an in-app capture-and-label mode, with recording built in for demos.&lt;/p></description></item></channel></rss>