Skip to content

Commit 8a86b8b

Browse files
committed
Added example for tracking a spot w/ a specific color
1 parent 502f046 commit 8a86b8b

File tree

1 file changed

+54
-3
lines changed
  • chapters/image_processing_computer_vision

1 file changed

+54
-3
lines changed

chapters/image_processing_computer_vision/chapter.md

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,13 @@ void ofApp::draw(){
318318
int w = laserTagImage.getWidth();
319319
int h = laserTagImage.getHeight();
320320

321-
float maxBrightness = 0; // these are used in the search
321+
float maxBrightness = 0; // these are used in the search
322322
int maxBrightnessX = 0; // for the brightest location
323323
int maxBrightnessY = 0;
324324

325325
// Search through every pixel. If it is brighter than any
326326
// we've seen before, store its brightness and coordinates.
327+
// After testing every pixel, we'll know which is brightest!
327328
for (int y=0; y<h; y++) {
328329
for(int x=0; x<w; x++) {
329330
ofColor colorAtXY = laserTagImage.getColor(x, y);
@@ -353,12 +354,62 @@ Being able to locate the brightest pixel in an image has other uses, too. For ex
353354

354355
![Not mine](images/kinect-forepoint.jpg)
355356

356-
*The brightest pixel in a depth image corresponds to the nearest object to the camera. In the configuration shown here, the "nearest object" is almost certain to be the user's hand or nose.*
357+
*The brightest pixel in a depth image corresponds to the nearest object to the camera. In the configuration shown here, the "nearest object" is almost certain to be the user's hand (or nose).*
357358

358-
Unsurprisingly, tracking *more than one* bright point requires more sophisticated forms of processing. If you're able to design and control the tracking environment, one simple yet effective way to track up to three objects is to search for the reddest, greenest and bluest pixels in the scene. Zachary Lieberman used a technique similar to this in his [*IQ Font*](https://vimeo.com/5233789) collaboration with typographers Pierre & Damien et al., in which letterforms were created by tracking the movements of a specially-marked sports car.
359+
Unsurprisingly, tracking *more than one* bright point requires more sophisticated forms of processing. If you're able to design and control the tracking environment, one simple yet effective way to track up to three objects is to search for the reddest, greenest and bluest pixels in the scene. Zachary Lieberman used a technique similar to this in his [*IQ Font*](https://vimeo.com/5233789) collaboration with typographers Pierre & Damien et al., in which letterforms were created by tracking the movements of a specially-marked sports car.
359360

360361
![Not mine](images/iq_font.jpg)
361362

363+
More generally, you can create a system that tracks a (single) spot with a *specific* color. A simple way to achieve this is to find the pixel whose color has the shortest Euclidean distance (in "RGB space") to the target color. Here is a code fragment which shows this.
364+
365+
```
366+
// Our target color is CSS LightPink: #FFB6C1 or (255, 182, 193)
367+
float rTarget = 255;
368+
float gTarget = 182;
369+
float bTarget = 193;
370+
371+
// these are used in the search for the location of the pixel
372+
// whose color is the closest to our target color.
373+
float leastDistanceSoFar = 255;
374+
int xOfPixelWithClosestColor = 0;
375+
int yOfPixelWithClosestColor = 0;
376+
377+
for (int y=0; y<h; y++) {
378+
for (int x=0; x<w; x++) {
379+
380+
// Extract the color components of the pixel at (x,y)
381+
// from myVideoGrabber (or some other image source)
382+
ofColor colorAtXY = myVideoGrabber.getColor(x, y);
383+
float rAtXY = colorAtXY.r;
384+
float gAtXY = colorAtXY.g;
385+
float bAtXY = colorAtXY.b;
386+
387+
// Compute the difference between those (r,g,b) values
388+
// and the (r,g,b) values of our target color
389+
float rDif = rAtXY - rTarget; // difference in reds
390+
float gDif = gAtXY - gTarget; // difference in greens
391+
float bDif = bAtXY - bTarget; // difference in blues
392+
393+
// The Pythagorean theorem gives us the Euclidean distance.
394+
float colorDistance =
395+
sqrt (rDif*rDif + gDif*gDif + bDif*bDif);
396+
397+
if (colorDistance < leastDistanceSoFar){
398+
leastDistanceSoFar = colorDistance;
399+
xOfPixelWithClosestColor = x;
400+
yOfPixelWithClosestColor = y;
401+
}
402+
}
403+
}
404+
405+
// At this point we now know the location of the pixel
406+
// whose color is closest to our target color:
407+
// (xOfPixelWithClosestColor, yOfPixelWithClosestColor)
408+
409+
```
410+
411+
This technique is often used with an "eyedropper-style" interaction, in which the user selects the target color interactively (by clicking). Note that there are more sophisticated ways of measuring "color distance", such as techniques that use other color spaces, that can be more robust to variations in lighting. The distance method used here is not particularly good at distinguishing among very dark colors.
412+
362413
#### Three-Channel (RGB) Images.
363414

364415
Our Lincoln portrait image shows an 8-bit, 1-channel image. Each pixel uses a single round number (technically, an unsigned char) to represent a single luminance value. But other data types and formats are possible.

0 commit comments

Comments
 (0)