CV-extrait différences entre deux images

je travaille actuellement sur un système d'intrusion basé sur la vidéosurveillance. Afin d'accomplir cette tâche, je prendre un instantané de l'arrière-plan de ma scène (supposons qu'elle est totalement propre, pas de personnes ou d'objets en mouvement). Ensuite, je compare le cadre que j'obtiens de la caméra vidéo (statique) et je cherche les différences. Je dois être en mesure de vérifier tout différences, non seulement la forme humaine ou autre, donc je ne peux pas l'extraction caractéristique spécifique.

Typiquement, j'ai:

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

J'utilise OpenCV, donc pour comparer je fais essentiellement:

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)));

voici le résultat:

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

comme vous pouvez le voir, le bras est dépouillé (en raison d'un conflit de couleur différentielle je suppose) et ce n'est malheureusement pas ce que je veux.

I pensé à ajouter l'utilisation de cv::Canny() afin de détecter les bords et remplir la partie manquante du bras, mais malheureusement (encore une fois), elle ne résout le problème en quelques pas de la plupart d'entre eux.

y a-t-il un algorithme ou une technique que je pourrais utiliser pour obtenir un rapport de différence exact ?

PS: désolé pour les images. En raison de mon nouvel abonnement, je n'ai pas assez de réputation.

Modifier J'utilise l'image en niveaux de gris ici, mais je suis ouvert à toute solution.

24
demandé sur pzp 2014-11-20 12:12:30

2 réponses

un problème dans votre code est cv::threshold qui n'utilise que des images sur 1 canal. Trouver la "différence" entre deux images dans le sens des pixels en échelle de gris seulement conduit souvent à des résultats peu intuitifs.

puisque vos images fournies sont un peu traduites ou que la caméra n'était pas stationnaire, j'ai manipulé votre image de fond pour ajouter un peu de premier plan:

image d'arrière-plan:

enter image description here

image au premier plan:

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;
            }
        }

donnant ce résultat:

enter image description here

avec cette image de différence:

enter image description here

en général, il est difficile de calculer une segmentation avant-plan/arrière-plan complète à partir de l'interprétation des différences en pixels.

vous aurez probablement à ajouter postprocessing stuff pour obtenir une véritable segmentation, où vous commencez à partir de votre masque de premier plan. Je ne sais pas s'il existe encore des solutions universelles stables.

comme berak l'a mentionné, dans la pratique, il ne sera pas suffisant d'utiliser une seule image de fond, vous devrez donc calculer/gérer votre image de fond au fil du temps. Il ya beaucoup de documents couvrant ce sujet et afaik aucune solution universelle stable encore.

voici un peu plus de tests. J'ai converti en HSV l'espace de couleur: cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); et effectué les mêmes opérations dans cet espace, conduisant à ce résultat:

enter image description here

après avoir ajouté un peu de bruit à l'entrée:

enter image description here

j'ai ce résultat:

enter image description here

alors peut-être que le seuil est un peu trop haut. Je vous encourage toujours à jeter un oeil à L'espace de couleur HSV trop, mais vous pourriez avoir à réinterpréter l ' "image de différence" et de revenir chaque canal pour combiner leurs valeurs de différence.

46
répondu Micka 2014-11-20 10:16:47

j'utilise Python, c'est mon résultat:

enter image description here

le 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)

mise à jour, voici le code C++:

//! 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;
}

réponses similaires:

  1. CV-extrait différences entre deux images

  2. "tout en trouvant une différence entre 2 images OpenCV différence est plus grande qu'elle est supposée être

11
répondu Silencer 2018-01-25 07:40:11