As I started testing Vuforia’s Augmented Reality tools, especially in Unity, I grew the need for good images to be used as Image Targets. Image Targets are a less constrained version of the classical fiducial markers and QR codes used by AR. As the name suggests, Image Targets are images. Yes, you could use any image, but should you? No 🙂 . It is better to use images which feature, for example, a lot of detail, good contrast, and non-repetitive patterns.
Using myself AR targets for a number of projects, I spent a bit of time with Processing in order to see if I could design a sketch for my needs. I was looking for something capable of creating good quality abstract images to be used as Image Targets. At the time, I was preparing an AR setup for some Psychology experiments together with a colleague. It seemed better to show to experimental subjects abstract images, instead of potentially distracting and incoherent pictures. Also, less time spent looking for good images in the future!
Here’s a test showing an Image Target generated by the Processing sketch you can find at the bottom of this page. The software running on the smartphone is the same we used for our experiments, and it was created using Unity + Vuforia. We needed specific colors for our targets, but it is also possible to use a random color palette generator and let it “choose” the colors for you.
Here’s the Processing sketch which creates these images.
/* * Image Target generator for Vuforia SDK * Author: Dario Mazzanti (darmaz@gmail.com), 2014 * * */ color c1; color c2; color c3; float greyControlValue = 0.2; int myWidth = 1280; int myHeight; float ratio = 4.0/3.0; PVector[] triangles; int colNum = 15; color[] mycolors = {#A6C534, #B3D255, #C0E078, #D2EE92, #E4FBAD, #CAD246, #D2DC5C, #D8E673, #E2F084, #ECFA97, #9AB8B9, #556F90, #1E4D6C, #2B394B, #2B394B}; void setup() { myHeight = int(myWidth/ratio); size(1280, 960); noStroke(); DrawPattern(20, 15); //filter(INVERT); // cool... other "free" targets just by inverting the frame :) } // empty draw, just to allow keyboard input! void draw() { } void DrawPattern(int columns, int rows) { background(0); float xIncr = width/columns; float yIncr = height/rows; smooth(); //noStroke(); for (int xPos = 0; xPos < width; xPos += xIncr*2) { for (int yPos = 0; yPos < height; yPos += yIncr*2) { // 1 fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos, yPos, xPos + xIncr, yPos, xPos + xIncr, yPos + yIncr); fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos, yPos, xPos, yPos + yIncr, xPos + xIncr, yPos + yIncr); // 2 fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos + xIncr, yPos, xPos + 2*xIncr, yPos, xPos + xIncr, yPos + yIncr); fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos + 2*xIncr, yPos, xPos + xIncr, yPos + yIncr, xPos + 2*xIncr, yPos + yIncr); // 3 fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos, yPos + yIncr, xPos, yPos + 2*yIncr, xPos + xIncr, yPos + yIncr); fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos, yPos + 2*yIncr, xPos + xIncr, yPos + 2*yIncr, xPos + xIncr, yPos + yIncr); // 4 fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos + xIncr, yPos + yIncr, xPos + 2*xIncr, yPos + yIncr, xPos + 2*xIncr, yPos + 2*yIncr); fill(mycolors [int(random(0, mycolors.length))]); triangle(xPos + xIncr, yPos + yIncr, xPos + xIncr, yPos + 2*yIncr, xPos + 2*xIncr, yPos + 2*yIncr); } } for (int i = 0; i < 1.5*columns*rows; i++) { float size = random(xIncr/10, xIncr); color col = mycolors [int(random(0, mycolors.length))]; fill(red(col), green(col), blue(col), 210); ellipse(random(width), random(height), size, size); } } void keyPressed() { if (keyCode == ENTER) { saveFrame("target####.png"); return; } if(key == ' ') { DrawPattern(20, 15); } } //that's it