Magic Eye Image Generator: Exploring 3D Visualization with SIRDS

This project involves using an algorithm to generate “Magic Eye” images from grayscale depth-mappings of photographs. These images are also known as Single Image Random Dot Stereograms (SIRDS) and were popularized by the Magic Eye books in the 1990s.

To create these Magic Eye images, the original algorithm required significant computational resources that made the process time-consuming. In this project, I have rewritten the original algorithm to be more efficient, using Node.js, while still producing the same high-quality images.

I started by taking JPEG images from a trip to Hawaii and converted them to grayscale depth-mappings using Photoshop. I then used the optimized algorithm, which was originally translated from C code by Harold W. Thimbleby, Stuart Inglis, and Ian H. Witten, to generate the Magic Eye images.

The new algorithm works by taking the depth-mapping image and using it to generate a new image that can be viewed as a 3D image with the help of stereoscopic viewing. The resulting image appears to be a pattern of random dots, but when viewed with a special technique (e.g., crossing your eyes or focusing behind the image), the viewer can see a 3D scene.

The project includes several Magic Eye images, including a tropical fish, a person snorkeling, a beach scene, and more. I wrote the code for this project using Node.js and added detailed comments to make it easier to understand.

The resulting Magic Eye images are fascinating to look at and can be a fun addition to any website. The project highlights my skills in image processing and computer graphics, as well as my ability to understand and optimize complex algorithms for faster processing times.

The Results:

Magic Eye - Tropical Fish

Magic Eye – Tropical Fish

Magic Eye - David Snorkeling

Magic Eye – David Snorkeling

Magic Eye - Hanalei Bay

Magic Eye – Hanalei Bay

Magic Eye - Palm Tree

Magic Eye – Palm Tree

Magic Eye - Waikiki Sunset

Magic Eye – Waikiki Sunset

Magic Eye - Ukulele

Magic Eye – Ukulele

Magic Eye - Garden of the Gods

Magic Eye – Garden of the Gods

 

My Implementation of Algorithm


// This program generates an autostereogram (also known as a Magic Eye image)
// from a grayscale depth map using a modified version of the MagicEye.js algorithm.
// The algorithm was published in a paper authored by Harold W. Thimbleby, Stuart Inglis, and Ian H. Witten.
// The following code is an efficient implementation of the algorithm in JavaScript.

// Author: David Maiolo
const round = x => Math.round(x);
const DPI = 72;
const E = round(2.5 * DPI);
const mu = 1 / 3.0;
const separation = z => round((1 - mu * z) * E / (2 - mu * z));
const far = separation(0);
const maxX = 256;
const maxY = 256;

function drawAutoStereogram(z) {
  const pix = new Array(maxX);
  const same = new Array(maxX);

  for (let y = 0; y < maxY; y++) {
    let s;
    let left, right;
    for (let x = 0; x < maxX; x++) {
      same[x] = x;
    }

    for (let x = 0; x < maxX; x++) {
      s = separation(z[x][y]);
      left = x - s / 2;
      right = left + s;
      if (0 <= left && right < maxX) {
        let visible;
        let t = 1;
        let zt;
        do {
          zt = z[x][y] + 2 * (2 - mu * z[x][y]) * t / (mu * E);
          visible = z[x - t][y] < zt && z[x + t][y] < zt;
          t++;
        } while (visible && zt < 1);

        if (visible) {
          let k;
          for (k = same[left]; k !== left && k !== right; k = same[left]) {
            if (k < right) { left = k; } else { left = right; right = k; } } same[left] = right; } } } for (let x = maxX - 1; x >= 0; x--) {
      const pixelOffset = y * maxX * 4 + x * 4;
      if (same[x] === x) {
        const randomColor = Math.floor(Math.random() * 2);
        pix[x] = randomColor;
      } else {
        pix[x] = pix[same[x]];
      }
      // call Set_Pixel with the x, y, and pix[x] values
      Set_Pixel(x, y, pix[x]);
    }
  }

  // call DrawCircle to draw the convergence dots
  DrawCircle(maxX / 2 - far / 2, maxY * 19 / 20);
  DrawCircle(maxX / 2 + far / 2, maxY * 19 / 20);
}

 

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *