una significa que para imagenes imagen como atributos atributo agregar opencv difference motion-detection

opencv - significa - seo imagenes wordpress



CV-Extrae diferencias entre dos imágenes (4)

Actualmente estoy trabajando en un sistema de intrusión basado en video vigilancia. Para completar esta tarea, tomo una instantánea del fondo de mi escena (supongo que está totalmente limpio, sin personas ni objetos en movimiento). Luego, comparo el cuadro que obtengo de la cámara de video (estática) y busco las diferencias. Tengo que poder verificar cualquier diferencia, no solo la forma humana o lo que sea, por lo que no puedo extraer características específicas.

Por lo general, tengo:

Estoy usando OpenCV, así que para comparar básicamente hago:

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

Aquí está el resultado:

Como puede ver, el brazo está despojado (supongo que debido al conflicto de diferencia de color) y lamentablemente esto no es lo que quiero.

Pensé en agregar el uso de cv::Canny() para detectar los bordes y llenar la parte faltante del brazo, pero lamentablemente (una vez más), solo resuelve el problema en pocas situaciones, no en la mayoría de ellos.

¿Hay algún algoritmo o técnica que pueda usar para obtener un informe de diferencia preciso ?

PD: Perdón por las imágenes. Debido a mi nueva suscripción, no tengo suficiente reputación.

EDITAR Uso la imagen en escala de grises aquí, pero estoy abierto a cualquier solución.


Este es un conocido problema clásico de visión por computadora llamado sustracción de fondo . Hay muchos enfoques que se pueden usar para resolver este problema, la mayoría de ellos ya están implementados, por lo que creo que primero debe echar un vistazo a varios algoritmos existentes, aquí está la implementación de código abierto de la mayoría de ellos: https://github.com/andrewssobral/bgslibrary (personalmente encontré SUBSENSE dando los mejores resultados, pero es muy lento)


Otra técnica para obtener las diferencias exactas de píxeles entre dos imágenes es utilizar el Índice de similitud estructural (SSIM) que se introdujo por primera vez en la Evaluación de calidad de imagen en papel : de la visibilidad del error a la similitud estructural . Este método se puede usar para determinar si dos imágenes son idénticas y / o muestran diferencias debido a pequeñas discrepancias de imagen. SSIM ya está implementado en la biblioteca de imágenes skimage.measure.compare_ssim() para el procesamiento de imágenes como skimage.measure.compare_ssim()

La función compare_ssim() devuelve una score y una imagen de diferencia, diff . El score representa el índice de similitud estructural promedio entre las dos imágenes de entrada y puede caer entre el rango [-1,1] con valores más cercanos a uno que representan mayor similitud. Pero dado que solo le interesa en qué difieren las dos imágenes, la imagen de diff es en lo que nos centraremos. Específicamente, la imagen de diff contiene las diferencias de imagen reales con regiones más oscuras que tienen más disparidad. Las áreas más grandes de disparidad están resaltadas en negro, mientras que las diferencias más pequeñas están en gris.

Usando estas dos imágenes de entrada

Obtenemos este resultado

Similitud de imagen: 0.9587009832317672

El puntaje SSIM después de comparar las dos imágenes muestra que son muy similares

from skimage.measure import compare_ssim import cv2 image1 = cv2.imread(''1.png'') image2 = cv2.imread(''2.png'') # Convert images to grayscale image1_gray = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY) image2_gray = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY) # Compute SSIM between two images (score, diff) = compare_ssim(image1_gray, image2_gray, full=True) print("Image similarity:", score) # The diff image contains the actual image differences between the two images # and is represented as a floating point data type in the range [0,1] # so we must convert the array to 8-bit unsigned integers in the range # [0,255] image1 we can use it with OpenCV diff = (diff * 255).astype("uint8") cv2.imshow(''diff'', diff) cv2.waitKey()


Un problema en su código es cv::threshold que solo usa imágenes de 1 canal. Encontrar la "diferencia" de píxeles entre dos imágenes en escala de grises a menudo conduce a resultados poco intuitivos.

Como sus imágenes proporcionadas están un poco traducidas o la cámara no estaba estacionaria, manipulé su imagen de fondo para agregar algo de primer plano:

imagen de fondo:

imagen de primer plano:

código:

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

dando este resultado:

con esta imagen de diferencia:

en general, es difícil calcular una segmentación completa de primer plano / fondo a partir de interpretaciones de diferencias en píxeles.

Probablemente tendrá que agregar cosas de postprocesamiento para obtener una segmentación real, desde la que comienza desde la máscara de primer plano. No estoy seguro si todavía hay soluciones universales estables.

Como mencionó berak, en la práctica no será suficiente usar una sola imagen de fondo, por lo que tendrá que calcular / administrar su imagen de fondo con el tiempo. Hay muchos documentos que cubren este tema y todavía no existe una solución universal estable.

Aquí hay algunas pruebas más. cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); espacio de color HSV : cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); cv::cvtColor(backgroundImage, HSVbackgroundImagebg, CV_BGR2HSV); cv::cvtColor(currentImage, HSV_currentImage, CV_BGR2HSV); y realizó las mismas operaciones en este espacio, lo que lleva a este resultado:

después de agregar algo de ruido a la entrada:

Me sale este resultado:

entonces quizás el umbral es un poco demasiado alto. Todavía le animo a que también eche un vistazo al espacio de color HSV, pero es posible que deba reinterpretar la "imagen de diferencia" y volver a escalar cada canal para combinar sus valores de diferencia.


Yo uso Python, este es mi resultado:

El código:

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

Actualización, aquí está el código 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; }

Respuestas similares:

  1. CV - Extrae diferencias entre dos imágenes

  2. Si bien encuentra una diferencia entre 2 imágenes, la diferencia de OpenCV es mayor de lo que se supone que es