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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
| #include <highgui.h>
#include <cv.h>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
// Maths methods
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) > 0 ? (x) : -(x))
#define sign(x) ((x) > 0 ? 1 : -1)
// Step mooving for object min & max
#define STEP_MIN 5
#define STEP_MAX 100
IplImage *image;
// Position of the object we overlay
CvPoint objectPos = cvPoint(-1, -1);
// Color tracked and our tolerance towards it
int h = 0, s = 0, v = 0, tolerance = 10;
/*
* Transform the image into a two colored image, one color for the color we want to track, another color for the others colors
* From this image, we get two datas : the number of pixel detected, and the center of gravity of these pixel
*/
CvPoint binarisation(IplImage* image, int *nbPixels) {
int x, y;
CvScalar pixel;
IplImage *hsv, *mask;
IplConvKernel *kernel;
int sommeX = 0, sommeY = 0;
*nbPixels = 0;
// Create the mask &initialize it to white (no color detected)
mask = cvCreateImage(cvGetSize(image), image->depth, 1);
// Create the hsv image
hsv = cvCloneImage(image);
cvCvtColor(image, hsv, CV_BGR2HSV);
// We create the mask
cvInRangeS(hsv, cvScalar(h - tolerance -1, s - tolerance, 0), cvScalar(h + tolerance -1, s + tolerance, 255), mask);
// Create kernels for the morphological operation
kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);
// Morphological opening (inverse because we have white pixels on black background)
cvDilate(mask, mask, kernel, 1);
cvErode(mask, mask, kernel, 1);
// We go through the mask to look for the tracked object and get its gravity center
for(x = 0; x < mask->width; x++) {
for(y = 0; y < mask->height; y++) {
// If its a tracked pixel, count it to the center of gravity's calcul
if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) {
sommeX += x;
sommeY += y;
(*nbPixels)++;
}
}
}
// Show the result of the mask image
cvShowImage("GeckoGeek Mask", mask);
// We release the memory of kernels
cvReleaseStructuringElement(&kernel);
// We release the memory of the mask
cvReleaseImage(&mask);
// We release the memory of the hsv image
cvReleaseImage(&hsv);
// If there is no pixel, we return a center outside the image, else we return the center of gravity
if(*nbPixels > 0)
return cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels)));
else
return cvPoint(-1, -1);
}
/*
* Add a circle on the video that fellow your colored object
*/
void addObjectToVideo(IplImage* image, CvPoint objectNextPos, int nbPixels) {
int objectNextStepX, objectNextStepY;
// Calculate circle next position (if there is enough pixels)
if (nbPixels > 10) {
// Reset position if no pixel were found
if (objectPos.x == -1 || objectPos.y == -1) {
objectPos.x = objectNextPos.x;
objectPos.y = objectNextPos.y;
}
// Move step by step the object position to the desired position
if (abs(objectPos.x - objectNextPos.x) > STEP_MIN) {
objectNextStepX = max(STEP_MIN, min(STEP_MAX, abs(objectPos.x - objectNextPos.x) / 2));
objectPos.x += (-1) * sign(objectPos.x - objectNextPos.x) * objectNextStepX;
}
if (abs(objectPos.y - objectNextPos.y) > STEP_MIN) {
objectNextStepY = max(STEP_MIN, min(STEP_MAX, abs(objectPos.y - objectNextPos.y) / 2));
objectPos.y += (-1) * sign(objectPos.y - objectNextPos.y) * objectNextStepY;
}
// -1 = object isn't within the camera range
} else {
objectPos.x = -1;
objectPos.y = -1;
}
// Draw an object (circle) centered on the calculated center of gravity
if (nbPixels > 10)
cvDrawCircle(image, objectPos, 15, CV_RGB(255, 0, 0), -1);
// We show the image on the window
cvShowImage("GeckoGeek Color Tracking", image);
}
/*
* Get the color of the pixel where the mouse has clicked
* We put this color as model color (the color we want to tracked)
*/
void getObjectColor(int event, int x, int y, int flags, void *param = NULL) {
// Vars
CvScalar pixel;
IplImage *hsv;
if(event == CV_EVENT_LBUTTONUP) {
// Get the hsv image
hsv = cvCloneImage(image);
cvCvtColor(image, hsv, CV_BGR2HSV);
// Get the selected pixel
pixel = cvGet2D(hsv, y, x);
// Change the value of the tracked color with the color of the selected pixel
h = (int)pixel.val[0];
s = (int)pixel.val[1];
v = (int)pixel.val[2];
// Release the memory of the hsv image
cvReleaseImage(&hsv);
}
}
int main()
{
// Image & hsvImage
IplImage *hsv;
// Video Capture
// Key for keyboard event
char key;
// Number of tracked pixels
int nbPixels;
// Next position of the object we overlay
CvPoint objectNextPos;
// Initialize the video Capture (200 => CV_CAP_V4L2)
CvCapture *capture = cvCreateCameraCapture(CV_CAP_ANY);
// Check if the capture is ok
if (!capture) {
printf("Can't initialize the video capture.\n");
return 10;
}
// Create the windows
cvNamedWindow("GeckoGeek Color Tracking", CV_WINDOW_AUTOSIZE);
cvNamedWindow("GeckoGeek Mask", CV_WINDOW_AUTOSIZE);
cvMoveWindow("GeckoGeek Color Tracking", 0, 100);
cvMoveWindow("GeckoGeek Mask", 650, 100);
// Mouse event to select the tracked color on the original image
cvSetMouseCallback("GeckoGeek Color Tracking", getObjectColor);
// While we don't want to quit
while(key != 'Q' && key != 'q') {
// We get the current image
image = cvQueryFrame(capture);
// If there is no image, we exit the loop
if(!image)
continue;
objectNextPos = binarisation(image, &nbPixels);
addObjectToVideo(image, objectNextPos, nbPixels);
// We wait 10 ms
key = cvWaitKey(10);
}
// Destroy the windows we have created
cvDestroyWindow("GeckoGeek Color Tracking");
cvDestroyWindow("GeckoGeek Mask");
// Destroy the capture
cvReleaseCapture(&capture);
return 0;
} |