I'm working on some tools for art and have some friends who want to collaborate so I'm putting together a little tutorial on how to install a python environment on your PC and use it to play with images. I figure other people might be interested as well so here it is.
This tutorial is probably best for people who have a rudimentary understanding of programming and above. Have you written hello world before and kinda know what an if statement is? I'd say this is for you.
If you want to look at any of the images here larger just click on em, it should open a full resolution image.
Installing Python
We'll be using an IDE (Integrated Development Environment) to install and interact with Python for our programming. An IDE is a set of tools that will allow us to program with greater ease. The IDE we're using is Visual Studio Code. It's free, supports a lot of languages and works on Windows, Mac and Linux.
from @garbo
This is really cool! One tip for people on Windows: you can install Python and VS Code via the Microsoft Store. This can be helpful if you're mucking around on a work machine where you don't have admin and/or AppLocker is enforced (Edit: assuming they haven't also blocked the Microsoft Store, otherwise RIP).
Python: https://apps.microsoft.com/detail/9ncvdn91xzqp
VS Code: https://apps.microsoft.com/detail/xp9khm4bk9fz7q
- Download and install Python the latest version
- Download and install VS Code
- Open VS Code, click the extensions tab

- Search for and install the Python extension

- Search for and install pip manager

- Select the new pip manager tab

- Click the + icon next to where it says pip manager installed
- Enter opencv-python into the input box and press enter

- After installing your package list should look like this

Running the script for the first time
We are at a point where now we should be able to run the script on an image and get some output, namely 3 images dithered with different algorithms first of all we're going to need to download the script, you can get that here: https://www.dropbox.com/scl/fi/92j4lhqj5k76bxltyxh3i/ditherScripts.zip?rlkey=j4ykcel8u66xajnxpboooe8yu&dl=1
When you open that zip file you'll find 2 .py files. These are exactly the same except one is commented to assist with understanding the script. Don't worry about opening and reading it yet, just make a new folder somewhere and put the 2 .py files in it as well as a small image you'd like to dither, any regular image format will be fine.
- Select the explorer tab and click open folder

- Navigate to the folder with the .py scripts and your image in, select it

- Select either of the .py files in the file tree area, they both do the same thing

- Replace the text shown with the name of your image, including the file extension. Be sure to include the single quotes around the file name.


- Click the arrow in the top right hand corner, this will run the script

- This added some notes to the output at the bottom of the window, when the circle goes blue the script has finished


- The output images should now be visible in the file tree panel to the left, click any of them to take a look, or look in the folder and open it with whatever image viewer you like

Go ahead and read the commented file now. It's not necessary that you understand it fully, we'll be going into more detail on what it's doing and how it achieves it in the next section.
Rad, how does the dithering work?
This is the source I used on the dithering algorithm. It's a good read and you should take a look, feel free to skip over all the code stuff and just focus on how it works. In short we're looking at each individual pixel of a greyscale image, changing it to black or white depending on how black or white it is, calculating how much we had to change it and spreading that change over adjacent pixels.
In the python code we can define how this change propagates over adjacent pixels, at the top of the file you'll find the constants section with the variables ATKINSONMASK, FLOYDMASK and CALEBMASK. These relate to the Atkinson method, the Floyd-Steinberg method and my own custom method, but how can we read this?
ATKINSONMASK = np.array(([1,0,1/8],[2,0,1/8],[-1,1,1/8],[0,1,1/8],[1,1,1/8],[0,2,1/8]))
FLOYDMASK = np.array(([1,0,7/16],[-1,1,5/16],[0,1,5/16],[1,1,1/16]))
CALEBMASK = np.array(([1,0,2/8],[2,0,1/8],[-1,1,1/8],[0,1,2/8],[1,1,1/8],[0,2,1/8]))
What we're looking at in these masks is an array, think of it like your play field in battleship. We can take a look at what is in each individual cell. In this case instead of boats we're storing a number. The first number is an adjustment in column, the second an adjustment in row and the third the amount of error to be diffused. It may help to show the mask in the same format as the diffusion from the beyond loom page linked above.




This, I hope, is enough information to start making your own dithering masks for fun. If there are any questions or you run into any problems send me a message and I will do my best to answer. Have fun!


















