Мы фактически работаем над проектом анализа изображений, где нам нужно идентифицировать объекты, которые исчезли/появились в сцене. Вот 2 изображения, один из которых был снят до того, как хирург и другие впоследствии сделали операцию.
Сначала мы просто вычислили разницу между двумя изображениями, и вот результат (обратите внимание, что я добавил 128 к результату Mat
, чтобы иметь более приятное изображение):
Цель состоит в том, чтобы обнаружить, что чаша (красная стрелка) исчезла со сцены, и шприц (черная стрелка) вошел в сцену, другими словами мы должны обнаружить ТОЛЬКО области, которые соответствуют объектам, оставленным/введенным в сцена. Кроме того, очевидно, что объекты в левом верхнем углу сцены немного смещены от их исходного положения. Я думал о Optical flow
, поэтому я использовал OpenCV C++
для вычисления Farneback, чтобы увидеть, достаточно ли этого для нашего случая, и вот результат, который мы получили, а затем код, который мы написали:
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;
}
И чтобы узнать, насколько точным этот оптический поток, я написал эту небольшую часть кода, которая вычисляет (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);
Цель этого ((intensityPointCalculated - intensityPointBefore) / 2) + 128;
состоит только в том, чтобы иметь понятное изображение.
РЕЗУЛЬТАТ ИЗОБРАЖЕНИЯ:
Поскольку он обнаруживает все области, которые были сдвинуты/введены/оставлены на сцене, мы считаем, что OpticalFlow
недостаточно, чтобы обнаружить только те области, которые отображают объекты, которые исчезли/появились в сцене. Есть ли способ игнорировать разреженные движения, обнаруженные OpticalFlow
? Или есть альтернативный способ определения того, что нам нужно?