web-dev-qa-db-fra.com

CV - Extraire les différences entre deux images

Je travaille actuellement sur un système d'intrusion basé sur la vidéosurveillance. Afin de mener à bien cette tâche, je prends un instantané de l'arrière-plan de ma scène (supposons que c'est totalement propre, sans personnes ni objets en mouvement). Ensuite, je compare l'image que je reçois de la caméra vidéo (statique) et cherche les différences. Je dois être en mesure de vérifier toutes les différences , pas seulement la forme humaine ou autre, de sorte que je ne peux pas extraire de caractéristiques spécifiques.

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 constater, le bras est dénudé (je suppose, à cause du conflit de couleur différentielle) et ce n’est malheureusement pas ce que je veux.

J'ai pensé à ajouter l'utilisation de cv::Canny() afin de détecter les arêtes et de remplir la partie manquante du bras, mais malheureusement (encore une fois), cela ne résout le problème que dans peu de situations, voire la plupart d'entre elles.

Existe-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 une image en niveaux de gris ici, mais je suis ouvert à toute solution.

28
Valentin Trinqué

Un problème dans votre code est cv::threshold Qui n'utilise que des images à 1 canal. Trouver la "différence" de pixel entre deux images en niveaux de gris seulement conduit souvent à des résultats non intuitifs.

Puisque les images que vous avez fournies sont un peu traduites ou que l'appareil photo n'était pas immobile, j'ai manipulé votre image d'arrière-plan pour en ajouter un au premier plan:

image de fond:

enter image description here

image de 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 complète avant/arrière-plan à partir d’interprétations différentielles en pixels.

Vous devrez probablement ajouter des éléments de post-traitement pour obtenir une véritable segmentation, à partir de votre masque de premier plan. Pas sûr s'il existe encore des solutions universelles stables.

Comme Berak l'a mentionné, en pratique, il ne suffira pas d'utiliser une seule image d'arrière-plan. Vous devrez donc calculer/gérer votre image d'arrière-plan au fil du temps. Il existe de nombreux articles sur ce sujet et il n’ya pas encore de solution universelle stable.

voici quelques tests supplémentaires. J'ai converti en HSV espace colorimétrique: cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); et effectué les mêmes opérations dans cet espace, ce qui a conduit à ce résultat:

enter image description here

après avoir ajouté du bruit à l'entrée:

enter image description here

J'obtiens ce résultat:

enter image description here

alors peut-être que le seuil est un peu trop élevé. Je vous encourage tout de même à regarder l'espace colorimétrique HSV également, mais vous devrez peut-être réinterpréter "l'image de différence" et redimensionner chaque canal pour combiner leurs valeurs de différence.

51
Micka

J'utilise Python, voici 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 - Extraire les différences entre deux images

  2. Tout en trouvant une différence entre 2 images, la différence OpenCV est supérieure à ce qu'elle est censée être

17
Kinght 金

C'est un problème de vision par ordinateur classique bien connu appelé soustraction d'arrière-plan . Il existe de nombreuses approches qui peuvent être utilisées pour résoudre ce problème, la plupart d'entre elles sont déjà implémentées, je pense donc que vous devriez d'abord examiner plusieurs algorithmes existants. Voici l'implémentation opensource de la plupart d'entre eux: https://github.com/andrewssobral/bgslibrary (J'ai personnellement trouvé SUBSENSE donnant les meilleurs résultats, mais sa lenteur est mortelle)

1
Stepan Yakovenko