Advertisement
Guest User

Untitled

a guest
Jan 8th, 2020
849
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.25 KB | None | 0 0
  1. #include <opencv/highgui.h>
  2. #include <opencv/cv.h>
  3. #include <cstdlib>
  4. #include <stdio.h>
  5. #include <opencv/cxcore.h>
  6. #include <X11/extensions/XTest.h>
  7.  
  8.  
  9. /*---------------------------------------------------------------------*
  10.  * Structure permettant de stocker des informations sur la trajectoire *
  11.  *---------------------------------------------------------------------*/
  12. typedef struct myPoint
  13. {
  14.   CvPoint myTarget;
  15.   myPoint *prevPoint;
  16.   myPoint *nextPoint;
  17.   int nFingers;
  18.   int rank;
  19. } myPoint;
  20.  
  21. /*--------------------------------------------------------------------------*
  22.  * Fonction permettant d'executer cvEqualizeHist() sur une image à 3 canaux *
  23.  *--------------------------------------------------------------------------*/
  24. void autoEqualize(IplImage *imgIN, IplImage *imgOUT)
  25. {
  26.   IplImage *imgB=cvCreateImage(cvGetSize(imgIN), imgIN->depth, 0);
  27.   IplImage *imgG=cvCloneImage(imgB);
  28.   IplImage *imgR=cvCloneImage(imgB);
  29.    
  30.   cvSplit(imgIN, imgB, imgG, imgR, NULL);
  31.   cvEqualizeHist(imgB, imgB);
  32.   cvEqualizeHist(imgG, imgG);
  33.   cvEqualizeHist(imgR, imgR);
  34.   cvMerge(imgB, imgG, imgR, NULL, imgOUT);
  35.  
  36.   cvReleaseImage(&imgB);
  37.   cvReleaseImage(&imgG);
  38.   cvReleaseImage(&imgR);
  39. }
  40.  
  41. /*-------------------------------------------*
  42.  * Fonction permettant de capturer une frame *
  43.  *-------------------------------------------*/
  44. IplImage *getFrame(CvCapture *capture)
  45. {
  46.   IplImage *img;
  47.   int flip=0;
  48.  
  49.   cvGrabFrame(capture);
  50.   img=cvRetrieveFrame(capture);
  51.   if(img->origin!=IPL_ORIGIN_TL) flip=CV_CVTIMG_FLIP;
  52.   cvConvertImage(img, img, flip);
  53.  
  54.   return img;
  55. }
  56.  
  57. /*--------------------------------------------------------------------*
  58.  * Fonction segmentant une image par sous-échantillonnage chromatique *
  59.  *--------------------------------------------------------------------*/
  60. void mySegmentation(IplImage *imgIN, IplImage *imgOUT, double factor)
  61. {
  62.   IplImage *imgTMP=cvCloneImage(imgIN);
  63.   IplImage *imgBIN=cvCreateImage(cvGetSize(imgIN), imgIN->depth, 0);
  64.   IplImage *imgG=cvCreateImage(cvGetSize(imgIN), imgIN->depth, 0);
  65.   IplImage *imgR=cvCloneImage(imgG);
  66.   IplImage *imgB=cvCloneImage(imgG);
  67.  
  68.   //Sous-échantillonnage
  69.   cvConvertScale(imgTMP, imgTMP, 1/factor);
  70.   cvConvertScale(imgTMP, imgTMP, factor);
  71.  
  72.   //Suppression des zones blanches par soustraction du canal vert au canal rouge (Utilisation d'un masque)
  73.   cvConvertImage(imgTMP, imgBIN);
  74.   cvThreshold(imgBIN, imgBIN, 250, 1, CV_THRESH_BINARY_INV);
  75.   cvSplit(imgTMP, imgB, imgG, imgR, NULL);
  76.   cvSub(imgR, imgG, imgBIN, imgBIN);
  77.   cvThreshold(imgBIN, imgBIN, 1, 255, CV_THRESH_BINARY);
  78.  
  79.   //Traitement final
  80.   cvSmooth(imgBIN, imgBIN, CV_MEDIAN, 3);  
  81.   cvDilate(imgBIN, imgBIN);  
  82.   cvCopy(imgBIN, imgOUT);
  83.  
  84.   cvReleaseImage(&imgTMP);
  85.   cvReleaseImage(&imgBIN);
  86.   cvReleaseImage(&imgG);
  87.   cvReleaseImage(&imgR);
  88.   cvReleaseImage(&imgB);
  89. }
  90.  
  91. /*----------------------------------------------------------------*
  92.  * Fonction determinant le plus petit CvRect encadrant un contour *
  93.  *----------------------------------------------------------------*/
  94. CvRect myMinAreaRect(CvSeq *seqContour)
  95. {
  96.   CvPoint arrContour[seqContour->total];
  97.   cvCvtSeqToArray(seqContour, arrContour, CV_WHOLE_SEQ);
  98.   int Xmax, Xmin, Ymax, Ymin;
  99.   CvRect myRect;
  100.  
  101.   Xmax=arrContour[0].x;
  102.   Ymax=arrContour[0].y;
  103.   Xmin=Xmax;
  104.   Ymin=Ymax;
  105.  
  106.   for(int i=1; i<seqContour->total; i++)
  107.   {
  108.     if(arrContour[i].x>Xmax) Xmax=arrContour[i].x;
  109.     if(arrContour[i].x<Xmin) Xmin=arrContour[i].x;
  110.     if(arrContour[i].y>Ymax) Ymax=arrContour[i].y;
  111.     if(arrContour[i].y<Ymin) Ymin=arrContour[i].y;
  112.   }
  113.  
  114.   myRect.x=Xmin-10;
  115.   myRect.y=Ymin-10;
  116.   myRect.width=Xmax-Xmin+20;
  117.   myRect.height=Ymax-Ymin+20;
  118.    
  119.   return myRect;
  120. }
  121.  
  122. /*----------------------------------------------------------*
  123.  * Fonction retournant le point "le plus haut" d'un contour *
  124.  *----------------------------------------------------------*/
  125. CvPoint myTarget(CvPoint *poly, int total)
  126. {
  127.   CvPoint pt=poly[0];
  128.   for(int i=1; i<total; i++) if(poly[i].y<pt.y) pt=poly[i];
  129.  
  130.   return pt;
  131. }
  132.  
  133. /*----------------------------------------------------*
  134.  * Fonction calculant l'angle forme par deux vecteurs *
  135.  *----------------------------------------------------*/
  136. double getAngle(CvPoint U, CvPoint V)
  137. {
  138.   double angle=acos((U.x*V.x+U.y*V.y)/(sqrt(U.x*U.x+U.y*U.y)*sqrt(V.x*V.x+V.y*V.y)));
  139.   return angle;
  140. }
  141.  
  142. void myTrajectoryReset(myPoint *traj, int nPt, int N)
  143. {
  144.   for(int i=0; i<nPt; i++) traj[i].myTarget=traj[N].myTarget;
  145. }
  146.  
  147. void myFingerReset(myPoint *traj, int nPt)
  148. {
  149.   for(int i=0; i<nPt; i++) traj[i].nFingers=3;
  150. }
  151.  
  152. /*---------------------------------------------------*
  153.  * Fonction caculant le determinant de deux vecteurs *
  154.  *---------------------------------------------------*/
  155. double getDet(CvPoint U, CvPoint V)
  156. {
  157.   double det=U.x*V.y-U.y*V.x;
  158.   return det;
  159. }
  160.  
  161. void myNext()
  162. {
  163.   Display *dpy = XOpenDisplay(NULL);
  164.  
  165.   XTestFakeKeyEvent(dpy, 114, true, CurrentTime);
  166.   XTestFakeKeyEvent(dpy, 114, false, CurrentTime);
  167.   XCloseDisplay(dpy);
  168. }
  169.  
  170. void myPrev()
  171. {
  172.   Display *dpy = XOpenDisplay(NULL);
  173.  
  174.   XTestFakeKeyEvent(dpy, 113, true, CurrentTime);
  175.   XTestFakeKeyEvent(dpy, 113, false, CurrentTime);
  176.   XCloseDisplay(dpy);
  177. }
  178.  
  179. void myUp()
  180. {
  181.   Display *dpy = XOpenDisplay(NULL);
  182.  
  183.   XTestFakeKeyEvent(dpy, 111, true, CurrentTime);
  184.   XTestFakeKeyEvent(dpy, 111, false, CurrentTime);
  185.   XCloseDisplay(dpy);
  186. }
  187.  
  188. void myDown()
  189. {
  190.   Display *dpy = XOpenDisplay(NULL);
  191.  
  192.   XTestFakeKeyEvent(dpy, 116, true, CurrentTime);
  193.   XTestFakeKeyEvent(dpy, 116, false, CurrentTime);
  194.   XCloseDisplay(dpy);
  195. }
  196.  
  197. void myValid()
  198. {
  199.   Display *dpy = XOpenDisplay(NULL);
  200.  
  201.   XTestFakeKeyEvent(dpy, 36, true, CurrentTime);
  202.   XTestFakeKeyEvent(dpy, 36, false, CurrentTime);
  203.   XCloseDisplay(dpy);
  204. }
  205.  
  206. void myBack()
  207. {
  208.   Display *dpy = XOpenDisplay(NULL);
  209.  
  210.   XTestFakeKeyEvent(dpy, 36, true, CurrentTime);
  211.   XTestFakeKeyEvent(dpy, 36, false, CurrentTime);
  212.   XTestFakeKeyEvent(dpy, 27, true, CurrentTime);
  213.   XTestFakeKeyEvent(dpy, 27, false, CurrentTime);
  214.   XCloseDisplay(dpy);
  215. }
  216.  
  217. void myLock()
  218. {
  219.   Display *dpy = XOpenDisplay(NULL);
  220.  
  221.   XTestFakeKeyEvent(dpy, 55, true, CurrentTime);
  222.   XTestFakeKeyEvent(dpy, 55, false, CurrentTime);
  223.   XCloseDisplay(dpy);
  224. }
  225.  
  226. void myUnlock()
  227. {
  228.   Display *dpy = XOpenDisplay(NULL);
  229.  
  230.   XTestFakeKeyEvent(dpy, 40, true, CurrentTime);
  231.   XTestFakeKeyEvent(dpy, 40, false, CurrentTime);
  232.   XCloseDisplay(dpy);
  233. }
  234.  
  235.  
  236. /*------------------------------*
  237.  * Debut du programme principal *
  238.  *------------------------------*/
  239. int main()
  240. {
  241. //----------[Initialisation des variables]----------
  242.   CvCapture *capture=cvCreateCameraCapture(-1);
  243.   IplImage *imgIN=getFrame(capture);
  244.   IplImage *imgBIN=cvCreateImage(cvGetSize(imgIN), imgIN->depth, 0);
  245.   IplImage *imgTMP=cvCloneImage(imgBIN);
  246.  
  247.   CvSeq *seqContour, *handContour, *seqApprox;
  248.   int nContours, area, tmpVar, nFingers, approxSize, nPt, moveLength, threshold;
  249.   nPt=16;
  250.   bool lock;
  251.   lock=1;
  252.   threshold=295;
  253.   myPoint myTrajectory[nPt], *currentPt;
  254.   double angle, det;
  255.   CvPoint U, V, myFinger;
  256.   CvRect myRect;
  257.   CvMemStorage *stor0=cvCreateMemStorage(0);
  258.   CvMemStorage *stor1=cvCreateMemStorage(0);
  259.   CvFont font;
  260.   char text[5];
  261.   cvInitFont(&font , CV_FONT_HERSHEY_SIMPLEX, .5, .5, 0.0, 1);
  262.   char key='\0';
  263.  
  264.   cvNamedWindow("BiNARY", CV_WINDOW_AUTOSIZE);
  265.  
  266.  
  267.  
  268.  
  269. //----------[Initialisation de la liste chainée de trajectoire]----------
  270.   for(int i=0; i<nPt; i++)
  271.   {
  272.     myTrajectory[i].nextPoint=&myTrajectory[(i+1)%nPt];
  273.     myTrajectory[i].rank=i;
  274.     myTrajectory[i].prevPoint=&myTrajectory[(i-1)%nPt];
  275.     myTrajectory[i].nFingers=0;
  276.   }
  277.   currentPt=&myTrajectory[nPt-1];               //Pointeur qui permettra d'enregistrer les infos sur la trajectoire
  278.  
  279.  
  280.  
  281.   while(key!='q')
  282.   {
  283.     if(key==81) threshold-=5;               //Fleche gauche : diminiue le seuil de segmentation
  284.     else if(key==83) threshold+=5;              //Fleche droite : augmente le seuil de segmentation
  285.    
  286.    
  287. //----------[Chargement d'une image]----------
  288.     imgIN=getFrame(capture);
  289.  
  290.    
  291.    
  292. //----------[Segmentation]----------
  293.     mySegmentation(imgIN, imgBIN, threshold);
  294.  
  295.    
  296.    
  297. //----------[Détection des contours]----------
  298.     cvCopy(imgBIN, imgTMP);
  299.     nContours=cvFindContours(imgTMP, stor0, &seqContour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
  300.     if(nContours>0)
  301.     {
  302.       area=tmpVar=0;
  303.       for(int i=0; i<nContours; i++)        //Determination du contour ayant l'aire la plus grande
  304.       {
  305.     tmpVar=abs(cvContourArea(seqContour));
  306.     if(tmpVar>area)
  307.     {
  308.       area=tmpVar;
  309.       handContour=seqContour;
  310.     }
  311.     seqContour=seqContour->h_next;
  312.       }
  313.  
  314.  
  315.  
  316. //----------[Sélection de la zone d'intérêt]----------
  317.       myRect=myMinAreaRect(handContour);
  318.       cvSetImageROI(imgBIN, myRect);
  319.       IplImage *imgROI_SEG=cvCreateImage(cvGetSize(imgBIN), IPL_DEPTH_8U, imgBIN->nChannels);
  320.       cvCopy(imgBIN, imgROI_SEG);
  321.       cvResetImageROI(imgBIN);
  322.      
  323.  
  324.  
  325. //----------[Détection des contours de la région d'intérêt]----------
  326.       IplImage *imgROI_TMP=cvCloneImage(imgROI_SEG);
  327.       cvClearMemStorage(stor0);
  328.       //On peut insérer ici un nouvel algorithme de segmentation plus fin
  329.       nContours=cvFindContours(imgROI_TMP, stor0, &seqContour, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
  330.       if(nContours>0)
  331.       {
  332.     area=tmpVar=0;
  333.     for(int i=0; i<nContours; i++)          //Selection du contour ayant la plus grande aire
  334.     {
  335.       tmpVar=abs(cvContourArea(seqContour));
  336.       if(tmpVar>area)
  337.       {
  338.         area=tmpVar;
  339.         handContour=seqContour;
  340.       }
  341.       seqContour=seqContour->h_next;
  342.     }
  343.    
  344. //  printf("%d\n", area);
  345.  
  346.     if(area>1000)
  347.     {
  348. //----------[Approche polygonale du contour précédent]----------
  349.       seqApprox=cvApproxPoly(handContour, sizeof(CvContour), stor1, CV_POLY_APPROX_DP, 9, 0);
  350.       if(seqApprox->total>0)
  351.       {
  352.         CvPoint arrTmp[seqApprox->total];
  353.         CvPoint arrApprox[seqApprox->total];
  354.         cvCvtSeqToArray(seqApprox, arrTmp, CV_WHOLE_SEQ);
  355.  
  356.         approxSize=seqApprox->total;
  357.         int j=0;
  358.         int k=0;
  359.         for(int i=0;i<approxSize;i++)
  360.         {
  361.           U.x=arrTmp[(i+1)%approxSize].x-arrTmp[i].x;
  362.           U.y=arrTmp[(i+1)%approxSize].y-arrTmp[i].y;  
  363.          
  364.           if(sqrt(U.x*U.x+U.y*U.y)>15)          //Suppression des sommets "trop proches"
  365.           {                         //afin d'obtenir des angles aigues au niveau des doigts
  366.         arrApprox[j]=arrTmp[i];
  367.         j++;
  368.           }
  369.           else { cvSeqRemove(seqApprox,i-k); k++; }
  370.         }
  371.        
  372.         if(seqApprox->total>0)
  373.         {
  374.           cvSetImageROI(imgIN, myRect);
  375.  
  376.          
  377.  
  378. //----------[Détection des doigts]----------
  379.           nFingers=0;
  380.           for(int i=0; i<seqApprox->total; i++)
  381.           {
  382.         U.x=arrApprox[(i+1)%seqApprox->total].x-arrApprox[i].x;
  383.         U.y=arrApprox[(i+1)%seqApprox->total].y-arrApprox[i].y;
  384.         V.x=arrApprox[(i+2)%seqApprox->total].x-arrApprox[(i+1)%seqApprox->total].x;
  385.         V.y=arrApprox[(i+2)%seqApprox->total].y-arrApprox[(i+1)%seqApprox->total].y;
  386.        
  387.         angle=getAngle(U, V);                   //Calcul de l'angle et du déterminant de chaque sommet
  388.         det=getDet(U, V);
  389.         myFinger=arrApprox[(i+1)%seqApprox->total];
  390.  
  391.         if(angle>2.0 && det<0 && myFinger.y<myRect.width*2/3)   //Sélection des doigts
  392.         {
  393.           cvCircle(imgIN, myFinger, 8, cvScalar(255,0,0), 2);
  394.           nFingers++;
  395.         }      
  396.           }
  397.           (*currentPt).nFingers=nFingers;
  398.           (*currentPt).myTarget=myTarget(arrApprox, seqApprox->total);
  399.  
  400.           cvResetImageROI(imgIN);
  401.          
  402.           ((*currentPt).myTarget).x+=myRect.x;
  403.           ((*currentPt).myTarget).y+=myRect.y;
  404.          
  405.  
  406. //----------[Traitement de la trajectoire]----------
  407.           for(int i=0; i<nPt; i++)          //Barre vert représentant la projection de la trajectoire sur X
  408.           {
  409.         U=myTrajectory[i].myTarget;
  410.         V=myTrajectory[(i+1)%nPt].myTarget;
  411.           }
  412.                
  413.           tmpVar=(*currentPt).rank;         //Calcul de la longueur de la trajectoire projettee
  414.           U=myTrajectory[tmpVar].myTarget;
  415.           V=myTrajectory[(tmpVar+1)%nPt].myTarget;
  416.           U.x=U.x-V.x;
  417.           U.y=U.y-V.y;
  418.           moveLength=sqrt(U.x*U.x+U.y*U.y);
  419.          
  420.          
  421.          
  422. //----------[LOCK/UNLOCK]----------
  423.           if(moveLength<5)                  //Si la mouvement n'excede pas 5 pixel...
  424.           {
  425.         tmpVar=0;
  426.         for(int i=0; i<nPt; i++) tmpVar+=myTrajectory[i].nFingers;
  427.         if(tmpVar==nPt*5 && lock) { lock=0; myUnlock(); myFingerReset(myTrajectory, nPt); }     //... et qu'on detecte bien 5 doigts pendant nPt frames : "on déverouille"
  428.         else if(tmpVar==0 && !lock) { lock=1; myLock(); myFingerReset(myTrajectory, nPt); }     //... et qu'on ne detecte aucun doigts pendant nPt frames : "on vérouille"
  429.           }
  430.          
  431.          
  432.          
  433.           if(!lock)                     //Si on est déverouille...
  434.           {
  435. //----------[VALID/RETOUR]----------
  436.         if(moveLength<5)                    //Si la mouvement n'excede pas 5 pixel...
  437.         {
  438.           tmpVar=0;
  439.           for(int i=0; i<nPt; i++) tmpVar+=myTrajectory[i].nFingers;
  440.           if(tmpVar==nPt*2) { myBack(); myFingerReset(myTrajectory, nPt); }
  441.           else if(tmpVar==nPt*5) { myValid(); myFingerReset(myTrajectory, nPt); }
  442.         }      
  443.        
  444.        
  445. //----------[MORE/LESS]----------
  446.         tmpVar=1;
  447.         for(int i=0; i<nPt; i++) tmpVar*=(myTrajectory[i].nFingers==1);     //... et qu'on détecte qu'un seul doigts sur nPt frames
  448.         if(tmpVar==1)
  449.         {
  450.           if(((*currentPt).myTarget).x-myRect.x>myRect.width/4) { myUp(); } //... et que le doigt est à droite alors : "on augmente"
  451.           else if(((*currentPt).myTarget).x-myRect.x<myRect.width/4) { myDown(); } // et que le doigt est à gauche alors : "on diminiue"
  452.         }
  453.        
  454.        
  455. //----------[NEXT/PREV]----------
  456.             tmpVar=(*currentPt).rank;
  457.         U=myTrajectory[tmpVar].myTarget;
  458.         V=myTrajectory[(tmpVar+nPt-5)%nPt].myTarget;                //Sélection de la longueur de trajectoire sur 5 frames
  459.         moveLength=U.x-V.x;
  460.        
  461.         if(abs(moveLength)>imgIN->width/3)                  //Si le mouvement est supérieur à 1/4 de l'ecran...
  462.         {
  463.           if(moveLength<0) { myPrev(); }            //... et que le mouvement va de droite à gauche alors : "precedent"
  464.           else { myNext(); }                    //... et que le mouvement va de gauche à droite alors : "suivant"
  465.           myTrajectoryReset(myTrajectory, nPt, tmpVar);
  466.         }
  467.        
  468.        
  469. //----------[UP/DOWN]----------
  470.             tmpVar=(*currentPt).rank;
  471.         U=myTrajectory[tmpVar].myTarget;
  472.         V=myTrajectory[(tmpVar+nPt-7)%nPt].myTarget;                //Sélection de la longueur de trajectoire sur 5 frames
  473.         moveLength=U.y-V.y;
  474.        
  475.         if(abs(moveLength)>imgIN->width/5)                  //Si le mouvement est supérieur à 1/4 de l'ecran...
  476.         {
  477.           if(moveLength<0) { myUp(); }          //... et que le mouvement va de droite à gauche alors : "precedent"
  478.           else { myDown(); }                    //... et que le mouvement va de gauche à droite alors : "suivant"
  479.           myTrajectoryReset(myTrajectory, nPt, tmpVar);
  480.         }
  481.           }
  482.         }
  483.       }
  484.     }
  485.    
  486.     else
  487.     {
  488.       tmpVar=(*currentPt).rank;
  489.       myTrajectoryReset(myTrajectory, nPt, tmpVar);
  490.     }
  491.     currentPt=(*currentPt).nextPoint;                       //On pointe sur l'élement suivant de la liste chainée
  492.    
  493.       }      
  494.      
  495. //----------[Libération de la mémoire]----------
  496.       cvReleaseImage(&imgROI_SEG);
  497.       cvReleaseImage(&imgROI_TMP);
  498.     }
  499.    
  500. //----------[Mise en forme de l'image à afficher]----------
  501.     myRect.x=0;
  502.     myRect.y=0;
  503.     myRect.width=200;
  504.     myRect.height=75;
  505.     cvSetImageROI(imgBIN, myRect);
  506. //     cvFillImage(imgBIN, 50);
  507.     cvRectangle(imgBIN, cvPoint(0,0), cvPoint(myRect.width-1, myRect.height-1), cvScalar(255), 2);
  508.    
  509.     cvPutText(imgBIN, "THRESHOLD :", cvPoint(10, 25), &font, cvScalar(255, 255, 255));
  510.     sprintf(text, "%d", threshold);
  511.     cvPutText(imgBIN, text, cvPoint(120, 25), &font, cvScalar(255, 255, 255));
  512.    
  513.     cvPutText(imgBIN, "LOCK :", cvPoint(10, 50), &font, cvScalar(255, 255, 255));
  514.     sprintf(text, "%d", lock);
  515.     cvPutText(imgBIN, text, cvPoint(120, 50), &font, cvScalar(255, 255, 255));
  516.    
  517.     cvResetImageROI(imgBIN);
  518.    
  519.    
  520.     cvShowImage("BiNARY", imgBIN);
  521.  
  522.    
  523.     cvClearMemStorage(stor0);
  524.     cvClearMemStorage(stor1);
  525.    
  526.     key=cvWaitKey(10);
  527.   }
  528.    
  529.   cvDestroyAllWindows();
  530.  
  531.   cvReleaseCapture(&capture);
  532.   cvReleaseImage(&imgIN);
  533.   cvReleaseImage(&imgBIN);
  534.   cvReleaseImage(&imgTMP);
  535.   cvClearMemStorage(stor0);
  536.   cvReleaseMemStorage(&stor0);
  537.   cvClearMemStorage(stor1);
  538.   cvReleaseMemStorage(&stor1);
  539.  
  540.   return 0;
  541. }
  542.  
  543. // clear && g++ cam29bis.cpp -o cam29bis -lcv -lhighgui -lXtst -Wall && ./cam29bis
  544. // xmodmap -pke
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement