import codeanticode.gsvideo.*; GSCapture cam; PFont font; // on a mac uncomment this //import processing.video.*; //Capture cam; int videoSliceX; int drawPositionX; import java.util.ArrayList; int current_set = 0; StringBuffer result = new StringBuffer(); int checksum = 0; int checksum_pos = 0; int checksum_val = 0; void setup() { size(720, 480); String[] parName = new String[1]; String[] parValue = new String[1]; parName[0] = "device"; parValue[0] = "/dev/video1"; cam = new GSCapture(this, 640, 480, "v4l2src", parName, parValue); // on a mac uncomment this // cam = new Caputre( this, 640, 480); font = loadFont( "Verdana-48.vlw" ); textFont( font, 48 ); } String barcode = ""; void draw() { if ( cam.available()) { cam.read(); background(255); // Display Camera image image( cam, 0, 0 ); // display red line where we look for the barcode stroke( 255, 0, 0); line( 0, height/2, width, height/2); stroke(0); // convert one line of the image to an rle encoded array of // black and white pixel ArrayList data = convertData( cam ); // find the first three bars from a start sequence int idx = find211( data ); if ( idx > 0 ) { // check if we find a barcode String res = parseCode( data, idx ); if ( res != null ) { barcode = res; } } } fill( 0, 155, 0 ); text( barcode, 30, 50 ); } // convert pixels to black and white by checking if the // brighness of a given pixel is higher than the average of the surrounding // 40 pixel (the actual values are the result of an hourlong tinkering // session - sorry, no rocketscience here) ArrayList convertData( PImage img ) { int last = 0; int count = 0; ArrayList data = new ArrayList(); for( int x = 0; x < img.width; x++ ) { int pos = (img.height/2)*img.width + x; float avg = 0; for ( int i = -20; i < 20; i ++ ) { avg += brightness( cam.pixels[pos + i] ); } avg = avg / 40; float c = brightness( cam.pixels[pos] ); int v = (c > avg * 0.96 ? 255 : 0 ); count++; if (v != last) { data.add(count); count =0; last = v; } } return data; } // find the first three bars of a start sequence int find211( ArrayList data ) { int idx = 0; while ( idx < data.size() - 2 ) { float f0 = float(((Integer)data.get(idx)).intValue()); float f1 = float(((Integer)data.get(idx+1)).intValue()); float f2 = float(((Integer)data.get(idx+2)).intValue()); float w = (f0 + f1 + f2)/4; if ( f1/f2 > 0.9 && f1/f2 < 1.1 && f0/w > 1.8 && f0/w < 2.2 ) { return idx; } idx++; } return -1; } String parseCode(ArrayList data, int idx ) { while ( idx + 7 < data.size() ) { float[] block = new float[6]; for (int i = 0; i<6; i++ ) { block[i] = float( ((Integer)data.get( idx + i )).intValue()); } // search for the character that matches best float best = 0; int best_idx = 0; for ( int i = 0; i < target.length; i++ ) { float bm = blockMatch( target[i], block ); if ( bm > best ) { best = bm; best_idx = i; } } if ( best > 0.1 ) { String val = ""; if (current_set == 0 ) { val = res_a[best_idx]; } else if ( current_set == 1 ) { val = res_b[best_idx]; } else if ( current_set == 2 ) { val = res_c[best_idx]; } if ("Start_A".equals( val ) || "CODE_A".equals( val )) { current_set = 0; } if ("Start_B".equals( val ) || "CODE_B".equals( val )) { current_set = 1; } if ("Start_C".equals( val ) || "CODE_C".equals( val )) { current_set = 2; } if (val.startsWith( "Start" )) { result = new StringBuffer(); checksum = best_idx; checksum_pos = 0; } else if ( val.equals( "Stop" )) { if ( checksum_val == (checksum - checksum_pos * checksum_val ) % 103 ) { String cv = ""; if (current_set == 0 ) { cv = res_a[checksum_val]; } else if ( current_set == 1 ) { cv = res_b[checksum_val]; } else if ( current_set == 2 ) { cv = res_c[checksum_val]; } return result.toString().substring( 0, result.toString().length() - cv.length()); } } else { result.append( val ); checksum_val = best_idx; checksum_pos++; checksum += best_idx * checksum_pos; } } idx += 6; } return null; } // return the matching value between the two arrays // the second array is normalized and compared to the // first one float blockMatch( float[] m, float[] b ) { boolean res = true; float sum = 0; for(int i=0; i < 6; i++) { sum += b[i]; } float ma = 1; for(int i=0; i < 6; i++) { float err = m[i] - b[i] / ( sum / 11 ); ma -= err*err; } return ma; } float[][] target = new float[][]{ new float[]{2,1,2,2,2,2}, new float[]{2,2,2,1,2,2}, new float[]{2,2,2,2,2,1}, new float[]{1,2,1,2,2,3}, new float[]{1,2,1,3,2,2}, new float[]{1,3,1,2,2,2}, new float[]{1,2,2,2,1,3}, new float[]{1,2,2,3,1,2}, new float[]{1,3,2,2,1,2}, new float[]{2,2,1,2,1,3}, new float[]{2,2,1,3,1,2}, new float[]{2,3,1,2,1,2}, new float[]{1,1,2,2,3,2}, new float[]{1,2,2,1,3,2}, new float[]{1,2,2,2,3,1}, new float[]{1,1,3,2,2,2}, new float[]{1,2,3,1,2,2}, new float[]{1,2,3,2,2,1}, new float[]{2,2,3,2,1,1}, new float[]{2,2,1,1,3,2}, new float[]{2,2,1,2,3,1}, new float[]{2,1,3,2,1,2}, new float[]{2,2,3,1,1,2}, new float[]{3,1,2,1,3,1}, new float[]{3,1,1,2,2,2}, new float[]{3,2,1,1,2,2}, new float[]{3,2,1,2,2,1}, new float[]{3,1,2,2,1,2}, new float[]{3,2,2,1,1,2}, new float[]{3,2,2,2,1,1}, new float[]{2,1,2,1,2,3}, new float[]{2,1,2,3,2,1}, new float[]{2,3,2,1,2,1}, new float[]{1,1,1,3,2,3}, new float[]{1,3,1,1,2,3}, new float[]{1,3,1,3,2,1}, new float[]{1,1,2,3,1,3}, new float[]{1,3,2,1,1,3}, new float[]{1,3,2,3,1,1}, new float[]{2,1,1,3,1,3}, new float[]{2,3,1,1,1,3}, new float[]{2,3,1,3,1,1}, new float[]{1,1,2,1,3,3}, new float[]{1,1,2,3,3,1}, new float[]{1,3,2,1,3,1}, new float[]{1,1,3,1,2,3}, new float[]{1,1,3,3,2,1}, new float[]{1,3,3,1,2,1}, new float[]{3,1,3,1,2,1}, new float[]{2,1,1,3,3,1}, new float[]{2,3,1,1,3,1}, new float[]{2,1,3,1,1,3}, new float[]{2,1,3,3,1,1}, new float[]{2,1,3,1,3,1}, new float[]{3,1,1,1,2,3}, new float[]{3,1,1,3,2,1}, new float[]{3,3,1,1,2,1}, new float[]{3,1,2,1,1,3}, new float[]{3,1,2,3,1,1}, new float[]{3,3,2,1,1,1}, new float[]{3,1,4,1,1,1}, new float[]{2,2,1,4,1,1}, new float[]{4,3,1,1,1,1}, new float[]{1,1,1,2,2,4}, new float[]{1,1,1,4,2,2}, new float[]{1,2,1,1,2,4}, new float[]{1,2,1,4,2,1}, new float[]{1,4,1,1,2,2}, new float[]{1,4,1,2,2,1}, new float[]{1,1,2,2,1,4}, new float[]{1,1,2,4,1,2}, new float[]{1,2,2,1,1,4}, new float[]{1,2,2,4,1,1}, new float[]{1,4,2,1,1,2}, new float[]{1,4,2,2,1,1}, new float[]{2,4,1,2,1,1}, new float[]{2,2,1,1,1,4}, new float[]{4,1,3,1,1,1}, new float[]{2,4,1,1,1,2}, new float[]{1,3,4,1,1,1}, new float[]{1,1,1,2,4,2}, new float[]{1,2,1,1,4,2}, new float[]{1,2,1,2,4,1}, new float[]{1,1,4,2,1,2}, new float[]{1,2,4,1,1,2}, new float[]{1,2,4,2,1,1}, new float[]{4,1,1,2,1,2}, new float[]{4,2,1,1,1,2}, new float[]{4,2,1,2,1,1}, new float[]{2,1,2,1,4,1}, new float[]{2,1,4,1,2,1}, new float[]{4,1,2,1,2,1}, new float[]{1,1,1,1,4,3}, new float[]{1,1,1,3,4,1}, new float[]{1,3,1,1,4,1}, new float[]{1,1,4,1,1,3}, new float[]{1,1,4,3,1,1}, new float[]{4,1,1,1,1,3}, new float[]{4,1,1,3,1,1}, new float[]{1,1,3,1,4,1}, new float[]{1,1,4,1,3,1}, new float[]{3,1,1,1,4,1}, new float[]{4,1,1,1,3,1}, new float[]{2,1,1,4,1,2}, new float[]{2,1,1,2,1,4}, new float[]{2,1,1,2,3,2}, // new float[]{2,3,3,1,1,1,2}, new float[]{2,3,3,1,1,1}, // This is a hack. the stop sequence is the onlyone // that has 7 bars but we check only for the first 6 // to make all arrays the same length }; String[] res_a = new String[]{ " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", "FNC_3", "FNC_2", "SHIFT", "CODE_C", "CODE_B", "FNC 4", "FNC_1", "Start_A", "Start_B", "Start_C", "Stop", }; String[] res_b = new String[]{ " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "I", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "DEL", "FNC_3", "FNC_2", "SHIFT", "CODE_C", "FNC_4", "CODE_A", "FNC_1", "Start_A", "Start_B", "Start_C", "Stop", }; String[] res_c = new String[]{ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "CODE_B", "CODE_A", "FNC_1", "Start_A", "Start_B", "Start_C", "Stop", };