2016-01-12 6 views
17

हम वास्तव में एक छवि विश्लेषण प्रोजेक्ट पर काम कर रहे हैं जहां हमें एक दृश्य में गायब/प्रकट वस्तुओं की पहचान करने की आवश्यकता है। यहां 2 छवियां हैं, एक सर्जन द्वारा और बाद में एक क्रिया के पहले एक कब्जा कर लिया गया है।ऑप्टिकल प्रवाह स्पैर मोशन को अनदेखा करता है

से पहले: enter image description here के बाद: enter image description here

सबसे पहले, हम सिर्फ 2 छवियों के बीच अंतर की गणना और यहाँ नतीजा है (ध्यान दें कि मैं परिणाम Mat को 128 जोड़ा सिर्फ एक अच्छे छवि के लिए) :

(बाद - पहले) + 128 enter image description here

लक्ष्य का पता लगाने के लिए कि कप (लाल तीर) SCE से गायब हो गया है ने और सिरिंज (काला तीर) दृश्य में प्रवेश कर चुका है, दूसरे शब्दों से हमें केवल उन क्षेत्रों का पता लगाना चाहिए जो दृश्य में बाएं/दर्ज वस्तुओं से मेल खाते हैं। साथ ही, यह स्पष्ट है कि दृश्य के ऊपरी बाईं ओर वाली वस्तुओं को अपनी प्रारंभिक स्थिति से थोड़ा सा स्थानांतरित कर दिया गया है। मैंने सोचा था कि Optical flow के बारे में तो मैं OpenCV C++ इस्तेमाल किया क्रम में Farneback की एक गणना करने के लिए कि क्या यह हमारे मामले के लिए काफी है और यहाँ है परिणाम हमारे पास देखने के लिए, कोड हम लिखा था, जिसके बाद:

फ्लो: enter image description here

void drawOptFlowMap(const Mat& flow, Mat& cflowmap, int step, double, const Scalar& color) 
{ 
    cout << flow.channels() << "/" << flow.rows << "/" << flow.cols << endl; 
    for(int y = 0; y < cflowmap.rows; y += step) 
     for(int x = 0; x < cflowmap.cols; x += step) 
     { 
      const Point2f& fxy = flow.at<Point2f>(y, x); 
      line(cflowmap, Point(x,y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), color); 
      circle(cflowmap, Point(x,y), 1, color, -1); 
     } 
} 

void MainProcessorTrackingObjects::diffBetweenImagesToTestTrackObject(string pathOfImageCaptured, string pathOfImagesAfterOneAction, string pathOfResultsFolder) 
{ 
    //Preprocessing step... 

    string pathOfImageBefore = StringUtils::concat(pathOfImageCaptured, imageCapturedFileName); 
    string pathOfImageAfter = StringUtils::concat(pathOfImagesAfterOneAction, *it); 

    Mat imageBefore = imread(pathOfImageBefore); 
    Mat imageAfter = imread(pathOfImageAfter); 

    Mat imageResult = (imageAfter - imageBefore) + 128; 
    //   absdiff(imageAfter, imageBefore, imageResult); 
    string imageResultPath = StringUtils::stringFormat("%s%s-color.png",pathOfResultsFolder.c_str(), fileNameWithoutFrameIndex.c_str()); 
    imwrite(imageResultPath, imageResult); 

    Mat imageBeforeGray, imageAfterGray; 
    cvtColor(imageBefore, imageBeforeGray, CV_RGB2GRAY); 
    cvtColor(imageAfter, imageAfterGray, CV_RGB2GRAY); 

    Mat imageResultGray = (imageAfterGray - imageBeforeGray) + 128; 
    //   absdiff(imageAfterGray, imageBeforeGray, imageResultGray); 
    string imageResultGrayPath = StringUtils::stringFormat("%s%s-gray.png",pathOfResultsFolder.c_str(), fileNameWithoutFrameIndex.c_str()); 
    imwrite(imageResultGrayPath, imageResultGray); 


    //*** Compute FarneBack optical flow 
    Mat opticalFlow; 
    calcOpticalFlowFarneback(imageBeforeGray, imageAfterGray, opticalFlow, 0.5, 3, 15, 3, 5, 1.2, 0); 

    drawOptFlowMap(opticalFlow, imageBefore, 5, 1.5, Scalar(0, 255, 255)); 
    string flowPath = StringUtils::stringFormat("%s%s-flow.png",pathOfResultsFolder.c_str(), fileNameWithoutFrameIndex.c_str()); 
    imwrite(flowPath, imageBefore); 

    break; 
} 

//Reference method just to see the accuracy of the optical flow calculation 
Mat accuracy = Mat::zeros(imageBeforeGray.rows, imageBeforeGray.cols, imageBeforeGray.type()); 

strinfor(int y = 0; y < imageAfter.rows; y ++) 
for(int x = 0; x < imageAfter.cols; x ++) 
{ 
    Point2f& fxy = opticalFlow.at<Point2f>(y, x); 
    uchar intensityPointCalculated = imageAfterGray.at<uchar>(cvRound(y+fxy.y), cvRound(x+fxy.x)); 
    uchar intensityPointBefore = imageBeforeGray.at<uchar>(y,x); 
    uchar intensityResult = ((intensityPointCalculated - intensityPointBefore)/2) + 128; 
    accuracy.at<uchar>(y, x) = intensityResult; 
} 
validationPixelBased = StringUtils::stringFormat("%s%s-validationPixelBased.png",pathOfResultsFolder.c_str(), fileNameWithoutFrameIndex.c_str()); 
imwrite(validationPixelBased, accuracy); 

टी होने के इरादे: IMAGEBEFORE -

और पता करने के लिए कितना सही इस ऑप्टिकल प्रवाह है, मैं कोड के इस छोटे से टुकड़े की गणना (IMAGEAFTER + फ्लो) ने लिखा है उसकी ((intensityPointCalculated - intensityPointBefore)/2) + 128; सिर्फ एक समझदार छवि है।

छवि परिणाम:

enter image description here

के बाद से यह सभी क्षेत्रों कि स्थानांतरित कर दिया गया है का पता लगाता है/दर्ज/दृश्य छोड़ दिया है, हमें लगता है कि OpticalFlow सिर्फ क्षेत्रों वस्तुओं का प्रतिनिधित्व गायब हो गया पता लगाने के लिए पर्याप्त नहीं है/दृश्य में दिखाई दिया। opticalFlow द्वारा पता लगाए गए स्पैर मोशन को अनदेखा करने का कोई तरीका है? या क्या हमें पता लगाने के लिए कोई वैकल्पिक तरीका है?

उत्तर

9

मान लें कि यहां लक्ष्य प्रकट/गायब वस्तुओं वाले क्षेत्रों की पहचान करना है, लेकिन दोनों चित्रों में मौजूद नहीं हैं बल्कि बस स्थानांतरित हो गए हैं।

ऑप्टिकल प्रवाह जाने का एक अच्छा तरीका होना चाहिए, जैसा कि आपने पहले से ही किया है। हालांकि मुद्दा यह है कि परिणाम का मूल्यांकन कैसे किया जाता है। के रूप में पिक्सेल करने वाली पिक्सेल diff से पता चलता है जो रोटेशन/स्केलिंग प्रसरण करने के लिए कोई सहिष्णुता है करने का विरोध किया है, तो आप

यहाँ मैं के साथ अच्छे विशेषताएं पाने से पहले अपनी छवि से ट्रैक करने के तरीके एक सुविधा मिलान कर सकते हैं (झारना आदि Check out here for what you can use with opencv)।

GoodFeaturesToTrackDetector detector; 
vector<KeyPoint> keyPoints; 
vector<Point2f> kpBefore, kpAfter; 
detector.detect(imageBefore, keyPoints); 

enter image description here

घने ऑप्टिकल प्रवाह के बजाय, आप एक विरल प्रवाह का उपयोग करें और केवल सुविधाओं को ट्रैक कर सकता है,

vector<uchar> featuresFound; 
vector<float> err; 
calcOpticalFlowPyrLK(imageBeforeGray, imageAfterGray, keyPointsBefore, keyPointsAfter, featuresFound, err, Size(PATCH_SIZE , PATCH_SIZE)); 

आउटपुट FeaturesFound और त्रुटि मान भी शामिल है। मैंने बस स्थानांतरित सुविधाओं और बेजोड़ गायब लोगों को अलग करने के लिए यहां एक सीमा का उपयोग किया।

vector<KeyPoint> kpNotMatched; 
for (int i = 0; i < kpBefore.size(); i++) { 
    if (!featuresFound[i] || err[i] > ERROR_THRESHOLD) { 
     kpNotMatched.push_back(KeyPoint(kpBefore[i], 1)); 
    } 
} 
Mat output; 
drawKeypoints(imageBefore, kpNotMatched, output, Scalar(0, 0, 255)); 

enter image description here

शेष गलत तरीके से मिलान सुविधाओं पर बाहर किए जा सकते हैं। यहां मैंने नए दिखाई देने वाले क्षेत्र के मुखौटे को पाने के लिए सरल माध्य फ़िल्टरिंग प्लस थ्रेसहोल्डिंग का उपयोग किया।

Mat mask = Mat::zeros(imageBefore.rows, imageBefore.cols, CV_8UC1); 
for (int i = 0; i < kpNotMatched.size(); i++) { 
    mask.at<uchar>(kpNotMatched[i].pt) = 255; 
} 
blur(mask, mask, Size(BLUR_SIZE, BLUR_SIZE)); 
threshold(mask, mask, MASK_THRESHOLD, 255, THRESH_BINARY); 

enter image description here

और फिर अपने उत्तल पतवार ढूँढने मूल छवि में क्षेत्र दिखाने के लिए (पीले रंग में)।

vector<vector<Point> > contours; 
vector<Vec4i> hierarchy; 
findContours(mask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

vector<vector<Point> >hull(contours.size()); 
for(int i = 0; i < contours.size(); i++) { 
    convexHull(Mat(contours[i]), hull[i], false); 
} 
for(int i = 0; i < contours.size(); i++) { 
    drawContours(output, hull, i, Scalar(0, 255, 255), 3, 8, vector<Vec4i>(), 0, Point()); 
} 

enter image description here

और बस रिवर्स रास्ता (imageBefore को imageAfter से मिलान) क्षेत्रों दिखाई दिया पाने के लिए करते हैं। :)

+0

मैं पुन: पेश करने में सक्षम नहीं कर रहा हूँ वही परिणाम .. क्या आप कृपया मुझे उन मूल्यों को बता सकते हैं जिनका उपयोग आप इन स्थिरांकों के लिए कर रहे हैं: BLUR_SIZE, ERROR_THRESHOLD, MASK_THRESHOLD – Maystro

+0

के आधार पर 960 x 540 इनपुट छवि, मेरे पास BLUR_SIZE = 35, ERROR_THRESHOLD = 30, MASK_THRESHOLD = 1.5 था। आप स्पैस ऑप्टिकल फ्लो पिरामिड लेवल, पैच साइज इत्यादि जैसे अन्य पैरा को भी ट्विक करना चाहेंगे। हालांकि सभी स्थिर परिस्थितियों में सरल निरंतर थ्रेसहोल्डिंग अच्छी तरह से काम नहीं कर सकती है और आप अपने उपयोग के मामलों के आधार पर अधिक परिष्कृत रणनीतियों को लागू करना चाहेंगे। – myin528

+0

आपके समर्थन के लिए धन्यवाद। आपके उत्तर में मेरे ज्यादातर मामलों को शामिल नहीं किया गया है, लेकिन मैं आपको पर्याप्त राशि के बाद से बक्षीस दूंगा। – Maystro

0

आप दो pronged दृष्टिकोण का प्रयास कर सकते हैं - छवि अंतर विधि का उपयोग करना उन वस्तुओं का पता लगाने में बहुत अच्छा है जो दृश्य में प्रवेश करते हैं और बाहर निकलते हैं, जब तक ऑब्जेक्ट का रंग पृष्ठभूमि के रंग से अलग होता है। मुझे क्या लगता है कि यदि आप विधि का उपयोग करने से पहले स्थानांतरित हो गए हैं तो आप इसे हटा सकते हैं।

ऑब्जेक्ट डिटेक्शन here के लिए एक महान ओपनसीवी विधि है जो किसी ऑब्जेक्ट के अनुवाद का पता लगाने के लिए किसी छवि में रुचि के बिंदु पाती है।मुझे लगता है कि आप प्राप्त कर सकते थे क्या आप निम्न विधि के साथ चाहते हैं -

1 OpenCV कोड के साथ छवियों की तुलना करें और वस्तुओं एक ही सेट पर पृष्ठभूमि के साथ पता लगाया वस्तुओं में दोनों छवियों में आगे बढ़

2 रंग अन्य चित्र पर प्रकाश डाला पिक्सल (या कुछ इसी तरह) जो चलती छवियों

3 छवि अंतर जो अब बड़े प्रमुख वस्तुओं और छोटे कलाकृतियों चलती छवियों

4 दहलीज से बचे होना चाहिए खोजें के कारण होता है छवियों में अंतर को कम करने का ऑब्जेक्ट के एक निश्चित आकार के लिए पता चला छवि अंतर

5 अधिक संभावना वाले

वस्तु पर नज़र रखने के लिए अन्य विकल्प हैं की एक सूची संकलित करें, इसलिए वहाँ कोड आप और अधिक की तरह हो सकता है लेकिन इस प्रक्रिया तुम क्या कर रहे हैं के लिए ठीक होना चाहिए, मुझे लगता है।

1

यहां मैंने जो कोशिश की है;

  • परिवर्तनों से गुजरने वाले क्षेत्रों का पता लगाएं।इसके लिए मैं सरल फ्रेम differencing, थ्रेसहोल्डिंग, morphological संचालन और convexhull का उपयोग करें।
  • दोनों छवियों में इन क्षेत्रों के फीचर पॉइंट खोजें और देखें कि वे मेल खाते हैं या नहीं। एक क्षेत्र में अच्छा मिलान इंगित करता है कि इसमें एक महत्वपूर्ण बदलाव नहीं आया है। खराब मैच का मतलब है कि दो क्षेत्र अब अलग हैं। इसके लिए मैं बो और भट्टाचार्य दूरी का उपयोग करता हूं।

पैरामीटर को ट्यूनिंग की आवश्यकता हो सकती है। मैंने उन मानों का उपयोग किया है जो सिर्फ दो नमूना छवियों के लिए काम करते हैं। फीचर डिटेक्टर/डिस्क्रिप्टर के रूप में मैंने एसआईएफटी (गैर-मुक्त) का उपयोग किया है। आप अन्य डिटेक्टरों और वर्णनकर्ताओं को आजमा सकते हैं।

diference छवि: diff

क्षेत्र: regions

परिवर्तन (लाल: प्रविष्टि/हटाने, पीला: विरल गति): changes

// for non-free modules SIFT/SURF 
cv::initModule_nonfree(); 

Mat im1 = imread("1.png"); 
Mat im2 = imread("2.png"); 

// downsample 
/*pyrDown(im1, im1); 
pyrDown(im2, im2);*/ 

Mat disp = im1.clone() * .5 + im2.clone() * .5; 
Mat regions = Mat::zeros(im1.rows, im1.cols, CV_8U); 

// gray scale 
Mat gr1, gr2; 
cvtColor(im1, gr1, CV_BGR2GRAY); 
cvtColor(im2, gr2, CV_BGR2GRAY); 
// simple frame differencing 
Mat diff; 
absdiff(gr1, gr2, diff); 
// threshold the difference to obtain the regions having a change 
Mat bw; 
adaptiveThreshold(diff, bw, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, 15, 5); 
// some post processing 
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3)); 
morphologyEx(bw, bw, MORPH_CLOSE, kernel, Point(-1, -1), 4); 
// find contours in the change image 
Mat cont = bw.clone(); 
vector<vector<Point> > contours; 
vector<Vec4i> hierarchy; 
findContours(cont, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE, Point(0, 0)); 
// feature detector, descriptor and matcher 
Ptr<FeatureDetector> featureDetector = FeatureDetector::create("SIFT"); 
Ptr<DescriptorExtractor> descExtractor = DescriptorExtractor::create("SIFT"); 
Ptr<DescriptorMatcher> descMatcher = DescriptorMatcher::create("FlannBased"); 

if(featureDetector.empty() || descExtractor.empty() || descMatcher.empty()) 
{ 
    cout << "featureDetector or descExtractor or descMatcher was not created" << endl; 
    exit(0); 
} 
// BOW 
Ptr<BOWImgDescriptorExtractor> bowExtractor = new BOWImgDescriptorExtractor(descExtractor, descMatcher); 

int vocabSize = 10; 
TermCriteria terminate_criterion; 
terminate_criterion.epsilon = FLT_EPSILON; 
BOWKMeansTrainer bowTrainer(vocabSize, terminate_criterion, 3, KMEANS_PP_CENTERS); 

Mat mask(bw.rows, bw.cols, CV_8U); 
for(size_t j = 0; j < contours.size(); j++) 
{ 
    // discard regions that a below a specific threshold 
    Rect rect = boundingRect(contours[j]); 
    if ((double)(rect.width * rect.height)/(bw.rows * bw.cols) < .01) 
    { 
     continue; // skip this region as it's too small 
    } 
    // prepare a mask for each region 
    mask.setTo(0); 
    vector<Point> hull; 
    convexHull(contours[j], hull); 
    fillConvexPoly(mask, hull, Scalar::all(255), 8, 0); 

    fillConvexPoly(regions, hull, Scalar::all(255), 8, 0); 

    // extract keypoints from the region 
    vector<KeyPoint> im1Keypoints, im2Keypoints; 
    featureDetector->detect(im1, im1Keypoints, mask); 
    featureDetector->detect(im2, im2Keypoints, mask); 
    // get their descriptors 
    Mat im1Descriptors, im2Descriptors; 
    descExtractor->compute(im1, im1Keypoints, im1Descriptors); 
    descExtractor->compute(im2, im2Keypoints, im2Descriptors); 

    if ((0 == im1Keypoints.size()) || (0 == im2Keypoints.size())) 
    { 
     // mark this contour as object arrival/removal region 
     drawContours(disp, contours, j, Scalar(0, 0, 255), 2); 
     continue; 
    } 

    // bag-of-visual-words 
    Mat vocabulary = bowTrainer.cluster(im1Descriptors); 
    bowExtractor->setVocabulary(vocabulary); 
    // get the distribution of visual words in the region for both images 
    vector<vector<int>> idx1, idx2; 
    bowExtractor->compute(im1, im1Keypoints, im1Descriptors, &idx1); 
    bowExtractor->compute(im2, im2Keypoints, im2Descriptors, &idx2); 
    // compare the distributions 
    Mat hist1 = Mat::zeros(vocabSize, 1, CV_32F); 
    Mat hist2 = Mat::zeros(vocabSize, 1, CV_32F); 

    for (int i = 0; i < vocabSize; i++) 
    { 
     hist1.at<float>(i) = (float)idx1[i].size(); 
     hist2.at<float>(i) = (float)idx2[i].size(); 
    } 
    normalize(hist1, hist1); 
    normalize(hist2, hist2); 
    double comp = compareHist(hist1, hist2, CV_COMP_BHATTACHARYYA); 

    cout << comp << endl; 
    // low BHATTACHARYYA distance means a good match of features in the two regions 
    if (comp < .2) 
    { 
     // mark this contour as a region having sparse motion 
     drawContours(disp, contours, j, Scalar(0, 255, 255), 2); 
    } 
    else 
    { 
     // mark this contour as object arrival/removal region 
     drawContours(disp, contours, j, Scalar(0, 0, 255), 2); 
    } 
} 
+0

मुझे जोड़ना था ((im1Keypoints.size() Maystro

संबंधित मुद्दे