Hilligoss Bitmap-to-Vector Encoder by BUS ERROR Collective

What Is The Hilligoss Encoder?

Hilligoss is a ridiculously fast and flexible image-to-vector encoder, written by BUS ERROR of BUS ERROR Collective. It is free to use, and its source code is free-as-in-beer to incorporate into your own work. Given any video file, Hilligoss will attempt to recreate the video as a series of vector points/line segments, stored as an audio file suitable for playback on any XY-mode oscilloscope or similarly-designed display medium.


Everything You Need To Get Started:

hilligoss-1.0.tar.gz - Download this file. It contains a couple batch processing scripts, and the Hilligoss encoder source code.

processall.sh - A script that allows you to easily batch-convert an entire video into oscilloscope audio in one shot. Requires ffmpeg and process.sh.
process.sh - You'll need to download this script as well..processall.sh relies upon process.sh.
hilligoss-nnsts-512.c - Source code for the "nearest-neighbor simplified travelling salesman" version of Hilligoss 1.0
hilligoss-hmsfc-512.c - Source code for the "Hilbert-Moore space filling curve" version of Hilligoss 1.0


How To Compile:

gcc -O3 hilligoss-nnsts-512.c -o hilligoss-nnsts-512 -lm
gcc -O3 hilligoss-hmsfc-512.c -o hilligoss-hmsfc-512 -lm


How To Use:

./processall.sh yourfavoritevideo.mp4

If all goes well, and provided you have ffmpeg installed, Hilligoss will spit out a .wav file. Just play this .wav against an oscilloscope, or load it into a software-based visualizer like Osci-Render, or Dood.Al/Oscilloscope (see below).


So How Does This Thing Work, In Detail?

At its core, the Hilligoss Encoder takes a single 512x512 8-bit binary/raw "P5" PGM image, examines it, and tries to find the best way to represent the image as a series of discrete points on an XY coordinate grid. You're able to vary how many points the Hilligoss encoder is allowed to use to do this. When it's done, it writes these XY coordinates to a file as audio data. When large numbers of these tiny snippets of audio are stacked together in sequence, the illusion of motion is created..an animated visual representation of sound!

When Hilligoss runs, the first thing it does is ingest the image you provide it with. You do this using the -f argument. The image file must be exactly 512x512 pixels, and must be stored in 8-bit binary/raw "P5" PGM format...Preferably black and white, for best results. (Don't worry--You may not have heard of PGM before, but, nearly every major graphics program in the world quietly supports this format. It just makes life simpler.) Once the image file is loaded, Hilligoss establishes a 512x512 array of values ranging from 0 (absolute black) to 255 (absolute white) to represent the image.

The next argument that Hilligoss needs to know is called the "desired vector count", or -c argument. Hilligoss will attempt to re-interpret the image you've specified as a series of vector points equal to this number. This might be a little hard to conceptualize at first, but think of it this way. Suppose you were tasked with drawing the Mona Lisa using just....dots. Very quickly, you'll realize you'll need a lot of dots to accomplish this. In fact, the larger the number of points, the better. Naturally, the larger this number of dots is, the higher quality the resulting image will tend to look.. However....there's a problem. It's going to take take much longer for the oscilloscope beam to "paint" 50000 dots than it would take to draw, say, 500 dots. If there are too many dots, the overall image will look too flickery, too glittery...and conversely, too few dots will result in an image that isn't even discernable.

For the sake of explaining how Hilligoss works, let's imagine that the 512x512 image you've provided happens to have 133,597 of its 262,144 pixels "lit", or have brightness values above zero. If you've specified a -c value of 2000, Hilligoss will begin selectively subtracting pixels from that initial population of 133,597, one by one, and reduce the pixel count all the way down until the number of pixels remaining matches the count (-c value) you've given. This is Hilligoss trying to preserve much of the original image as possible. It decides which pixels to remove from the image on the basis of their brightness; the brighter the pixel, the less likely it is to be removed. Pixels which are nearly white are almost never removed. Pixels which are near black are far more likely to be removed. This probability-based approach tends to yeild exceptionally good output, as this strategy preserves pixels which have a higher qualitative impact on the overall image, while still preserving fine detail in darker areas. Hilligoss will continue to disassemble an image, pixel by pixel until only -c pixels remain. The list of surviving pixels then become the XY coordinates the pathfinding algorithm will consider when drawing the image on the screen.

The next two arguments -b and -w, control something called the the "black threshold", and the "white threshold", respectively. By specifying a value like -b 20, for example, you are telling Hilligoss to basically consider any pixels which are dimmer than a value of 20 out of 255 to be pure black... In other words, you're telling Hilligoss to not even bother wasting time considering pixels this dark, because they're so dark that they don't really contribute to the overall image.. The same logic applies to the "white threshold", the -w argument, where any pixel brighter than the given value is considered to be pure white, and thus will be largely excluded from any sort of subtraction/removal efforts. These values allow you some degree of fine-tuning, as it basically narrows down the number of points that Hilligoss' travelling salesman algorithm will have to choose from, later.

The -x and -y arguments control the size of the ASCII-art preview that Hilligoss will produce when it runs. This is just something fun I wrote that attempts to approximate what Hilligoss is thinking, using ASCII art as a medium. The preview that it generates can be a useful tool for debugging image quality on the command line. Make sure your terminal is wider, and taller than the -x and -y values you supply.

The tarball you downloaded actually contains two slightly different versions of the Hilligoss encoder. One is called "Hilligoss-NNSTS-512", and the other, "Hilligoss-HMSFC-512". Most likely, you'll want to use the "Nearest Neighbor Simplified Travelling Salesman" (NNSTS) version, over the "Hilbert-Moore Space Filling Curve" (HMSFC) version. Both have their relative strengths and weaknesses, but, for the sake of keeping things simple, 99% of the time, 99% of people will want to use the NNSTS version of Hilligoss.


What's A "Travelling Salesman" Algorithm, You Ask?

Suppose you were a salesman, and you've been told to visit 20 potential customers spread out among different towns across the country. Some of these customers live close together, while others live very far away from eachother. In order to keep your travel time (and distance!) to a minimum, you'll need to map out which locations you will visit first, and in what order. This is a fairly simple task for a human to do, but, for a computer, finding the most optimal route that includes every destination can be very time consuming. For Hilligoss, every "city" the travelling salesman must visit is a pixel..a location...an XY coordinate on the oscilloscope screen that the beam must ultimately visit in order to paint the image you've provided.

Automated approaches to this process can be problematic.. For example, what happens to the salesman when he's stuck on an "island" of pixels? Where does he jump to next? To avoid stranding our intrepid salesman, we can forcibly teleport him to a new random location on the 512x512 image every -j iterations. Doing so ensures that an even amount of attention is paid to different parts of the image, including parts which are off the beaten path, so to speak. Be mindful, however.. Teleporting the salesman too frequently will produce unusual results, as will teleporting him too infrequently. In most cases, the default jump frequency will work fine.

Once processing is complete, and Hilligoss has deconstructed your 512x512 image down to a sorted list of critical, must-visit XY coordinates, it writes these locations to a file as signed, 16-bit little endian values. The filename it saves this data to is the same base filename as the input, but with a .pcm suffix. By content, it just so happens that this file is exactly what the body of an 16-bit PCM audio file looks like, where the X coordinate is the loudness of the left speaker, and the Y coordinate is the loudness of the right speaker. With a proper AIFF WAV file header attached, this list of coordinates can then be played as an audio file by any number of devices, and played against an oscilloscope...and voila, you have a discernable image made from a vector points. This basic idea, stretched over the course of several hundred or several thousand frames, is what makes bitmap animation on an oscilloscope possible.

When used together, your Hilligoss command might look something like this:

./hilligoss-nnsts-512 -f "picture.pgm" -c2000 -b3 -w253 -x64 -y32 -j500

In plain English, "Convert picture.pgm to vector data using 2000 points in total, where any pixel dimmer than 3 out of 255 is ignored, and any pixel brighter than 253 out of 255 is preserved. When doing so, show me an ASCII-art preview thats 64x32 characters. For every 500 iterations, teleport the travelling salesman to a random location to prevent stranding him on an island of pixels."

The example arguments provided in the process.sh script are a pretty good starting point. Hilligoss will do its best to look out for you by rejecting any weird, out-of-spec, or nonsensical values provided. For example, a -c value above 262144 doesn't make any sense, because there are only 262144 pixels in a 512x512 image. Similarly, pixel brightness values range from 0-255, so, specifying thresholds outside of this range will be rejected. You get the idea.


Who's The Girl Up There?

That's Candace. Candace has been our trusty "test pattern" / calibration image for about a year now. The original image came from a Midjourney prompt, something like, "photorealistic black and white 1960's blonde model, dark background, three quarter profile", or words to that effect.. In an interesting coincidence, we think it got ahold of the public domain horror movie "Carnival Of Souls" (1962), starring Candace Hilligoss, one of BUS ERROR's favorite spooky movies. The encoder is named in her honor.


Resources:

Dood.al Web-Based XY Mode Oscilloscope
Osci-Render v2
Galleria - A little video to test out the Hilligoss batch processing scripts with
An example 512x512 PGM image to experiment with


Metadata:

Current Version: 1.0
Release Date: Oct 5, 2024
Last Revised: Oct 14, 2024