Оптимизация программы отслеживания формы — C++ OpenCV

Приведенный ниже код предназначен для отслеживания объектов на основе их формы (с помощью вершин) с камеры. Хотя этот код работает без ошибок, файл, в котором хранится информация об отслеживаемых объектах (положение, форма, время регистрации данных), записывается всего около 30 раз в секунду. Я хотел бы значительно улучшить эту скорость (желательно примерно до 100 раз в секунду). Я попытался изменить используемую камеру, которая может снимать со скоростью более 100 кадров в секунду, но это не повлияло на вышеупомянутую проблему и дает те же результаты, что и веб-камера со скоростью 30 кадров в секунду. Есть ли в моем коде что-то, что излишне замедляет процесс, или есть что-то, что я могу добавить в свой код, чтобы ускорить его? Любая помощь более чем приветствуется.

EDIT: я совсем забыл - спасибо Dan Mašek за написание большая часть приведенного ниже кода.

РЕДАКТИРОВАНИЕ: здесь представлено видео отслеживания в в этом случае всего один четырехугольник на сферической поверхности.

РЕДАКТИРОВАТЬ: Сейчас моя цель состоит в том, чтобы зарегистрировать "центроид" фигур, обозначенных этой программой, для отслеживания в файле данных как можно точнее (что я реализовал), предпочтительно по крайней мере 100 зарегистрированных точек данных в секунду (с чем я продолжаю бороться).

РЕДАКТИРОВАНИЕ: измененный код для включения двух камер, каждая из которых записывает в отдельный текстовый файл. В настоящее время оба записываются в shape_data1.txt, поэтому на самом деле это работает неправильно. Кроме того, findPos() был удален, потому что на самом деле он не регистрировал позицию, а только миллисекундное значение текущего времени процессора.

Код:

#include <fstream>
#include <time.h>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>

std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
std::ofstream file_;
std::ofstream file1_;

void morphOps(cv::Mat &thresh){

    //create structuring element that will be used to "dilate" and "erode" image.
    //the element chosen here is a 3px by 3px rectangle

    cv::Mat erodeElement = cv::getStructuringElement( cv::MORPH_RECT,cv::Size(10,10));
    //dilate with larger element so make sure object is nicely visible
    cv::Mat dilateElement = cv::getStructuringElement( cv::MORPH_RECT,cv::Size(10,10));

    cv::erode(thresh,thresh,erodeElement);
    cv::erode(thresh,thresh,erodeElement);


    cv::dilate(thresh,thresh,dilateElement);
    cv::dilate(thresh,thresh,dilateElement);
}

void process_contour(cv::Mat& frame, std::vector<cv::Point> const& contour, int num)
{
    clock_t t;
    t = clock();

    int minArea = 100;
    int x1,y1;

    cv::Scalar TRIANGLE_COLOR(0, 0, 255);
    cv::Scalar QUADRILATERAL_COLOR(0, 255, 0);
    cv::Scalar HEPTAGON_COLOR(255, 0, 0);
    cv::Scalar DECA_COLOR(126, 126, 0);

    cv::Scalar color;

    if (contour.size() == 3 && contourArea(contour) > minArea) {
        color = TRIANGLE_COLOR;
        for (int index = 0; index >= 0; index = hierarchy[index][0]) {
            cv::Moments moment = cv::moments((cv::Mat)contours[index]);
            double area = moment.m00;
            if(area > minArea){
                x1 = moment.m10/area;
                y1 = moment.m01/area;
            }
        }
        if (num = 0) {
            file_ << "Triangle  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        } else {
            file1_ << "Triangle  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        }

    } else if (contour.size() == 4 && contourArea(contour) > minArea) {
        color = QUADRILATERAL_COLOR;
        for (int index = 0; index >= 0; index = hierarchy[index][0]) {
            cv::Moments moment = cv::moments((cv::Mat)contours[index]);
            double area = moment.m00;
            if(area > minArea){
                x1 = moment.m10/area;
                y1 = moment.m01/area;
            }
        }
        if (num = 0) {
            file_ << "Quadrilateral  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        } else {
            file1_ << "Quadrilateral  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        }

    } else if (contour.size() == 7 && contourArea(contour) > minArea) {
        color = HEPTAGON_COLOR;
        for (int index = 0; index >= 0; index = hierarchy[index][0]) {
            cv::Moments moment = cv::moments((cv::Mat)contours[index]);
            double area = moment.m00;
            if(area > minArea){
                x1 = moment.m10/area;
                y1 = moment.m01/area;
            }
        }
        if (num = 0) {
            file_ << "Heptagon  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        } else {
            file1_ << "Heptagon  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        }

    } else if (contour.size() == 10 && contourArea(contour) > minArea) {
        color = DECA_COLOR;
        for (int index = 0; index >= 0; index = hierarchy[index][0]) {
            cv::Moments moment = cv::moments((cv::Mat)contours[index]);
            double area = moment.m00;
            if(area > minArea){
                x1 = moment.m10/area;
                y1 = moment.m01/area;
            }
        }
        if (num = 0) {
            file_ << "Decagon  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        } else {
            file1_ << "Decagon  " << "X: " << x1 << " Y: " << y1 << "  " << /*"Area: " << contourArea(contour) << "  " <<*/ double(t)/CLOCKS_PER_SEC << " seconds" << "\n";
        }

    } else {
        return;
    }

    cv::Point const* points(&contour[0]);
    int n_points(static_cast<int>(contour.size()));

    polylines(frame, &points, &n_points, 1, true, color, 4);
}

void process_frame(cv::Mat const& frame, cv::Mat& result_frame, int num)
{
    cv::Mat feedGrayScale;
    cv::cvtColor(frame, feedGrayScale, cv::COLOR_BGR2GRAY);
    //cv::imshow("Grayscale", feedGrayScale);

    frame.copyTo(result_frame);

    //thresholding the grayscale image to get better results
    cv::threshold(feedGrayScale, feedGrayScale, 128, 255, cv::THRESH_BINARY);
    //morphOps(feedGrayScale);
    if (num = 0) {
        cv::imshow("Threshold - Webcam", feedGrayScale);
    }
    if (num = 1) {
        cv::imshow("Threshold - Basler Cam", feedGrayScale);
    }

    cv::findContours(feedGrayScale, contours, hierarchy, CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE );
    for (size_t k(0); k < contours.size(); ++k) {
        std::vector<cv::Point> approx_contour;
        cv::approxPolyDP(cv::Mat(contours[k]), approx_contour, 3, true);
        process_contour(result_frame, approx_contour, num);
    }
}

int main()
{
    file_.open("shape_data.txt");
    file1_.open("shape_data1.txt");

    cv::VideoCapture cap(0); // open the video camera no.0 
    cv::VideoCapture cap1(1); // open the video camera no.0 
    //cap.set(CV_CAP_PROP_FRAME_WIDTH,1000);
    //cap.set(CV_CAP_PROP_FRAME_HEIGHT,1000);
    //cap.set(CV_CAP_PROP_FPS,120);
    //cap.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    if (!cap.isOpened() || !cap1.isOpened())  // if not success, exit program
    {
        std::cout << "Cannot open the video cam\n";
        return -1;
    }

    //cv::namedWindow("Original", CV_WINDOW_AUTOSIZE);
    cv::namedWindow("Tracked - Webcam", CV_WINDOW_AUTOSIZE);
    cv::namedWindow("Tracked - Basler Cam", CV_WINDOW_AUTOSIZE);

    // Process frames from the video stream...
    for(;;) {
        cv::Mat frame, result_frame;
        cv::Mat frame1, result_frame1;

        // read a new frame from video
        if (!cap.read(frame)) {
            std::cout << "Cannot read a frame from video stream\n";
            break;
        }
        if (!cap1.read(frame1)) {
            std::cout << "Cannot read a frame from video stream\n";
            break;
        }
        process_frame(frame, result_frame, 0);
        process_frame(frame1, result_frame1, 1);

        cv::imshow("Tracked - Webcam", result_frame);
        cv::imshow("Tracked - Basler Cam", result_frame1);

        cv::waitKey(1);
    }

    return 0;
}

Образец части текстового файла, который записывается в:

Quadrilateral  X: 361 Y: 136  168.156 seconds
Quadrilateral  X: 361 Y: 138  168.204 seconds
Quadrilateral  X: 361 Y: 138  168.212 seconds
Quadrilateral  X: 371 Y: 138  168.259 seconds
Quadrilateral  X: 371 Y: 138  168.308 seconds
Quadrilateral  X: 372 Y: 139  168.349 seconds
Quadrilateral  X: 372 Y: 139  168.381 seconds
Quadrilateral  X: 372 Y: 138  168.411 seconds
Quadrilateral  X: 372 Y: 140  168.443 seconds
Quadrilateral  X: 372 Y: 140  168.473 seconds
Quadrilateral  X: 373 Y: 141  168.504 seconds
Quadrilateral  X: 374 Y: 140  168.535 seconds
Quadrilateral  X: 374 Y: 142  168.566 seconds
Quadrilateral  X: 374 Y: 143  168.597 seconds
Quadrilateral  X: 375 Y: 145  168.631 seconds
Quadrilateral  X: 376 Y: 145  168.663 seconds
Quadrilateral  X: 376 Y: 146  168.694 seconds
Quadrilateral  X: 375 Y: 147  168.769 seconds
Quadrilateral  X: 376 Y: 147  168.799 seconds
Quadrilateral  X: 377 Y: 146  168.831 seconds
Quadrilateral  X: 376 Y: 145  168.862 seconds
Quadrilateral  X: 376 Y: 145  168.894 seconds
Quadrilateral  X: 377 Y: 145  168.925 seconds
Quadrilateral  X: 376 Y: 146  169.034 seconds
Quadrilateral  X: 376 Y: 146  169.065 seconds
Quadrilateral  X: 377 Y: 146  169.095 seconds
Quadrilateral  X: 378 Y: 145  169.127 seconds
Quadrilateral  X: 377 Y: 144  169.158 seconds
Quadrilateral  X: 377 Y: 144  169.192 seconds
Quadrilateral  X: 378 Y: 144  169.254 seconds
Quadrilateral  X: 378 Y: 144  169.286 seconds
Quadrilateral  X: 377 Y: 145  169.319 seconds
Quadrilateral  X: 378 Y: 145  169.366 seconds
Quadrilateral  X: 378 Y: 145  169.398 seconds
Quadrilateral  X: 379 Y: 144  169.439 seconds
Quadrilateral  X: 379 Y: 144  169.471 seconds
Quadrilateral  X: 380 Y: 144  169.534 seconds
Quadrilateral  X: 380 Y: 144  169.565 seconds
Quadrilateral  X: 380 Y: 144  169.595 seconds
Quadrilateral  X: 378 Y: 145  169.628 seconds
Quadrilateral  X: 379 Y: 145  169.658 seconds
Quadrilateral  X: 379 Y: 145  169.688 seconds
Quadrilateral  X: 380 Y: 143  169.758 seconds
Quadrilateral  X: 380 Y: 143  169.807 seconds
Quadrilateral  X: 379 Y: 143  169.85 seconds
Quadrilateral  X: 377 Y: 135  169.928 seconds
Quadrilateral  X: 377 Y: 134  169.975 seconds
Quadrilateral  X: 381 Y: 134  170.02 seconds
Quadrilateral  X: 382 Y: 134  170.051 seconds
Quadrilateral  X: 381 Y: 136  170.113 seconds
Quadrilateral  X: 382 Y: 137  170.145 seconds
Quadrilateral  X: 382 Y: 137  170.175 seconds
Quadrilateral  X: 380 Y: 135  170.267 seconds
Quadrilateral  X: 380 Y: 135  170.295 seconds
Quadrilateral  X: 381 Y: 134  170.328 seconds
Quadrilateral  X: 380 Y: 133  170.391 seconds
Quadrilateral  X: 381 Y: 134  170.47 seconds
Quadrilateral  X: 381 Y: 134  170.502 seconds
Quadrilateral  X: 380 Y: 134  170.534 seconds
Quadrilateral  X: 380 Y: 134  170.566 seconds
Quadrilateral  X: 380 Y: 134  170.597 seconds
Quadrilateral  X: 381 Y: 133  170.629 seconds
Quadrilateral  X: 381 Y: 133  170.662 seconds
Quadrilateral  X: 381 Y: 133  170.735 seconds
Quadrilateral  X: 381 Y: 133  170.765 seconds
Quadrilateral  X: 381 Y: 134  170.806 seconds
Quadrilateral  X: 380 Y: 134  170.855 seconds
Quadrilateral  X: 381 Y: 134  170.891 seconds
Quadrilateral  X: 381 Y: 135  170.923 seconds
Quadrilateral  X: 382 Y: 134  170.955 seconds
Quadrilateral  X: 382 Y: 134  170.986 seconds
Quadrilateral  X: 382 Y: 134  171.018 seconds
Quadrilateral  X: 382 Y: 134  171.048 seconds
Quadrilateral  X: 382 Y: 134  171.079 seconds
Quadrilateral  X: 381 Y: 135  171.142 seconds
Quadrilateral  X: 382 Y: 135  171.176 seconds
Quadrilateral  X: 382 Y: 135  171.219 seconds
Quadrilateral  X: 383 Y: 134  171.251 seconds
Quadrilateral  X: 383 Y: 134  171.283 seconds
Quadrilateral  X: 383 Y: 134  171.314 seconds
Quadrilateral  X: 383 Y: 134  171.345 seconds
Quadrilateral  X: 383 Y: 134  171.376 seconds
Quadrilateral  X: 383 Y: 134  171.408 seconds
Quadrilateral  X: 382 Y: 135  171.438 seconds
Quadrilateral  X: 383 Y: 135  171.468 seconds
Quadrilateral  X: 383 Y: 135  171.5 seconds
Quadrilateral  X: 384 Y: 134  171.544 seconds
Quadrilateral  X: 384 Y: 134  171.608 seconds
Quadrilateral  X: 384 Y: 134  171.639 seconds
Quadrilateral  X: 384 Y: 134  171.67 seconds
Quadrilateral  X: 383 Y: 135  171.765 seconds
Quadrilateral  X: 384 Y: 135  171.798 seconds
Quadrilateral  X: 384 Y: 134  171.829 seconds
Quadrilateral  X: 384 Y: 134  171.91 seconds
Quadrilateral  X: 384 Y: 134  171.95 seconds
Quadrilateral  X: 384 Y: 134  171.981 seconds
Quadrilateral  X: 385 Y: 134  172.013 seconds
Quadrilateral  X: 383 Y: 135  172.045 seconds
Quadrilateral  X: 384 Y: 135  172.074 seconds
Quadrilateral  X: 384 Y: 135  172.106 seconds
Quadrilateral  X: 385 Y: 134  172.137 seconds
Quadrilateral  X: 385 Y: 135  172.168 seconds
Quadrilateral  X: 385 Y: 134  172.199 seconds
Quadrilateral  X: 385 Y: 134  172.246 seconds
Quadrilateral  X: 385 Y: 134  172.31 seconds
Quadrilateral  X: 384 Y: 135  172.341 seconds
Quadrilateral  X: 385 Y: 135  172.373 seconds
Quadrilateral  X: 385 Y: 135  172.405 seconds
Quadrilateral  X: 386 Y: 134  172.437 seconds
Quadrilateral  X: 385 Y: 134  172.469 seconds
Quadrilateral  X: 386 Y: 134  172.502 seconds
Quadrilateral  X: 385 Y: 134  172.544 seconds
Quadrilateral  X: 385 Y: 134  172.574 seconds
Quadrilateral  X: 386 Y: 134  172.638 seconds
Quadrilateral  X: 385 Y: 134  172.676 seconds
Quadrilateral  X: 386 Y: 133  172.787 seconds
Quadrilateral  X: 385 Y: 133  172.903 seconds
Quadrilateral  X: 385 Y: 134  172.935 seconds
Quadrilateral  X: 385 Y: 133  173.007 seconds
Quadrilateral  X: 385 Y: 133  173.056 seconds
Quadrilateral  X: 386 Y: 132  173.093 seconds
Quadrilateral  X: 385 Y: 132  173.126 seconds
Quadrilateral  X: 385 Y: 132  173.172 seconds
Quadrilateral  X: 385 Y: 131  173.234 seconds
Quadrilateral  X: 384 Y: 132  173.265 seconds
Quadrilateral  X: 384 Y: 132  173.295 seconds
Quadrilateral  X: 384 Y: 132  173.327 seconds
Quadrilateral  X: 383 Y: 131  173.359 seconds
Quadrilateral  X: 382 Y: 131  173.408 seconds
Quadrilateral  X: 380 Y: 131  173.449 seconds
Quadrilateral  X: 379 Y: 131  173.481 seconds
Quadrilateral  X: 378 Y: 130  173.512 seconds
Quadrilateral  X: 376 Y: 134  173.606 seconds
Quadrilateral  X: 377 Y: 133  173.638 seconds
Quadrilateral  X: 377 Y: 134  173.672 seconds

person Crazed    schedule 28.07.2017    source источник
comment
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат.   -  person Brad Larson    schedule 02.08.2017
comment
(Перемещение в чат, запрошенное спрашивающим.)   -  person Brad Larson    schedule 02.08.2017


Ответы (1)


Чтобы ускорить запись файлов, попробуйте использовать файлы с отображением памяти (согласно этому вопросу: c++ boost write файл отображения памяти).

Я думаю, вам нужно передать обработку в рабочий поток (см. cppreference.com/w/cpp/thread для STL, а отличным ресурсом является книга C++ Concurrency in Action Энтони Уильямса)

Для оптимизации вам необходимо измерить бенчмарк Google (https://github.com/google/benchmark) является одним из лучших, которые я когда-либо видел. Вы можете использовать его в своих функциях с фиктивными данными, чтобы работать над их оптимизацией индивидуально, а затем в группе, пока не найдете фактические узкие места.

person Treebeard    schedule 28.07.2017
comment
Насколько я могу судить, здесь записывается только минимальный текстовый вывод, а идентификация функций и/или захват видео являются вероятными узкими местами. Кроме того, связанная оболочка файла с отображением памяти, похоже, не обеспечивает установку обработчика ошибок для обработки ошибок. В любом случае я бы рекомендовал начать с профилирования приложения, чтобы не делать никаких предположений о узких местах. - person doynax; 29.07.2017