1 / 1 / 0
Регистрация: 22.10.2011
Сообщений: 18
1

Motion Detector (OpenCV)

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

Author24 — интернет-сервис помощи студентам
Всем привет! =)
Только начал разбираться с 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
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.10.2011, 15:30
Ответы с готовыми решениями:

Vusial Leak Detector ничего не выводит
Естественно подключил все заголовочные файлы и статические библиотеки. Рядом почти такой-же проект...

Motion Detector (OpenCV)
Всем привет! =) Только начал разбираться с OpenCV. Хочу попробовать камеру распознавать движение....

SURF DETECTOR на EmguCV
При компиляции проекта выдает ошибку в строке: Dim surfDetector As SURFDetector = New...

Spyware process detector(dllhost)
Всем доброго времени суток! Проблема такая, скачал программку Spyware Process Detector v3.22(может...

4
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
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
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
Эксперт С++
1674 / 1046 / 174
Регистрация: 27.09.2009
Сообщений: 1,945
23.10.2011, 17:04 4
Цитата Сообщение от Drony Посмотреть сообщение
Этим способом не получается, потому что у cv::Mat& mask есть вложенные функции, поэтому на эту переменную нельзя ссылаться внутри тела лямбда-выражения =((
А вот и можно, достаточно начинать лямбду не с [], а с [&]

Цитата Сообщение от Drony Посмотреть сообщение
Я не совсем понимаю... Можно поподробней? Что передавать в эту функцию
Передавать надо только имя самой функции AreaTooSmall, как и написано у меня в примере:
C++
1
std::remove_if(targets.begin(), targets.end(), AreaTooSmall);
1
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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.10.2011, 17:43
Помогаю со студенческими работами здесь

Raspberry и Motion
Решил сделать нечто вроде IP видеокамеры на Raspberry, которая будет транслировать видео в браузер,...

SURF DETECTOR на EmguCV - ошибка компиляции проекта
При компиляции проекта выдает ошибку в строке: Dim surfDetector As SURFDetector = New...

slow motion bug
система: AMD Phenom II X4 925 Processor, 8.0GB RAM, NVIDIA GeForce GTS 450 MS Windows 7 Ultimate...

Motion + mencoder + wput = ?
Всем доброе время суток. В общем сразу по делу. Поставился задачей, цель которой - это ...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru