Tag Archives: script

How to glitch images using RGB channel shifting

Channel shifting is the process of taking the red, green or blue values of pixels in an image and applying those values to pixels in different positions on the image. In this tutorial we are going to accomplish this effect using the Processing language.

If you don’t have the time or inclination to glitch images using scripts you can use dedicated apps such as Glitch for iOS.

glitch4ios

To get started download and install the latest version of Processing, version 3.1.1 at the time of writing this. I’ve written a channel shifting script you can download here, you’ll have to unzip it once it’s downloaded. Once you’ve installed and opened Processing you can load the script by accessing the menu.

File > Open

And navigating to the ChannelShiftGlitch.pde script file. In the script, which are referred to as sketches in Processing, you’ll need to change the following lines to point the script at the image you want to glitch. It’s easiest to place the image in the same directory as the script file.

// image path is relative to sketch directory
String imgFileName = "MyImage";
String fileType = "jpg";

I’ve set up some settings variables to make the script easier to use, you can see these towards the top of the script under the comment of script settings.

// repeat the process this many times
int iterations = 5;

// use result image as new source for iterations
boolean recursiveIterations = false;

// shift the image vertically true/false
boolean shiftVertically = false;

// shift the image horizontally true/false
boolean shiftHorizontally = true;

This script is able to apply the same channel shifting effect multiple times, the number of times is specified by the iterations variable, currently set to 5. This variable drives a for loop around the channel shifting code as seen below.

// repeat the process according 
// to the iterations variable
    for(int i = 0;i < iterations;i++)
    {
      // generate random numbers 
      // for which channels to swap
      int sourceChannel = int(random(3));
      int targetChannel = int(random(3));

You can also see in this code where the script generates a random number which will determine which of the three channels, red, green or blue are used as a source, and which of the three channels are used as a target. Next the script sets up the shifting positions, how far vertically and how far horizontally the channel should be shifted. These are either 0 if shifting is set to false for that plane (determined by the shiftHorizontally and shiftVertically settings), or a random number between the 0 and the height or width of the image.

// start with no horizontalShift 
int horizontalShift = 0; 

// if shiftHorizontally is true generate a 
// random number to shift horizontally by
if(shiftHorizontally)
  horizontalShift = int(random(targetImg.width));
      
// start with no verticalShift 
int verticalShift = 0;
      
// if shiftVertically is true generate a 
// random number to shift vertically by
if(shiftVertically)
  verticalShift = int(random(targetImg.height));

Next the script calls the main copyChannel method. This method accepts pixel arrays of the source and target images and will copy one channel to another from one part of the image to another and wrap around both horizontally and vertically if it runs out of space.

// shift the channel
copyChannel(
  sourceImg.pixels, 
  targetImg.pixels, 
  verticalShift, 
  horizontalShift, 
  sourceChannel, 
  targetChannel
  );

The method starts by starting a counter to loop through the rows of pixels in the image, top-to-bottom. This counter is added to the sourceYOffset variable to apply the vertical shift. If the vertical shift plus the counter is higher than the image height we subtract the image height to wrap the shift around to the top of the image.

// starting at the sourceY and pointerY
// loop through the rows
for(int y = 0; y < targetImg.height; y++) { 
  // add y counter to sourceY 
  int sourceYOffset = sourceY + y; 

  // wrap around the top of the 
  // image if we've hit the bottom 
  if(sourceYOffset >= targetImg.height)
    sourceYOffset -= targetImg.height;

Within the row loop the script starts another counter to loop through the columns in that row, left-to-right. It also adds that counter to the sourceXOffset to apply the horizontal shift. If the horizontal shift plus the counter is wider than the image width we subtract the image width to wrap the shift around to the left of the image.

// starting at the sourceX and pointerX 
// loop through the pixels in this row
for(int x = 0; x < targetImg.width; x++) 
{ 
  // add x counter to sourceX 
  int sourceXOffset = sourceX + x; 

  // wrap around the left side of the 
  // image if we've hit the right side 
  if(sourceXOffset >= targetImg.width)
    sourceXOffset -= targetImg.width;

Processing stores image pixels in an array as illustrated in the image below.

pixelarray

In order to access a pixel at specific x/y coordinates in the image we use the formula below.

y * width + x

Next the script isolates the RGB (red, green, blue) values for both the source and target pixels by using the formula above to access the pixel and then some Processing methods to extract the separate RGB channel values.

// get the color of the source pixel
color sourcePixel = 
  sourcePixels[sourceYOffset * targetImg.width + sourceXOffset];
            
// get the RGB values of the source pixel
float sourceRed = red(sourcePixel);
float sourceGreen = green(sourcePixel);
float sourceBlue = blue(sourcePixel);
   
// get the color of the target pixel
color targetPixel = targetPixels[y * targetImg.width + x]; 

// get the RGB of the target pixel
// two of the RGB channel values are required 
// to create the new target color
// the new target color is two of the target
// RGB channel values and one RGB channel value 
// from the source
float targetRed = red(targetPixel);
float targetGreen = green(targetPixel);
float targetBlue = blue(targetPixel);

Now that the script has the RGB of the source pixel and RGB of the target pixel we can proceed to shift one of the channels. We use a switch statement for this, deciding which source channel to use based on the sourceChannel variable which has a holds a random number we generated earlier, either 0, 1 or 2.

// create a variable to hold 
// the new source RGB channel value
float sourceChannelValue = 0;
            
// assigned the source channel value 
// based on sourceChannel random number passed in
switch(sourceChannel)
{
  case 0:
    // use red channel from source
    sourceChannelValue = sourceRed;
    break;
  case 1:
    // use green channel from source
    sourceChannelValue = sourceGreen;
    break;
  case 2:
    // use blue channel from source
    sourceChannelValue = sourceBlue;
    break;
}

After selecting a source channel we apply that channel value to either the red, green or blue channel of the target pixel, again using a switch statement, this time based on the targetChannel variable.

// assigned the source channel value to a 
// target channel based on targetChannel 
// random number passed in
switch(targetChannel)
{
  case 0:
    // assign value to target red channel
    targetPixels[y * targetImg.width + x] = 
      color(sourceChannelValue, 
        targetGreen, 
        targetBlue);
    break;
 case 1:
    // assign value to target green channel
    targetPixels[y * targetImg.width + x] = 
      color(targetRed, 
        sourceChannelValue, 
        targetBlue);
    break;
 case 2:
    // assign value to target blue channel
    targetPixels[y * targetImg.width + x] = 
      color(targetRed, 
        targetGreen, 
        sourceChannelValue);
    break;
}

That’s it for the copyChannel method. The channel has been shifted in the target image at this point. Back in the main draw method of the script there is an if statement that determines whether or not the next iteration (if the iterations variable is to to greater than 1) will use the original image as a source, or use the new shifted image as a source.

// use the target as the new source 
// for the next iteration
if(recursiveIterations)
  sourceImg.pixels = targetImg.pixels;

Using the original image as a source for more than 3 iterations is rather pointless because there are only three channels in the original image to shift to around, always resulting in three shifted ghost images. So if you set iterations higher than 3 you should probably set recursiveIterations to true.

Vertical-Channel-Shift

Setting the recursiveIterations variable to true at the beginning of the script will use each new shifted image as a source for the next iteration and will result in much more dynamic results when iterations is set higher than 3, say 25 or 50.

Recursive-Channel-Shift

Personally I prefer restricting the shifting to either horizontal or vertical alone, but the script allows for the combination  by changing the shiftVertically and shiftHorizontally settings. You can find more Processing tutorials here, and remember, if you’re going to corrupt, corrupt absolutely. #corruptabsolutely

iOS (iPhone, iPad)

Windows

OSX

Processing

How to glitch images using pixel sorting

Pixel sorting is the process of isolating a horizontal or vertical line of pixels in an image and sorting their positions based on any number of criteria. For instance pixels positions may be sorted by each pixel’s luminosity, hue or saturation. Manual pixel sorting, while possible, would be overly time consuming, instead Pixel sorting is accomplished using scripting or programming languages.

If you don’t have the time or inclination to pixel sort images using scripts you can use dedicated apps such as Glitch for iOS.

glitch4ios

One popular programming language for pixel sorting is Processing. To get started download and install the latest version of Processing, version 3.1.1 at the time of writing this. Next select a pixel sorting script to start from, my own pixel sorting scripts are not written for Processing so for the purposes of this tutorial we’ll use a popular script made available by glitch artist Kim Asendorf, the ASDF Pixel Sort.

Download the ASDFPixelSort.pde from Kim’s GitHub repository by clicking the green button labelled Clone or download and select Download ZIP. If you’re familiar with GitHub you can do this a number of other ways. Once you’ve downloaded the ZIP you can extract the sorting script and open it in Processing by selecting:

File > Open

And navigating to the ASDFPixelSort.pde script file. In the script, which are referred to as sketches in Processing, you’ll need to change the following lines to point the script at the image you want to pixel sort:

// image path is relative to sketch directory
PImage img;
String imgFileName = "MyImage";
String fileType = "png";

For this tutorial we’ll use a PNG, though Processing supports GIF, JPG and TGA as well. Place your PNG in the same directory as the ASDFPixelSort.pde (which Processing may have placed in a new sub directory) and update the script with the filename.

Once you’ve updated the script with the name of your file simply press the Run button at the top left of the Processing window (it looks like a play button) and in a few seconds you should see a window with the results, a new image should also be saved to the sketch directory.

pixel-sort-run

This particular script loops through both the columns and the rows of the image, but it doesn’t pixel sort the entire column or row, if it did, the result would look more like a blank gradient than anything interesting. Instead for each column and row it looks for a pixel to start sorting on and then it looks for a pixel to stop sorting on — this makes the algorithm somewhat intelligent resulting in identifiable elements of the image being left untouched.

In order to decide which pixel to start sorting on and which to stop sorting on this script can operate in three different modes. The mode can be changed by adjusting the mode variable, by default it is set to 1, but can be changed to either 0 or 2 as well. Different modes will work better depending on the image itself.

 sorting modes
 
 0 = black
 1 = brightness
 2 = white
 
 */

In mode 0, or black mode, the script will begin sorting when it finds a pixel which is not black in the column or row, and will stop sorting when it finds a black pixel. The script identifies black pixels by comparing the pixel’s color value to a threshold, if it’s lower than the black threshold the pixel is deemed to not be black, if it’s higher it’s deemed to be black. You can adjust this threshold by changing the blackValue variable which is by default set to -16000000.

suit-0

In mode 1, or brightness mode, the script will begin sorting when it finds a pixel which is bright in the column or row, and will stop sorting when it finds a dark pixel. The script identifies black pixels by comparing the pixel’s brightness value to a threshold, if it’s lower than the brightness threshold the pixel is deemed to be dark, if it’s higher it’s deemed to be bright. You can adjust this threshold by changing the brightnessValue variable which is by default set to 60.

suit-0

In mode 2, or white mode, the script will begin sorting when it finds a pixel which is not white in the column or row, and will stop sorting when it finds a white pixel. The script identifies white pixels by comparing the pixel’s color value to a threshold, if it’s lower than the white threshold the pixel is deemed to not be white, if it’s higher it’s deemed to be white. You can adjust this threshold by changing the whiteValue variable which is by default set to -13000000.

suit-0

The script can also be run many times to apply the pixel sorting effect multiple times. This can be set by adjusting the loops variable which is by default set to 1.

int loops = 1;

// threshold values to determine sorting start and end pixels
int blackValue = -16000000;
int brightnessValue = 60;
int whiteValue = -13000000;

Pixel sorting is a powerful, and fun, concept. Start by trying out different modes and adjusting the various threshold values. From there you can try moving the row sorting above the column sorting, this will result in more visible vertical sorting (similar to the featured image of this post) as whichever sort is performed last will have the greatest impact on the final image. Alternately you can rotate your image in image editing software before pixel sorting it and then rotate it back to accomplish a similar result. If you break the script, just download the original and get back to experimenting.

  // loop through columns
  while(column < width-1) {
    println("Sorting Column " + column);
    img.loadPixels(); 
    sortColumn();
    column++;
    img.updatePixels();
  }
  
  // loop through rows
  while(row < height-1) {
    println("Sorting Row " + column);
    img.loadPixels(); 
    sortRow();
    row++;
    img.updatePixels();
  }

Some scripts haven’t been updated in a while. If the script you are trying to use is having errors (that don’t seem to do with not finding your image) right from the get-go you might want to try an early version of Processing, versions 2.2.1 and 1.5.1 are listed towards the bottom of the download page.

For more advanced pixel sorting scripts you can have a look at Jeff Thompson’s GitHub which has a number of examples. At the time of writing this I was experiencing errors running them though — they may need updating to function correctly, or at all. If you’ve got the hang of Processing than there’s no reason why you can’t craft an entirely original script. There are two main concepts to explore here, the first is how to determine which pixels to sort, and the second is how to sort them. I’ve had success experimenting with hue based sorting, as well as combining pixel sorting with Sobel edge detection algorithms. #corruptabsolutely

iOS (iPhone, iPad)

Windows

OSX

Processing