Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 32, средняя оценка - 4.91
Drony
1 / 1 / 0
Регистрация: 22.10.2011
Сообщений: 18
#1

Motion Detector (OpenCV) - C++

22.10.2011, 15:30. Просмотров 4617. Ответов 4
Метки нет (Все метки)

Всем привет! =)
Только начал разбираться с OpenCV. Хочу попробовать камеру распознавать движение. Детектор движения должен реализоваться на C++ при помощи библиотеки OpenCV.
Но возникла одна проблемка. Вот, собственно код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "v_motion_detector.h"
 
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/tracking.hpp>
 
const double VMotionDetector::MOTION_THRESHOLD = 10;
const double VMotionDetector::MIN_CONTOUR_AREA = 150;
 
VMotionDetector::VMotionDetector( const cv::Size& imageSize, double cycleTime) :
        m_previousImage( cv::Mat::zeros( imageSize, CV_8UC1 ) ),
        m_motionHistoryImage( imageSize, CV_32FC1 ),
        m_openingKernel( 5, 5, CV_8UC1 ),
        m_segmask( imageSize, CV_32FC1 ),
        m_maxMotionGradient( 1.5 * cycleTime ),
        m_motionHistoryDuration( 7 * cycleTime )
{
}
 
void VMotionDetector::detectMovingRegions( const cv::Mat& currentFrame, double timestamp,
                                           std::vector<cv::Rect>& targets , cv::Mat& mask )
{
 //Сглаживаем текущий кадр (currentFrame) фильтром Гаусса, чтобы избавиться от шумов.
 
    cv::GaussianBlur( currentFrame, m_bluredImage, cv::Size( 3, 3 ), -1 );
 
//Из сглаженного текущего кадра (m_bluredImage ) вычитаем предыдущий (m_previousImage).
//Если искомые изображения были в градациях серого, то и значения пикселей
//в разности (mask) будут изменяться от нуля до 255(при восьми битной глубине цвета).
 
    cv::absdiff( m_bluredImage, m_previousImage, mask );
 
//Сравниваем значения полученной разности с некоторым пороговым
//значением (MOTION_THRESHOLD). Если значение пикселя больше порогового,
//то этот пиксель принадлежит движущемуся объекту, иначе отбрасываем его.
//Теперь мы получили бинарное изображение (mask), где ноль означает, что 
//пиксель не движется, отличное от нуля значение – пиксель движется.
 
    cv::threshold( mask, mask,  MOTION_THRESHOLD, 255, cv::THRESH_BINARY );
 
//Применяем морфологические операции закрытия и открытия,
//чтобы избавиться от движущихся регионов малого размера (шумы камеры).
//Полученное изображение (mask) и есть движущийся контур.
 
    cv::morphologyEx( mask, mask, cv::MORPH_CLOSE, cv::Mat() );
    cv::morphologyEx( mask, mask, cv::MORPH_OPEN, m_openingKernel,
                      cv::Point( -1, -1 ), 1, cv::BORDER_CONSTANT, cv::Scalar( 0 ) );
 
//Наносим бинарное изображение на так называемое изображение истории движения
//(motionHistoryImage). На нём нарисованы движущиеся контуры за последние, например,
//200 мс (m_motionHistoryDuration). Контуры были получены через постоянные промежутки
//времени. Интенсивность пикселей контура обратно пропорциональна времени, которое
//прошло от измерения контура до данного момента. Т.е. чем раньше был получен
//движущийся контур, тем он бледнее изображён на изображение истории движения.
        
    cv::updateMotionHistory( mask, m_motionHistoryImage, timestamp, m_motionHistoryDuration );
 
//Выделяем регионы (targets) с различными движениями на изображение истории движения.  
 
    cv::segmentMotion(m_motionHistoryImage, m_segmask, targets, timestamp, m_maxMotionGradient);
        
//Отбрасываем все регионы, площадь которых меньше некоторого значения (MIN_CONTOUR_AREA).
 
        std::vector<cv::Rect>::const_iterator it = targets.begin();
        
        for(it = targets.begin(); it != targets.end(); ++it) {
                if(cv::countNonZero(mask(*it)) < MIN_CONTOUR_AREA) 
                        targets.erase(it);
        }
//Сохраняем сглаженный текущий кадр как предыдущий кадр.
    m_bluredImage.copyTo( m_previousImage );
}
На этапе выполнения возникает ошибка:
"Expression: vector iterator not dereferencable."
Облазил весь интеренет, ничего не нашёл. Одна надежда на вас)) Помогите, пожалуйста!!!!!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.10.2011, 15:30
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Motion Detector (OpenCV) (C++):

OpenCV - C++
уважаемые участники, я чайник по ОpenCV. помогите?! с чего начать и как обучаться, чему стоит а чему нет

OpenCV с изображениями - C++
Здравствуйте, приложил программу, картинка выходит за пределы окна, как это избежать? Итог должен получится такой, изображение должно...

[OpenCV] Поиск по шаблону - C++
Добрый день, имеется код с robocraft, в котором используется функция cvMatchTemplate, вопрос состоит в том, чтобы узнать нашла ли функция...

Распознавание текста OpenCV - C++
Доброго времени суток! посмотрел на днях видео https://www.youtube.com/watch?v=pgth0qxTgYY и меня заитересовал этот проект. моя идея...

Проект на OpenCV вылетает - C++
Коротко: 1. Скачал бинарники (Win) 2. Создал проект (VS2010). 3. Написал семпл код. 4. Добавил зависимости, прописал include,...

OpenCV/C++ обработка изображений - C++
В общем задача следующая, есть изображение(бинарное), подсчитать кол-во объектов т.е изначально нужно его промаркировать. Использовал...

4
Nick Alte
Эксперт С++
1642 / 1014 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
23.10.2011, 14:31 #2
Классическая ошибка - удаление элементов "в лоб" приводит к тому, что итераторы, "выписанные" вектором до удаления элемента, портятся после удаления.
Вместо
C++
1
2
3
        for(it = targets.begin(); it != targets.end(); ++it) {
                if(cv::countNonZero(mask(*it)) < MIN_CONTOUR_AREA) 
                        targets.erase(it);
лучше воспользоваться стандартным алгоритмом
C++
1
        std::remove_if(targets.begin(), targets.end(), AreaTooSmall);
где bool AreaTooSmall (const cv::Rect& rect) - функция, проверяющая требуемое условие.
Ну или на новом стандарте, на GCC или Visual Studio 2010 можно через лямбда-функцию сразу
C++
1
        std::remove_if(targets.begin(), targets.end(), [] (const cv::Rect& r) {return cv::countNonZero(mask(r)) < MIN_CONTOUR_AREA});
1
Drony
1 / 1 / 0
Регистрация: 22.10.2011
Сообщений: 18
23.10.2011, 15:22  [ТС] #3
Nick Alte,
Ок, спасибо))


C++
1
std::remove_if(targets.begin(), targets.end(), [] (const cv::Rect& r) {return cv::countNonZero(mask(r)) < MIN_CONTOUR_AREA});
Этим способом не получается, потому что у cv::Mat& mask есть вложенные функции, поэтому на эту переменную нельзя ссылаться внутри тела лямбда-выражения =((

А первым способом с функцией:
C++
1
bool AreaTooSmall (const cv::Rect& rect);
Я не совсем понимаю... Можно поподробней? Что передавать в эту функцию, когда мы пишем:

C++
1
std::remove_if(targets.begin(), targets.end(), AreaTooSmall(/*?????*/));
0
Nick Alte
Эксперт С++
1642 / 1014 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
23.10.2011, 17:04 #4
Цитата Сообщение от Drony Посмотреть сообщение
Этим способом не получается, потому что у cv::Mat& mask есть вложенные функции, поэтому на эту переменную нельзя ссылаться внутри тела лямбда-выражения =((
А вот и можно, достаточно начинать лямбду не с [], а с [&]

Цитата Сообщение от Drony Посмотреть сообщение
Я не совсем понимаю... Можно поподробней? Что передавать в эту функцию
Передавать надо только имя самой функции AreaTooSmall, как и написано у меня в примере:
C++
1
std::remove_if(targets.begin(), targets.end(), AreaTooSmall);
1
Drony
1 / 1 / 0
Регистрация: 22.10.2011
Сообщений: 18
24.10.2011, 17:43  [ТС] #5
Nick Alte, Вот так?)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "v_motion_detector.h"
 
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/tracking.hpp>
 
const double VMotionDetector::MOTION_THRESHOLD = 10;
const double VMotionDetector::MIN_CONTOUR_AREA = 150;
 
VMotionDetector::VMotionDetector( const cv::Size& imageSize, double cycleTime) :
        m_previousImage( cv::Mat::zeros( imageSize, CV_8UC1 ) ),
        m_motionHistoryImage( imageSize, CV_32FC1 ),
        m_openingKernel( 5, 5, CV_8UC1 ),
        m_segmask( imageSize, CV_32FC1 ),
        m_maxMotionGradient( 1.5 * cycleTime ),
        m_motionHistoryDuration( 7 * cycleTime )
{
}
 
void VMotionDetector::detectMovingRegions( const cv::Mat& currentFrame, double timestamp,
                                           std::vector<cv::Rect>& targets , cv::Mat& mask )
{
    cv::GaussianBlur( currentFrame, m_bluredImage, cv::Size( 3, 3 ), -1 );
    cv::absdiff( m_bluredImage, m_previousImage, mask );
    cv::threshold( mask, mask,  MOTION_THRESHOLD, 255, cv::THRESH_BINARY );
    cv::morphologyEx( mask, mask, cv::MORPH_CLOSE, cv::Mat() );
    cv::morphologyEx( mask, mask, cv::MORPH_OPEN, m_openingKernel,
                      cv::Point( -1, -1 ), 1, cv::BORDER_CONSTANT, cv::Scalar( 0 ) );
    
    cv::updateMotionHistory( mask, m_motionHistoryImage, timestamp, m_motionHistoryDuration );
    cv::segmentMotion(m_motionHistoryImage, m_segmask, targets, timestamp, m_maxMotionGradient);
 
    std::remove_if(targets.begin(), targets.end(), [&] (const cv::Rect& r) {return cv::countNonZero(mask(r)) < MIN_CONTOUR_AREA;});
    
    m_bluredImage.copyTo( m_previousImage );
}
Новая ошибка на этапе выполнения:
invalid iterator range

Добавлено через 3 часа 33 минуты
а как вообще работает cv::segmentMotion(…); ?
ну т. е. откуда берёимя вектор targets?
может, у меня тут проблемка? может, есть что-то похожее?
0
24.10.2011, 17:43
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
24.10.2011, 17:43
Привет! Вот еще темы с ответами:

Определение расстояния до объекта OpenCV - C++
Добрый день. При выполнении лабораторной работы по физике возникла проблема. Есть установка, выпускающая пулю, нужно определить, на...

Программа с opencv жрет память - C++
Вообщем есть программа, после каждой итерации очищаю память, но все-равно почему то буквально за 2-3 цикла по j, программа падает из-за...

Выделение объектов в рамку Opencv - C++
Здравствуйте! В моей программе сохраняется фон, затем в режиме реального времени фиксируются пиксели, отличные от ранее сохраненного фона....

Изменение цвета пикселя в opencv - C++
Добрый вечер. Скажите, пожалуйста, есть ли какой-либо метод у opencv, который выполняет преобразование с изображением, делая его более...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.