<?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 Sumit Kumar Arora on Medium]]></title>
        <description><![CDATA[Stories by Sumit Kumar Arora on Medium]]></description>
        <link>https://medium.com/@sumit-arora?source=rss-93b61e3f97aa------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*0ODOChCsQ6eGEM0ywNmnrw.jpeg</url>
            <title>Stories by Sumit Kumar Arora on Medium</title>
            <link>https://medium.com/@sumit-arora?source=rss-93b61e3f97aa------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 21 Jun 2026 23:32:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@sumit-arora/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[Audio Steganography : The art of hiding secrets within earshot (part 2 of 2)]]></title>
            <link>https://sumit-arora.medium.com/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-2-of-2-c76b1be719b3?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/c76b1be719b3</guid>
            <category><![CDATA[music]]></category>
            <category><![CDATA[steganography]]></category>
            <category><![CDATA[moderation]]></category>
            <category><![CDATA[lsb]]></category>
            <category><![CDATA[subliminal]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Sun, 17 Jun 2018 19:06:17 GMT</pubDate>
            <atom:updated>2018-06-24T21:43:51.118Z</atom:updated>
            <content:encoded><![CDATA[<p>In the previous installment of this piece on Audio Steganography, I described the fundamentals of Audio Steganography along with some applications and related concepts. If you haven’t yet read the earlier post, I recommend reading it before going further with this post.</p><p><a href="https://medium.com/@sumit.arora/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-1-of-2-6a3bbd706e15">Audio Steganography : The art of hiding secrets within earshot (part 1 of 2)</a></p><h3>Audio Steganography Methods</h3><p>In this article, we will take a look at some of the popular methods to embed “secret” text, images and audios inside a “public” sound file. Our purpose is to enable a sender to secretly send their data, hidden within a song.</p><p><strong>LSB (Least Significant Bit) Algorithm</strong></p><p>LSB algorithm is a classic Steganography method used to conceal the existence of secret data inside a “public” cover. The LSB or “Least Significant Bit”, in computing terms, represents the bit at the unit’s place in the binary representation of a number.</p><p>For example, we can represent the decimal number 170 in binary notation as 10101010 (we assume <a href="https://en.wikipedia.org/wiki/Endianness">little-endian machine</a> with address starting from the right and increasing towards left). As shown in the figure, the least significant bit, in this case, is 0.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/241/1*yuyri9si6XBK5-2UVEXm-w.png" /></figure><p>In the simplistic form, LSB algorithm replaces the LSB of each byte in the “carrier” data with one bit from the “secret” message. This concept is visualized in the diagram below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*THFuhBPeMI5lE4JiLcF-OQ.png" /></figure><p>The sender performs “embedding” of the bits of secret messages onto the carrier data byte-by-byte. Whereas the receiver performs the “extraction” procedure by reading LSB bits of each byte of received data, this way the receiver reconstructs the secret message.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/891/1*7ElCrXNicOSyqXdD9XMy3w.png" /></figure><p><strong>Isn’t this corrupting the carrier signal?</strong></p><p>Yes, but the main idea here is that we are trying to exploit the human perception of the integrity of the carrier signal. LSB steganography is very popular for Image Steganography, i.e. hiding secrets in images. And the change in LSB affects the color just so slightly that the change in color is not generally perceptible to the human eye. However, the human ear is more sensitive to slights changes in sound and hence the “noise” that we are adding would have a higher chance of being noticed. To overcome this problem of this trivial form of LSB algorithm, many researchers have suggested variants that increase robustness in the audio domain.</p><p><strong>LSB algorithm implementation in Python</strong></p><p>Let’s implement this method with some sound data as our carrier signal that would carry our secret text. As our sound data, I am taking a sample from a <a href="https://nucleya.bandcamp.com/track/aaja-feat-avneet-khurmi-guri-gangsta">song</a> by Indian electronic music producer Udyan Sagar’s (better known as <a href="https://en.wikipedia.org/wiki/Nucleya">Nucleya</a>). This song will be the carrier of our secret text message, “Peter Parker is the Spiderman!”.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459519369%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsong&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/9fdf9bff1e28be023532bd96d2897dbe/href">https://medium.com/media/9fdf9bff1e28be023532bd96d2897dbe/href</a></iframe><p>The underlying bit manipulation in LSB is pretty straightforward. We will perform logical AND operation between each byte of carrier audio (the “song”) and a bit mask that resets the LSB of carrier byte.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bb_rTu8JtQNMxc4XBAGPnA.png" /></figure><p>Then we will perform a simple logical OR operation between the modified carrier byte and the next bit (0 or 1) from the secret message.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FsLKSuLm4qy0eVcDggGJWg.png" /></figure><p>We will use .wav audio file format for our carrier song. Wave is one of the most popular lossless compression format. Python has a native library called “wave” that provides us basic tools to manipulate audio data.</p><p>Below code is used by the sender to embed the secret text message. The code is sufficiently commented to explain the process step-by-step.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/18fbfba7a7679173ab01e80a33021e70/href">https://medium.com/media/18fbfba7a7679173ab01e80a33021e70/href</a></iframe><p>As the output of the above code, we get the below audio file that has the secret text embedded in it. There is some noticeable noise in this audio file. As an experiment, you could try and embed every 2nd or 3rd byte of carrier audio with one bit from the secret, and see if that fetches a more robust result.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459517908%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsong-embedded&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/c1242a7267da53ddb4e39e7ef6136dfa/href">https://medium.com/media/c1242a7267da53ddb4e39e7ef6136dfa/href</a></iframe><p>To extract the secret from this audio, the receiver shall run the below Python code.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ac87710c442b647c197b1f0ff73e0c31/href">https://medium.com/media/ac87710c442b647c197b1f0ff73e0c31/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/56cd9f8c438097e0c5bc41b53d4ba5d9/href">https://medium.com/media/56cd9f8c438097e0c5bc41b53d4ba5d9/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/730/1*eoXn3k2dG-Uy1srChlei2A.png" /></figure><p>Among other popular techniques for Audio Steganography are Phase Coding, Echo Hiding, and Spread Spectrum. These classic techniques do not induce noise in the carrier signal and hence are more robust methods for achieving Steganography. I encourage you to read related literature if you want to study them in more details or let me know in the comments if you would like me to write on these methods.</p><p><strong>A note on SSTV</strong></p><p>As you can image, we can embed any text, document, audio, video within the carrier audio by simply encoding bits of the secret data within each byte of carrier audio. However, the carrier message has to have enough data bytes so as to carry all the bits of the secret message. In the next section, we will take a look at a frequency modulation based method to hide secret data in the inaudible frequency range. But before that I would like to talk about a method that you can use to encode your image data to audio and then use the Steganography method described in the next section to embed and extract the image from the carrier audio.</p><p><a href="https://en.wikipedia.org/wiki/Slow-scan_television">SSTV</a> is an acronym for Slow-Scan Television, which is a very popular method in radio transmission to send image data over a long distance via ionoshperic propagation. SSTV enables transmission of images in places where very little bandwidth is available, for example, over the Plain Old Telephone Service(POTS) line. In fact, Apollo 11 moon mission had used SSTV to transmit images back to earth.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*XSqSa8TYQnQxH7L3fpm_FA.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/705/1*4sjglooH88btPkbl_KOZ9A.jpeg" /><figcaption>Apollo 11 moonwalk unconverted slow-scan television image [<a href="https://en.wikipedia.org/wiki/Apollo_11_missing_tapes">Source</a>]</figcaption></figure><p>SSTV is based on analog frequency modulation, that looks at the brightness of each pixel and the accordingly allocates a different audio frequency for it. Usually, SSTV is used to transfer greyscale images, we can also use it to transfer colored images with some loss in image resolution.</p><p>Amateur-Radio wiki has a <a href="http://www.amateur-radio-wiki.net/index.php?title=SSTV_software">list of some of the available SSTV software</a> on different platforms. <a href="mailto:vsza@vsza.hu">András Szentkirályi</a> has made a Python package called <a href="https://github.com/dnet/pySSTV">PySSTV</a> that generates SSTV modulated wave file for image files. You can use pip to install this package.</p><pre>pip install pysstv </pre><p>After installing the package, you can run below command to convert an image file (image.jpg) to SSTV modulated audio (audio.wav) file.</p><pre>python -m pysstv /path/to/image.jpg /path/to/audio.wav</pre><p>This package also has the implementation for different SSTV modes including the popular Martin, Robot, and Scottie. You can specify the modes and other parameters while converting the image.</p><p>Now you can play this audio on your computer using any media player and that is all you need to do at the sender end. To receive this audio, I would recommend installing some application on your mobile phone that can extract the image back by listening to our “audio.wav” through the phone’s mic. One such Android app is the Robot36 on play store.</p><p><a href="https://play.google.com/store/apps/details?id=xdsopl.robot36">Robot36 - SSTV Image Decoder - Apps on Google Play</a></p><p>As an example, I encoded below image using PySSTV and got the given encoded audio.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*9xEWBieDSi2U2oL1a6Z9ZA.png" /><figcaption>“secret” image</figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459522153%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsstv-audio&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/82ab3d1277e8f8cd6fb7cc79c0c87657/href">https://medium.com/media/82ab3d1277e8f8cd6fb7cc79c0c87657/href</a></iframe><p>The resulting audio is not pleasant on the ear, but you can modulate it to the inaudible range and have it transferred covertly within a “public” audio.</p><p>In the below video I have given a demonstration of encoding and decoding an image by transferring it as SSTV modulated audio.</p><p>[Video to be added soon.]</p><p><strong>Frequency Modulation based Steganography</strong></p><p>The Frequency-modulation based method that we are going to discuss here is very powerful and doesn’t induce noise in the carrier signal. Using this method we will embed one “secret” audio onto another “public” audio. The secret audio shall be imperceptible to the human ear and the receiver would be able to extract the secret audio at their end.</p><p>The main idea of this algorithm is that we will conceal our secret audio in the near-ultrasound range while keeping our public audio data in the normal hearing range. As explained in <a href="https://medium.com/@sumit.arora/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-1-of-2-6a3bbd706e15">the previous installment</a> of this post, the near-ultrasound audio will be inaudible to most humans above a certain age. You can decide what frequency modulation frequency to use, based on the age and even gender of your target.</p><p>To modulate the secret audio onto the inaudible range, we will use the method described by Lowery Oliver M, in below patent.</p><p><a href="https://patents.google.com/patent/US5159703A/en">US5159703A - Silent subliminal presentation system - Google Patents</a></p><p>We will use near-ultrasound frequencies to encode the secret rather than infrasounds because as we saw in the last post, long exposure to infrasounds <a href="http://www.sciencemag.org/news/2014/09/sounds-you-cant-hear-can-still-hurt-your-ears">can be harmful</a>, whereas there is <a href="http://randombio.com/ultrasound.html">no scientific evidence</a> of any harm being induced to human ear by small exposure to near-hypersounds.</p><p>We can use the method described above to make a demonstration on a regular sound card present on most computers with support for 44.1 kHz sampling rate. Audacity user, <a href="https://forum.audacityteam.org/memberlist.php?mode=viewprofile&amp;u=5642">edgar-rft</a>, has provided one implementation of the method in above patent in <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/music/web/music.software.html">Nyquist programming language</a>. This code sample can directly be imported in Audacity as a <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/music/web/music.software.html">Nyquist plugin</a>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a6759477eb7f947793344e10ac4b3e59/href">https://medium.com/media/a6759477eb7f947793344e10ac4b3e59/href</a></iframe><p><strong>Points to note:</strong></p><ul><li>This plugin produces a single-side-band modulated signal with a suppressed carrier.</li><li>The sample rate must be more than double the frequency of the modulation carrier frequency. So, for example, if you wish to use a carrier frequency of 17500 Hz, then the sample rate of the secret audio must be more than 35000 Hz. You can use the “Tracks menu &gt; Resample” option in Audacity, if this condition is not satisfied for your secret audio.</li><li>Most of the speakers and headphones reliably transmit audio up to 20,000 Hz. This is one reason why in my example, I will use a near-ultrasound carrier frequency range (17.5 kHz).</li><li>Make sure that when you export the processed audio, the sampling rate in “Project rate” is more than double the carrier frequency.</li></ul><p>For this demonstration, let’s assume that we want to transfer the same <a href="https://nucleya.bandcamp.com/track/aaja-feat-avneet-khurmi-guri-gangsta">song</a> by the artist Nucleya, that we used in the earlier example. This will be our “secret” audio.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459645816%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsecret&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/08909e52ebc101f33a9c9486208c7747/href">https://medium.com/media/08909e52ebc101f33a9c9486208c7747/href</a></iframe><p>Frequency distribution for our secret audio shows that the data is well spread in the spectrum.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/597/1*vOC5eJhYCu7VSCoq9xWaCA.png" /></figure><p>We will hide this audio within the below music by <a href="http://ww12.theindianjamproject.com/">The Indian Jam Project</a>. This music is their <a href="https://www.youtube.com/watch?v=TKILNbrWxBQ">rendition of the Interstellar theme</a> music. This will be the “public” cover for our secret audio.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459611241%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fpublic-1&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/2d62761934f7943422752fbfdf6d34cd/href">https://medium.com/media/2d62761934f7943422752fbfdf6d34cd/href</a></iframe><p>This is what frequency distribution for public audio looks like.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*MVKCdisE35yNW84flp40ow.png" /></figure><p>Next, we use the above Nyquist code to convert our secret to a subliminal audio. Here I am using the carrier frequency of 17500 Hz. You can use a different level as per your requirement and capability of the sound card. The output audio confirms that the secret is inaudible (it may still be <a href="https://medium.com/@sumit.arora/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-1-of-2-6a3bbd706e15">audible to young people</a> who have healthy hearing range).</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459646419%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsecret-modulated&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/0d8664e8afa5ee4711bb631f7bb05441/href">https://medium.com/media/0d8664e8afa5ee4711bb631f7bb05441/href</a></iframe><p>Frequency distribution for the subliminal confirms the modulation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*0I9ePPVT1LlpEVwclZaS8w.png" /></figure><p>Next, we mix the public audio and modulated secret audio to create a mixed output that has our secret in the audible range. This embedded audio file shall be sent to the intended receiver.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459642588%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fmixed&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/b1e01576b681ac6fbb04167925c726ec/href">https://medium.com/media/b1e01576b681ac6fbb04167925c726ec/href</a></iframe><p>The frequency distribution for the mixture looks great.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/594/1*AGrY7Aona2e75cCTemqccQ.png" /></figure><p>At the receiver end simply run below code to extract the original secret.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1038cefa5eb6cee688413cef8d19949b/href">https://medium.com/media/1038cefa5eb6cee688413cef8d19949b/href</a></iframe><p>Below is the extracted secret audio data.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F459641943%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fsecret-extracted&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528881780&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/87013bc4dc7e5e01aff03b6ac12f9ee2/href">https://medium.com/media/87013bc4dc7e5e01aff03b6ac12f9ee2/href</a></iframe><p>The sound quality is a bit poor, because for a sample rate of 44100 Hz and a carrier frequency of 17500 Hz, the audio bandwidth is less than 4500 Hz, which is not enough for high-quality audio. Hence, you should expect some distorted speech signal, because there is not much “room” for sound quality in the range between 17500 and 22050 Hertz on a soundcard with only 44100 Hertz sample frequency. I encourage you to repeat this experiment with higher range for carrier frequency if you have a better sound card at your disposal.</p><p>That’s all from my side for this post on Audio Steganography. I hope you enjoyed learning about this cool concept, and I would love to hear your feedback in the comment section below.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c76b1be719b3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Audio Steganography : The art of hiding secrets within earshot (part 1 of 2)]]></title>
            <link>https://sumit-arora.medium.com/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-1-of-2-6a3bbd706e15?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/6a3bbd706e15</guid>
            <category><![CDATA[music]]></category>
            <category><![CDATA[steganography]]></category>
            <category><![CDATA[hearing-range]]></category>
            <category><![CDATA[audio]]></category>
            <category><![CDATA[silent-subliminal]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Wed, 13 Jun 2018 09:32:04 GMT</pubDate>
            <atom:updated>2018-06-17T19:25:11.476Z</atom:updated>
            <content:encoded><![CDATA[<h3>What is Steganography?</h3><p>The word “Steganography”, like many other cool terms, has a Greek origin. It is derived from two Greek words <em>steganos</em>, meaning “covered,” and <em>graphein</em>, meaning “to write”, and refers to the art of enabling covert communication that uses clever methods to hide information in plain sight.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/1*7JDa7b84_GASJaxy_H7bJQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/210/1*4Zc0h8uqH52gm7zW2rgiYw.jpeg" /><figcaption><a href="http://hareenlaks.blogspot.com/2011/04/history-of-steganography.html">Image source</a></figcaption></figure><p>The earliest recorded use of this word <a href="http://classics.mit.edu/Herodotus/history.5.v.html">dates back to 440 BC</a>, when Histiaeus; the Persian Chief Miletus; shaved the head of one of his servants and tattooed a secret message the servant’s scalp. The message got covered, when the servant grew his hair back. And Histiaeus sent the man to Aristagoras who shaved the man’s head and read the secret message.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/260/1*ALkRyXqbNGrbrMeUjlBOiw.png" /><figcaption><a href="https://www.networkworld.com/article/2870165/lan-wan/the-history-of-steganography.html#slide4">Image Source</a></figcaption></figure><p>And also when <a href="http://ovid.cs.depaul.edu/Classes/CS233-W04/Papers/Steganography.doc">Demaratus fooled the Persian spies</a> by covering the engraved wooden tablets with wax to secretly forewarn Greece of the arrival of Xerxes’s naval fleet.</p><p>Perhaps one of the more notoriously known examples is of the time of when <a href="https://en.wikipedia.org/wiki/USS_Pueblo_(AGER-2)#Aftermath">North Korea captured the crew of USS Pueblo</a> and forced the ship’s crew to pose in propaganda photos to make it look like to they were being treated fairly. The crew actually decided to make hand-gesture in the clicked pictures to covertly protest their captivity.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/534/1*Q5CuEQ_3WVHar5vkgCHS8g.jpeg" /><figcaption><a href="http://www.usspueblo.org/Prisoners/The_Digit_Affair.html">Image Source</a></figcaption></figure><p>As you would notice, in all of these incidents the “secret” message was covertly placed inside another message or document such that it remained imperceptible to the unintended receiver.</p><h3>Steganography Vs Cryptography</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*f2BFNvVgIttCpvctgwZFpw.jpeg" /><figcaption><a href="http://knowyourmeme.com/memes/is-this-a-pigeon">maymay reference</a></figcaption></figure><p>Note that Steganography is not the same as Encryption / Cryptography. In Steganography we do not aesthetically alter the publicly communicated message, meaning that the intelligibility of the “carrier” message remains intact. This has an important advantage that “public” message doesn’t attract undue attention to itself, and the fact that this message is carrying a “secret” message is not known to eavesdroppers. On the other hand, encrypted messages are masked using well-known algorithms and arouse the curiosity of hackers and/or researchers to try and break the encryption.</p><p>(Remember the time in primary school, when you returned your crush’s notebook with a confession written at the back in invisible ink? That was Steganography. Now you know!)</p><h3>Audio Steganography</h3><p>While in theory, you can conceal any text, file, image, audio or video within another text, file, image, audio or video; I will only deal with audio domain examples in this article. Audio Steganography is the art of covertly embedding secret messages into digital audio.</p><p><strong>What’s the trick behind Audio Steganography?</strong></p><p>The key to all of the methods that we will discuss is that we are going to exploit the Human Auditory System. <a href="http://www.yamahaproaudio.com/europe/en_gb/training_support/selftraining/audio_quality/chapter4/01_ear_anatomy/">Due to its anatomy</a>, the human ear can pick up the vibrations of a membrane between the frequency range of 20 Hz and 20 kHz. The actual range for a person may vary based on various factors such as age, gender, and health. For example, the upper limit for a middle-aged adult is usually about 12–15 kHz, and it further degrades with age. Also, the hearing range for men degrades quicker than that of women.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*YTahM2ecNBo-mAes2rrnOA.jpeg" /><figcaption>One more thing your pet is better at! <a href="http://www.cochlea.org/en/hear/human-auditory-range">Image source: Cochela</a></figcaption></figure><p>Hearing range for animals is <a href="https://en.wikipedia.org/wiki/Hearing_range">different from humans</a>. For example, with its big ears, an elephant can hear “infrasounds” (sounds lower than the human range of 20 Hz) such as a heartbeat of 1 or 2 Hz. And similarly, dogs can hear “ultrasounds” (sounds higher than the human limit of 20000 Hz) such as a dog whistle.</p><p>So one way to achieve the Audio Steganography would be to use Infrasound and/or Ultrasound range to transmit our “secret” message, which would be accompanied by a “public” audio data being played on the audible frequency range, in order to deceive the unintended receiver. In the coming sections, I will explain this method in more detail.</p><h3><strong>Case in point</strong></h3><p>There have been many instances in history when the applications that use Audio Steganography methods have attracted some major news headlines. I will share some examples here to help you understand some of the possible applications that Audio Steganography can have.</p><ol><li><strong>Malicious apps on mobile phones can lookout for the inaudible sounds</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/879/1*xjNCQ-kcKi8-jxzH0aIBuw.png" /><figcaption><a href="https://arstechnica.com/information-technology/2017/05/theres-a-spike-in-android-apps-that-covertly-listen-for-inaudible-sounds-in-ads/">Source</a></figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ywQc-zCj5TCISAVmqjXlOw.png" /><figcaption><a href="https://www.theatlantic.com/technology/archive/2015/11/your-phone-is-literally-listening-to-your-tv/416712/">Source</a></figcaption></figure><p>In 2014, <a href="https://www.silverpush.co/">SilverPush</a>, a Gurugram-based Indian advertisement company, <a href="https://techcrunch.com/2014/07/24/silverpush-audio-beacons/">was found to be using unscrupulous means</a> to track users across multiple devices. All of the apps that used SilverPush’s SDK, were able to listen to the “audio beacons” through the phone’s mic in order to facilitate a more effective user habit tracking. These beacons were covertly transmitted as ultrasonic sound waves coming from the company’s advertisement running on television or in a web browser running on a computer. These secret triggers were, of course, imperceptible to the device owners.</p><p><strong>2. Hidden sounds can trigger the smart home devices</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/987/1*0DC49sefioDsS0kJUhmnxw.png" /><figcaption><a href="https://www.theverge.com/2018/2/2/16965484/amazon-alexa-super-bowl-ad-activate-frequency-commercial-echo">Source</a></figcaption></figure><p>Earlier this year, Amazon announced that it had taken steps to ensure that the Amazon Echo devices in viewers’ home will not get unintentionally activated during the Super Bowl ad for Alexa devices. <a href="https://www.reddit.com/r/amazonecho/comments/5oer2u/i_may_have_found_how_amazon_prevents_the_echo/">It is speculated</a> that Amazon made <a href="https://iot.stackexchange.com/questions/828/why-doesnt-the-amazon-echo-respond-to-advertisements-or-reports-about-alexa">clever use of acoustic frequency range</a> to achieve this.</p><p>The point to note here is that the same concept can be extended to inaudible audio waves from seemingly innocuous sources such as television, that may interface with smart home devices unbeknownst to the device owners.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*R_EInXjfokf3E_5oIMMXbg.png" /><figcaption><a href="https://arstechnica.com/tech-policy/2015/11/beware-of-ads-that-use-inaudible-sound-to-link-your-phone-tv-tablet-and-pc/">Source</a></figcaption></figure><p><strong>3. A ringtone that only the young people can hear</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/1*hOD1CmiDvPXP6UyDzsVn7g.png" /><figcaption><a href="https://boingboing.net/2006/05/24/kids-turn-teen-repel.html">Source</a></figcaption></figure><p>You might have heard of <a href="https://en.wikipedia.org/wiki/The_Mosquito">The Mosquito</a>. It is an electronic device that is used in some countries to deter young people from congregating, mainly outside shops and marts, and hopes to reduce anti-social behavior such as loitering and vandalism. It works on the simple principle that hearing range for humans deteriorates with age. So the ultrasounds that The Mosquito produces, can only be heard by the young people. To cause slight discomfort, these audio waves could also be transmitted at higher sound pressure levels.</p><p>Taking advantage of the fact that the cellphones are generally capable of producing and recording ultrasounds, some teenagers recorded the sounds from The Mosquito to their smartphones and began to use it as call ringtone in order to get away with using phones in classrooms. This ringtone is also commercially available now.</p><p>The point to take away from this is that if your target audience or the intended receiver of the message is young, you can use near-ultrasound ranges to encode your “secret“ message.</p><p>Below is an audio sample to replicate “The Mosquito Ringtone” effect. You can use it to see if you can hear the infamous “Teen Buzz” sound</p><p>17.4 kHz for below-23 age group:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457661802%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fthe-mosquito-ringtone&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/a4f51df68bf6f97f328b56ef65457baf/href">https://medium.com/media/a4f51df68bf6f97f328b56ef65457baf/href</a></iframe><p>21 kHz for below-20 age group:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457717116%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2Fthe-mosquito-ringtone-2&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/1ba75eb64fd3d84c0534a0c24982c365/href">https://medium.com/media/1ba75eb64fd3d84c0534a0c24982c365/href</a></iframe><p><strong>4. Hidden sounds in movies to play with your emotions</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sNzlt0SnBrJONY9LEJYxIw.png" /><figcaption><a href="https://www.atlasobscura.com/articles/how-the-hidden-sounds-of-horror-movie-soundtracks-freak-you-out">Source</a></figcaption></figure><p>Have you ever wondered why the horror movies feel scarier at your local movie theatre (that is equipped with Dolby Sound), compared to watching the same movie at home? Well, with Audio Steganography the filmmakers can use infrasounds to unnerve the audiences.</p><p><a href="https://en.wikipedia.org/wiki/Infrasound#Human_reactions">Studies have shown</a> that the infrasounds (extreme bass waves) can cause the feeling such as sorrow, unease, fear, panic, depression and physical sensations. A famous paper titled “<a href="http://web.archive.org/web/20060621050809/http://www.ghostexperiment.co.uk/ghost-in-machine.pdf">The Ghost in the Machine</a>” published in the 1990s talked about how a broken metal fan in the lab of Vic Tandy, a British Researcher, caused him to experience a supernatural presence. The sound produced by the fan was measured to be at 18.98 Hz, which is below the human hearing range and is very close to <a href="http://illumin.usc.edu/assets/submissions/92/TheSoundsinSilence.docx">the resonant frequency of the eye</a> (18 Hz) defined by NASA.</p><p>If you are interested in knowing more about the acoustic trickery used in cinemas, I recommend watching the below Ted Talk.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fembed.ted.com%2Ftalks%2Ftasos_frantzolas_everything_you_hear_on_film_is_a_lie&amp;url=https%3A%2F%2Fwww.ted.com%2Ftalks%2Ftasos_frantzolas_everything_you_hear_on_film_is_a_lie&amp;image=https%3A%2F%2Fpi.tedcdn.com%2Fr%2Ftalkstar-photos.s3.amazonaws.com%2Fuploads%2F5401a8ff-d819-4926-9c15-f7aec2ea851a%2FTasosFrantzolas_2016X-embed.jpg%3Fh%3D316%26w%3D560&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=ted" width="560" height="316" frameborder="0" scrolling="no"><a href="https://medium.com/media/d07f56e1b42f97561154c45e8672dd7d/href">https://medium.com/media/d07f56e1b42f97561154c45e8672dd7d/href</a></iframe><p><strong>5. Silent Subliminal Technology</strong></p><p>Some people believe in subliminal audios to be influential to the subconscious mind. It is known that certain frequencies activate particular areas of the human brain. The proponents of subliminal methods advocate listening to useful audios such as self-help recordings as ultrasounds. The basic idea is that even though the audio playback will be completely “silent” to the human ear, but the human subconscious mind can still listen to these audio and take advantage of the positive influence of the audio content. Usually, these subliminals are mixed some other audible acoustics so that the listener doesn’t feel bored with the “silence” of subliminals. Also, at present, there is no clear evidence that proves the effectiveness of the subliminal technology.</p><p><strong>So, How about a quick hearing range test?</strong></p><blockquote>“Experiments have shown that a healthy young person hears all sound frequencies from approximately 20 to 20,000 hertz.”</blockquote><blockquote>- <a href="https://amzn.to/2JHNzEV">Cutnell, John D. and Kenneth W. Johnson. <em>Physics</em>. 4th ed. New York</a>: Wiley, 1998: 466.</blockquote><p>As explained earlier, a person’s hearing range deteriorates based on various factors such as age, gender, and health. You can use the following audio files to test your current hearing range.</p><p><strong>NOTE:</strong> I have made sure to keep the “loudness” of these audio files to be much lower than the limit that might be remotely damaging to the human ear, and each frequency is within the human audible range. But I still recommend not using earphones to listen to these audios for a long duration.</p><p>Lower Bound Test:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457359936%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F20-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/f6b61648e2fbdf4095f8162c50126acf/href">https://medium.com/media/f6b61648e2fbdf4095f8162c50126acf/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356828%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F100-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/217f6ecfbecb3c1f0d70cfff17521164/href">https://medium.com/media/217f6ecfbecb3c1f0d70cfff17521164/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356894%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F200-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/046eddfb2521f66e15719eba5eb908c6/href">https://medium.com/media/046eddfb2521f66e15719eba5eb908c6/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356888%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F300-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/ecf882ac020061e34c864d45467f13eb/href">https://medium.com/media/ecf882ac020061e34c864d45467f13eb/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356882%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F400-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/768e0e1a211c7b60cbcb7d4311992f7b/href">https://medium.com/media/768e0e1a211c7b60cbcb7d4311992f7b/href</a></iframe><p>Upper Bound Test:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356879%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F8000-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/b466f38e718fd1746b3f1a3950e3ac55/href">https://medium.com/media/b466f38e718fd1746b3f1a3950e3ac55/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356876%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F12000-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/169e3211cd651f5bf3e107badc1ad517/href">https://medium.com/media/169e3211cd651f5bf3e107badc1ad517/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356843%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F15000-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/f1402fa527ef237c09713bbfab38460f/href">https://medium.com/media/f1402fa527ef237c09713bbfab38460f/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356861%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F17000-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/286191d62bf8cd2b14cd72610f885b53/href">https://medium.com/media/286191d62bf8cd2b14cd72610f885b53/href</a></iframe><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fw.soundcloud.com%2Fplayer%2F%3Furl%3Dhttp%253A%252F%252Fapi.soundcloud.com%252Ftracks%252F457356822%26show_artwork%3Dtrue&amp;url=https%3A%2F%2Fsoundcloud.com%2Fsumit-kumar-arora%2F20000-hz&amp;image=http%3A%2F%2Fa1.sndcdn.com%2Fimages%2Ffb_placeholder.png%3F1528714495&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=soundcloud" width="800" height="166" frameborder="0" scrolling="no"><a href="https://medium.com/media/4a1e5557740d3359b9e24afcfbc093f4/href">https://medium.com/media/4a1e5557740d3359b9e24afcfbc093f4/href</a></iframe><p>(Maybe leave a comment below with your age, gender and hearing range?)</p><p>By now you should have a good understanding of the Audio Steganography concept. In the next installment of this two-part writing, I will describe some of the methods to achieve the magic of Audio Steganography along with the hands-on examples with accompanying code/tools.</p><p>Thank you for reading this article. Feel free to leave your comments/questions /feedback in the comments section below. And I will see you in the next one!</p><p>Edit: Part 2 is live! Access it using the link given below.</p><p><a href="https://medium.com/@sumit.arora/audio-steganography-the-art-of-hiding-secrets-within-earshot-part-2-of-2-c76b1be719b3">Audio Steganography : The art of hiding secrets within earshot (part 2 of 2)</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6a3bbd706e15" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Getting Started with SpaceNet data]]></title>
            <link>https://sumit-arora.medium.com/getting-started-with-aws-spacenet-and-spacenet-dataset-visualization-basics-7ddd2e5809a2?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/7ddd2e5809a2</guid>
            <category><![CDATA[computer-vision]]></category>
            <category><![CDATA[qgis]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[spacenet]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Tue, 06 Feb 2018 01:18:55 GMT</pubDate>
            <atom:updated>2018-06-24T21:41:13.968Z</atom:updated>
            <content:encoded><![CDATA[<h3>Getting Started with SpaceNet</h3><p>The commercially captured satellite imagery that is available in SpaceNet dataset provides wide array of opportunities for advancements in computer vision and machine learning. This article attempts to create understanding and awareness for SpaceNet dataset for those who are unfamiliar with it.</p><p><strong>What is SpaceNet ?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*mWK6J_xJRaVbBom4khrKlA.png" /><figcaption>SpaceNet logo</figcaption></figure><p><a href="https://aws.amazon.com/public-datasets/spacenet/">SpaceNet</a> is a publicly available dataset containing commercial satellite imagery. This imagery is accompanied by labelled information that can be used to train machine learning models. CosmiQ Works, Radiant Solutions and NVIDIA have partnered to release the SpaceNet data set to the public in order to foster innovation in the field of computer vision with algorithms that can automatically extract geometric features such as roads, buildings etc.</p><h3><strong>Dataset Source</strong></h3><p>In order to better understand the dataset, it is helpful to know from where the data is sourced. The satellite imagery is provided by <a href="http://www.digitalglobe.com/">Digital Globe</a>, an American vendor of space imagery and geospatial content. Digital Globe owns a “constellation” of satellites that capture high quality remote sensing imagery. The satellites include QuickBird, GeoEye-1 and the WorldView Series (WorldView-1, WorldView-2, WorldView-3 and WorldView-4). The data generated from each satellite varies in terms of features such as resolution, geolocational accuracy etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*E7eO2X5-rpG9RSANd9CBAw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Se1fDInMBcR1_OrTcrPX2Q.png" /><figcaption>Comparison of data captured by different Digital Globe satellite (For a more detailed comparison of each satellite, read the official Digital Globe specification document <a href="https://dg-cms-uploads-production.s3.amazonaws.com/uploads/document/file/223/Constellation_Brochure_forWeb.pdf">here</a>)</figcaption></figure><p><strong>What locations are covered in SpaceNet?</strong></p><p>SpaceNet contains satellite data for 5 Area of Interests (AOIs). Below table summarizes the data in 5 AOIs.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/eb6e58fd857a031e7f1752564c00d68e/href">https://medium.com/media/eb6e58fd857a031e7f1752564c00d68e/href</a></iframe><p>In the round 1 of SpaceNet Challenge(Nov, 2016) open corpus of imagery from WorldView-2 satellite for Rio De Janeiro (AOI_1 location) was used. This imagery was 50 cm mosaic of Ground Sample Distance (GSD) with eight spectral bands. In round 1, 42 developers competed in an open challenge hosted by <a href="https://crowdsourcing.topcoder.com/spacenet">TopCoder<strong> </strong></a>to create algorithms that extract building footprints from satellite imagery.</p><p>The next phases of the SpaceNet Challenge are a follow-on competition using DigitalGlobe’s 30 cm imagery from WorldView-3 and building footprints across four new geographically diverse cities spread around the globe. These datasets now have multiple imagery formats (panchromatic, multi-spectral, RGB-pansharpen, multispectral-pansharpen) to allow experimentation with different types of imagery. Also, the data is available for download in training-test split.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MhNVYmlsWP9PfL2VdiPI_Q.jpeg" /><figcaption>Sample of a high-resolution image captured by WorldView-3 satellite (<a href="https://apollomapping.com/imagery/high-resolution-imagery/worldview-3">see more examples here</a>)</figcaption></figure><p><strong>How much area is covered?</strong></p><p>Below visualization show the geographical area covered in the SpaceNet dataset for all AOIs.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e17216740f8bda910b95ff8d1be74791/href">https://medium.com/media/e17216740f8bda910b95ff8d1be74791/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/16691340429085fcecfe57f5d64fe252/href">https://medium.com/media/16691340429085fcecfe57f5d64fe252/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0665372ada2e9f747475433163a2a918/href">https://medium.com/media/0665372ada2e9f747475433163a2a918/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/482c538d32729c246d9642d8cf1df906/href">https://medium.com/media/482c538d32729c246d9642d8cf1df906/href</a></iframe><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f969b345e399f54faed9d41f10132dfc/href">https://medium.com/media/f969b345e399f54faed9d41f10132dfc/href</a></iframe><h3><strong>Understanding the Dataset</strong></h3><p>For better understanding, you can visualize the SpaceNet dataset to be divided in 2 categories: vector data and raster data.</p><p>In <strong>vector representation</strong>, we describe the data in terms of geometric shapes such as points, lines and polygons. This representation is usually written in a mark-up language syntax (such as <a href="https://en.wikipedia.org/wiki/Well-known_text">Well-Known Text</a>) and explicitly stores the actual coordinates of vertex.</p><p>In <strong>Raster representation</strong>(including imagery), we divide the area in equal squares and assign characteristics to these squares. For example, we may use a 2-dimensional matrix to represent an area. Other than an origin point, e.g. bottom left corner or top-left corner, no geographic coordinates are stored.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*eib1gXVh5I9x-8a0.png" /><figcaption>Raster vs Vector data</figcaption></figure><p>Now, let’s take a look at both kind of data in the context of SpaceNet.</p><p><strong>Raster data in SpaceNet</strong></p><p>Raster data in SpaceNet dataset is present in the form of .tif images. These GeoTiff images are a special format of image data which incorporate meta-data that can be used for georeferencing an image and how a pixel in the image is mapped to real world distances.</p><p>The Rio de Janeiro dataset (AOI_1) used in Round-1 of SpaceNet challenge, is formated slightly differently and is missing pansharpened, 8-band and multispectral data. This dataset only contains RGB channels pansharpened to a resolution of 0.5m. In all the other datasets, you would observe following directory structure for both train and test data.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/781c920682fba02318bd0b1f710d8b8d/href">https://medium.com/media/781c920682fba02318bd0b1f710d8b8d/href</a></iframe><p>Most commercial satellites capture imagery over multiple coarse resolution multispecral bands as well as a finer spatial resolution panchromatic band. This is done because of the tradeoff between the spectral resolution (i.e. the range of wavelengths that are sampled by an imaging detector) and the spatial resolution (<a href="https://gis.stackexchange.com/questions/113896/panchromatic-image-association-with-high-spatial-resolution">read more</a>). Spacenet dataset provides us images with panchromatic, RGB and 8-band channels. Let’s discuss the characteristic properties of these images.</p><p><strong>MUL/RGB</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fvvi-el6TzasDTqZ1D3TYg.png" /><figcaption>Example of a pansharpened RGB image</figcaption></figure><p>The 8-band, multispectral images include the following bands: Coastal Blue, Blue, Green, Yellow, Red, Red Edge, Near Infrared 1 (NIR1), and Near Infrared 2 (NIR2). These images have a resolution of ~1.3 m. However, 8-band and RGB images can have their resolutions increased to their respective satellite’s panchromatic resolution through <a href="https://en.wikipedia.org/wiki/Pansharpened_image">pansharpening</a>. This pansharpening to ~0.3m resolution is already done for MUL and RGB images in their respective -PanSharpen directories.</p><p><strong>PAN</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YhMT2fZWxa38jfeo7P6jJQ.jpeg" /><figcaption>Example of a Panchromatic image</figcaption></figure><p><a href="https://en.wikipedia.org/wiki/Panchromatic_film">Panchromatic images</a> are single band images for which the sensor is sensitive to all wavelengths of visible light, hence providing most realistic reproduction of a scene.This imagery is extremely useful, as it is generally of a much higher (spatial) resolution than the multispectral imagery from the same satellite. Panchromatic images are generally displayed as shades of gray and are also used to perform pansharpening for multispectral bands.</p><p><strong>But what is the advantage of having different types of images?</strong></p><p>Images captured by WorldView-3 satellite vary in terms of wavelengths as shown below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/931/1*Vaiag8mEL2Xfm-1L7_C0Dg.png" /><figcaption><a href="http://content.satimagingcorp.com.s3.amazonaws.com/media/pdf/WorldView-3-PDF-Download.pdf">Source: WorldView-3 Specifications</a> (SWIR and CAVIS bands not shown here)</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aGaifiVMgfrIIZxRoy_2mw.jpeg" /><figcaption>Application areas for different spectral bands (NOTE: SpaceNet dataset doesn’t include SWIR and CAVIS bands)</figcaption></figure><p>As you can see in the above image, the RGB bands in 8-band images do not include Yellow band. Separating Yellow and also including Coastal Blue bands allow for novel feature extraction such as vegetative analysis by providing “yellower” and “bluer” information of objects. The Red-Edge (705–745nm) provides wavelengths of light just beyond the Red wavelengths. The significance of this channel is that Chlorophyll is transparent to wavelengths &gt; 700nm, leading to nicer application for vegetative analysis. Near Infrared (NIR) bands 1 &amp; 2 can be used to perform <a href="https://en.wikipedia.org/wiki/Near-infrared_spectroscopy">NIR spectroscopy</a>, whose applications include investigating plant health, soil conditions and atmospheric analysis.</p><p><strong>Vector data in SpaceNet</strong></p><p>Vector data, such as building footprints, are provided in SpaceNet dataset in both CSV and GeoJSON formats. The CSV provides the coordinates of the vertices of the building footprint (polygons) as latitude and longitude in the same map projection as the images, and the GeoJSON provides this same information in pixel coordinates relative to the image.</p><p>CSV files are present in “<em>summaryData</em>” directory and GeoJSON files are present in “<em>geojson/buildings</em>” for buildings’ labels or inside “<em>geojson/spacenetroads</em>” for roads’ labels. Note that the vector data is, understandably so, available only for training datasets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*r9l_GgkCaPNqhgZUctzvig.png" /><figcaption>Example of GeoJSON data</figcaption></figure><p>If you are new to GeoJSON standard or want a refresher on it, I recommend reading <a href="https://medium.com/@sumit.arora/what-is-geojson-geojson-basics-visualize-geojson-open-geojson-using-qgis-open-geojson-3432039e336d">this article</a> that I wrote for explaining GeoJSON standard and tools that you might use to visualize GeOJSON data.</p><p><a href="https://medium.com/@sumit.arora/what-is-geojson-geojson-basics-visualize-geojson-open-geojson-using-qgis-open-geojson-3432039e336d">A primer on GeoJSON standard and visualization tools</a></p><h3><strong>Download the Datasets</strong></h3><p>SpaceNet dataset is available on AWS in “<a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/RequesterPaysBuckets.html">Requester Pays</a>” S3 buckets, meaning that the requester instead of the bucket owner pays the cost of the request and the data download from the bucket. You can use <a href="https://aws.amazon.com/cli/">aws-cli</a> to download the datasets by <a href="https://spacenetchallenge.github.io/datasets/spacenetRoads_summary.html">following these instructions</a>.</p><h3><strong>Visualize the Data</strong></h3><p>Visualizing data is a good way to familiarize yourself with the nature of quality of your dataset. As an example, I am going to visualize the sample data available in the SpaceNet dataset. Also, I will use <a href="https://qgis.org/en/site/">QGIS software</a> to visualize vector and raster data of SpaceNet. QGIS is a free, open-source cross-platform software for viewing, editing, and analyzing geospatial data.</p><p><strong>QGIS Browser</strong></p><p>Similar to what ArcCatalog is for ArcGIS, QGIS Browser is the standalone visualization application in QGIS that comes bundled with default QGIS installation. You can use QGIS Browser to have a quick look at your geospatial data.</p><ul><li>Open “QGIS Browser” on your computer and use the left pane to browse to the directory that contains SpaceNet data. The “Preview” tab in right pane will show you a quick preview of the data points, after you click on .geojson, .tif or .csv file.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ds-ODr16YWiXgEFSknhnsQ.png" /><figcaption>Preview geoJSON files</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9yQ-3wDPhi54nnTcqdtjcQ.png" /><figcaption>Preview tif files</figcaption></figure><ul><li>Switch to the “Attributes” tab to see the associated attributes values for the vector data.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l41xV693VhWRiCTjNsoMxQ.png" /></figure><p><strong>QGIS Desktop</strong></p><p>QGIS Desktop is the “batteries included” standalone application in QGIS package. We will use it to map over vector data over raster imagery.</p><ul><li>First open the .tif file in QGIS Desktop, using menu option <em>Layer -&gt; Add Layer -&gt; Add Raster Layer</em>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T6dmg2qxftlea-Tl7Q_6Cg.png" /></figure><ul><li>You should now to able to see the raster preview and the raster image should be added in the “<em>Layers</em>” pane, as shown below.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7RYf80b0-3p7-KE-qynvbg.png" /></figure><ul><li>Now open the vector (geojson) file using L<em>ayer -&gt; Add Layer -&gt; Add Vector Layer-&gt;Browse</em> menu options.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n8Ps4ZzMbOh2gzuilmYJlw.png" /></figure><ul><li>You should be able to see vector data layer overlaid on raster layer. If not, make sure your vector layer is above the raster layer in the “Layers” pane. You can change this by simply dragging and dropping a layer above or below another. You can also customize the line width and color for the drawn vector by double-clicking on the corresponding layer and choosing the respective option.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zVhgUpgEj_uGTsHmNo5BPQ.png" /></figure><p>Note: The SpaceNet data has both vectors and rasters numbered according to the index of grid they represent. To see overlay, use same indexed vector and raster data. For example, we used RGB-PanSharpen_AOI_2_Vegas_<strong>img517</strong>.tif as raster and spacenetroads_AOI_2_Vegas_<strong>img517</strong>.geojson as vector data.</p><p>You can also open multiple raster and vector files to visualize more grids together.</p><p>Hopefully this article was helpful for you to start working with SpaceNet data. In the next article, I will explain how to use Python to work with SpaceNet data. Thank you for your time and I will see you in the next one! :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7ddd2e5809a2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A primer on GeoJSON standard and visualization tools]]></title>
            <link>https://sumit-arora.medium.com/what-is-geojson-geojson-basics-visualize-geojson-open-geojson-using-qgis-open-geojson-3432039e336d?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/3432039e336d</guid>
            <category><![CDATA[data-visualization]]></category>
            <category><![CDATA[gis]]></category>
            <category><![CDATA[geojson]]></category>
            <category><![CDATA[qgis]]></category>
            <category><![CDATA[json]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Sat, 03 Feb 2018 19:32:58 GMT</pubDate>
            <atom:updated>2018-07-09T19:33:17.959Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>What is GeoJSON ?</strong></p><p>Well, the name GeoJSON (Geo+<a href="http://www.json.org/">JSON</a>) itself is a giveaway. The GeoJSON is a format for encoding geographical data structures, using the <a href="https://www.w3schools.com/js/js_json_syntax.asp">JavaScript Object Notation</a> (JSON). Simply put, GeoJSON gives you an easy format for representing simple geographical features, along with their non-spatial attributes.</p><p>As described <a href="https://tools.ietf.org/html/rfc7159">in the RFC</a>, JSON was designed to be a lightweight, text-based and language-independent data interchange format that is easy for both humans and machines to read and write. And GeoJSON basically uses this design strategy to represent data about geographic features, their properties, and their spatial extents.</p><p><strong>Fancy an example ?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/1*cdc81Pd78wPMfY8NxrZXHQ.jpeg" /><figcaption><a href="http://xmodulo.com/validate-json-command-line-linux.html">image source</a></figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/951/1*MJW19a5cMC1kaOANLW7YdA.png" /><figcaption><a href="http://geojson.org/">image source</a></figcaption></figure><p>Does the structure make sense ? No ? Read on!</p><p><strong>So, what all goes inside a GeoJSON object ?</strong></p><p>Glad you asked! A GeoJSON object can define the followings:</p><ul><li><strong>Geometric objects in space</strong>: for example, a Point, LineString or Polygon etc.</li><li><strong>Features</strong>: A feature is a spatially bounded entity.</li><li><strong>List of Features</strong>:<strong> </strong>Also known as a FeatureCollection.</li></ul><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FwSCAy1zJbcUG4%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FwSCAy1zJbcUG4%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FwSCAy1zJbcUG4%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="236" frameborder="0" scrolling="no"><a href="https://medium.com/media/11aa3cc8b0a9296960539840f9ba038c/href">https://medium.com/media/11aa3cc8b0a9296960539840f9ba038c/href</a></iframe><p>Okay, this terminology might be too much to digest at once. So, let’s look into each part one-by-one.</p><p><strong>Geometric Objects</strong></p><p>Geometry objects represent points, curves, and surfaces in coordinate space. The <a href="https://tools.ietf.org/html/rfc7946">GeoJSON RFC</a> defines 7 “types” of a geometric shapes that a GeoJSON object can represent. These are “Point”, “MultiPoint”, “LineString”, “MultiLineString”, “Polygon”, “MultiPolygon”, and “GeometryCollection”.</p><p>Point, LineString and Polygon shapes are also known as single type Geometry objects. While MultiPoint, MultiLineString, and MultiPolygon are also called homogeneously typed multipart Geometry objects.</p><p>Construct for many of these shapes will become clear once you understand the concept of a Position.</p><p>A <strong>Position</strong> is a fundamental geometric construct. Simply put, it is an array of 2 or three numbers. The first two numbers represent longitude and latitude(in that order). And the third (optional) number represents altitude or elevation. So, a position is basically the array [longitude, latitude, elevation/altitude].</p><blockquote><strong>NOTE:</strong> Among different geographical tools or libraries, there seems to be no common consent about whether the ordering should be [longitude, latitude] or [latitude, longitude]. For example, Google Maps API and Leaflet.js expect the coordinates to be [latitude, longitude] while GeoJSON, shapefile, D3.js, ArcGIS API expect the coordinates to be in the format [longitude, latitude]. So, always be wary of what order is required for your application. For reference, you could use the below table compiled by <a href="https://twitter.com/tmcw/">Tom MacWright</a> on <a href="https://macwright.org/lonlat/">his blog</a>.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/819/1*VK1iZ1Lp-9fo7z8Rt-hwzw.png" /><figcaption><a href="https://macwright.org/lonlat/">image source</a></figcaption></figure><p>All geometric shapes have two key value pairs defining that shape. You might have also noticed them in the sample GeoJSON object you saw above. The two keys are type and coordinates. “type” must be one of the seven types we saw above and “coordinates” is an array of Position values. The exact structure of the elements in this array is determined by the type of geometry.</p><p><strong>Point:</strong> As you can guess, if we want to represent a Point geometry, we need to have one position. So, we can define a Point in GeoJSON as:</p><pre>{ &quot;type&quot;: &quot;Point&quot;, <br>    &quot;coordinates&quot;: [30, 10]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*e5sTZPzfzi9RtY6mWT-XLw.png" /></figure><p><strong>MultiPoint: </strong>The “coordinates” value would be an array of Position objects for a MultiPoint object.</p><pre>{ &quot;type&quot;: &quot;MultiPoint&quot;, <br>    &quot;coordinates&quot;: [<br>        [10, 40], [40, 30], [20, 20], [30, 10]<br>    ]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*JLhpiWL7ToT0ha6r8YVVOw.png" /></figure><p><strong>LineString: </strong>For LineString, we need to provide two positions, i.e. the start and end points of the line segment. For example:</p><pre>{ &quot;type&quot;: &quot;LineString&quot;, <br>    &quot;coordinates&quot;: [<br>        [30, 10], [10, 30], [40, 40]<br>    ]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*6ofLjjNmO8qex5NqTuccqQ.png" /></figure><p><strong>MultiLineString:</strong> For type “MultiLineString”, the “coordinates” member is an array of LineString coordinate arrays.</p><pre>{ &quot;type&quot;: &quot;MultiLineString&quot;, <br>    &quot;coordinates&quot;: [<br>        [[10, 10], [20, 20], [10, 40]], <br>        [[40, 40], [30, 30], [40, 20], [30, 10]]<br>    ]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*fBnw3FscsCkYn9PPi1Y6-g.png" /></figure><p><strong>Polygon</strong></p><p>Polygons in GeoJSON standard, are slightly more complex than the other geometric shapes. A Polygon is defined <a href="https://tools.ietf.org/html/rfc7946#section-3.1.6">in RFC document</a> as “<em>For type “Polygon”, the “coordinates” member MUST be an array of linear ring coordinate arrays</em>”. So to understand a Polygon definition, we must first have a look at the LinearRing concept.</p><p>A LinearRing is a closed LineString with four or more positions. “Closed” simply means that the start and end point of the LinearRing must be the same Position. A Polygon in GeoJSON format is specified in terms of multiple LinearRing shapes. The outer boundary of the Polygon is one LinearRing, and there could be multiple other LinearRing shapes defining the other intricate ring shapes inside that Polygon.</p><p>As per the standard, the first LinearRing array inside the “coordinate” array must be the exterior ring and all following LinearRing arrays define the interior rings. RFC 7946 also defined winding order for these rings, which specifies that the exterior rings Position are defined counterclockwise, and interior rings Position values are defined clockwise. This winding order is useful for many drawing APIs.</p><pre>{ &quot;type&quot;: &quot;Polygon&quot;, <br>    &quot;coordinates&quot;: [<br>        [[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], <br>        [[20, 30], [35, 35], [30, 20], [20, 30]]<br>    ]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*kaZvlncuHBFGVwEDQs8AYw.png" /></figure><p><strong>MultiPolygon</strong></p><p>For type “MultiPolygon”, the “coordinates” member is an array of Polygon coordinate arrays.</p><pre>{ &quot;type&quot;: &quot;MultiPolygon&quot;, <br>    &quot;coordinates&quot;: [<br>        [<br>            [[30, 20], [45, 40], [10, 40], [30, 20]]<br>        ], <br>        [<br>            [[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]<br>        ]<br>    ]<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/51/1*Fg9_5pdI0IKZzWnbLLITtA.png" /></figure><p><strong>GeometryCollection</strong></p><p>A GeometryCollection is a heterogeneous composition of the other geometry types you saw above. A GeometryCollection object has no “coordinates” member, instead it has a member named “geometries”. The value of “geometries” is an array. Each element of this array is a GeoJSON Geometry object. It is possible for this array to be empty.</p><pre>{ &quot;type&quot;: &quot;GeometryCollection&quot;, <br>    &quot;geometries&quot;: [<br>      {<br>        &quot;type&quot;: &quot;Point&quot;,<br>        &quot;coordinates&quot;: [0, 0]<br>      }, {<br>        &quot;type&quot;: &quot;Polygon&quot;,<br>        &quot;coordinates&quot;: [[[45, 45], [45, -45], [-45, -45], [-45, 45], [45,45]]]<br>       }<br>    ]<br>}</pre><p><strong>Feature Object</strong></p><p>The Geometric shapes that you saw in last section, define shapes that can be plotted on a map. However, our shapes on map should also have some real-world meaning. This meaning is defined by attributes of that shape. For example, a building marked by a Polygon on map could have a name property like “Taj Mahal” and possibly some other parameters further describing the shape. In GeoJSON, an object of type “Feature” defines both the gemoetric shape and attributes for an entity.</p><p>The Feature object has a member with name “type” with the value “Feature”. It also has a member with the name “geometry” with value of any geometric shape that we discussed above or a null value. Further, it has a member with the name “properties” whose value is a JSON object (or null value) defining the attributes for that object. It can also have an optional “id” member with a unique string or null value specifying an identifier for the Feature.</p><p>As an example of Feature object, take a look at the sample GeoJSON object that you saw at the start of this article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/698/1*ETZo9Nr0R9uaeOlxCQr5aw.png" /></figure><p>I hope it makes more sense now.</p><p><strong>FeatureCollection Object</strong></p><p>A FeatureCollection object is a composition of Feature objects. It is the most common top-level construct you will observe in a GeoJSON file. It has a member “type” with value “FeatureCollection” and another member with name “features” with array of Feature object as value.</p><pre>{<br>  &quot;type&quot;: &quot;FeatureCollection&quot;,<br>  &quot;features&quot;: [<br>    {<br>      &quot;type&quot;: &quot;Feature&quot;,<br>      &quot;geometry&quot;: {<br>        &quot;type&quot;: &quot;Point&quot;,<br>        &quot;coordinates&quot;: [-80.83775386582222, 35.24980190252168]<br>      },<br>      &quot;properties&quot;: {<br>        &quot;name&quot;: &quot;DOUBLE OAKS CENTER&quot;,<br>        &quot;address&quot;: &quot;1326 WOODWARD AV&quot;<br>      }<br>    },<br>    {<br>      &quot;type&quot;: &quot;Feature&quot;,<br>      &quot;geometry&quot;: {<br>        &quot;type&quot;: &quot;Point&quot;,<br>        &quot;coordinates&quot;: [-80.83827000459532, 35.25674709224663]<br>      },<br>      &quot;properties&quot;: {<br>        &quot;name&quot;: &quot;DOUBLE OAKS NEIGHBORHOOD PARK&quot;,<br>        &quot;address&quot;: &quot;2605  DOUBLE OAKS RD&quot;<br>      }<br>    }<br>  ]<br>}</pre><p>Miscellaneous: Bounding Box</p><p>A GeoJSON object might also contain a bounding box that defines the bounding range for the GeoJSON object. For example, in a 2-dimensional geometry, a bounding box is simply a member with name “bbox” and an array of four numbers as values. These four values define the rectangle that contains the complete GeoJSON object.</p><pre>{<br>       &quot;type&quot;: &quot;FeatureCollection&quot;,<br>       &quot;bbox&quot;: [100.0, 0.0, 105.0, 1.0],<br>       &quot;features&quot;: [<br>       //...<br>       ]<br>}</pre><p>Cool! So now that you know the basics you need to master GeoJSON data, let’s take a look some of the tools that you can use to visualize the GeoJSON data.</p><p><strong>How to visualize GeoJSON data ?</strong></p><p>In this section, I will share some of the popular GUI based tools that you may use to quickly visualize the GeoJSON data. Tom MacWright has an exhaustive list of utilities that convert, process, and analyze GeoJSON data on his Github.</p><p><a href="https://github.com/tmcw/awesome-geojson">GitHub - tmcw/awesome-geojson: GeoJSON utilities that will make your life easier.</a></p><p>For a Python based environment such as a Jupyter Notebook, you might use a module like GeoPandas. Twilio has a nice little tutorial using Shaply and GeoPandas.</p><p><a href="https://www.twilio.com/blog/2017/08/geospatial-analysis-python-geojson-geopandas.html">Getting Started on Geospatial Analysis with Python, GeoJSON and GeoPandas</a></p><p><a href="https://google-developers.appspot.com/maps/documentation/utils/geojson/"><strong>Google Developers — GeoJSON appspot</strong></a></p><p>On this web app, you can plot geometric shapes directly on Google Maps and visualize the GeoJSON code side-by-side in two panes. This visualization is really helpful to understand GeoJSON concept. You may also download .geojson file in a single click.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SY365W5fSYXqd4hU8WmkdQ.png" /></figure><p><a href="http://geojson.io"><strong>geojson.io</strong></a></p><p><a href="http://geojson.io/">geojson.io</a> is a web-based editor where you can import and export GeoJSON data. It also shows you GeoJSON code and visual output in side-by-side panes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GFO0xNv31cpeJEuA-8qMjg.png" /></figure><p><a href="https://qgis.org/en/site/"><strong>QGIS</strong></a></p><p>QGIS is a free, open-source cross-platform software for viewing, editing, and analyzing geospatial data. GeoJSON format is supported by QGIS, along with plethora of other geospatial data standards. You can download and install latest QGIS software <a href="https://qgis.org/en/site/">from here</a>. As an example, I will use the crime incidents data of Nanaimo city of Canada. This data is <a href="https://www.nanaimo.ca/crimereporting/api/incidents.geojson">available here</a> in GeoJSON format.</p><ul><li>Open “QGIS Browser” on your computer and browse the .geojson file in the left pane. The right pane will show you a quick preview of the data points.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HNnxkwz72Qp77NoHiBLRnA.png" /></figure><ul><li>You may also view attributes by clicking on the Attributes tab next to Preview tab.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mXgdTz1VDEZobgfkorofKA.png" /></figure><p>In the next article, I will explain how to overlay the GeoJSON data on a raster data layer using QGIS Desktop. I will be using Spacenet satellite imagery dataset <a href="https://aws.amazon.com/public-datasets/spacenet/">available on AWS</a>.</p><p>I hope this article was helped you to better understand the GeoJSON standard. Thank you for your time! And I’ll see you in the next one! :)</p><p><strong>Edit:</strong> The follow up article with SpaceNet dataset is live. <a href="https://medium.com/@sumit.arora/getting-started-with-aws-spacenet-and-spacenet-dataset-visualization-basics-7ddd2e5809a2">In this article</a>, you will learn about the high resolution satellite imagery made available in SpaceNet and how to access and visualize it.</p><p><a href="https://medium.com/@sumit.arora/getting-started-with-aws-spacenet-and-spacenet-dataset-visualization-basics-7ddd2e5809a2">Getting Started with SpaceNet data</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3432039e336d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to make a Chrome browser extension from scratch | Understanding extension architecture]]></title>
            <link>https://medium.com/front-end-weekly/how-to-make-a-chrome-browser-extension-from-scratch-chrome-extension-development-basics-basic-ba1daee11123?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba1daee11123</guid>
            <category><![CDATA[jquery]]></category>
            <category><![CDATA[university-of-chicago]]></category>
            <category><![CDATA[google-chrome]]></category>
            <category><![CDATA[chrome-extension]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Wed, 31 Jan 2018 06:03:43 GMT</pubDate>
            <atom:updated>2018-02-09T19:18:15.236Z</atom:updated>
            <content:encoded><![CDATA[<h3>How to make a Chrome browser extension from scratch | Understanding Chrome extension anatomy</h3><p>As a student at the University of Chicago, I regularly use the university’s <a href="https://canvas.uchicago.edu/">Canvas portal</a> to access class materials. However, this portal, along with a few uChicago portals require the user to take some unnecessary navigational steps to download files. So, I decided to make a Chrome extension that allows the user to download all the course material in a single click, right from the course page, without having to go to each module and then click each file link separately.</p><p>To do this, I designed my extension in such a way that it will scrape the current page and all the linked webpages to fetch a list of available downloads links. And then display the module-wise download buttons to the end-user, to enable bulk downloading of all the files with a single click. In this post, I will share the learning from making my first Chrome extension.</p><p><strong>Building blocks of a Chrome browser extension</strong></p><p>To create a Chrome extension, you need to have following components:</p><ol><li>manifest.json file</li><li>Popup page</li><li>Content script</li><li>Events page</li></ol><p>Let’s discuss each of the component one-by-one.</p><p><strong>Create Manifest.json</strong></p><p>This file is basically some metadata in json format that contains basic properties about our extension, such as extension’s name, description, version number etc. For more information about manifest file, read Google’s <a href="https://developer.chrome.com/extensions/manifest">Manifest File Format documentation</a>.</p><p>At a bare minimum, our extension needs below content:</p><pre>{<br> “manifest_version”: 2,<br> “name”: “UC Grabber”,<br> “version”: “0.1”<br>}</pre><p>manifest_version has to be 2. Since manifest version 1 has been deprecated in Chrome 18. (<a href="https://developer.chrome.com/extensions/manifestVersion">read more here</a>)</p><p>Let’s add a bit more jazz in our manifest by supplying a plain description, an icon and a popup window that will open when user click on the extension icon.</p><pre>{<br>  &quot;manifest_version&quot;: 2,<br>  &quot;name&quot;: &quot;UC Grabber&quot;,<br>  &quot;version&quot;: &quot;0.1&quot;,<br>  <br>  &quot;browser_action&quot;: {<br>    &quot;default_icon&quot;: &quot;images/icon.png&quot;,<br>    &quot;default_popup&quot;: &quot;html/popup.html&quot;,<br>    &quot;default_title&quot;: &quot;Grabber for uChicago Canvas!&quot;<br>  }<br>}</pre><ul><li>As a good practice, we will keep images, scripts and html files in their respective directories and refer to them with a relative URL.</li><li>icon.png will be a 19-px square PNG file. Use any file that you want to be used as the icon for your extension.</li><li>popup.html: Simple html file whose content will be populated inside the small window that pops-up when a user clicks on the extension icon.</li></ul><p>Let’s create a sample ‘popup.html’ file with just ‘Hello world!’ inside it and test our extension. To test the extension in chrome, click the hamburger menu, go to More tools -&gt; Extensions. Enable “Developer mode” on the top-right and click “Load Unpacked Extension” button, now browse to the main directory where manifest.json is located, click ok.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/373/1*sR4TR2Khj73kEzED4_Al5w.png" /></figure><p>and Voila! our cute little extension is up and running.</p><p><strong>Create Content script</strong></p><p>As our script needs to access content inside the webpage loaded by user, it needs a content script. This script will be equivalent to a JavaScript file that is loaded by the browser as part of the webpage. You could read more about content scripts <a href="https://developer.chrome.com/extensions/content_scripts">here</a>.</p><p>For our purpose, our content script will check the webpage to see if the URL of the current page belongs to our target website, which happens to be Canvas portal URL in this case. If it is Canvas URL, content script will fetch downloadable links from the webpage and pass it onto the popup.html page so that user can be shown the options to download the desired files.</p><p>Note: Content script can’t directly modify the content of it’s parent extension, but we can always pass the desired download content to the parent extension.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/256/0*xXZlCFkaegX6RR8P.gif" /><figcaption>Popup reads events only when it is active, hence message passing from content script is not feasible</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/238/0*sT9zZ6dggV9B0MOz.gif" /><figcaption>So, we make the content script talk to the background(events) page, which in turns saves all the information for popup page</figcaption></figure><p>We will connect the content script with the manifest file. By passing in the “matches” key, we ensure that we call our content.js script only when the URL matches</p><pre>{<br> “manifest_version”: 2,<br> “name”: “UC Grabber”,<br> “version”: “0.1”,<br> <br> “permissions”: [<br> “activeTab”<br> ],<br> <br> “browser_action”: {<br> “default_icon”: “images/icon.png”,<br> “default_popup”: “html/popup.html”,<br> “default_title”: “Grabber for uChicago Canvas!”<br> },<br> <br> “content_scripts”: [<br> {<br>    &quot;matches&quot;: [<br>  &quot;*://canvas.uchicago.edu/*&quot;<br>    ],<br>    &quot;js&quot;: [&quot;scripts/content_canvas.js&quot;]<br>  }<br>]<br>}</pre><p>In our project, content script will scrape the webpage and fetches the desired URLs. The exact scraping expression will depend upon the webpage that you want to scrape, and how the desired url is nested among html tags.</p><p>Of course, you can you any of your favorite JavaScript library to make your content scripts more efficient. As an added feature, I made my extension to be able to insert download buttons in the webpage itself. So, I used jQuery to manipulate DOM based on my needs.</p><p><strong>Create Event Page</strong></p><p>Event pages are the single long-running scripts used to manage certain tasks and states. Chrome supports and recommends using event pages since Chrome 22. Event pages carry advantage over background pages that they are unloaded when they are not active, hence consuming lesser memory. This performance optimization becomes significant, especially on low-power devices.</p><p>Event pages will get loaded in below situations:</p><ol><li>Extension is first installed or is updated to a new version.</li><li>An event is dispatched.</li><li>Content script sends a message.</li><li>Popup view calls background page.</li></ol><p><strong>Why do we need events script ?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/342/1*vunqNEBobvN8I-KurxZj0Q.png" /><figcaption>Overview of scripts</figcaption></figure><p>In our extension, the content script scrapes the webpages and creates a JavaScript object of the download file titles and download links. This JavaScript object is sent to the popup which is supposed to show the download buttons to the end-user. But there is one problem! The popup page can only listen to the content script only if the popup window is open. And as you can imagine, the end-user might not want to keep waiting for the result with popup window open all the time (Note: popup window gets closed when user switches to another tab). So, we need an intermediary script between content and popup, and the events script does just that.</p><p>In our extension, the events page will temporarily save the download information scraped by content script in a local JavaScript object that neatly stores download information returned by each tab organized by respective tab id. So that when popup view is opened, it asks for scraping status of the content script to the events script. If the scraping is done, the events script simply checks the tab id for the tab for which popup window is requesting scraping status and simply returns the stored information to popup. Similarly, if scraping is ongoing, the events script has to maintain status for the respective tab so that end-user can be shown some wait-screen animation, such as one in the next section.</p><p><strong>Create Popup Page</strong></p><p>The popup window is the “front-end” of your extension. This is the interface that the user sees and interacts with. Simply put, a popup window is just an HTML file that is displayed each time end-user clicks on the icon of your extension. In our project, this popup window gets the start scraping request from user, shows the available download options to the user, and communicates with the events page to fetch scraping status and results. Also, to make your extension appealing, you can also add certain animations in terms of loading, waiting, results etc. For example, in my extension, user sees below gif file as waiting screen, when the scraping is ongoing at the content script.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fi.imgur.com%2FyC3NiwO.mp4&amp;src_secure=1&amp;url=https%3A%2F%2Fi.imgur.com%2FyC3NiwO.gifv&amp;image=https%3A%2F%2Fi.imgur.com%2FyC3NiwO.gif%3Fnoredirect&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=video%2Fmp4&amp;schema=imgur" width="392" height="422" frameborder="0" scrolling="no"><a href="https://medium.com/media/574627e2c8796b42a475c3afff1c4f91/href">https://medium.com/media/574627e2c8796b42a475c3afff1c4f91/href</a></iframe><p>Note that this animation is actually a gif file, that can be stored as part of your extension, or you could also render an image hosted elsewhere on the internet.</p><p>And by utilizing the “matches” parameter of the manifest file. We can also show some attractive screen to the user for the websites that are not supported by the extension.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fi.imgur.com%2Fa98loeO.mp4&amp;src_secure=1&amp;url=https%3A%2F%2Fi.imgur.com%2Fa98loeO.gifv&amp;image=https%3A%2F%2Fi.imgur.com%2Fa98loeO.gif%3Fnoredirect&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=video%2Fmp4&amp;schema=imgur" width="398" height="429" frameborder="0" scrolling="no"><a href="https://medium.com/media/16a3972c86a03b426a52c72896069153/href">https://medium.com/media/16a3972c86a03b426a52c72896069153/href</a></iframe><p>With that we have the knowledge of all the necessary concepts required to build a Chrome Browser Extension. When you are done with unit testing, you can publish your extension using the <a href="https://chrome.google.com/webstore/developer/dashboard">Official Chrome Developer Dashboard</a>. To activate the developer account, you need to pay a one-time activate fee of 5$. This should set you up for publishing up to 20 extensions on Google Chrome Web Store.</p><p>The extension that I made is available <a href="https://chrome.google.com/webstore/detail/uc-grabber/dimmeocemhglaadjicpnogdadmkkgpln">here on Google Chrome Web Store</a>. The complete source code is available on <a href="https://github.com/sumit-code/uchicago-canvas-file-grabber">the project repository on my GitHub</a>. You can also check out the extension in action on this post.</p><p>With that, I hope I could inspire you to start working on a project of your own. Thank you for reading this post! And I will see you in the next one! :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba1daee11123" width="1" height="1" alt=""><hr><p><a href="https://medium.com/front-end-weekly/how-to-make-a-chrome-browser-extension-from-scratch-chrome-extension-development-basics-basic-ba1daee11123">How to make a Chrome browser extension from scratch | Understanding extension architecture</a> was originally published in <a href="https://medium.com/front-end-weekly">Frontend Weekly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[UC Grabber! A simple tool to batch download files from Canvas/ilykei]]></title>
            <link>https://sumit-arora.medium.com/uc-grabber-a-simple-tool-to-batch-download-files-from-canvas-ilykei-496f81f82621?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/496f81f82621</guid>
            <category><![CDATA[university-of-chicago]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[software-projects]]></category>
            <category><![CDATA[chrome-extension]]></category>
            <category><![CDATA[canvas]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Thu, 25 Jan 2018 17:05:52 GMT</pubDate>
            <atom:updated>2018-02-24T06:20:15.913Z</atom:updated>
            <content:encoded><![CDATA[<p>Dear Fellow UoC Student,</p><p>Hope you’re doing well!</p><p>I just want to share a software that I wrote in last few days, to automate some routine and mundane tasks. I think it might be useful for all of us who use Canvas and/or <a href="http://ilykei.com/">ilykei.com</a> portal.</p><p><strong>The Problem</strong></p><p>The problem that I wanted to solve was very simple, both of these websites require students to take some unnecessary steps to download files. For example, to download the lecture materials for a certain week’s module, one has to click on each link and open all the files in their respective tabs and then click the download link for each file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sNTy1BKnQ0_Kd0T0ubTi7w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ve7XMuClKUAA8EGm7jsOQQ.png" /></figure><p>Similarly, for <a href="http://ilykei.com/">ilykei.com</a>, a user has to go through each link to download course material.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yzPclDfB_0osKM26FT2R0A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IBo4E1_EFJ0V4bn447CJGg.png" /></figure><p>Also, as per the default behavior, single click on .html workshop documents opens them in a new tab. And also, the downloaded files retain the ASCII URL encoding characters.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/483/1*c4UvQcEwnNoOEJ_Vj0qdUw.png" /><figcaption>The file that I downloaded in above screenshot, was downloaded with name “<em>documents%2FMScA Linear and Non-Linear Models 31010%2FMScA 31010 Lecture 3%2FWeek3_Homework_Project_Data.csv</em>”, while the corresponding name for the file in demo is “<em>Week3_Homework_Project_Data.csv</em>”</figcaption></figure><p>So, to be able to easily download content from Canvas and/or <a href="http://ilykei.com/">ilykei.com</a>, I developed an application that can be installed in our browser. Its purpose is to provide easy, one-click workarounds to the above problems that I mentioned. This application can be installed as a chrome extension from the official Google Chrome Web Store.</p><p><strong>How to use this extension?</strong></p><p>Say for example, if I want to download the course material for Data Mining class, I would go the data mining module page on Canvas, and then click on the extension icon next to the address bar, then click the Process button.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cDvbOUK0TEssHdUrZs0Xrw.png" /></figure><p>Parsing might take a few seconds, depending upon the number of modules/files on the page.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/647/1*RP6U_uqKuyck2NgrGWFTDg.png" /></figure><p>In a few seconds, you should be able to see a list of buttons, clicking on a button would download all the available files for the corresponding module. The downloads are organized in directories named according to the module.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*8GTdE9BNJaz3ghgrkBG0Aw.png" /></figure><p>Here are the complete steps:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/508/1*sjqDg_aG0XsCEFk7euw_5A.gif" /></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fi.imgur.com%2FbcXcakx.mp4&amp;src_secure=1&amp;url=https%3A%2F%2Fi.imgur.com%2FbcXcakx.gifv&amp;image=https%3A%2F%2Fi.imgur.com%2FbcXcakx.gif%3Fnoredirect&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=video%2Fmp4&amp;schema=imgur" width="1898" height="986" frameborder="0" scrolling="no"><a href="https://medium.com/media/22b79dc0d1fd1b128fee81e47d571b96/href">https://medium.com/media/22b79dc0d1fd1b128fee81e47d571b96/href</a></iframe><p><strong>On </strong><a href="http://ilykei.com/"><strong>ilykei.com</strong></a>, if you navigate to a lecture page and click on the Process button, the extension will put two download links on the lecture page itself.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aNxuoVn2fQBe1_KSUDS04A.png" /><figcaption>Before</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PhwAqeoz1wJGaILyEjTlWQ.png" /><figcaption>After</figcaption></figure><p>Clicking on the first link would download all the documents in the lecture material. And clicking on the second link would download all the documents in the sidebar. See this in action below:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fi.imgur.com%2FT3pb7qD.mp4&amp;src_secure=1&amp;url=https%3A%2F%2Fi.imgur.com%2FT3pb7qD.gifv&amp;image=https%3A%2F%2Fi.imgur.com%2FT3pb7qD.gif%3Fnoredirect&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=video%2Fmp4&amp;schema=imgur" width="1898" height="986" frameborder="0" scrolling="no"><a href="https://medium.com/media/c2ad0e66321687be008f6038dcbb46f8/href">https://medium.com/media/c2ad0e66321687be008f6038dcbb46f8/href</a></iframe><p><strong>Link?/How to install this extension?</strong></p><p>1. Make sure you are using Google Chrome</p><p>2. Go to this URL: <a href="https://chrome.google.com/webstore/detail/uc-grabber/dimmeocemhglaadjicpnogdadmkkgpln">https://chrome.google.com/webstore/detail/uc-grabber/dimmeocemhglaadjicpnogdadmkkgpln</a></p><p>3. Click “Add To Chrome”</p><p>4. You’re set! :)</p><p><strong>Tl;dr?</strong></p><p>Download this extension <a href="https://chrome.google.com/webstore/detail/uc-grabber/dimmeocemhglaadjicpnogdadmkkgpln">https://chrome.google.com/webstore/detail/uc-grabber/dimmeocemhglaadjicpnogdadmkkgpln</a>. It makes it easy to batch download documents from Canvas/ilykei.com</p><p>The complete code for this project is available on my GitHub. I tried my best to handle all the possible corner cases, but if you still find a bug, please let me know. And I would appreciate if you also let your uChicago friends know about this extension.</p><p>Thank you. And I hope this extension is helpful for you! :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=496f81f82621" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Training a neural network using Mobilenets in TensorFlow for image classification on Android]]></title>
            <link>https://sumit-arora.medium.com/training-a-neural-network-using-mobilenets-in-tensorflow-for-image-classification-on-android-14f2792f64c1?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/14f2792f64c1</guid>
            <category><![CDATA[tensorflow]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[transfer-learning]]></category>
            <category><![CDATA[deep-learning]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Sat, 20 Jan 2018 06:56:20 GMT</pubDate>
            <atom:updated>2018-06-24T21:37:32.461Z</atom:updated>
            <content:encoded><![CDATA[<p>First, a few definitions for the uninitiated.</p><p><strong>TensorFlow</strong> is an open-source library for numeric computation using dataflow graphs. It was developed by Google brain team as a proprietary machine learning system based on deep learning neural networks. TensorFlow is causing quite a stir in research and development field and is set very to make its way into mainstream machine learning.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/352/0*f3TEfKbvCKRV-CkY.png" /><figcaption><a href="https://www.tensorflow.org/">About TensorFlow</a></figcaption></figure><p>In this tutorial, we are going to make an Android app that uses a neural network trained by TensorFlow. For our purpose, we will use a special class of convolutional neural networks called MobileNets. As also suggested by the name, the special thing about the MobileNets is that they are “mobile-friendly”, meaning that they are optimized to be executed using minimal possible computing power on a smartphone device.</p><p>As you can imagine, there has to be a catch with something so customized for a minimal resource footprint. MobileNets do not provide as good of an accurate model as produced by a full-fledged deep neural network. However, the accuracy is surprisingly very high and good enough for many applications. Below graph shows the graph of accuracy versus the number of calculations required for a choice of neural network libraries. Model size is shown as the size of circle, and different model size of the MobileNets show the tradeoffs assumed during selection of model parameters. See <a href="https://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html">this Google research blog post</a> for more details. We will also come back to the choice of model parameters later.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/712/0*tNq38yBWJ2t6-2v2.png" /><figcaption>Accuracy (y-axis) vs. the number of required operations (x-axis) for available configurations</figcaption></figure><p><strong>Data collection</strong></p><p>The image classifier that we are going to train in this example will be able to classify cars to their respective model. We are going to use “<a href="http://ai.stanford.edu/~jkrause/cars/car_dataset.html">Cars Dataset</a>“ made available by Stanford. [<a href="http://imagenet.stanford.edu/internal/car196/car_ims.tgz">Link to dataset</a> ~ 1.8GB]</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LNPKOc23HOFMUDr3qNlFoQ.jpeg" /></figure><p>This dataset consists of 16,185 images of 196 classes of cars. The label information for this dataset provides make, model and year for each of the 196 classes. The data is also available as separate train and test sets in a 50–50 split. But for this project, we will download the full dataset of 16,185 images, along with the label information.</p><p><strong>Data Preprocessing</strong></p><p>The image dataset from the Stanford is organized as a single directory containing 16,185 images of cars. To use these images for our training step, we need to reorganize these images so that each car image is inside a directory that contains all the images for a single class. Also, the name of the directory should reflect the name of the corresponding class. We will use the label information available in the .mat file provided by Stanford. Below Python script performs this task.</p><p>Edit: As correctly pointed out by a reader, I missed specifying that the name for class 174, i.e. ‘Ram C/V Cargo Van Minivan 2012’ has a forward slash, ‘/’, in it and it should be renamed to remove the slash character.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/006adfd50a359760ee38ed69af4e825a/href">https://medium.com/media/006adfd50a359760ee38ed69af4e825a/href</a></iframe><p><strong>Training the classifier</strong></p><p>For training our image classifier, we are going to use the transfer learning concept. Transfer learning basically refers to a supervised learning technique that takes advantage of an already existing trained model that solves a similar problem. For our purpose, we will take TensorFlow’s fully trained model for Imagenet and retrain just the last layer of the neural network on our Cars dataset. Though this approach is not as powerful as a fully trained model, but it can provide a surprisingly high accuracy for most tasks that are related. You can read more about this concept from this article:</p><p><a href="https://www.tensorflow.org/tutorials/image_retraining">How to Retrain an Image Classifier for New Categories | TensorFlow</a></p><p>As mentioned in the above article, you can clone the retrain scripts from <a href="https://github.com/tensorflow/hub/tree/master/examples/image_retraining">this GitHub repository</a>.</p><p>As we are only training the final layer of the neural network, the training will end in reasonable amount of time. TensorFlow’s retraining procedure allows you to optimize the training procedure by tweaking certain parameters. Following two are probably the most important of those parameters:</p><ol><li>Input image resolution: The corresponding value can be 128,160,192, or 224px. As you can imagine training with a higher resolution image will take longer time, but also has higher chances of providing a better classification accuracy. Since, we are only training final layer and our dataset is not very huge, we will keep this value as 224.</li><li>Relative model size: This value represents the relative size of the model as a fraction of the largest MobileNet. It can take value such as 1.0, 0.75, 0.50, or 0.25. The larger the size of the model, more accurate it will be. For our purpose, we will keep this value to 0.75.</li></ol><p>Both the above parameters can be configured as environment variables as:</p><pre>IMAGE_SIZE=224<br>ARCHITECTURE=&quot;mobilenet_0.75_${IMAGE_SIZE}&quot;</pre><p>With these parameters setup, let’s run the retrain python script provided by TensorFlow with following parameters.</p><pre>python -m scripts.retrain <br> — bottleneck_dir=tf_files/bottlenecks <br> — how_many_training_steps=5000 <br> — model_dir=tf_files/models/”${ARCHITECTURE}” <br> — summaries_dir=tf_files/training_summaries/”${ARCHITECTURE}” <br> — output_graph=tf_files/retrained_graph.pb <br> — output_labels=tf_files/retrained_labels.txt <br> — architecture=”${ARCHITECTURE}” <br> — image_dir=tf_files/dataset</pre><p>Above command sets up directory paths for bottleneck, model and summary files. image_dir refers to the directory where our image image data is stored. output_graph and output_labels provides the path where we will store our training model and label information respectively.</p><p>Parameter how_many_training_steps is the count of how many times retraining iterates over the data. By default it is set to reiterate 500 times. If you have time, you could increase this iteration count to achieve better results.</p><p>There are still a lot more configuration options that the retraining script provides. Run the below command help command to read more about the available options.</p><pre>python -m scripts.retrain -h</pre><p>If the final size of your trained model is large, you could look into some of the techniques that can reduces the model size, such as making the model compressible and to quantize the network weights. Refer to below article to read more on this.</p><p><a href="https://www.tensorflow.org/performance/quantization">How to Quantize Neural Networks with TensorFlow | TensorFlow</a></p><p><strong>Deploying the solution in Android app</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/128/0*sJZsufM_vpDJmBrJ.png" /></figure><p>TensorFlow GitHub repository contains <a href="https://github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android">an Android project</a> that you can directly load into your Android studio and compile directly to create an image classifier application. Simply copy the trained model(graph.pb) and label information(labels.txt) that we generated in the last step, to the project’s “assets” directory And run the Gradle build. This will generate a .apk file that you can run on your computer in a emulator with camera access, or you can deploy it on an Android phone.</p><p><strong>Result</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/828/1*L4RWpqRZtEcrI84CBK-sGw.jpeg" /><figcaption><a href="https://play.google.com/store/apps/details?id=com.reachsumit.whichcaristhat">Android app in action</a></figcaption></figure><p>The resulting Android app uses the phone’s camera stream to classify objects into the identified class. The application by default also provides probability value of a car belonging to the corresponding category. You could take a look at the <a href="https://play.google.com/store/apps/details?id=com.reachsumit.whichcaristhat">Android application that I published on Google Play store</a> to see this project in action.</p><p><a href="https://play.google.com/store/apps/details?id=com.reachsumit.whichcaristhat">Which Car Is That ? - Android Apps on Google Play</a></p><p>As you can see transfer learning with TensorFlow makes it easy to quickly build our own classifiers. I hope you liked this article, and I’ll see you in the next one. :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=14f2792f64c1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Plotting Population Weighted Mean Centroids on a Country Map]]></title>
            <link>https://sumit-arora.medium.com/plotting-weighted-mean-population-centroids-on-a-country-map-22da408c1397?source=rss-93b61e3f97aa------2</link>
            <guid isPermaLink="false">https://medium.com/p/22da408c1397</guid>
            <category><![CDATA[mini-projects]]></category>
            <category><![CDATA[data-science]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[data-analytics]]></category>
            <category><![CDATA[weighted-mean]]></category>
            <dc:creator><![CDATA[Sumit Kumar Arora]]></dc:creator>
            <pubDate>Wed, 20 Dec 2017 07:28:15 GMT</pubDate>
            <atom:updated>2023-11-27T07:50:15.898Z</atom:updated>
            <content:encoded><![CDATA[<p>A few days ago, a reddit user posted a beautiful visualization for Mean Centers of U.S. population by state on /r/MapPorn subreddit.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hU3J73baFXc_ogL-rjhCTA.png" /><figcaption><a href="https://www.reddit.com/r/MapPorn/7k1m6e/">Source: /r/MapPorn Reddit post</a></figcaption></figure><p>Pretty neat, right ? This map conveys the point across and also maintains an appeasing simplicity. This inspired me to create a similar population map for my motherland, India.</p><p>But what I imagined to be a straightforward task, turned into something really complicated. While the original creator of the above reddit post was able to get the desired data in nicely arranged format from the <a href="https://www.census.gov/geo/reference/centersofpop/state_cenpop_year.html">US Census Bureau website</a>, similar information wasn’t readily available for India. So, I set out to create my map from scratch, And I would like to share that experience with you. :)</p><h3>Step 1: Set the Goals</h3><ul><li>I decided that I would plot comparison of state-wise population for last 2 years for which census was conducted in India (2001 and 2011).</li><li>My preferred choice of programming language is Python. So I need to work out a solution that is Python based.</li><li>For plotting the output, one way in Python could be to create a <a href="https://plot.ly/python/choropleth-maps/">choropleth map using Plot.ly</a>. But unfortunately, Plot.ly does not support India for plotting country level choropleth maps. So, I decided to use Tableau for plotting the output on a map.</li></ul><h3>plotly on Twitter</h3><p>@DHagan7 Right, not in India. Ssetting up CDN to load topojson. That will let us do state-level globally. You could draw your own lines.</p><h3>Step 2: Defining Process</h3><p>To create the target map I need the followings:</p><ol><li>Find a way to map each district in India as a polygon. The borders of the polygon would be the 2-D points (latitude, longitude). Of course, there would be multiple districts in a single state.</li><li>Find out the mean center for each district that constitutes a state. “Mean” center simply signifies a point inside district on which the district map would balance perfectly.</li><li>Assign a weight to each district centroid. This weight value is essentially the population of that district. I might need to (web) scrape this population data from some website.</li><li>For all of the weighted [longitude, latitude] 2-D point inside a state, find one weighted mean centroid that would represent a state in the final map. “Weighted” mean is required because I need to take into account that different districts would have a different population and a weighted mean centroid would be a true depiction of the population center.</li><li>Plot each state on a map using Tableau. Each state would display two points, one centroid each for 2 census years (2001 vs 2011).</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*y-v_XXBoGRq3Grhc8bVWTA.jpeg" /><figcaption><a href="https://support.esri.com/en/other-resources/gis-dictionary/term/weighted%20mean%20center">Definition of weighted mean from ESRI</a></figcaption></figure><h3>Step 3: Implement the plan</h3><p>Let’s go step-by-step through the implementation procedure:</p><p><strong>Draw Polygons</strong></p><p>After searching a bit, I found an excellent source of district-wise longitude, latitude coordinates for India. Tableau user <a href="https://community.tableau.com/people/indumon">Indumon</a> was kind enough to share a csv file with enough information to plot Indian districts as polygons. You can download the csv file from <a href="https://www.kaggle.com/datasets/sirpunch/district-level-longitude-latitude-for-india">this link</a>.</p><p>Here’s a snippet of this csv file:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/899/1*NMmiuHkEECGEyPwdDgxo4g.png" /><figcaption>output from head() call on a Pandas dataframe</figcaption></figure><p>And here’s what the polygons look like on a Tableau map:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AtdiA7yDWs6a_yYk4ZcZlQ.png" /><figcaption>Indian districts mapped as polygons</figcaption></figure><p><strong>Calculate Mean Centroids</strong></p><p>As you would imagine, there are multiple rows for one district in the above csv file, forming the borders for the districts (polygons). I used <a href="https://pypi.python.org/pypi/Shapely">shapely Python library</a> to calculate the mean centroids.</p><blockquote>Shapely is a BSD-licensed Python package for manipulation and analysis of planar geometric objects. (<a href="https://github.com/Toblerity/Shapely">shapely GitHub</a>)</blockquote><p>As also explained in the <a href="https://toblerity.org/shapely/manual.html#object.centroid">shapely documentation</a>, it is not guaranteed that the mean center of a polygon would always lie inside the polygon. Imagine a state shaped as English letter ‘L’ or ‘C’ in this case the mean of the coordinates might not lie inside the polygon. But even though shapely does provide a “cheat” method to get a point inside the polygon, I didn’t require it as my initial runs showed that none of the Indian provinces were highly twisted in shape.</p><p>To calculate the mean center, I imported the csv data inside a Pandas dataframe and calculated center mean for each of the districts. Below is the code that I used for this task. The code is pretty much self-explanatory.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e1661b50ce658e2df9f2062431f16de4/href">https://medium.com/media/e1661b50ce658e2df9f2062431f16de4/href</a></iframe><p>The output from this step is exported to a csv file. Below is a brief snippet of the output saved in csv file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/529/1*F4TsbQUlbJKBNHiWr3bbLg.png" /><figcaption>centroid output for each district</figcaption></figure><p>Here’s how centroids look like on a Tableau map:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*viLwWvgk0PWIafUQSzLBqQ.png" /><figcaption>mapping centroids for each district</figcaption></figure><p><strong>Scrape the population data</strong></p><p>After hours of trudging through the sluggish <a href="http://censusindia.gov.in/">Indian Census Library</a>, I came across <a href="http://www.citypopulation.de/India.html">City Population</a> website, that neatly displays census data for each district in India, for last 3 decennial Censuses of India. However, this information is available on separate webpages, so next step was to write a simple scraper to get this data into a nicely formatted csv file.</p><p>Below code shows the scraping steps and saves the scraped data into a csv file.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/10a7722a7bd3fcab58390a417ebe171c/href">https://medium.com/media/10a7722a7bd3fcab58390a417ebe171c/href</a></iframe><p>As you can see from the code above, the nifty Pandas ability to read tables directly from webpages is very handy, especially for such small tasks. Here is a brief look at the contents of the saved csv file:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/754/1*NUonN8-yQiqs02eYsUM4RA.png" /><figcaption>district-wise population data</figcaption></figure><p><strong>Merge the data</strong></p><p>At this stage, we have geospatial data for each district in one csv file, and population data for them in a separate csv file. Naturally, the next step would be to combine them. Note that one important reason for having two csv files is to deal with the fact that our geospatial misses a few districts(yes, I counted). So, it is a good option to have our location and population data in separate tables and then perform a join operation on the two, to get the clean merged table of data. The Python code below does it by performing a merge operation on the two dataframes that we have established from above examples.</p><pre># merge data<br>merged_df = pd.merge(df,population_df,on=[&#39;District&#39;,&#39;State&#39;],how=&#39;left&#39;)<br>#save merged data<br>merged_df.to_csv(&#39;merged.csv&#39;,index=False)<br># drop null-valued rows (not recommended, see below)<br>merged_df.dropna(axis=0,how=&#39;any&#39;).to_csv(&#39;merged_withoutNA.csv&#39;,index=False)</pre><p>In the above code, we performed a merge operation with District and State as key columns. Unfortunately, there are some rows with null values in the above code. This is because the website, that we used to scrape population data, has slightly different naming conventions for a few states and cities (for example, our location data has state name “Jammu and Kashmir” while the population data has “Jammu &amp; Kashmir”, and so on for a few districts). One could write a simple fuzzy match to handle this siutation, but considering that only a few rows had the missing data values, I manually filled out the corresponding population data by reading the numbers from the City Population website.</p><p><strong>Calculate Weighted Mean Center</strong></p><p>In the previous step, we have effectively assigned weights(population data) to each district centroid. Next step is to calculate the center of population density for each state based on the weighted averages.</p><p>First, I considered using <a href="https://pro.arcgis.com/en/pro-app/">ArcGis Pro</a>’s <a href="http://pro.arcgis.com/en/pro-app/tool-reference/spatial-statistics/mean-center.htm">MeanCenter_stats</a> functionality for this purpose. ArcGis has a powerful set of tools for analyzing geospatial data, along with a very useful Python driver <a href="http://pro.arcgis.com/en/pro-app/arcpy/get-started/what-is-arcpy-.htm">arcpy</a>. However, upon diving down into the <a href="http://resources.esri.com/help/9.3/arcgisengine/java/gp_toolref/spatial_statistics_tools/how_mean_center_spatial_statistics_works.htm">ESRI documentations</a>, I realized that the mean center implementation technique was pretty straightforward. So, I decided to write my own code to calculate the weighted means, based on below formula.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/599/0*A32RmYe2Y1HlUpOd.png" /><figcaption>read more about the formula <a href="http://webspace.ship.edu/pgmarr/Geo441/Examples/Mean%20and%20Weighted%20Mean%20Centers.pdf">here</a></figcaption></figure><p>Below is the Python implementation to generate the desired weighted means.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3edb96d5320087af3be577c3b0d1451d/href">https://medium.com/media/3edb96d5320087af3be577c3b0d1451d/href</a></iframe><p>Repeat the above process for 2011 population data, and we have all the weighted centered means along with the year-wise population data.</p><p><strong>Step 4: (Profit?) Plot the Results</strong></p><p>Phew! Now that we have all the information we need, the only thing left is to plot the results in tableau to see the state-wise population density trends. And here’s how the output looks like on a Tableau dashboard:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*f50rwoMlTzi7MlXqumvfGg.png" /><figcaption>Mean centers of population by state, 2001 vs. 2011</figcaption></figure><p>Well, the results are not quite what I was expecting. There has been very little population density movement between the last two decennial Censuses of India. I reckon a city-level density plot, instead of a district-level map might exhibit more interesting movement. But it was a fun little project and I got to learn many new things out of it.</p><p>I hope you too learned something new from reading this post. And I hope I could inspire you to work on some mini-project (the way the original reddit post inspired me). Thank you for taking time to read this. Till next time. :)</p><p>Edit:<br>I was requested to plot national center of population density for the data I have. Here’s the output on Tableau:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*WI5x24gWg6tlFAxgnBQe0A.png" /><figcaption>National center of population</figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=22da408c1397" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>