<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Matteo Ronchetti on Medium]]></title>
        <description><![CDATA[Stories by Matteo Ronchetti on Medium]]></description>
        <link>https://medium.com/@matteoronchetti?source=rss-8a1b78e3fb22------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AsLvVc_gqnv1Jr6fkoylZA.jpeg</url>
            <title>Stories by Matteo Ronchetti on Medium</title>
            <link>https://medium.com/@matteoronchetti?source=rss-8a1b78e3fb22------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 16:09:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@matteoronchetti/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Extract SURF features from transparent images]]></title>
            <link>https://medium.com/@matteoronchetti/extract-surf-features-from-transparent-images-db09d66cd94e?source=rss-8a1b78e3fb22------2</link>
            <guid isPermaLink="false">https://medium.com/p/db09d66cd94e</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[opencv]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Matteo Ronchetti]]></dc:creator>
            <pubDate>Fri, 11 May 2018 07:22:17 GMT</pubDate>
            <atom:updated>2018-05-11T07:22:17.877Z</atom:updated>
            <content:encoded><![CDATA[<p>When working on my beer <a href="https://towardsdatascience.com/bibirra-beer-label-recognition-8546c233d6f4">recognition project BiBirra</a> I’ve encountered problems loading images that had a transparent background. OpenCV by default mess this images up, and this is especially problematic when we extract SURF features from the loaded image.</p><p>The key idea is to load the image with the flag cv2.IMREAD_UNCHANGED that tells OpenCV to keep the alpha (transparency) channel. Then we save separately the alpha channel as a binary mask for latter use.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6dd5b1720645cf34168bbbe820dc79ce/href">https://medium.com/media/6dd5b1720645cf34168bbbe820dc79ce/href</a></iframe><p>Notice that when the original image has no alpha channel the mask will be simply returned as None.</p><p>Now it is possible to correctly extract SURF features from the masked image</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5c48919c854aaa235cffdf27049bc162/href">https://medium.com/media/5c48919c854aaa235cffdf27049bc162/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F4aaf2a%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F4aaf2a%2F&amp;image=https%3A%2F%2Fe.enpose.co%2F%3Fkey%3DdRXnS9Gplk%26w%3D700%26h%3D425%26url%3Dhttps%253A%252F%252Fupscri.be%252F4aaf2a%252F%253Fenpose&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/a2503ef17cfc467566f01572cdf2f485/href">https://medium.com/media/a2503ef17cfc467566f01572cdf2f485/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=db09d66cd94e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[BiBirra: Beer Label Recognition]]></title>
            <link>https://medium.com/data-science/bibirra-beer-label-recognition-8546c233d6f4?source=rss-8a1b78e3fb22------2</link>
            <guid isPermaLink="false">https://medium.com/p/8546c233d6f4</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[computer-vision]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[deep-learning]]></category>
            <dc:creator><![CDATA[Matteo Ronchetti]]></dc:creator>
            <pubDate>Thu, 15 Mar 2018 23:15:05 GMT</pubDate>
            <atom:updated>2019-08-08T15:20:21.487Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/763/1*9V8KNwp2hgrPdOdCN8tTDA.png" /></figure><p>A few weeks ago I was in a supermarket with my girlfriend, we were invited to a dinner and we wanted to bring wine. Neither of us is a wine expert but she had a fantastic ace in the hole, she pulled out her phone, took a picture of the wine label and immediately got a description and a review of that bottle. I was impressed by the power of that app (it is called <a href="https://www.vivino.com/">ViVino</a>) and she challenged me to build something similar.</p><p>I accepted the challenge but added a few personalizations to it:</p><ul><li>Since I prefer beer to wine I wanted to make a beer recognition app</li><li>I wanted to be better than ViVino and be able to recognize even multiple bottles from a single photo.</li></ul><p>This is how I came up with BiBirra (birra is the italian word for beer)</p><h3>Scraping</h3><p>The first thing we need to build a beer recognizer is a database of beer images. To my knowledge no such database exists so there is only one thing we can do:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/811/1*hWOlRny3IiFDLutlMkn16Q.jpeg" /><figcaption>That’s not exactly <a href="https://www.youtube.com/watch?v=FNyi3nAuLb0">what Jian Yang said</a></figcaption></figure><p>Luckily the web is full of online shops selling beers and I’ve already developed <a href="https://hackernoon.com/raschietto-a-simple-library-for-web-scraping-46957c6aa5b7">a small library for web scraping called Raschietto</a>. This library allowed me to write the scrapers really fast and in less than a day I was able to collect ~2&#39;300 beer bottles pictures together with their basic information (name, type, color, alcohol by volume, bitterness…) from the web.</p><p>The information about each beer had some missing data here and there (mainly because some shops don’t contains much information about beers), cleaning up this data to get a polished result like in ViVino is really time consuming and requires a lot of hand work. My goal was to create a working prototype and the images where good to go, so I decided to proceed to the next phase.</p><h3><strong>Bottle Detection</strong></h3><p>Before doing the actual beer recognition we first need to detect every bottle in the image. Since the shape of a bottle is pretty much unique this could be done quite easily. One way to do this is to train a binary (two class: beer or not beer) classifier and then apply a sliding window approach to detect each bottle. Concretely this means applying the classifier at different locations and scales all over the input image and then apply <a href="https://www.pyimagesearch.com/2014/11/17/non-maximum-suppression-object-detection-python/">Non Maximum Suppression</a> to remove overlapping bounding boxes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/240/1*F2EhLb9jRHdm_HCH3E9-Bg.gif" /><figcaption>An example of sliding window</figcaption></figure><p>The classifier can be built using the classical HOG+SVM combination, which is very good in detecting objects which don’t exhibit too many changes in shape (for example <a href="https://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf">humans</a>). We just need to extract an <a href="https://en.wikipedia.org/wiki/Histogram_of_oriented_gradients">Histogram of Oriented Gradients (HOG) </a>from each training image</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1017/1*mjEZhWpUh7NB_8Qpw8chsw.png" /></figure><p>and then train a linear <a href="https://en.wikipedia.org/wiki/Support_vector_machine">Support Vector Machine (SVM)</a> on the transformed data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*MStS2dBWSZo8iJPiL2_uXg.png" /></figure><p>This time honored approach is quite powerful but training such a classifier is time consuming, especially when we consider that we can get a modern deep learning-based off-the-shelf model for free and in almost no time.</p><h4>Single Shot Detectors</h4><p>For the detection I decided to use a particular type of CNN (<a href="https://medium.com/@ageitgey/machine-learning-is-fun-part-3-deep-learning-and-convolutional-neural-networks-f40359318721">Convolutional Neural Network</a>) called Single Shot Detector. This neural networks directly output a set of bounding boxes and classes achieving detection without using a sliding window.</p><p>A big advantage of this architecture is that each pixel of the input image is fed only once to the model (compared to many times when using a sliding window) this means that we don’t waste resources recomputing local features many times. This observation motivates the name of a famous detection model: YOLO (<a href="https://arxiv.org/abs/1506.02640">You</a> <a href="https://arxiv.org/abs/1612.08242">Only Look</a> <a href="https://pjreddie.com/darknet/yolo/">Once</a>). Many similar models exists: <a href="https://arxiv.org/abs/1512.02325">SSD</a>, <a href="https://arxiv.org/abs/1311.2524">R-CNN</a>, <a href="https://arxiv.org/abs/1506.01497">Faster R-CNN</a>.</p><p>I’ve decided to use the model presented <a href="https://www.pyimagesearch.com/2017/09/11/object-detection-with-deep-learning-and-opencv/">here</a> which is a combination of <a href="https://arxiv.org/abs/1704.04861">MobileNet</a> architecture and the Single Shot Detector framework which can detect: airplanes, bicycles, birds, boats, <strong>bottles</strong>, buses, cars, cats, chairs, cows, dining tables, dogs, horses, motorbikes, people, potted plants, sheep, sofas, trains, and TV monitors. This model by using the MobileNet architecture is lightweight but still has good performances.</p><p>I just need the bottle class so this model is probably an overkill but it works quite well (and the recognition algorithm is robust to detection errors), is fast and ready to use so I’ve decided to adopt it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*ln8vMmN5ffVHxSblc7TbCQ.png" /><figcaption>An example of detection failure but correct recognition (I know, the background is quite strange but this is what I’ve found on the internet)</figcaption></figure><h3>Beer Recognition</h3><p>Here comes the key part of the algorithm, given the image of a bottle we need to come up with a beer label. If we view this problem as a classification one we have 2’300 classes with 1 or 2 examples per class, an impossible problem. A better approach is to view it as a <a href="https://en.wikipedia.org/wiki/Content-based_image_retrieval">Content Based Image Retrieval (CBIR)</a> problem: given a picture of a beer we need to find in our database the most similar image. The only thing we need to do is define (or learn) a similarity measure and use it to compare the query image to all the images in our database and chose the most similar one. The process of retrieval can be divided in two steps:</p><ol><li><strong>Embed:</strong> from each image we need to extract a succinct representation of its content. We then use this representation to compute the similarity between two images. One example of embedding might be computing the <a href="https://en.wikipedia.org/wiki/Color_histogram">color histogram</a> or using the latent representation learnt by an <a href="https://en.wikipedia.org/wiki/Autoencoder">Autoencoder</a>.</li><li><strong>Index</strong>: given the embedding of the query image we will need an efficient way of retrieving the most similar images from the database. Indexing algorithms comes to our rescue, allowing us to do fast nearest-neighbors queries.</li></ol><h4>SIFT/SURF Features</h4><p>Each beer label is unique and fixed (except for changes in perspective and light) therefore a good representation can be obtained by using <a href="https://en.wikipedia.org/wiki/Scale-invariant_feature_transform">SIFT</a> (or <a href="https://en.wikipedia.org/wiki/Speeded_up_robust_features">SURF</a>) descriptors. What these descriptors does is finding a set of keypoints on the image (together with their scale and orientation) and then representing each keypoint with a float vector (for example SIFT produces a vector of length 128). These descriptors are engineered to be robust to changes in scale, rotation and lighting.</p><p>With local descriptors like SIFT or SURF one can use many approaches:</p><ul><li>Use a <a href="https://en.wikipedia.org/wiki/Bag-of-words_model_in_computer_vision">bag of visual words</a> approach representing each image with an histogram of descriptor frequencies and then compaing the histograms to find the image in the database most similar to the query image.</li><li>Use the local descriptors together with <a href="https://en.wikipedia.org/wiki/Random_sample_consensus">RANSAC</a> to try to align the query image to every image in the DB and then chose the best matching one. As proposed in the paper “<a href="https://pdfs.semanticscholar.org/f6c6/d26851cd0df13592e5e0b8c0752789ca2c09.pdf">Mobile Wine Label Recognition</a>”.</li><li>Given a query image, for each descriptor find the most similar descriptors from the DB and give some points to the corresponding images. After using all the descriptors chose the image with the highest scores as a match.</li></ul><p>I’ve found the latter approach (which I think I’ve invented) to work better in this case, so I’ve decided to adopt it. Notice that this approach doesn’t require any alignment phase so it is faster than the method proposed in the paper and, by querying over all the images at the same time, allow the use of an index to speed up queries.</p><p>To further make queries faster I’ve compressed the descriptors down to 16 dimensions using <a href="https://en.wikipedia.org/wiki/Principal_component_analysis">PCA</a>. This compression does not affect accuracy (it removes a lot of unimportant features) but reduces the space and time requirements quite a lot.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*m6b9UHmddhEBxiligpFmyw.png" /><figcaption>A visualization of the structure used by Annoy</figcaption></figure><h4>Approximate Nearest Neighbors with Annoy</h4><p>To get fast nearest neighbors queries I decided to use <a href="https://github.com/spotify/annoy">Annoy</a> (developed by Spotify)</p><blockquote>Annoy (<a href="http://en.wikipedia.org/wiki/Nearest_neighbor_search#Approximate_nearest_neighbor">Approximate Nearest Neighbors</a> Oh Yeah) is a C++ library with Python bindings to search for points in space that are close to a given query point. It also creates large read-only file-based data structures that are <a href="https://en.wikipedia.org/wiki/Mmap">mmapped</a> into memory so that many processes may share the same data.</blockquote><p>Under the hood Annoy creates a forest of binary trees each built by splitting data with random hyperplanes. Each query will return a set of approximate nearest neighbors. The results produced by Annoy are only approximate, there is no guarantee of getting exactly the closest points, but this is the price to pay to mitigate the curse of dimensionality and get good performances.</p><h3>Results</h3><p>I’ve gathered a very small test set of 45 beer images on which I achieved 100% accuracy. Such a small test set is not statistically significant but this result is certainly a sign of good performances.</p><p>Let’s see the algorithm in action:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/467/1*Azhx7FCOybakrrV190MMNA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/293/1*kvEX0rhPcyONeD-TlCIg0w.png" /><figcaption>The algorithm works also in case of detector failure (left) and in presence of occlusion (right)</figcaption></figure><p>You can find more information about me, all my projects and all my posts on my website <a href="https://matteo.ronchetti.xyz/">https://matteo.ronchetti.xyz</a></p><p>Other articles I wrote about Computer Vision:</p><p><a href="https://hackernoon.com/https-medium-com-matteoronchetti-pointillism-with-python-and-opencv-f4274e6bbb7b">Creating Pointillist Paintings with Python and OpenCV</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8546c233d6f4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/data-science/bibirra-beer-label-recognition-8546c233d6f4">BiBirra: Beer Label Recognition</a> was originally published in <a href="https://medium.com/data-science">TDS Archive</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Raschietto: a simple library for web scraping]]></title>
            <link>https://medium.com/hackernoon/raschietto-a-simple-library-for-web-scraping-46957c6aa5b7?source=rss-8a1b78e3fb22------2</link>
            <guid isPermaLink="false">https://medium.com/p/46957c6aa5b7</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[scraping]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Matteo Ronchetti]]></dc:creator>
            <pubDate>Sun, 25 Feb 2018 13:32:42 GMT</pubDate>
            <atom:updated>2019-05-23T06:09:13.649Z</atom:updated>
            <content:encoded><![CDATA[<p>I often find myself in a situation where I need to get data from a <a href="https://hackernoon.com/tagged/website">website</a> that has no API or RSS feed. There exists many different web scraping libraries but I’m unsatisfied, I want something capable of:</p><ul><li><strong>Using CSS selectors</strong>. I have <a href="https://matteo.ronchetti.xyz/#resume">worked as a fullstack developer</a> so I prefer using CSS selectors than XPath.</li><li><strong>Creating a working scraper in almost no time</strong>. Most of the times I don’t need something very complex or advanced, I just need to make a simple scraper very quickly.</li></ul><p>This motivated me to create a simple scraping library called <a href="https://github.com/matteo-ronchetti/raschietto">Raschietto</a> (the Italian word for scraper). Here are its main features:</p><ul><li>CSS Selectors</li><li>Single line getting and parsing of an HTML page</li><li>Simple and extensible methods for matching elements in the page</li><li>Prebuilt matchers for common tasks (for example extracting links and images)</li></ul><p>The library is currently in beta (but is sufficiently stable) and supports only Python3 (adding Python2 support is quite straightforward).</p><p>I’m sharing this library because I think it can speed up the process of building simple scrapers and because its small codebase (&lt;170 lines of code) can be useful for learning purpose.</p><p>You can install it with:</p><pre>pip install raschietto</pre><h3>Scraping arXiv</h3><p>As an example to learn how to use <a href="https://hackernoon.com/tagged/raschietto">raschietto</a> and to showcase its capabilities I will guide you trough the scraping of an arXiv webpage. Please note that arXiv has <a href="https://arxiv.org/help/rss">a very nice RSS feed</a> so its data can be easily accessed without the need for scraping, but we will still scrape it for educational purpose.</p><p>We will focus on <a href="https://arxiv.org/list/stat.ML/recent">the page that contains the latest machine learning papers</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*m_h0iSLkumYiHdgVceh4fw.jpeg" /><figcaption>The page with Chrome dev tools opened</figcaption></figure><p>As a starting point we begin with just getting the titles of the latest papers. Since raschietto uses CSS selectors this task is quite easy. Using Chrome we can copy the CSS selector that will select a specific element using the dev tools. Just place the mouse on the desired element (in the DOM view)&gt; right click &gt; Copy &gt; Copy selector</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pIb7ypjyDsiBQdfq5wxhXQ.jpeg" /><figcaption>How to get a CSS selector with Chrome dev tools</figcaption></figure><p>We get the following selector:</p><p>#dlpage &gt; dl &gt; dd:nth-child(2) &gt; div &gt; div.list-title.mathjax</p><p>This selector is specific to that title element so it will not select other title elements. By looking at the HTML code of the page we can modify it to get a simpler selector that will select all the desired elements:</p><p>.meta .list-title</p><p>If we are unsure about the correctness of our selector we can test it using the console (in the dev tools)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/439/1*jh3koVnT-KhFsOz5KdqaMQ.jpeg" /></figure><p>The code for getting the titles of the papers with raschietto is straightforward and self explanatory</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e6c3f3ea2927b724774168b0f1cf393c/href">https://medium.com/media/e6c3f3ea2927b724774168b0f1cf393c/href</a></iframe><p>We are using two raschietto components:</p><ul><li><strong>Raschietto </strong>is a class that contains all the main functionalities of the library. In this example we are using it to get and parse an HTML page</li><li><strong>Matcher</strong> is a class that encapsulates the matching logic. As a default it return the inner text of the matched element(s), we will later see how to change this behavior.</li></ul><p>We now get as a result a list of titles that all start with “Title: ” to remove this first 7 characters we can use the mapping capability of the Matcher class</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8666b386492065079a4edc9768466d0d/href">https://medium.com/media/8666b386492065079a4edc9768466d0d/href</a></iframe><p>The only change we made is adding the mapping argument to our matcher. This is a function that takes 2 arguments: the matched element, and the containing page. We use a Raschietto function to map the matched element to its inner text and then use python slicing to remove the first 7 characters, obtaining the cleaned up list of titles.</p><p>We now wish to do something more advanced: we want to match both the title and list of authors for each paper. To achieve this we need to:</p><ol><li>Match all the “.meta” elements</li><li>For each matched element get the contained paper title</li><li>For each matched element get the contained list of authors</li></ol><p>The mapping capability of the Matcher class make this task really simple, we just need to match all “.meta” elements and map them to a <em>dict</em> containing the title and the list of authors.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8eb21acc60bb8086cbf8a849f7a46535/href">https://medium.com/media/8eb21acc60bb8086cbf8a849f7a46535/href</a></iframe><p>With just a few lines of code we have created a nice scraper!</p><p>Of course this is not enough for us: we also want to get the link to the paper. This may seem problematic because of the structure of the arXiv page.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rc2uirEVsEZTE8YGYhKAzQ.png" /><figcaption>I’m terrible at drawing</figcaption></figure><p>The title and the link are contained by different elements and it is not useful to use their first common parent because it contains all the papers elements. To get the link we have to:</p><ol><li>Match the “.meta” element</li><li>Select its parent (the “dd” element)</li><li>Select the element right before the “dd” element (so we get the “dt” element)</li><li>Match the “a” element that links to “https://arxiv.org/abs/&lt;paper id&gt;”</li><li>Extract the <em>href</em> from the matched link</li></ol><p>We already went through step 1. To achieve step 2 and 3 we can leverage the fact that the “el” parameter passed to the mapping function is an instance of <a href="http://lxml.de/index.html">lxml</a> <a href="http://lxml.de/api/lxml.html.HtmlElement-class.html">HtmlElement</a> so we can use lxml methods to get the “dt” elemen by selecting the previous element of the parent of <em>el</em>.</p><pre>dt = el.getparent().getprevious()</pre><p>To complete step 4 and 5 we can use a prebuilt matcher that matches links , extracts the <em>href</em> from each of them and make each url absolute (for example it maps “/abs/1802.08246” to the absolute url “https://arxiv.org/abs/1802.08246”). Matching links is quite common when scraping so I’ve included this matcher in the raschietto library. This matcher has also a parameter <em>startswith</em> that, when specidied, will tell the matcher to keep only the results that begins with the given string. Using this matcher the code for our task is very short:</p><pre>link_matcher = Matcher.link(&quot;.list-identifier &gt; a&quot;, startswith=&quot;https://arxiv.org/abs/&quot;)</pre><p>With this changes we get the final version of our arXiv scraper</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8666b386492065079a4edc9768466d0d/href">https://medium.com/media/8666b386492065079a4edc9768466d0d/href</a></iframe><p>Notice that we passed the <em>page</em> argument to the <em>link_matcher</em> to let it know the source url of the element (otherwise is impossible to make the url absolute)</p><h3>Conclusions</h3><p>With just 15 lines of elegant code (empty lines don’t count) we developed a working scraper capable of extracting information from a webpage. We were easily able to group the matched elements, overcome the problem of “no useful common parent” and extract the needed information from each element without writing a lot of code.</p><p>I truly hope you like this small library. If you have some questions about it feel free to ask them in the comments. If you want to collaborate to development of the library don’t hesitate to contact me :)</p><p>You can find more information about me, all my projects and all my posts on my website <a href="https://matteo.ronchetti.xyz/">https://matteo.ronchetti.xyz</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F4aaf2a%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F4aaf2a&amp;image=https%3A%2F%2Fe.enpose.co%2F%3Fkey%3DdRXnS9Gplk%26w%3D700%26h%3D425%26url%3Dhttps%253A%252F%252Fupscri.be%252F4aaf2a%252F%253Fenpose&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/6e16e6b4f38aa2b62a4c8c47a41345e6/href">https://medium.com/media/6e16e6b4f38aa2b62a4c8c47a41345e6/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fdde502%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fhackernoon%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href">https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46957c6aa5b7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/raschietto-a-simple-library-for-web-scraping-46957c6aa5b7">Raschietto: a simple library for web scraping</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Creating Pointillist Paintings with Python and OpenCV]]></title>
            <link>https://medium.com/hackernoon/https-medium-com-matteoronchetti-pointillism-with-python-and-opencv-f4274e6bbb7b?source=rss-8a1b78e3fb22------2</link>
            <guid isPermaLink="false">https://medium.com/p/f4274e6bbb7b</guid>
            <category><![CDATA[art]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[opencv]]></category>
            <category><![CDATA[computer-vision]]></category>
            <dc:creator><![CDATA[Matteo Ronchetti]]></dc:creator>
            <pubDate>Sat, 10 Feb 2018 11:48:14 GMT</pubDate>
            <atom:updated>2019-05-23T06:10:10.945Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0OyMRhqjWzugfVxcxwaJkw.jpeg" /><figcaption>The final result</figcaption></figure><p>One of my favorite painting techniques is pointillism, a technique of painting in which small distinct dots of color are applied in patterns to form an image.</p><p>This technique relies on the ability of the eye and mind of the viewer to blend the color spots into a fuller range of tones. The juxtaposition of different colors make them more vivid, giving the whole image more vibrancy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/412/1*a7Fm9ZlcAffkN2v9g0h8wQ.jpeg" /><figcaption>Notice the juxtaposition of colors</figcaption></figure><p>Pointillism is a gorgeous technique, but in order to make these types of paintings, you need to take a methodical and long approach. Not to mention, you need to be a skilled painter!</p><p>As a computer vision developer, I know a lot about processing images — but let’s face it, I’m terrible at drawing.</p><p>During my trip to Paris I was inspired to try to emulate pointillists using <a href="https://hackernoon.com/tagged/python">Python</a> and <a href="https://hackernoon.com/tagged/opencv">OpenCV</a>. In this post I will guide you through the approach I developed and the code I’ve written to produce images like the one at the top of this blog post.</p><p><a href="https://github.com/matteo-ronchetti/Pointillism">JUST LOOKING FOR THE SOURCE CODE? YOU CAN FIND IT HERE</a></p><h3>Simulating the Painting Process</h3><p>The painting process simulation is done in three steps:</p><ol><li>Color palette creation</li><li>Stroke size and length computation</li><li>Actual painting</li></ol><p>As an example I’ve chosen a beautiful picture of Paris from <a href="https://unsplash.com/">https://unsplash.com</a> a website where you can get free pictures of amazing quality. I’ve preprocessed the image with The Gimp to reduce the green shades on the gargoyle and to upscale the Tour Eiffel to make it more eye catching. In general doing a little bit of preprocessing, especially increasing the general saturation, helps getting more pleasing results.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7mPqVRajHhr89DRds4hnDw.jpeg" /><figcaption>The starting image (source: <a href="https://unsplash.com/photos/v6Sy3kyBROE">https://unsplash.com/photos/v6Sy3kyBROE</a>)</figcaption></figure><h4>Color Palette Creation</h4><p>First thing we need to decide which colors will be in the palette of our “virtual artist”. We need to choose a set of colors that is coherent with the colors of the image but yet vivid and distinct.</p><p>We start by running <a href="https://en.wikipedia.org/wiki/K-means_clustering">k-means</a> to select n=20 dominant colors from the image. The “adversarial” nature of k-means produces distinct colors that concentrates around the most frequent colors in the image.</p><p>To add vibrancy we augment the palette by adding some variations of the colors chosen by kmeans. I’ve chosen to add a more saturated version of the base palette, and two small variations in the colors (± 20 hue) with a little bit of added saturation.</p><p>The first row of the following image represents the palette computed by kmeans, the subsequent rows contains the color variations included in the final palette.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CoNuWmC-9L4nwXC-dlznTg.jpeg" /><figcaption>The color palette computed by kmeans and augmented to be more vibrant</figcaption></figure><h4>Stroke direction and length computation</h4><p>To give our final result a more dynamic look we can use small distinct strokes of color instead of circular dots. This is actually a technique used in a lot of pointillist paintings! We want the direction of the brush strokes to be coherent with the content of the image and to use longer strokes to depict edges. For this reason we use the image gradient to decide the length and direction of each paint stroke.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GinP2g6FM1fCJA8HGCZutg.jpeg" /><figcaption>Comparison of style of painting: dots (left), small strokes (right)</figcaption></figure><p>To compute the direction and length of the brush strokes we take the Scharr image derivative on the x and y axis thus defining a vector field over the image. We then smooth this field using Gaussian blur to give a more coherent look to the final “painting”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AjGUM-cWwxJnY1a2t6B91w.jpeg" /><figcaption>A visualization of the magnitude of image gradient(before Gaussian smoothing)</figcaption></figure><h3>The Painting Process</h3><p>We paint the final results just like a real artist, one stroke at a time! For each stroke we have to decide:</p><ol><li>The position</li><li>The orientation and length of each stroke</li><li>Which color of the palette to use</li></ol><p>It may be tempting to chose a random position but this approach has a major drawback: we don’t know when we have painted enough strokes to fill the entire image. So we create a list of strokes positions by sampling uniformly over the image, we add a little bit of random noise to each position and we shuffle the list to give the strokes a random order.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/34b3b92d5d2a7876e28de512c9c392b8/href">https://medium.com/media/34b3b92d5d2a7876e28de512c9c392b8/href</a></iframe><p>The direction and length are easy to compute once we have defined a vector field over the image using the image gradient.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/65b54751af04e5d804ead0fed2577c27/href">https://medium.com/media/65b54751af04e5d804ead0fed2577c27/href</a></iframe><p>We rotate the direction of the gradient by 90 degrees because we want the strokes to be parallel to the image edges (the image gradient is perpendicular to the edges). The length is computed depending on the magnitude (i.e. strength) of the image gradient. Here <em>stroke_scale </em>is a parameter that specify the global scale for the strokes, the square root is used to make the strokes more uniform. We don’t want to have too much variance in the length of the strokes.</p><p>The choice of the stroke color is probably the hardest part. We want it to be random to get that beautiful juxtaposition of colors, yet we want to be consistent with the source photo. The idea is to chose a color randomly from the palette, giving the colors that are more similar to the underling pixel of the photo a greater probability of being chosen. The probabilities are determined using a <a href="https://en.wikipedia.org/wiki/Softmax_function">softmax</a> function of the similarities between colors.</p><h3>The Code</h3><p>You can find the <a href="https://github.com/matteo-ronchetti/Pointillism">source code here</a>. It corresponds to the algorithm I’ve described here, with some performance improvements. The code is commented and should be quite easy to understand. If you have any questions feel free to ask in the comments :)</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2F4aaf2a%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2F4aaf2a&amp;image=https%3A%2F%2Fe.enpose.co%2F%3Fkey%3DdRXnS9Gplk%26w%3D700%26h%3D425%26url%3Dhttps%253A%252F%252Fupscri.be%252F4aaf2a%252F%253Fenpose&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/6e16e6b4f38aa2b62a4c8c47a41345e6/href">https://medium.com/media/6e16e6b4f38aa2b62a4c8c47a41345e6/href</a></iframe><h3>Results</h3><p>Some results with other photos:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-FxeRtx7ARCSzPn7CS_9Bg.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mY54wTSkxL5-_sXXvaKWBA.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DX_p6UObyBqdV9Uhc8aDgg.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xDUgXlrhIcoZZqJseejFiA.jpeg" /></figure><p>I hope you enjoyed this article! If you have any questions feel free to ask in the comments. If you produce some great paintings please post them in the comments, I’m really looking forward to see what you can do with this program!</p><p>You can find more information about me on my website <a href="https://matteo.ronchetti.xyz/">https://matteo.ronchetti.xyz</a></p><p>Other articles I wrote about Computer Vision:</p><p><a href="https://towardsdatascience.com/bibirra-beer-label-recognition-8546c233d6f4">BiBirra: Beer Label Recognition</a></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fupscri.be%2Fdde502%3Fas_embed%3Dtrue&amp;dntp=1&amp;url=https%3A%2F%2Fupscri.be%2Fhackernoon%2F&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=upscri" width="800" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href">https://medium.com/media/3c851dac986ab6dbb2d1aaa91205a8eb/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f4274e6bbb7b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/hackernoon/https-medium-com-matteoronchetti-pointillism-with-python-and-opencv-f4274e6bbb7b">Creating Pointillist Paintings with Python and OpenCV</a> was originally published in <a href="https://medium.com/hackernoon">HackerNoon.com</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>