<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Langly.org</title>
    <link>https://langly.org/blog/</link>
    <description>Recent content on Langly.org</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 11 Jun 2025 21:42:31 -0700</lastBuildDate><atom:link href="https://langly.org/blog/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Xor Swap</title>
      <link>https://langly.org/blog/posts/xor/</link>
      <pubDate>Wed, 11 Jun 2025 21:42:31 -0700</pubDate>
      
      <guid>https://langly.org/blog/posts/xor/</guid>
      <description>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Recently I came over this old school xor swap trick. It&amp;rsquo;s a trick that impressed me when I was a young coder and one of my friends first showed it to me. As I&amp;rsquo;ve grown older and with more understanding of computer architecture I use this trick as an example of how more complex solution does not really imply better. And in the fact of the XOR swap trick it is one of the things that makes you feel good over a tricky implementation, but will hurt performance at the end of the day.&lt;/p&gt;</description>
      <content>&lt;h1 id=&#34;introduction&#34;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Recently I came over this old school xor swap trick. It&amp;rsquo;s a trick that impressed me when I was a young coder and one of my friends first showed it to me. As I&amp;rsquo;ve grown older and with more understanding of computer architecture I use this trick as an example of how more complex solution does not really imply better. And in the fact of the XOR swap trick it is one of the things that makes you feel good over a tricky implementation, but will hurt performance at the end of the day.&lt;/p&gt;
&lt;h1 id=&#34;swap&#34;&gt;Swap&lt;/h1&gt;
&lt;p&gt;So what is the XOR swap trick you might ask. Consider the following C code where you want to swap the variables A and B. You might want to write something akin to&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; A &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; B &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; tmp; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	tmp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; A; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	A &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; B; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	B &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; tmp;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then at some point in the past, somebody has the idea of reducing this down to using 2 registers instead of the 3 which are implied in the above program. I suspect this trick is a relic of an age long past when register usage was important. Hence they did the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; A &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; B &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	A &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; B &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt; A; &lt;span style=&#34;color:#75715e&#34;&gt;// B XOR A
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	B &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; A &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt; B; &lt;span style=&#34;color:#75715e&#34;&gt;// A XOR B
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	A &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; B &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt; A; &lt;span style=&#34;color:#75715e&#34;&gt;// B XOR A
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which in itself is a rather nifty little trick. I like the elegance of it.&lt;/p&gt;
&lt;h1 id=&#34;problem&#34;&gt;Problem&lt;/h1&gt;
&lt;p&gt;Now, what is the problem you might ask. And on the face of it, this looks innocently enough. However, for those that has studied computer architecture or compilers, you can see that the XOR swap method introduces a dependency on the results. If you look at the code itself, you can see that each line in the XOR swap code depends on the line above it. This alone prevents the computer / CPU to issue the instructions in parallel, and it has to wait for the result to return before it can issue the next instruction ( very simplified ). The CPU has also a bunch of move optimization tricks that is doing which makes the simple straight-forward implementation quite fast.&lt;/p&gt;
&lt;h1 id=&#34;benchmark&#34;&gt;Benchmark&lt;/h1&gt;
&lt;p&gt;Now, how much worse/better are the two different strategies. To test, I wrote two different pieces of code. Mind you, the code was written at the airport waiting for my delayed plane so might have bugs in it. It basically implements the code from above plus some tricks to make sure that the code does not get constant optimized away. I then did an &lt;code&gt;objdump -D&lt;/code&gt; ont the executable files to make sure no compiler tricks had been done. Finally, I timed the binaries over a  bunch of iterations ( 268435456 to be exact ). The experiments were run on a macbook pro with an Apple M2.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./mv 34 54  0.63s user 0.00s system 99% cpu 0.639 total
./xor 34 54  1.65s user 0.01s system 99% cpu 1.665 total
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, the xor implementation is 2.6 times slower than the naive mv implementation.&lt;/p&gt;
&lt;h1 id=&#34;conclusions&#34;&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;So, to sum it up. I think what I am trying to say that be careful with premature optimizations, and solutions that looks fancy. There are a lot of optimization tricks happening in the entire stack from your simple program to the gates on the CPU. At least try the straightforward implementation first, and if that does not work you can go tricky. Otherwise, you might up creating more problems than solving with the tricky solution.&lt;/p&gt;
&lt;h1 id=&#34;refs&#34;&gt;Refs&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/langly/xorSwap&#34;&gt;https://github.com/langly/xorSwap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </item>
    
    <item>
      <title>Dithering</title>
      <link>https://langly.org/blog/posts/dithering/</link>
      <pubDate>Fri, 29 Nov 2024 20:58:04 -0800</pubDate>
      
      <guid>https://langly.org/blog/posts/dithering/</guid>
      <description>&lt;h1 id=&#34;background&#34;&gt;Background&lt;/h1&gt;
&lt;p&gt;Some time ago, I got myself one of these black and white e-ink paper without any support for grayscale. I.e. per pixel on the e-ink, I could only have either black or white, and no scale between. This kind of worked fine for true type font rendering, but I also wanted to be able to output images. And for that I had to be creative.  &lt;img src=&#34;frame.png&#34; alt=&#34;Frame&#34;&gt;
Now, there were a lot of specific problems related to the actual version of the e-ink screen that I got, but this post in particular is not going to focus on those. They might be covered in a future post if I get around to it.  For now, this post is only going to cover dithering, and more specifically Floyd-Steinberg and algorithms derived from those.&lt;/p&gt;</description>
      <content>&lt;h1 id=&#34;background&#34;&gt;Background&lt;/h1&gt;
&lt;p&gt;Some time ago, I got myself one of these black and white e-ink paper without any support for grayscale. I.e. per pixel on the e-ink, I could only have either black or white, and no scale between. This kind of worked fine for true type font rendering, but I also wanted to be able to output images. And for that I had to be creative.  &lt;img src=&#34;frame.png&#34; alt=&#34;Frame&#34;&gt;
Now, there were a lot of specific problems related to the actual version of the e-ink screen that I got, but this post in particular is not going to focus on those. They might be covered in a future post if I get around to it.  For now, this post is only going to cover dithering, and more specifically Floyd-Steinberg and algorithms derived from those.&lt;/p&gt;
&lt;p&gt;It is assumed by the reader that some understanding of programming is had. For the examples and pseudo code, I will use C/++ and CImg. However, the concepts should be transferrable to your programming language of choice.&lt;/p&gt;
&lt;h1 id=&#34;problem&#34;&gt;Problem&lt;/h1&gt;
&lt;p&gt;Ok, so what is the problem that I am trying to solve?  For the frame I have, I can only display pixels being either black or white. I don&amp;rsquo;t have the full range of grey ( for small values of grey say 255 ) to select from. So somehow, I have to quantize the picture in such a way that it looks believable as a gray scale picture without actually being so.  The two first pictures shows the ideal. The first one in color shows the golden gate bridge in its full colors. The 2nd picture shows the &amp;ldquo;ideal&amp;rdquo; version of the bridge in gray scale. This is the experience we try to recreate.
&lt;img src=&#34;original-greyscale.png&#34; alt=&#34;Greyscale&#34;&gt;&lt;/p&gt;
&lt;p&gt;However, if we approach this in a simplistic manner, we can apply a simple thresholding algorithm. The thresholding algorithm would look like the following&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; each pixel in image {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	pixel_out &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;convert_grey&lt;/span&gt;(pixel) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; threshold &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Whereas simplistic, it does not lead to a good image quality. For the pictures below, I have chosen a threshold value of .25, .5 and .75.
&lt;img src=&#34;thresholding.png&#34; alt=&#34;Threshold&#34;&gt;
As you can see here, the black and white pictures lacks quite a lot of details. And they for certain does not look good. There exists possibilities of tweaking the threshold value for each picture until you find something that looks good. However, that is not going to be sustainable.&lt;/p&gt;
&lt;p&gt;Instead we are going to introduce the concept of dithering. In short, for image processing, dithering is the act of introducing noise into the image to avoid artifacts of the quantization process. ( There probably exists a better scientific description of the problem.) The way to think about it is that in this particular case, we try to approximate the same ratio of black/white pixels in a region to match the intensity of the greyscale value as in the &amp;ldquo;ideal&amp;rdquo; greyscale picture.&lt;/p&gt;
&lt;p&gt;The final result can be seen below. It looks a bit dodgy here, but remember that it is meant to be seen on the e-ink paper as seen above.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;dithered.png&#34; alt=&#34;Dithered&#34;&gt;&lt;/p&gt;
&lt;h1 id=&#34;algorithm&#34;&gt;Algorithm&lt;/h1&gt;
&lt;p&gt;The overall algorithm for this is relatively simple.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Convert the picture into greyscale.&lt;/li&gt;
&lt;li&gt;Apply dithering to the greyscale image converting it into a black and white image.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Step number one should be relatively easy, I will however briefly touch upon it. I&amp;rsquo;ll talk a bit more about step number two, which is the actual dithering step.&lt;/p&gt;
&lt;h2 id=&#34;converting-to-greyscale&#34;&gt;Converting to Greyscale&lt;/h2&gt;
&lt;p&gt;First step is as mentioned to convert the image to an internal greyscale format. Nothing too magical about this process. The only thing I would caution against is a naive  way of converting an RGB value to greyscale using equal weights for all of the components. This can be seen in the code snippet below.  It turns out that your eye perceives different levels of red/green/blue of different intensity. I.e. the same amount of red will not appear as bright as green. As such, the different channels gets weighted differently.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Convert to greyscale
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Naive: 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;convert_naive&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; r, &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; g, &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; b){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (r&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.33&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; ( g&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.33&lt;/span&gt; ) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; ( c &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.33&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Better 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;convert_grey&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; r, &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; g, &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; b){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (r&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.299&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; ( g&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0.587&lt;/span&gt; ) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; ( b &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.113&lt;/span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this in place, the pseudo-algorithm to convert the image should look similar to this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; grey[];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; each pixel in image{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	grey[pixel] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;convert_grey&lt;/span&gt;(pixel.r, pixel.g, pixel.b);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, you should have the picture in greyscale format, and ready for input into the dithering stage.&lt;/p&gt;
&lt;h2 id=&#34;dithering&#34;&gt;Dithering&lt;/h2&gt;
&lt;p&gt;So, we have finally gotten to the dithering stage.  Dithering as mentioned earlier is the art of applying noise to the signal to reduce the artifacts of the quantization process. For image processing the most famous technique is &amp;rsquo; Floyd Steinberg&amp;rsquo;, and then there are other variants that all builds upon Floyd-Steinberg.&lt;/p&gt;
&lt;p&gt;The general principle behind the algorithm is the following.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go through sequentially each pixel in the image.&lt;/li&gt;
&lt;li&gt;For each pixel, calculate the error of the pixel from that of the ideal. E.g.  error = ideal - quantized&lt;/li&gt;
&lt;li&gt;Then distribute an weighted error amount to the neighboring pixels.
&lt;ol&gt;
&lt;li&gt;The weight amount, and which pixels to distribute to is the difference between the variants that I&amp;rsquo;ve investigated.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Or in pseudo code, it will be something like this&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; x,y in greyscale_image.size: 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Get the value from the image
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; old &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; image[x][y];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Quantize the new value to 1.0 or 0.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; new &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; old &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.5&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// Calculate the error
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; err &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; old &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; new;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; err_amt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; err &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// For the Floyd-Steinberg algorithm.  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the Floyd-Steinberg algorithm the distribution of the errors is quite simple. The code can be found below&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image[x&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;][y]   &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; error &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;7.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image[x&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;][y&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; error &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image[x][y&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]   &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; error &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;image[x&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;][y&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; error &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3.0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now, some boundary conditions and technicalities has to be fixed before you have the full program, but this is the general gist of how to apply dithering.&lt;/p&gt;
&lt;h3 id=&#34;different-dithering-matrices&#34;&gt;Different dithering matrices&lt;/h3&gt;
&lt;p&gt;Now, I mentioned that there are different weight schemes. The one that is presented here is the Floyd Steinberg variant. However, from some investigation and experimentation I&amp;rsquo;ve found that, at least for me, the one that gave the best results for my use-case was the Atkinson dithering.  It is using the same algorithm. The only thing that changes is the weight distribution, and which pixels it maps into. You can find that in the attached reference code on github.&lt;/p&gt;
&lt;h1 id=&#34;references&#34;&gt;References&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/langly/dithering&#34;&gt;https://github.com/langly/dithering&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
    </item>
    
  </channel>
</rss>
