LINUX.ORG.RU

Детектор движения на С/С++ с IP камеры, помогите начать

 , ,


1

5

Доброго времени суток, есть необходимость создать детектор движения используя rtsp поток с IP камеры, чаще всего встречаю похожие проекты с использованием OpenCV, но так же встречал не очень хорошие отзывы о этой библиотеке, говорят кривая, косая используйте что-то другое, но что другое, никто не говорит. Так как я начинающий, хотелось бы действительно узнать, что лучше использовать для таких целей? Возможно кто-то разбирается в этом и может подсказать, а еще лучше если и пару примеров сможет дать/показать. Интересует только Linux, windowые библиотеки не интересны.

Заранее благодарю!


OpenCV.

Кривой он, или косой - не важно. Альтернатив нет.

RazrFalcon ★★★★★ ()

Вариант №1 - OpenCV

Если вдруг он почему-то она точно не подходит, тогда можно начинать искать... Что-нибудь вроде dlib к примеру

mike666 ()

Купите камеры с детекторами движения и не мучайтесь - на кой хер вам понаддобился софтовый детектор ?

anonymous ()
Ответ на: комментарий от anonymous

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

Harald ★★★★★ ()

юзай OpenCV, альтернатива - самому руками писать все операции над изображениями

Harald ★★★★★ ()
Ответ на: комментарий от anonymous

Детектор в камере есть, вот только как этот детектор связать с моей программой? Если такая возможность есть и кто-то может подсказать, буду очень благодарен!

VladV ()
Ответ на: комментарий от VladV

По соотношению результата к скорости и простоте разработки лучше OpenCV ничего нет. Тем более для такой элементарной задачи. В камерах с детекторами, обычно, есть специальный вывод (такой себе GPIO), который меняет логический уровень при появлении движущегося объекта в кадре. Как его связать с компьютером — отдельная история. У современных ПК, увы, нет доступных GPIO (эх LPT ...). Так что придется городить что-то через USB.

baldman88 ()

Есть пример кода на opencv, который смотрит, есть ли движение между двумя снимками. Могу дать, если нужну. Другой скрипт mplayer-ом делает снимки с камеры (USB) и подсовывает для той программы.

Вроде я делал что сама программа может проверять, есть ли движение прямо с камеры, но уже не помню точно.
Код на С++, OpenCV 2.4.

ymuv ★★★★ ()
Последнее исправление: ymuv (всего исправлений: 1)
Ответ на: комментарий от ymuv

Камера GRANDSTREAM GXV3615WP_HD.

Если не сложно поделиться кодом, с удовольствием посмотрел бы. Когда есть реально рабочий пример, проще разобраться.

Спасибо!

VladV ()
Ответ на: комментарий от VladV

Компиляция:
g++ opencv_move_detect_gray.cpp `pkg-config --libs opencv`

Использование:
./a.out /t/1/1.jpg /t/1/2.jpg /t/diff.jpg

/t/diff.jpg - необязательный параметр (разница).
https://gist.github.com/ymuv/e76759ef780145c9b46700cd7a17a16f

2-ой пример:
тут захватывается напрямую с ЮСБ камеры.
https://gist.github.com/ymuv/092e2a700c4ce6841e2384ed1ae2be03

код в основном не мой, я только правил.

Если расскоментировать #define __SHOW__ то будет показывать разницу. Сейчас программа возвращает 1 - если есть движение, 0 - нет. Она еще реагирует на резкие изменения яркости (к примеру солнце за тучу зашло).

ymuv ★★★★ ()
Последнее исправление: ymuv (всего исправлений: 2)
Ответ на: комментарий от VladV

Камера — говно. Простите за резкость, но это убогая камера, обвешанная всякими свистелками и перделками.
Вот простой пример, как детектировать движение в видеопотоке:

#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>

int main(int argc, char* argv[])
{
    cv::VideoCapture capture;
    if (capture.open(0) == false)
    {
        exit(EXIT_FAILURE);
    }
    cv::namedWindow("Output");
    char key = 0;
    cv::Mat frame;
    if (capture.read(frame) == false)
    {
        exit(EXIT_FAILURE);
    }
    cv::Mat fgMask;
    cv::Ptr<cv::BackgroundSubtractor> MOG = cv::createBackgroundSubtractorMOG2();
    MOG->apply(frame, fgMask);
    while (key != 'q')
    {
        if (capture.read(frame) == false)
        {
            exit(EXIT_FAILURE);
        }
        MOG->apply(frame, fgMask);
        cv::blur(fgMask, fgMask, cv::Size(15, 15));
        cv::threshold(fgMask, fgMask, 10, 255, cv::THRESH_BINARY);
        std::vector<std::vector <cv::Point>> contours;
        std::vector<cv::Vec4i> hierarchy;
        cv::findContours(fgMask, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
        std::vector<std::vector<cv::Point>> contours_poly(contours.size());
        std::vector<cv::Rect> boundRects;
        for (size_t i = 0; i < contours.size(); i++)
        {
            cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);
            cv::Rect rect = cv::boundingRect(cv::Mat(contours_poly[i]));
            boundRects.push_back(rect);
        }
        for (size_t i = 0; i < boundRects.size(); i++)
        {
            cv::rectangle(frame, boundRects[i], cv::Scalar(0, 255, 0));
        }
        cv::imshow("Output", frame);
        key = cv::waitKey(1);
    }
    capture.release();
    return 0;
}
Нужно поменять параметр в capture.open() на адрес камеры.

baldman88 ()
Ответ на: комментарий от VladV

Если камера поддерживает ONVIF, то можешь через него подключаться. Правда поддержка ONVIF во многих китайских камерах только на бумаге, а по факту от силы поддерживается Core часть

ncuxer ()
Ответ на: комментарий от baldman88

Простите, а чего говно? Работает на ура, onvif нет, так просто старая)) Мне просто как человеку только начинающему. За пример, больше спасибо! Сегодня начну тестить))

VladV ()
Ответ на: комментарий от ncuxer

ONVIF тут нет, но есть другая камера с ONVIF, правда Китай))) Но как я сказал выше, только начинаю свой путь и моя первая камера с onvif появилась у меня месяца два назад. Был бы благодарен если бы Вы объяснили как проверить можно ли с моей китайской камеры получит данные о движении Спасибо!

VladV ()

я задам вопрос от дилетанта:

обнаружение движения производится сравнением дву полных соседних кадров, т. е. поток надо декодировать. В то же время сжатый поток суть есть полный кадр + дельты между кадрами. Нельзя ли не декодировать поток, а сразу смотреть дельты. Если дельта «большая» значит в кадре значительное изменение = движение

?

anonymous ()
Ответ на: комментарий от VladV

Ставь soap ui и читай спеки ONVIF. Еще есть onvif device manager - можешь попробовать использовать, чтобы убедиться, что камеры поддерживают хотя бы базовый набор ONVIF. Часть про motion detection находится где -то в ONVIF Video Analytics. Еще я wiresharkom снимал траффик с ODM, чтобы быстрее разобраться с протоколом.

Мои камеры ничего не поддерживали, поэтому детальней помочь не могу

ncuxer ()
Ответ на: комментарий от ncuxer

Спасибо и за это! Как я понял onvif device manager, как и аналогов, под Линукс нет?

VladV ()
Ответ на: комментарий от baldman88

Не подскажите, при компиляции не может найти header opencv2/videoio.hpp. В папке его таки нет. Может версию не ту поставил или нужно что-то еще доустанавливать? OpenCV брал с оф сайта и вроде ставил по инструкции.

Спасибо!

VladV ()
Ответ на: комментарий от VladV

Это был пример для 3-й версии OpenCV. Для 2-й как-то так:

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>

int main(int argc, char* argv[])
{
    cv::VideoCapture capture;
    if (capture.open(0) == false)
    {
        exit(EXIT_FAILURE);
    }
    cv::namedWindow("Output");
    char key = 0;
    cv::Mat frame;
    if (capture.read(frame) == false)
    {
        exit(EXIT_FAILURE);
    }
    cv::Mat fgMask;
    cv::Ptr<cv::BackgroundSubtractor> MOG = new BackgroundSubtractorMOG2();
    MOG->operator()(frame, fgMask);
    while (key != 'q')
    {
        if (capture.read(frame) == false)
        {
            exit(EXIT_FAILURE);
        }
        MOG->operator()(frame, fgMask);
        cv::blur(fgMask, fgMask, cv::Size(15, 15));
        cv::threshold(fgMask, fgMask, 10, 255, cv::THRESH_BINARY);
        std::vector<std::vector <cv::Point>> contours;
        std::vector<cv::Vec4i> hierarchy;
        cv::findContours(fgMask, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
        std::vector<std::vector<cv::Point>> contours_poly(contours.size());
        std::vector<cv::Rect> boundRects;
        for (size_t i = 0; i < contours.size(); i++)
        {
            cv::approxPolyDP(cv::Mat(contours[i]), contours_poly[i], 3, true);
            cv::Rect rect = cv::boundingRect(cv::Mat(contours_poly[i]));
            boundRects.push_back(rect);
        }
        for (size_t i = 0; i < boundRects.size(); i++)
        {
            cv::rectangle(frame, boundRects[i], cv::Scalar(0, 255, 0));
        }
        cv::imshow("Output", frame);
        key = cv::waitKey(1);
    }
    capture.release();
    return 0;
}

baldman88 ()
Ответ на: комментарий от baldman88

Спасибо за еще один пример! Я конечно извиняюсь, за возможно глупый вопрос, но как его все таки компилировать? Перепробовал кучу команд которые нашел в интернете, снес второй OpenCV и поставил 3-й, не могу собрать Ваш пример и все тут.

Вариаций было много, но вкратце все сводится к следующим ошибкам: если собираю используя `pkg-config opencv --cflags --libs`, получаю в ответ /usr/bin/ld: cannot find -lippicv. Если использую -I/usr/local/include/opencv2 -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui, получаю

md_test.cpp:(.text+0x35): undefined reference to `cv::VideoCapture::VideoCapture()'
md_test.cpp:(.text+0x49): undefined reference to `cv::VideoCapture::open(int)'
md_test.cpp:(.text+0xd9): undefined reference to `cv::VideoCapture::read(cv::_OutputArray const&)'
md_test.cpp:(.text+0x13c): undefined reference to `cv::createBackgroundSubtractorMOG2(int, double, bool)'
md_test.cpp:(.text+0x22e): undefined reference to `cv::VideoCapture::read(cv::_OutputArray const&)'
md_test.cpp:(.text+0x877): undefined reference to `cv::VideoCapture::release()'
md_test.cpp:(.text+0x8b8): undefined reference to `cv::VideoCapture::~VideoCapture()'
md_test.cpp:(.text+0xb14): undefined reference to `cv::VideoCapture::~VideoCapture()'

Добавление «using namespace cv» - не помогло, так же как и добавления хедера «opencv2/opencv.hpp». Хочется начать разбираться в этой чудо-библиотеке, но я, блин, даже пример не могу собрать ((

VladV ()
Ответ на: комментарий от VladV

День добрый всем! Подскажите, несколько дней долбался с попыткой открыть rtsp поток, ничего не выходит. Сегодня решил попробовать выполнить захват с вебки в ноуте - все получилось, значит проблема именно с rtsp. В VLC поток воспроизводится, через ffplay тоже, в чем может быть проблема?

VladV ()
Ответ на: комментарий от VladV

разобрался с компиляцией?

собираю

$ g++ -I /opt/opencv/include/ -L /opt/opencv/lib/ -lopencv_core -lopencv_objdetect -lopencv_videoio -lopencv_video -lopencv_highgui -lopencv_imgproc objectDetection.cpp

та же фигня с

objectDetection.cpp:(.text+0x4b): undefined reference to `cv::VideoCapture::VideoCapture()'
objectDetection.cpp:(.text+0x69): undefined reference to `cv::CascadeClassifier::load(cv::String const&)'
objectDetection.cpp:(.text+0x93): undefined reference to `cv::CascadeClassifier::load(cv::String const&)'
objectDetection.cpp:(.text+0xc2): undefined reference to `cv::VideoCapture::open(int)'
objectDetection.cpp:(.text+0xd1): undefined reference to `cv::VideoCapture::isOpened() const'
objectDetection.cpp:(.text+0x14d): undefined reference to `cv::waitKey(int)'
objectDetection.cpp:(.text+0x18b): undefined reference to `cv::VideoCapture::read(cv::_OutputArray const&)'
objectDetection.cpp:(.text+0x1c4): undefined reference to `cv::VideoCapture::~VideoCapture()'
objectDetection.cpp:(.text+0x210): undefined reference to `cv::VideoCapture::~VideoCapture()'
bender ★★★★★ ()
Ответ на: комментарий от bender

короче, собралось. нужно было сразу собирать с cmake, как рекомендуют, а не вручную

export OpenCV_DIR=/opt/opencv/share/OpenCV/
cmake .
make
bender ★★★★★ ()

Если тебе просто движение детектировать, просто вычитай из N-го кадра (N-m)-й, где m≥1.

Если же нужно выделить движущийся объект, дело немного усложняется, но тоже ничего страшного нет: почитай Гонсалеса & Вудса.

P.S. А opencv не советую.

anonymous ()
Ответ на: комментарий от anonymous

Правильнее конечно выделить движущийся объект. Но я понял, что мне хотя бы понять как захватить кадр)) Спасибо за литературу!

VladV ()
Ответ на: комментарий от bender

Спасибо, но вы используете софт для захвата, а мне нужно этот софт встроить в свою программу, если так можно сказать)

VladV ()
Ответ на: комментарий от VladV

Opencv, судя по api, умеет захватывать видео внутри кода своей программы. Если у него с конкретной вебкой не срастется, можно переправить поток через тот же ффмпег и кормить опенциви уже через него.

bender ★★★★★ ()
Ответ на: комментарий от VladV

Плюс там второй пример - нодежсная часть хавает поток от ффмпега и покадрово переправляет в вебсокет для отрисовки в браузере. При сильном желании можно там куда-нибудь в промежуток подсосаться со своей прослойкой

bender ★★★★★ ()
Ответ на: комментарий от bender

Спасибо! Еще раз снес полностью OpenCV и поставил как указано тут http://docs.opencv.org/3.0-beta/doc/tutorials/introduction/linux_install/linu... Плюс к этому собрал этот http://docs.opencv.org/3.1.0/d1/dc5/tutorial_background_subtraction.html#gsc.... как Вы сказали, через cmake, как по мне бред, но он собрался и даже заработал захват видео с rtsp. Это прорыв, для меня)) Правда пока работает программа FFMPEG ругается вот таким матом (Invalid UE golomb code), при этом трансляция работает, это нормально?

VladV ()
Ответ на: комментарий от baldman88

Здравствуйте. Подскажите пожалуйста, при компиляции этого кода получаю ошибку undefined reference to `cv::createBackgroundSubtractorMOG2(int, double, bool)'

Apparatchik ()
Ответ на: комментарий от Apparatchik

Была похожая ошибка при попытке собирать через make. Cmake пробовали? И ещё проверьте адреса и наличие хедеров, у меня тоже была такая проблема

VladV ()
Ответ на: комментарий от VladV

Я использую Eclipse она заботится о сборке, хедеры вроде все есть, другие проекты, например распознавание лиц компилятся нормально.

Apparatchik ()
Ответ на: комментарий от Apparatchik

Задача была распознавать свободные парковочные места, с детектором движения не прокатило, пасажиры выходящие с машины фиксируются как выезд с места парковки. Распознавание с помощью каскадов Хаара тоже не дает нужного результата, машины накладываются друг на друга и т.д. Может кто нибудь подскажет алгоритм хоть в какую сторону копать?

Apparatchik ()
Ответ на: комментарий от Apparatchik

Выложите изображение с камеры которая наблюдает за парковкой. Универсального метода нет. Нужно смотреть, что больше подойдет в Вашем случае.

baldman88 ()
Ответ на: комментарий от Apparatchik

Может кто нибудь подскажет алгоритм хоть в какую сторону копать?

А если тупо фон вычитать? Если что-то остается в течение промежутка времени Х, то это машина запаркована. Фильтровать по размеру.

Deleted ()
Ответ на: комментарий от Deleted

Background subtraction называется метод. Обычно используется для отслеживания движения объектов в кадре. В твоем случае понадобится чистый фон без машин на парковке. Надо будет его разметить сообразно парковочным местам. Ну и в отличие от оригинального метода, вычитаемый фон не нужно обновлять.

Дальше дело техники — вычел фон, получил бинарное изображение, отфильтровал мелкие объекты, определил в каких участках крупные и всё.

Примеры: http://docs.opencv.org/master/d1/dc5/tutorial_background_subtraction.html#gsc...

Deleted ()

первое: тебе нужно как уже сказали ранее получить фото пустой парковки и вычитать его из кадра фотокамеры.

во вторых, чтоб не срабатывать на людей, тебе надо еще хранить кадры с шагом в 10-20 секунд и из них вычитать новый кадр, чтоб убедиться что машина именно стоит и стоит долго(человек будет шариться по парковке и не пройдёт этот тест).

в третьих, камера может шататься и пакостить в плане вычитания кадров. этот момент надо учесть. тут надо больше данных: разрешение камеры, например. будет очень хорошо если камера будет слать кадры без сжатия и реже(раз в 10 секунд для парковки хватит)

i36_zubov ()
Ответ на: комментарий от i36_zubov

забыл добавить:

1) набор кадров пустой парковки не подойдет.

ибо в разное время суток и с разными метеоусловиями будут разные изображения.

лучше сделать так: сделать кадры пустой парковки в разное время суток, на них руками обвести «полигоны» которые по твоему мнению являются однотонными поверхностями. этот «тон» алгоритм должен ожидать от незанятого пространства. учти что под определёнными ракусами большой автомобиль может закрыть несколько мест. нет смысла их засчитывать. лучше поставить больше камер под разными углами и для них по отдельности выделить те полигоны, где точно попадаешь в одно место.

у полигона должна быть ожидаемая яркость от времени суток.

это разовая работа и она проще чем на OpenCV что-то распознавать.

i36_zubov ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.