The change counter is an in-class exercise we had to do for Spatial Media, where we had to write an application which counts change in a given image. We didn’t finish on time and it’s been on my mind, so I decided to have a go at it. Here is the openFrameworks code for the finished app. The sample images can be found here.
testApp.h
1 2 3 4 5 6 7 8 9 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 | #ifndef _TEST_APP #define _TEST_APP #define WHITE_THRESHOLD 244 #define AREA_THESHOLD 50 #define COLOR_THESHOLD 10 #include "ofMain.h" class coin { public: void load(string imgName); int area; int color; }; class change { public: void load(string imgName); void seedFill(int x, int y, int tag); int count(coin penny, coin nickel, coin dime, coin quarter); unsigned char* colorPixels; unsigned char* grayPixels; unsigned char* tagPixels; ofImage img; int currTag; }; class testApp : public ofBaseApp { public: void setup(); coin penny; coin nickel; coin dime; coin quarter; change inMyPocket; }; #endif |
testApp.cpp
1 2 3 4 5 6 7 8 9 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #include "testApp.h" //-------------------------------------------------------------- void coin::load(string imgName) { // load the image ofImage img; img.loadImage(imgName); unsigned char* pixels = img.getPixels(); // calculate the area area = 0; color = 0; int numPixels = img.width * img.height; for (int i=0; i < numPixels; i++) { int pixelAvg = pixels[3*i+2]; if (pixelAvg < WHITE_THRESHOLD) { area++; color += pixelAvg; } } color /= area; printf("[area: %i color: %i]\n", area, color); } //-------------------------------------------------------------- void change::load(string imgName) { // load the image img.loadImage(imgName); colorPixels = img.getPixels(); // init the grayscale and the tags grayPixels = new unsigned char[img.width*img.height]; tagPixels = new unsigned char[img.width*img.height]; for (int i=0; i < img.width * img.height; i++) { int pixelAvg = (colorPixels[3*i] + colorPixels[3*i+1] + colorPixels[3*i+2]) / 3; grayPixels[i] = pixelAvg; tagPixels[i] = 0; } // find the blobs printf("Coin Detection\n"); currTag = 0; for (int i=1; i < img.width-1; i++) { for (int j=1; j < img.height-1; j++) { if (grayPixels[j*img.width + i] < WHITE_THRESHOLD && tagPixels[j*img.width + i] == 0) { currTag++; printf("> Found a coin with color %i at (%i, %i)!\n", grayPixels[j*img.width + i], i, j); seedFill(i, j, currTag); } } } } //-------------------------------------------------------------- void change::seedFill(int x, int y, int tag) { if (grayPixels[y*img.width + x] < WHITE_THRESHOLD) { tagPixels[y*img.width + x] = tag; if (y > 0 && tagPixels[(y-1)*img.width + x] == 0) // north seedFill(x, y-1, tag); if (y < img.height-1 && tagPixels[(y+1)*img.width + x] == 0) // south seedFill(x, y+1, tag); if (x < img.width-1 && tagPixels[y*img.width + (x+1)] == 0) // east seedFill(x+1, y, tag); if (x > 0 && tagPixels[y*img.width + (x-1)] == 0) // west seedFill(x-1, y, tag); } } //-------------------------------------------------------------- int change::count(coin penny, coin nickel, coin dime, coin quarter) { // identify the coins int** coinAreas = new int*[currTag]; for (int i=0; i < currTag; i++) { coinAreas[i] = new int[2]; coinAreas[i][0] = 0; coinAreas[i][1] = 0; } for (int i=0; i < img.width * img.height; i++) { if (tagPixels[i] != 0) { coinAreas[tagPixels[i]-1][0]++; int pixelAvg = colorPixels[3*i+2]; coinAreas[tagPixels[i]-1][1] += pixelAvg; } } for (int i=0; i < currTag; i++) { coinAreas[i][1] /= coinAreas[i][0]; } // count the value of all the change printf("Coin Identification\n"); int value = 0; for (int i=0; i < currTag; i++) { if (ABS(coinAreas[i][0] - quarter.area) < AREA_THESHOLD) { printf("> Found a quarter"); value += 25; } else if (ABS(coinAreas[i][0] - dime.area) < AREA_THESHOLD) { printf("> Found a dime"); value += 10; } else if (ABS(coinAreas[i][1] - penny.color) < COLOR_THESHOLD) { printf("> Found a penny"); value += 1; } else { printf("> Found a nickel"); value += 5; } printf(" [%i - %i]\n", coinAreas[i][0], coinAreas[i][1]); } printf("Found %i coins worth %i cents!\n", currTag, value); return value; } //-------------------------------------------------------------- void testApp::setup() { printf("Coin Reference\n"); printf("> Penny: "); penny.load("image1.jpg"); printf("> Nickel: "); nickel.load("image2.jpg"); printf("> Dime: "); dime.load("image3.jpg"); printf("> Quarter: "); quarter.load("image4.jpg"); printf("---------------------------\n"); inMyPocket.load("image5.jpg"); inMyPocket.count(penny, nickel, dime, quarter); printf("---------------------------\n"); inMyPocket.load("image6.jpg"); inMyPocket.count(penny, nickel, dime, quarter); printf("---------------------------\n"); inMyPocket.load("image7.jpg"); inMyPocket.count(penny, nickel, dime, quarter); printf("---------------------------\n"); inMyPocket.load("image8.jpg"); inMyPocket.count(penny, nickel, dime, quarter); std::exit(0); } |
0 Responses to “Change Counter”