Stiamo attualmente lavorando a un progetto di analisi delle immagini in cui è necessario identificare gli oggetti scomparsi/comparsi in una scena. Qui ci sono 2 immagini, una catturata prima che un'azione sia stata fatta dal chirurgo e l'altra in seguito.Il flusso ottico ignora i movimenti sparsi
In primo luogo, abbiamo appena calcolato la differenza tra le 2 immagini ed ecco il risultato (Si noti che ho aggiunto 128 al risultato Mat
solo per avere un immagine più bella) :
l'obiettivo è quello di rilevare che la coppa (freccia rossa) è scomparso dal sce ne e la siringa (freccia nera) è entrata nella scena, in altre parole dovremmo rilevare SOLO le regioni che corrispondono agli oggetti lasciati/inseriti nella scena. Inoltre, è ovvio che gli oggetti in alto a sinistra della scena si sono spostati un po 'dalla loro posizione iniziale. Ho pensato a Optical flow
così ho usato OpenCV C++
per calcolare quello del Farneback per vedere se è abbastanza per il nostro caso, ed è qui il risultato che abbiamo ottenuto, seguito dal codice che abbiamo scritto:
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;
}
E per sapere quanto accurata questo flusso ottico è, ho scritto questo piccolo pezzo di codice che calcola (IMAGEAFTER + fLOW) - IMAGEBEFORE:
//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);
L'intento di avere t il suo ((intensityPointCalculated - intensityPointBefore)/2) + 128;
è solo per avere un'immagine comprensibile.
Risultato Immagine:
Dal momento che rileva tutte le regioni che sono state spostate/entrato/uscito di scena, pensiamo che il OpticalFlow
non è sufficiente per rilevare solo le regioni che rappresentano gli oggetti scomparsi/apparso nella scena. C'è un modo per ignorare i movimenti sparsi rilevati da opticalFlow
? O esiste un modo alternativo per rilevare ciò di cui abbiamo bisogno?
io non sono in grado di riprodurre gli stessi risultati .. puoi per favore dirmi i valori che stai utilizzando per queste costanti: BLUR_SIZE, ERROR_THRESHOLD, MASK_THRESHOLD – Maystro
In base a l'immagine di input 960 x 540, avevo BLUR_SIZE = 35, ERROR_THRESHOLD = 30, MASK_THRESHOLD = 1.5. Potresti anche voler modificare altri parametri come i livelli sparsi del piramide del flusso ottico, le dimensioni delle patch, ecc. Tuttavia, la semplice soglia costante potrebbe non funzionare bene in tutte le situazioni e potresti voler applicare strategie più sofisticate basate sui tuoi casi d'uso. – myin528
Grazie per il vostro supporto. La tua risposta non copre la maggior parte dei miei casi, ma ti darò la taglia poiché è abbastanza vicina. – Maystro