Как обнаружить наличие объекта на нестационарном фоне с помощью Opencv в Android? - PullRequest
1 голос
/ 28 марта 2019

Я разрабатываю приложение для обработки кадров и выполнения сегментации и сопоставления изображений в реальном времени с использованием Opencv в Android.

Основная проблема заключается в том, что мне нужно начинать эту обработку изображений только тогда, когда объект для обработкидоступно в кадре камеры, и фон не является стационарным, что усложняет мою задачу.

Я пробовал многие решения, такие как обнаружение движения, используя absdiff, и это код

    imgSource = inputFrame.rgba().t();
    Core.transpose(imgSource, imgSource);

    //imgSource.convertTo(enhancedMat, imgSource.type(), 1.3);



    gray = imgSource;
    Imgproc.cvtColor(imgSource, gray, Imgproc.COLOR_BGR2GRAY);
    Imgproc.GaussianBlur(gray, gray, new Size(25, 25), 5);
    if (firstframe == null) {
        firstframe = gray;
    }
    Core.absdiff(firstframe, gray, frameDelta);
    Imgproc.threshold(frameDelta, frameDelta, 25, 255, Imgproc.THRESH_BINARY);
    for (int i =0 ; i <2 ; i++)
        Imgproc.dilate(frameDelta, frameDelta, Imgproc.getStructuringElement(Imgproc.THRESH_BINARY, new Size(3, 3)));

    Imgproc.findContours(frameDelta, abs_contours, abs_hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
    for (int idx = 0; idx < abs_contours.size(); idx++) {

        double a = Imgproc.contourArea(abs_contours.get(idx));  //Find the area of contour

        if (a < 10000) {

            continue;
        }

        Rect rect = Imgproc.boundingRect(abs_contours.get(idx));
        Imgproc.rectangle(imgSource, rect.tl(), rect.br(), new Scalar(0, 255, 0), 2);
    }

я такжепробовал фоновое вычитание, используя этот метод Opencv createBackgroundSubtractorMOG2.

Ни один из них не работал, потому что фон тоже движется, поэтому эти логики совсем не устойчивы.

Есть ли какой-то подход, которому я должен следоватьили какое-либо решение для такого рода проблем?

Я надеюсь, что вы, ребята, поможете мне найти хорошее решение и заранее благодарим вас.

1 Ответ

1 голос
/ 28 марта 2019

Чтобы решить эту проблему, я использовал оптический поток .

Вы можете вычислить оптический поток для каждого кадра, используя calcOpticalFlowFarneback.

Затем вы получаете матрицу из 2 компонентов (градиент в направлении x и y) для каждого пикселя вашего изображения.

Я вычислил для каждой точки atan2(flow_y,flow_x) и сохранил ее в vector<Point2f>.

Затем просто выполните кластеризацию, используя kmeans и с 2 метками. (для дифференциации фона на переднем плане движущихся объектов в последовательности).

Возвращенная матрица из kmeans дает вам метки.

Надеюсь, это поможет!

РЕДАКТИРОВАТЬ:

Я работал с OpenCV C ++, но вот мой код

int calculateOptFlow(Mat prev_frame, Mat frame, Mat& output) 
{
    Mat flow;

    //the algorithm uses gray images
    cvtColor(frame,frame,CV_BGR2GRAY);
    cvtColor(prev_frame,prev_frame,CV_BGR2GRAY);

    calcOpticalFlowFarneback(prev_frame, frame, flow,0.4, 1, 12, 2, 8, 1.2, 0);

    Mat angle(flow.rows,flow.cols,CV_32FC1);
    Mat dst(flow.rows,flow.cols,CV_32FC1);
    vector<Point2f> samples(flow.rows*flow.cols);

    int n=0;
    for(int y=0;y<flow.rows;y++)
    {
        for(int x=0;x<flow.cols ; x++)
        {

            angle.at<float>(y,x) = (atan2(flow.at<Point2f>(y,x).y,flow.at<Point2f>(y,x).x));
            samples[n++] =  flow.at<Point2f>(y,x);
        }
    }

    // split into 2 clusters : background and foreground
    Mat labels,centers;
    kmeans(samples,2,labels,TermCriteria(TermCriteria::EPS+TermCriteria::COUNT,10,1.0),3,KMEANS_PP_CENTERS,centers);

    // create a B&W matrix from the labels
    for(int i=0;i<(int)samples.size();i++)
    {
        int row = static_cast<int>(i/dst.cols);
        int col = i%dst.cols;
        if(labels.at<int>(i) == 1)
        {
            dst.at<float>(row,col) = 255;
        }
        else
        {
            dst.at<float>(row,col) = 0;
        }
    }

    //conversion for the use of findContours afterwards
    dst.convertTo(output,CV_8UC1);

    return 1;
}
...