2014-11-20 9 views
22

Ich arbeite derzeit an einem Intrusionssystem basierend auf Videoüberwachung. Um diese Aufgabe zu erledigen, mache ich eine Momentaufnahme des Hintergrunds meiner Szene (gehe davon aus, dass sie völlig sauber ist, keine Menschen oder sich bewegende Objekte). Dann vergleiche ich den Rahmen, den ich von der (statischen) Videokamera erhalte, und suche nach den Unterschieden. Ich muss in der Lage sein, irgendwelche Unterschiede zu überprüfen, nicht nur menschliche Form oder was auch immer, also kann ich nicht spezifische Merkmalsextraktion.CV - Unterschiede zwischen zwei Bildern extrahieren

Normalerweise habe ich:

http://postimg.org/image/dxtcp4u8h/

ich OpenCV verwende, so dass ich zum Vergleich im Grunde tun:

cv::Mat bg_frame; 
cv::Mat cam_frame; 
cv::Mat motion; 

cv::absdiff(bg_frame, cam_frame, motion); 
cv::threshold(motion, motion, 80, 255, cv::THRESH_BINARY); 
cv::erode(motion, motion, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3))); 

Hier ist das Ergebnis:

http://postimg.org/image/3kz0o62id/

Wie Sie sehen können, ist der Arm Streifen d (aufgrund von Farbdifferenzkonflikt denke ich) und das ist leider nicht das, was ich will.

Ich dachte über die Verwendung von cv::Canny() hinzufügen, um die Kanten zu erkennen und füllen Sie den fehlenden Teil des Armes, aber leider (noch einmal), löst es nur das Problem in wenigen Situationen nicht die meisten von ihnen.

Gibt es einen Algorithmus oder eine Technik, die ich verwenden könnte, um einen genauen Differenzbericht zu erhalten?

PS: Entschuldigung für die Bilder. Aufgrund meines neuen Abonnements habe ich nicht genug Ansehen.

EDIT Ich benutze Graustufenbild hier, aber ich bin offen für jede Lösung.

+1

vielleicht versucht [nicht das Rad neu zu erfinden] (http://docs.opencv.org/modules/video/ doc/motion_analysis_and_object_tracking.html # backgroundsubtractor) – berak

+0

schau mal, was schon eingebaut ist (und ob es besser funktioniert), ja. – berak

+0

haben Sie in Graustufen konvertiert? Wenn Sie die openCV-Klassen nicht verwenden möchten: Versuchen Sie, die Differenz jedes Kanals zu berechnen und kombinieren Sie sie, versuchen Sie es mit HSV-Bildern. Wenn Sie vorhandene Techniken verwenden möchten, versuchen Sie ViBe. Denken Sie daran, dass sogar Änderungen der Beleuchtung "irgendwelche Unterschiede, nicht nur menschliche Form oder was auch immer" sein werden, was ein Problem für die meisten Hintergrundsubtraktionsmethoden sein könnte. – Micka

Antwort

42

Ein Problem in Ihrem Code ist cv::threshold, das nur 1 Kanalbilder verwendet. Das Finden der pixelweisen "Differenz" zwischen zwei Bildern in nur Graustufen führt oft zu nicht intuitiven Ergebnissen.

Da Ihre gelieferten Bilder ist ein bisschen übersetzt oder die Kamera ist nicht stationär, habe ich Ihr Hintergrundbild manipuliert etwas Vordergrund hinzuzufügen:

Hintergrundbild:

enter image description here

Vordergrundbild:

enter image description here

Code:

cv::Mat diffImage; 
    cv::absdiff(backgroundImage, currentImage, diffImage); 

    cv::Mat foregroundMask = cv::Mat::zeros(diffImage.rows, diffImage.cols, CV_8UC1); 

    float threshold = 30.0f; 
    float dist; 

    for(int j=0; j<diffImage.rows; ++j) 
     for(int i=0; i<diffImage.cols; ++i) 
     { 
      cv::Vec3b pix = diffImage.at<cv::Vec3b>(j,i); 

      dist = (pix[0]*pix[0] + pix[1]*pix[1] + pix[2]*pix[2]); 
      dist = sqrt(dist); 

      if(dist>threshold) 
      { 
       foregroundMask.at<unsigned char>(j,i) = 255; 
      } 
     } 

gibt dieses Ergebnis:

enter image description here

mit diesem Differenzbild:

enter image description here

im Allgemeinen es schwierig ist, eine komplette Vorder-/Hintergrund Segmentierung von Pixel- zu berechnen weise unterschiedliche Interpretationen.

Sie müssen wahrscheinlich Postprocessing-Sachen hinzufügen, um eine echte Segmentierung zu erhalten, wobei Sie von Ihrer Vordergrundmaske aus beginnen. Ich bin mir nicht sicher, ob es überhaupt stabile universelle Lösungen gibt.

Wie bereits erwähnt, wird es in der Praxis nicht ausreichen, ein einzelnes Hintergrundbild zu verwenden, so dass Sie Ihr Hintergrundbild im Laufe der Zeit berechnen/verwalten müssen. Zu diesem Thema gibt es eine Fülle von Beiträgen und afaik gibt es noch keine stabile universelle Lösung.

Hier sind einige weitere Tests. I umgewandelt HSV Farbraum: cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); und ausgeführt, um die gleichen Operationen in diesem Raum zu diesem Ergebnis führen:

enter image description here

nach etwas Rauschen an den Eingang Zugabe:

enter image description here

ich Dieses Ergebnis:

enter image description here

also vielleicht ist die Schwelle ein bisschen zu hoch. Ich ermutige Sie immer noch, sich auch den HSV-Farbraum anzusehen, aber Sie müssen möglicherweise das "Differenzbild" neu interpretieren und jeden Kanal neu skalieren, um ihre Differenzwerte zu kombinieren.

+0

Woaw ... Vielen Dank für Ihre Hilfe! Ich teste deine Lösung. Ich werde Sie so schnell wie möglich informieren! Danke noch einmal. –

+1

Ihre Lösung hat mir sehr geholfen. Jetzt schaue ich mir die Hintergrundbewertung im Laufe der Zeit an. –

+0

Ich konnte die Bilder nicht sehen? Was könnte das Problem sein ... –

6

ich Python verwenden, ist dies mein Ergebnis:

enter image description here

Der Code:

# 2017.12.22 15:48:03 CST 
# 2017.12.22 16:00:14 CST 
import cv2 
import numpy as np 

img1 = cv2.imread("img1.png") 
img2 = cv2.imread("img2.png") 
diff = cv2.absdiff(img1, img2)) 
mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) 

th = 1 
imask = mask>th 

canvas = np.zeros_like(img2, np.uint8) 
canvas[imask] = img2[imask] 

cv2.imwrite("result.png", canvas) 

aktualisieren, hier ist C++ Code:

//! 2017.12.22 17:05:18 CST 
//! 2017.12.22 17:22:32 CST 

#include <opencv2/opencv.hpp> 
#include <iostream> 
using namespace std; 
using namespace cv; 
int main() { 

    Mat img1 = imread("img3_1.png"); 
    Mat img2 = imread("img3_2.png"); 

    // calc the difference 
    Mat diff; 
    absdiff(img1, img2, diff); 

    // Get the mask if difference greater than th 
    int th = 10; // 0 
    Mat mask(img1.size(), CV_8UC1); 
    for(int j=0; j<diff.rows; ++j) { 
     for(int i=0; i<diff.cols; ++i){ 
      cv::Vec3b pix = diff.at<cv::Vec3b>(j,i); 
      int val = (pix[0] + pix[1] + pix[2]); 
      if(val>th){ 
       mask.at<unsigned char>(j,i) = 255; 
      } 
     } 
    } 

    // get the foreground 
    Mat res; 
    bitwise_and(img2, img2, res, mask); 

    // display 
    imshow("res", res); 
    waitKey(); 
    return 0; 
} 

ähnliche Antworten:

  1. CV - Extract differences between two images

  2. While finding a difference between 2 pictures OpenCV difference is bigger than it is supposed to be