2013-07-03 1 views
1

J'ai essayé de développer un programme simple de suivi des caractéristiques. L'utilisateur trace une zone sur l'écran avec sa souris, et un masque est créé pour cette zone et transmis à goodFeaturesToTrack. Les entités trouvées par la fonction sont ensuite dessinées sur l'écran (représentées par des cercles bleus).Suivi d'inactivité lors du dessin du vecteur de caractéristiques en sortie de calcOpticalFlow

Ensuite, je passe le vecteur de fonction retourné par la fonction à calcOpticalFlowPyrLk et dessine le vecteur de points résultant sur l'écran (représenté par des cercles verts). Bien que le programme suive correctement la direction du flux, les fonctions fournies par la fonction calcOpticalFlow ne sont pas alignées avec l'emplacement de l'objet sur l'écran. J'ai l'impression que c'est une petite erreur dans la logique que j'ai utilisée de ma part, mais je ne peux pas sembler la décomposer, et j'apprécierais vraiment l'aide de vous.

J'ai posté mon code ci-dessous, et je voudrais m'excuser grandement pour les variables globales et la structure désordonnée. Je ne fais que tester en ce moment, et je prévois de nettoyer et de convertir en format OOP dès que je l'aurai lancé.

De plus, voici un link pour une vidéo YouTube que j'ai téléchargée et qui démontre le comportement que je combats.

bool drawingBox = false; 
bool destroyBox = false; 
bool targetAcquired = false; 
bool featuresFound = false; 
CvRect box; 
int boxCounter = 0; 
cv::Point objectLocation; 
cv::Mat prevFrame, nextFrame, prevFrame_1C, nextFrame_1C; 
std::vector<cv::Point2f> originalFeatures, newFeatures, baseFeatures; 
std::vector<uchar> opticalFlowFeatures; 
std::vector<float> opticalFlowFeaturesError; 
cv::TermCriteria opticalFlowTermination = cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.3); 
cv::Mat mask; 
cv::Mat clearMask; 

long currentFrame = 0; 

void draw(cv::Mat image, CvRect rectangle) 
{ 

    if (drawingBox) 
    { 
     cv::rectangle(image, cv::Point(box.x, box.y), cv::Point(box.x + box.width, box.y + box.height), cv::Scalar(225, 238 , 81), 2); 
     CvRect rectangle2 = cvRect(box.x, box.y, box.width, box.height); 
    } 

    if (featuresFound) 
    { 
     for (int i = 0; i < originalFeatures.size(); i++) 
     { 
      cv::circle(image, baseFeatures[i], 4, cv::Scalar(255, 0, 0), 1, 8, 0); 
      cv::circle(image, newFeatures[i], 4, cv::Scalar(0, 255, 0),1, 8, 0); 
      cv::line(image, baseFeatures[i], newFeatures[i], cv::Scalar(255, 0, 0), 2, CV_AA); 
     } 
    } 
} 

void findFeatures(cv::Mat mask) 
{ 
    if (!featuresFound && targetAcquired) 
    { 
     cv::goodFeaturesToTrack(prevFrame_1C, baseFeatures, 200, 0.1, 0.1, mask); 
     originalFeatures= baseFeatures; 
     featuresFound = true; 
     std::cout << "Number of Corners Detected: " << originalFeatures.size() << std::endl; 

     for(int i = 0; i < originalFeatures.size(); i++) 
     { 
      std::cout << "Corner Location " << i << ": " << originalFeatures[i].x << "," << originalFeatures[i].y << std::endl; 
     } 
    } 
} 


void trackFeatures() 
{ 
    cv::calcOpticalFlowPyrLK(prevFrame_1C, nextFrame_1C, originalFeatures, newFeatures, opticalFlowFeatures, opticalFlowFeaturesError, cv::Size(30,30), 5, opticalFlowTermination); 
    originalFeatures = newFeatures; 

} 

void mouseCallback(int event, int x, int y, int flags, void *param) 
{ 
    cv::Mat frame; 
    frame = *((cv::Mat*)param); 

    switch(event) 
    { 
    case CV_EVENT_MOUSEMOVE: 
     { 
      if(drawingBox) 
      { 
       box.width = x-box.x; 
       box.height = y-box.y; 
      } 
     } 
     break; 

    case CV_EVENT_LBUTTONDOWN: 
     { 
      drawingBox = true; 
      box = cvRect (x, y, 0, 0); 
      targetAcquired = false; 
      cv::destroyWindow("Selection"); 
     } 
     break; 

    case CV_EVENT_LBUTTONUP: 
     { 
      drawingBox = false; 
      featuresFound = false; 
      boxCounter++; 
      std::cout << "Box " << boxCounter << std::endl; 
      std::cout << "Box Coordinates: " << box.x << "," << box.y << std::endl; 
      std::cout << "Box Height: " << box.height << std::endl; 
      std::cout << "Box Width: " << box.width << std:: endl << std::endl; 

      if(box.width < 0) 
      { 
       box.x += box.width; 
       box.width *= -1; 
      } 

      if(box.height < 0) 
      { 
       box.y +=box.height; 
       box.height *= -1; 
      } 

      objectLocation.x = box.x; 
      objectLocation.y = box.y; 
      targetAcquired = true; 

     } 
     break; 

    case CV_EVENT_RBUTTONUP: 
     { 
      destroyBox = true; 
     } 
     break; 
    } 
} 

int main() 
{ 
    const char *name = "Boundary Box"; 
    cv::namedWindow(name); 

    cv::VideoCapture camera; 
    cv::Mat cameraFrame; 
    int cameraNumber = 0; 
    camera.open(cameraNumber); 

    camera >> cameraFrame; 

    cv::Mat mask = cv::Mat::zeros(cameraFrame.size(), CV_8UC1); 
    cv::Mat clearMask = cv::Mat::zeros(cameraFrame.size(), CV_8UC1); 

    if (!camera.isOpened()) 
    { 
     std::cerr << "ERROR: Could not access the camera or video!" << std::endl; 
    } 

    cv::setMouseCallback(name, mouseCallback, &cameraFrame); 

    while(true) 
    { 

     if (destroyBox) 
     { 
      cv::destroyAllWindows(); 
      break; 
     } 

     camera >> cameraFrame; 

     if (cameraFrame.empty()) 
     { 
      std::cerr << "ERROR: Could not grab a camera frame." << std::endl; 
      exit(1); 
     } 

     camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame); 
     camera >> prevFrame; 
     cv::cvtColor(prevFrame, prevFrame_1C, cv::COLOR_BGR2GRAY); 

     camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame ++); 
     camera >> nextFrame; 
     cv::cvtColor(nextFrame, nextFrame_1C, cv::COLOR_BGR2GRAY); 

     if (targetAcquired) 
     { 
      cv::Mat roi (mask, cv::Rect(box.x, box.y, box.width, box.height)); 
      roi = cv::Scalar(255, 255, 255); 
      findFeatures(mask); 
      clearMask.copyTo(mask); 
      trackFeatures(); 
     } 

     draw(cameraFrame, box); 
     cv::imshow(name, cameraFrame); 
     cv::waitKey(20); 
    } 

    cv::destroyWindow(name); 
    return 0; 
} 
+0

La direction du mouvement semble correct, il semble donc être une chose d'échelle. Pourriez-vous essayer de multiplier les points par une certaine valeur? – Nallath

+1

Oui, la direction du mouvement est en effet correcte, mais je voudrais bien comprendre pourquoi il ne correspond pas pour que je puisse le corriger en conséquence. Je ne veux pas prendre la route hacky et juste l'escalader par une valeur arbitraire. – szakeri

+0

Découvrir l'échelle aiderait à déterminer pourquoi cette échelle est correcte. Il se peut que l'échelle soit l'échelle entre le retour sur investissement et la taille réelle de l'image capturée. – Nallath

Répondre

1

À mon avis, vous ne pouvez pas utiliser camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame) sur une webcam, mais je ne suis pas positif à ce sujet. Au lieu de cela, je vous suggère de sauvegarder l'image précédente dans votre variable prevFrame.

À titre d'exemple, je peux vous suggérer ce code de travail, je change seulement à l'intérieur de la boucle while et j'ajouter un commentaire avant tout mon ajoute:

while(true) 
{ 

    if (destroyBox) 
    { 
     cv::destroyAllWindows(); 
     break; 
    } 

    camera >> cameraFrame; 

    if (cameraFrame.empty()) 
    { 
     std::cerr << "ERROR: Could not grab a camera frame." << std::endl; 
     exit(1); 
    } 

    // new lines 
    if(prevFrame.empty()){ 
      prevFrame = cameraFrame; 
      continue; 
    } 
    // end new lines 

    //camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame); 
    //camera >> prevFrame; 
    cv::cvtColor(prevFrame, prevFrame_1C, cv::COLOR_BGR2GRAY); 

    //camera.set(CV_CAP_PROP_POS_FRAMES, currentFrame ++); 
    //camera >> nextFrame; 
    // new line 
    nextFrame = cameraFrame; 
    cv::cvtColor(nextFrame, nextFrame_1C, cv::COLOR_BGR2GRAY); 

    if (targetAcquired) 
    { 
     cv::Mat roi (mask, cv::Rect(box.x, box.y, box.width, box.height)); 
     roi = cv::Scalar(255, 255, 255); 
     findFeatures(mask); 
     clearMask.copyTo(mask); 
     trackFeatures(); 
    } 

    draw(cameraFrame, box); 
    cv::imshow(name, cameraFrame); 
    cv::waitKey(20); 

    // old = new 
    // new line 
    prevFrame = cameraFrame.clone(); 

}

+0

Merci pour l'aide! Cela fonctionne magnifiquement. Parfois j'ai un problème mineur où les points suivis décident de converger ensemble, mais je n'ai écrit aucun code pour traiter des dispositifs qui sont perdus ou sortent de l'écran. Je pense que traiter ces scénarios correctement devrait résoudre ce problème. Merci encore :) – szakeri

+0

En fait, auriez-vous un quelconque aperçu de la raison pour laquelle ils ont tendance à fusionner comme ça? – szakeri

Questions connexes