├── README └── TrackColour.cpp /README: -------------------------------------------------------------------------------- 1 | Object Tracking based on color using OpenCV 2 | Author: Adarsha Joisa 3 | If you have downloaded the source code, please send me an email at adarshajoisa[at]gmail[dot]com. It'd help me keep track of the number of people using this tool. :) I hope you enjoy it and improve it. 4 | 5 | This is a simple tool to track random colored objects using the computer's webcam. I've developed it on my laptop, so the default webcam has been used. If you are using a different(external) webcam,change the line: "capture = cvCaptureFromCAM(0);" by replacing the "0" with the appropirate index for your webcam. 6 | The algorithm for color detection is as follows: 7 | 1. A capture is created to capture video from the webcam. A yellow square (20x20 pixels) is displayed at the center of the screen. This is considered to be the ROI. 8 | 2. The user shows the object to the camera such that the object fills the yellow square, and hits Space. 9 | 3. The current frame is captured. We extract the most prominent color in the ROI using the getHSVranges() function. 10 | 4. Once we get the HSV ranges, the camera starts capturing live video. The frames are thresholded using the range we got earlier. (NOTE: I've written my own function for thresholding, but the openCV function cvInrangeS() works in the same way.) 11 | 5. By calculating the moments for the thresholded image, we get the center of the object. (Note: If there's anything else in the camera's field of view with a color similar to the object, this center will be offset towards the colored region. Hence, it's best to use some object with a bright and rare color. (I've tried objects of red, orange, yellow, blue and purple, and they worked well.)) 12 | 13 | 14 | The position of the center is used to perform any useful function. In this program, I've provided 2 options, one to control the mouse pointer and second to simulate the arrow keys of the keyboard. The arrow keys are simulated by just moving the object in similar directions: left for left, up for up, left and up for left+up, and so on. The input is sent to the currently active window. You can comment out these lines to hide the webcam video and thresholded video windows: 15 | cvShowImage("thresh", imgThresh); 16 | cvShowImage("video", frame); 17 | 18 | Note: compile on linux as: 19 | g++ -ggdb `pkg-config --cflags opencv` -o track TrackColour.cpp `pkg-config --libs opencv` 20 | 21 | Note: You need to have OpenCV development libraries installed on your system to compile this code. Refer to http://http://opencv.willowgarage.com/wiki/ for instructions on installing opencv. -------------------------------------------------------------------------------- /TrackColour.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | //definitions of ROI values 8 | #define centerX 270 9 | #define centerY 210 10 | #define ROISTARTX 310 11 | #define ROISTARTY 230 12 | #define ROIENDX 330 13 | #define ROIENDY 250 14 | #define ROIHEIGHT 20 15 | #define ROIWIDTH 20 16 | 17 | struct centroidposition 18 | { 19 | int x; 20 | int y; 21 | }; 22 | 23 | centroidposition pos[10]; 24 | int curtop = 0; 25 | const int qmaxlen = 10; 26 | int fullcount = 0, partialcount = 0; 27 | IplImage* frame = 0; 28 | 29 | using namespace std; 30 | 31 | 32 | void InRangeS(IplImage * img, CvScalar hsv_min, CvScalar hsv_max, IplImage* imgThreshed) 33 | { 34 | IplImage* imgHSV = cvCreateImage(cvGetSize(img), 8, 3); 35 | cvCvtColor(img, imgHSV, CV_BGR2HSV); 36 | // imgThreshed = cvCreateImage(cvGetSize(imgHSV), 8, 1); 37 | if(imgHSV == NULL || imgThreshed == NULL) 38 | { 39 | cout<<"Null pointer encountered. Aborting..."< pos[curtop].x + 5) 47 | { 48 | sidedirection = -1; 49 | xIncrement = (pos[(curtop + 4) % 10].x - pos[curtop].x ) / 5; 50 | } 51 | 52 | else if( pos[(curtop + 5 ) % 10].x < pos[curtop].x - 5) 53 | { 54 | sidedirection = 1; 55 | xIncrement = (pos[curtop].x - pos[(curtop + 4) % 10].x) / 5; 56 | } 57 | 58 | else 59 | { 60 | sidedirection = 0; 61 | xIncrement = 0; 62 | } 63 | 64 | 65 | 66 | if( pos[(curtop + 5 ) % 10].y > pos[curtop].y + 5) 67 | { 68 | yIncrement = (pos[(curtop + 4) % 10].y - pos[curtop].y ) / 5; 69 | updirection = 1; 70 | } 71 | 72 | else if( pos[(curtop + 5 ) % 10].y < pos[curtop].y - 5) 73 | { 74 | yIncrement = (pos[curtop].y - pos[(curtop + 4) % 10].y) / 5; 75 | updirection = -1; 76 | } 77 | 78 | else 79 | { 80 | updirection = 0; 81 | yIncrement = 0; 82 | } 83 | 84 | 85 | //Set ROI for thresholding based on the previous position and direction of movement 86 | int ROIx; 87 | if( sidedirection == 0) 88 | ROIx = pos[curtop].x - (xIncrement - 100); 89 | else if(sidedirection == -1) 90 | ROIx = pos[curtop].x - (xIncrement - 100); 91 | else 92 | ROIx = pos[curtop].x - (xIncrement - 100); 93 | 94 | if(ROIx < 0) 95 | ROIx = 0; 96 | if(ROIx > 440) 97 | ROIx = 440; 98 | 99 | 100 | int ROIy; 101 | if( updirection == 0) 102 | ROIy = pos[curtop].y - (yIncrement - 100); 103 | else if(updirection == -1) 104 | ROIy = pos[curtop].y - (yIncrement - 100); 105 | else 106 | ROIy = pos[curtop].y - (yIncrement - 100); 107 | 108 | if(ROIy < 0) 109 | ROIy = 0; 110 | if(ROIy > 280) 111 | ROIy = 280; 112 | 113 | cvSetImageROI( imgHSV, cvRect(ROIx, ROIy, 200, 200)); 114 | 115 | //Initialize the threshold image ( imgThreshed ) to black 116 | for(int y = 0; y < imgThreshed->height; y++) 117 | { 118 | uchar* tempthreshptr = (uchar*) ( imgThreshed->imageData + y * imgThreshed->widthStep ); 119 | for(int x = 0; x < imgThreshed->width; x++) 120 | tempthreshptr[x] = 0x00; 121 | } 122 | 123 | 124 | //Threshold the ROI and write to imgThreshed 125 | int whitecount = 0; 126 | for( int y=ROIy; y<(ROIy + 150); y++ ) 127 | { 128 | uchar* ptr = (uchar*) ( imgHSV->imageData + y * imgHSV->widthStep ); 129 | uchar* frameptr = (uchar*) ( frame->imageData + y * frame->widthStep ); 130 | uchar* threshptr = (uchar*) ( imgThreshed->imageData + y * imgThreshed->widthStep ); 131 | for( int x=ROIx; x<(ROIx + 150); x++ ) 132 | { 133 | int prevline = x - imgHSV->width; 134 | if( prevline < 0 ) 135 | prevline = 0; 136 | if( (ptr[3*x] > hsv_min.val[0] && ptr[3*x] < hsv_max.val[0]) && 137 | (ptr[3*x + 1] > hsv_min.val[1] && ptr[3*x + 1] < hsv_max.val[1]) && 138 | (ptr[3*x + 2] > hsv_min.val[2] && ptr[3*x + 2] < hsv_max.val[2])) 139 | { 140 | //threshold 141 | threshptr[x] = 0xff; 142 | frameptr[3*x] = 0x00; 143 | frameptr[3*x + 1] = 0x4d; 144 | frameptr[3*x + 2] = 0x4d; 145 | whitecount++; 146 | } 147 | else 148 | { 149 | threshptr[x] = 0x00; 150 | } 151 | } 152 | } 153 | 154 | if(whitecount < 50 ) 155 | { 156 | whitecount = 0; 157 | for( int y=ROIy; y<(ROIy + 150); y++ ) 158 | { 159 | uchar* ptr = (uchar*) ( imgHSV->imageData + y * imgHSV->widthStep ); 160 | uchar* frameptr = (uchar*) ( frame->imageData + y * frame->widthStep ); 161 | uchar* threshptr = (uchar*) ( imgThreshed->imageData + y * imgThreshed->widthStep ); 162 | for( int x=ROIx; x<(ROIx + 150); x++ ) 163 | { 164 | int prevline = x - imgHSV->width; 165 | if( prevline < 0 ) 166 | prevline = 0; 167 | if( (ptr[3*x] > (hsv_min.val[0] - 5) && ptr[3*x] < (hsv_max.val[0] + 5)) && 168 | (ptr[3*x + 1] > (hsv_min.val[1] - 10) && ptr[3*x + 1] < (hsv_max.val[1] + 10)) && 169 | (ptr[3*x + 2] > (hsv_min.val[2] - 10) && ptr[3*x + 2] < (hsv_max.val[2] + 10))) 170 | { 171 | //threshold 172 | threshptr[x] = 0xff; 173 | frameptr[3*x] = 0x00; 174 | frameptr[3*x + 1] = 0x4d; 175 | frameptr[3*x + 2] = 0x4d; 176 | whitecount++; 177 | } 178 | else 179 | { 180 | threshptr[x] = 0x00; 181 | } 182 | } 183 | } 184 | } 185 | 186 | cvResetImageROI(imgHSV); 187 | // cout< 50) 191 | { 192 | partialcount++; 193 | return; 194 | } 195 | else 196 | { 197 | fullcount++; 198 | for( int y=0; yheight; y++ ) 199 | { 200 | uchar* ptr = (uchar*) ( imgHSV->imageData + y * imgHSV->widthStep ); 201 | uchar* frameptr = (uchar*) ( frame->imageData + y * frame->widthStep ); 202 | uchar* threshptr = (uchar*) ( imgThreshed->imageData + y * imgThreshed->widthStep ); 203 | for( int x=0; xwidth; x++ ) 204 | { 205 | int prevline = x - imgThreshed->width; 206 | if( prevline < 0 ) 207 | prevline = 0; 208 | if( (ptr[3*x] > hsv_min.val[0] && ptr[3*x] < hsv_max.val[0]) && 209 | (ptr[3*x + 1] > hsv_min.val[1] && ptr[3*x + 1] < hsv_max.val[1]) && 210 | (ptr[3*x + 2] > hsv_min.val[2] && ptr[3*x + 2] < hsv_max.val[2])) 211 | { 212 | //threshold 213 | threshptr[x] = 0xff; 214 | } 215 | else if( ( threshptr[x-1] == 0xff || threshptr[prevline] == 0xff) 216 | && 217 | ( (ptr[3*x] > hsv_min.val[0] - 5 && ptr[3*x] < hsv_max.val[0] + 5) && 218 | (ptr[3*x + 1] > hsv_min.val[1] - 10 && ptr[3*x + 1] < hsv_max.val[1] + 10) && 219 | (ptr[3*x + 2] > hsv_min.val[2] - 10 && ptr[3*x + 2] < hsv_max.val[2] + 10))) 220 | { 221 | //threshold 222 | threshptr[x] = 0xff; 223 | frameptr[3*x] = 0x00; 224 | frameptr[3*x + 1] = 0x4d; 225 | frameptr[3*x + 2] = 0x4d; 226 | } 227 | else 228 | { 229 | threshptr[x] = 0x00; 230 | } 231 | } 232 | } 233 | } 234 | cvReleaseImage(&imgHSV); 235 | } 236 | 237 | 238 | 239 | IplImage* GetThresholdedImage(IplImage* imgHSV, CvScalar hsv_min, CvScalar hsv_max) 240 | { 241 | IplImage* imgThreshed = cvCreateImage(cvGetSize(imgHSV), 8, 1); 242 | cvSmooth( imgHSV, imgHSV, CV_BLUR, 5, 0, 0, 0 ); 243 | // cvInRangeS(imgHSV, hsv_min, hsv_max, imgThreshed); 244 | InRangeS(imgHSV, hsv_min, hsv_max, imgThreshed); 245 | return imgThreshed; 246 | } 247 | 248 | 249 | 250 | void getHSVRanges(IplImage * img, CvScalar *HSVranges) 251 | { 252 | 253 | IplImage * frame = 0; 254 | frame = cvCloneImage(img); 255 | cvCvtColor(frame, frame, CV_BGR2HSV); 256 | cvSetImageROI(frame, cvRect(ROISTARTX, ROISTARTY, ROIHEIGHT, ROIWIDTH)); 257 | 258 | IplImage *sub_img = cvCreateImageHeader(cvSize( ROIHEIGHT, ROIWIDTH ), frame->depth, frame->nChannels); 259 | sub_img->origin = frame->origin; 260 | sub_img->widthStep = frame->widthStep; 261 | sub_img->imageData = frame->imageData + 262 | ROISTARTY * frame->widthStep + 263 | ROISTARTX * frame->nChannels; 264 | 265 | CvScalar hsv_avg, hsv_sdv; 266 | 267 | //Get the average and standard deviation of HSV values for the recognized object 268 | cvAvgSdv(frame, &hsv_avg, &hsv_sdv, 0); 269 | 270 | 271 | int Hbuckets[256]; 272 | int Sbuckets[256]; 273 | int Vbuckets[256]; 274 | int Hbucketindex = 0; 275 | int Sbucketindex = 0; 276 | int Vbucketindex = 0; 277 | 278 | for(int i = 0; i < 256; i++) 279 | { 280 | Hbuckets[i] = 0; 281 | Sbuckets[i] = 0; 282 | Vbuckets[i] = 0; 283 | } 284 | for( int y=0; yheight; y++ ) 285 | { 286 | uchar* ptr = (uchar*) ( sub_img->imageData + y * sub_img->widthStep ); 287 | for( int x=0; xwidth; x++ ) 288 | { 289 | Hbucketindex = (int)ptr[3*x]; 290 | Hbuckets[Hbucketindex] ++; 291 | Sbucketindex = (int)ptr[3*x + 1]; 292 | Sbuckets[Sbucketindex] ++; 293 | Vbucketindex = (int)ptr[3*x + 2]; 294 | Vbuckets[Vbucketindex] ++; 295 | } 296 | } 297 | 298 | int Hmaxbucket = 0; 299 | int Hmaxval = 0; 300 | int Smaxbucket = 0; 301 | int Smaxval = 0; 302 | int Vmaxbucket = 0; 303 | int Vmaxval = 0; 304 | for(int i = 0; i < 256; i++) 305 | { 306 | // cout< Hmaxval) 308 | { 309 | Hmaxval = Hbuckets[i]; 310 | Hmaxbucket = i; 311 | } 312 | } 313 | 314 | for(int i = 0; i < 256; i++) 315 | { 316 | // cout< Smaxval) 318 | { 319 | Smaxval = Sbuckets[i]; 320 | Smaxbucket = i; 321 | } 322 | } 323 | 324 | for(int i = 0; i < 256; i++) 325 | { 326 | // cout< Vmaxval) 328 | { 329 | Vmaxval = Vbuckets[i]; 330 | Vmaxbucket = i; 331 | } 332 | } 333 | 334 | //Code to find the longest sequence of non-zero pixel values 335 | 336 | int Hseqcount = 0, Hmaxseqcount = 0; 337 | int Hindex = 0; 338 | int Hmaxindex = 0; 339 | int Hflag = 0; 340 | 341 | for(int i = 0; i < 256; i++) 342 | { 343 | if(Hbuckets[i] == 0) 344 | { 345 | if(Hflag == 0) 346 | Hflag = 1; 347 | else if(Hflag == 1) 348 | { 349 | if(Hseqcount > Hmaxseqcount) 350 | { 351 | Hmaxseqcount = Hseqcount; 352 | Hmaxindex = Hindex; 353 | 354 | } 355 | Hseqcount = 0; 356 | } 357 | } 358 | 359 | else if(Hbuckets[i] > 0) 360 | { 361 | if(Hseqcount == 0) 362 | Hindex = i; 363 | Hflag = 0; 364 | Hseqcount++; 365 | } 366 | } 367 | 368 | if(Hseqcount > Hmaxseqcount) 369 | { 370 | Hmaxseqcount = Hseqcount; 371 | Hmaxindex = Hindex; 372 | 373 | } 374 | int Hrangestart = Hmaxindex; 375 | int Hrangeend = Hmaxindex + Hmaxseqcount; 376 | // cout<<"HStart : "< Hmaxrangebucket) 401 | { 402 | Hmaxrangebucket = Hrangebuckets[i]; 403 | Hmaxrangestart = i; 404 | } 405 | } 406 | 407 | 408 | 409 | 410 | int Sseqcount = 0, Smaxseqcount = 0; 411 | int Sindex = 0; 412 | int Smaxindex = 0; 413 | int Sflag = 0; 414 | for(int i = 0; i < 256; i++) 415 | { 416 | if(Sbuckets[i] == 0) 417 | { 418 | if(Sflag == 0) 419 | { 420 | Sflag = 1; 421 | } 422 | else if(Sflag == 1) 423 | { 424 | if(Sseqcount > Smaxseqcount) 425 | { 426 | Smaxseqcount = Sseqcount; 427 | Smaxindex = Sindex; 428 | 429 | } 430 | Sseqcount = 0; 431 | } 432 | } 433 | 434 | else if(Sbuckets[i] > 0) 435 | { 436 | if(Sseqcount == 0) 437 | { 438 | Sindex = i; 439 | } 440 | Sflag = 0; 441 | Sseqcount++; 442 | } 443 | } 444 | 445 | if(Sseqcount > Smaxseqcount) 446 | { 447 | Smaxseqcount = Sseqcount; 448 | Smaxindex = Sindex; 449 | 450 | } 451 | 452 | int Srangestart = Smaxindex; 453 | int Srangeend = Smaxindex + Smaxseqcount; 454 | // cout<<"SStart : "< Smaxrangebucket) 479 | { 480 | Smaxrangebucket = Srangebuckets[i]; 481 | Smaxrangestart = i; 482 | } 483 | } 484 | 485 | int Vseqcount = 0, Vmaxseqcount = 0; 486 | int Vindex = 0; 487 | int Vmaxindex = 0; 488 | int Vflag = 0; 489 | for(int i = 0; i < 256; i++) 490 | { 491 | if(Vbuckets[i] == 0) 492 | { 493 | if(Vflag == 0) 494 | Vflag = 1; 495 | else if(Vflag == 1) 496 | { 497 | if(Vseqcount > Vmaxseqcount) 498 | { 499 | Vmaxseqcount = Vseqcount; 500 | Vmaxindex = Vindex; 501 | } 502 | Vseqcount = 0; 503 | } 504 | } 505 | 506 | else if(Vbuckets[i] > 0) 507 | { 508 | if(Vseqcount == 0) 509 | Vindex = i; 510 | Vflag = 0; 511 | Vseqcount++; 512 | } 513 | } 514 | 515 | if(Vseqcount > Vmaxseqcount) 516 | { 517 | Vmaxseqcount = Vseqcount; 518 | Vmaxindex = Vindex; 519 | } 520 | 521 | int Vrangestart = Vmaxindex; 522 | int Vrangeend = Vmaxindex + Vmaxseqcount; 523 | // cout<<"VStart : "< Vmaxrangebucket) 548 | { 549 | Vmaxrangebucket = Vrangebuckets[i]; 550 | Vmaxrangestart = i; 551 | } 552 | } 553 | 554 | cvResetImageROI(frame); 555 | double avg_val[4], sdv_val[4]; 556 | for(int i = 0; i < 4; i++) 557 | { 558 | avg_val[i] = hsv_avg.val[i]; 559 | sdv_val[i] = hsv_sdv.val[i]; 560 | } 561 | 562 | // Values 20,100,100 to 30,255,255 working perfect for ping pong ball at around 6pm 563 | //Set min and max values for the object to be tracked 564 | double min[4]; 565 | min[0] = Hrangestart; //*/avg_val[0] - hsv_sdv.val[0]; 566 | min[1] = Srangestart;// - 50; //*/avg_val[1] - hsv_sdv.val[1] -50; 567 | min[2] = Vrangestart;// - 25; //*/avg_val[2] - hsv_sdv.val[2] - 50; 568 | min[3] = avg_val[3] - hsv_sdv.val[3]; 569 | if(min[1] < 0) 570 | min[1] = 0.00; 571 | if(min[2] < 0) 572 | min[2] = 0.00; 573 | 574 | 575 | 576 | HSVranges[0] = cvScalar( min[0], min[1], min[2], min[3] ); 577 | // CvScalar hsv_min = cvScalar( 0, 200, 200, 0 ); 578 | 579 | 580 | double max[4]; 581 | max[0] = Hrangeend; //*/avg_val[0] + hsv_sdv.val[0]; 582 | max[1] = 255;//Srangeend;// + 50; //*/avg_val[1] + hsv_sdv.val[1] + 50; 583 | max[2] = 255;//Vrangeend;// + 50; //*/avg_val[2] + hsv_sdv.val[2] + 50; 584 | max[3] = avg_val[3] + hsv_sdv.val[3]; 585 | if(max[1] > 255) 586 | max[1] = 255.00; 587 | if(max[2] > 255) 588 | max[2] = 255.00; 589 | HSVranges[1] = cvScalar( max[0], max[1], max[2], max[3] ); 590 | 591 | } 592 | 593 | 594 | 595 | int main(int argc, char** argv) 596 | { 597 | CvCapture* capture = 0; 598 | capture = cvCaptureFromCAM(0); 599 | 600 | 601 | 602 | int framecount = 0; 603 | 604 | if(!capture) 605 | { 606 | printf("Could not start capturing from camera...\n"); 607 | return -1; 608 | } 609 | 610 | int choice; 611 | 612 | if(argv[1][1] == 'm') 613 | choice = 1; 614 | else if(argv[1][1] == 'k') 615 | choice = 2; 616 | else 617 | { 618 | choice = 1; 619 | //cout<<"Usage: track -m|-k"<>keyflag; 627 | if(choice == 1) 628 | cout<<"Starting mouse control"< -3)) && 699 | (((posY - pos[(curtop + 8)%10].y) < 3) && ((posY - pos[(curtop + 8)%10].y) > -3)) && 700 | (((posX - pos[(curtop + 7)%10].x) < 3) && ((posX - pos[(curtop + 7)%10].x) > -3)) && 701 | (((posY - pos[(curtop + 7)%10].y) < 3) && ((posY - pos[(curtop + 7)%10].y) > -3)) && 702 | (((posX - pos[(curtop + 6)%10].x) < 3) && ((posX - pos[(curtop + 6)%10].x) > -3)) && 703 | (((posY - pos[(curtop + 6)%10].y) < 3) && ((posY - pos[(curtop + 6)%10].y) > -3)) 704 | ) 705 | { 706 | posflag = 1; 707 | } 708 | 709 | 710 | 711 | if(posX <= 0) 712 | posX = lastX; 713 | if(posY <= 0) 714 | posY = lastY; 715 | 716 | 717 | char command[50], clickcmd[50]; 718 | 719 | //Code to emulate mouse click by hitting Space 720 | // ch = cvWaitKey(1); 721 | // if(ch == ' ') 722 | // strcpy(clickcmd,"xdotool mousedown 1"); 723 | // else 724 | // strcpy(clickcmd,"xdotool mouseup 1"); 725 | 726 | cvDestroyAllWindows(); 727 | //The below sprintf is to be used if running in linux. You need to install a utility called xdotool to use this 728 | //sprintf(command, "xdotool mousemove %d %d", (int)posX*2, (int) (posY*1.66)); //converting 640x480 into 1280x800 729 | 730 | 731 | if(choice == 1 ) 732 | { 733 | //Comment the below if condition to disable physical mouse control. 734 | if(posflag == 0) 735 | //system(command); 736 | SetCursorPos((int)posX*2, (int) (posY * 1.66)); 737 | } 738 | else 739 | { 740 | int count = 0; 741 | 742 | //Convert object positions into directions, and emulate the appropriate direction key 743 | left = 0, right = 0, up = 0, down = 0; 744 | if(posX > 250 && posX < 390 ) 745 | { 746 | count ++; 747 | left = right = 0; 748 | system("xdotool keyup Left"); 749 | system("xdotool keyup Down"); 750 | } 751 | else if( posX < 250 ) 752 | { 753 | count ++; 754 | left = 1; 755 | system("xdotool keyup Right"); 756 | if(keyflag == 0) 757 | system("xdotool keydown Left"); 758 | else 759 | system("xdotool key Left"); 760 | } 761 | else if( posX > 390 ) 762 | { 763 | count ++; 764 | right = 1; 765 | system("xdotool keyup Left"); 766 | if(keyflag == 0) 767 | system("xdotool keydown Right"); 768 | else 769 | system("xdotool key Right"); 770 | } 771 | 772 | 773 | if( posY > 190 && posY < 270 ) 774 | { 775 | count ++; 776 | up = down = 0; 777 | system("xdotool keyup Down"); 778 | system("xdotool keyup Up"); 779 | } 780 | else if( posY < 190 ) 781 | { 782 | count ++; 783 | up = 1; 784 | system("xdotool keyup Down"); 785 | if(keyflag == 0) 786 | system("xdotool keydown Up"); 787 | else 788 | system("xdotool key Up"); 789 | } 790 | else if( posY > 270 ) 791 | { 792 | count ++; 793 | down = 1; 794 | system("xdotool keyup Up"); 795 | if(keyflag == 0) 796 | system("xdotool keydown Down"); 797 | else 798 | system("xdotool key Down"); 799 | } 800 | 801 | cout<<"up = "<