Monthly Archive for March, 2009

Change Counter

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);
}

Social Homes Fix

So, I totally overlooked the fact that the new version of Social Homes erased all the settings from version 2.x. I just made another update that fixes this; version 3.1 will import all your old settings and generate the new URLs for you.

If you had already updated to version 3.0, this will not work, but you can always roll back to version 2.5, copy all your settings, then re-update and add them manually. If you don’t know how to do this, just send me an e-mail with your usernames and services, and it will be my pleasure to generate the new addresses for you.

Major Update to Social Homes

By popular request, I’ve just made a major update to the Social Homes plugin for Wordpress. The new version allows you to add any service you want just by typing in the page URL; the title and favicon are found automatically (but you can also use a custom title if you want).¬†

Enjoy!

DizzyCat User Testing

Here are some images of the completed object. It is a little bulkier than I originally intended, mainly to accommodate the 4 AA batteries. My original idea of powering the whole circuit using a coin cell battery did not fly because it does not supply enough current.

IMG_0079 IMG_0094 IMG_0107 IMG_0098

The base is made out of a thin custom cut piece of wood. The shell is a plastic dome covered with some fur I got from skinning a teddy bear. The dome offers good protection for the electronics on the top of the base, but I still need to find a way to guard the motor and batteries at the bottom.

IMG_0102 IMG_0099 

I took DizzyCat up to Montreal with me to test it out with my cat before working on the collar. I was a little worried that she would not be too crazy about it since it is a little slow and noisy. As can be seen in the following video, I was right to worry. Back to the drawing board…

http://www.vimeo.com/3763609

Rats vs. Bedbugs

My idea for the Mainstreaming Information project is to create a visualization of the amount of rats and bedbugs throughout New York City. This idea came to me when I read that there are 6 rats per person in the city, and that sort of freaked me out. After a bit of research, I found out that there is plenty of data on this subject, most notably the NYC Health Rat Information Portal and the New York vs. Bed Bugs website.

The project would start with a simple animation of an uneasy person with 6 rats on his left and a bunch of bedbugs squirming on his right. The user would then click on one of the two sides, which will take her to the in-depth visualization.

pests-intro 

The visualization will consist of a map showing the concentration of rats or bedbugs at different focuses in New York City. These are:

  • The five boroughs
  • The many neighbourhoods in a borough
  • The subway stations in a neighbourhood
  • A single person at this subway station

The focus will change by zooming in and out, through simply clicking on or off the area of interest. This zoom will be accompanied by scattering or flocking of pests as the numbers get adjusted.

The rat or bedbug concentration will be represented as a bunch of animated critters moving around the territory they belong to. Since these numbers are in the millions, the amount of pests shown will be scaled according to the number of people living in the area of focus. For example, if 1 000 000 people live in Manhattan and 5 000 000 rats live in Manhattan, this could be represented as 100 human sprites vs. 500 rat sprites. Each rat sprite will be randomly generated by combining features from a library of ears, eyes, bodies, tails, etc… The rats and the bedbugs will each have their own unique behaviour, representative of their real counterparts.

pests-mnhtn