<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Emanuele Cesaroni</title>
    <description>The latest articles on DEV Community by Emanuele Cesaroni (@runout77).</description>
    <link>https://dev.to/runout77</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4202091%2F42d8f0cb-fcaa-43b8-b51b-f26eb2514fe8.png</url>
      <title>DEV Community: Emanuele Cesaroni</title>
      <link>https://dev.to/runout77</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/runout77"/>
    <language>en</language>
    <item>
      <title>Contrek: Vectorizing 10 Billion Pixels on a Raspberry Pi 5 with Just 4 GB RAM</title>
      <dc:creator>Emanuele Cesaroni</dc:creator>
      <pubDate>Fri, 23 Oct 2026 08:57:08 +0000</pubDate>
      <link>https://dev.to/runout77/contrek-vectorizing-10-billion-pixels-on-a-raspberry-pi-5-with-just-4-gb-ram-3bh9</link>
      <guid>https://dev.to/runout77/contrek-vectorizing-10-billion-pixels-on-a-raspberry-pi-5-with-just-4-gb-ram-3bh9</guid>
      <description>&lt;p&gt;I've been developing &lt;a href="https://github.com/runout77/contrek" rel="noopener noreferrer"&gt;Contrek&lt;/a&gt;, a C++ library for extracting polygon contours from raster images and merging contours obtained by processing different parts of an image.&lt;/p&gt;

&lt;p&gt;One of the problems I wanted to solve was handling very large rasters without having to load everything into memory.&lt;/p&gt;

&lt;p&gt;Contrek can extract contours directly or merge contours produced by other libraries, including OpenCV. It supports parallel processing of image tiles and reconstructs polygons crossing tile boundaries, including complex shapes and holes.&lt;/p&gt;

&lt;p&gt;But one of its main strengths is memory efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streaming vectorization
&lt;/h2&gt;

&lt;p&gt;Contrek can process an image in horizontal stripes, reconnecting contours across stripe boundaries and progressively writing completed polygons to disk.&lt;/p&gt;

&lt;p&gt;This avoids keeping millions of finished polygons in memory. Memory usage depends mainly on the current stripe and the geometry still waiting to be completed, rather than the total size of the output.&lt;/p&gt;

&lt;p&gt;To see how far I could push this approach, I decided to test it on a Raspberry Pi 5 with just 4 GB of RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Raspberry Pi test
&lt;/h2&gt;

&lt;p&gt;I used a Raspberry Pi 5 with 4 GB RAM, a 250 GB NVMe SSD and an Ubuntu 24.04 ARM64 Docker container.&lt;/p&gt;

&lt;p&gt;The input was a &lt;strong&gt;100,000 × 100,000 pixel PNG image&lt;/strong&gt;, containing 10 billion pixels. The compressed PNG file is about 900 MB.&lt;/p&gt;

&lt;p&gt;The image was processed in horizontal stripes of 1,000 rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Input image&lt;/td&gt;
&lt;td&gt;100,000 × 100,000 pixels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygons extracted&lt;/td&gt;
&lt;td&gt;19,551,269&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution time&lt;/td&gt;
&lt;td&gt;13 min 52 sec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak process memory&lt;/td&gt;
&lt;td&gt;2.42 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output SVG&lt;/td&gt;
&lt;td&gt;21.03 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU usage&lt;/td&gt;
&lt;td&gt;99% (one core equivalent)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The process completed successfully, with zero swaps reported by GNU &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What I found particularly interesting is that the resulting SVG is over 21 GB, while the benchmark process never exceeded 2.42 GiB of resident memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source code and benchmark
&lt;/h2&gt;

&lt;p&gt;Contrek is open source and available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/runout77/contrek" rel="noopener noreferrer"&gt;https://github.com/runout77/contrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've also published the complete Raspberry Pi benchmark, including the Docker environment, input image, commands and measurements, so anyone interested can reproduce it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/runout77/test_contrek" rel="noopener noreferrer"&gt;https://github.com/runout77/test_contrek&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm continuing to work on the library, particularly on the merging algorithms and their performance. I'd be interested to hear from anyone working with similar problems on large raster datasets.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>opensource</category>
      <category>performance</category>
      <category>raspberrypi</category>
    </item>
  </channel>
</rss>
