LINUX.ORG.RU

Либу на С/C++ на анализ движения?

 ,


0

2

Посоветуйте, пожалста???

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

★★★
Ответ на: комментарий от wolverin

2 версию вывозил. Там еще от разрешения изображения и от количества кадров в секунду, количества камер зависит. Но в целом ресурсоемкость гибкая и настраивается, в том числе со стороны opencv

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

да, но для этого потребуется декодировать на нем же 1920х1080, а это около 100-120мс + масштабирование для жпега в моем случае и главное одно из 4х почти 100% занятое ядро.

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

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

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

В теории ты можешь сделать 2 потока: один шакальный, который будет обрабатывать OpenCV и полноценный (для задачи), на который будут накладываться те же сдвиги, которые OpenCV посчитал для шакального.

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

если вам не сложно, можете сориентировать для анализа движения по снимкам что из опенсв мне нужно? а то склонировался с гитхаба и там >700мб прилетело ) от чего то бы оттолкнуться, чтобы во всем сразу не разбираться.

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

есть оптический поток https://docs.opencv.org/3.4/d4/dee/tutorial_optical_flow.html, но возможно для вашего случая слишком ресурсоемкий. Самое просто - разность кадров, соседних, или взятых через N. тоже в опенсв алг должен быть, но сходу не нашел, но там и руками несложно пишется

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

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

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

На основе яркостей пикселей, то есть просто попиксельная разность двух кадров. В результате будет матрица, где области в которых движение не произошло будут черные (яркость пикселей 0), а там где что-то двигалось яркость будет отличной от нуля. Только в опенсв надо разность эту самому считать по модулю, тк библиотечная функция обрезает результат до 0 при отрицательной разности. То есть условно будет 54 - 200 = 0, а вам надо по модулю |54 - 200| = 146. Это вообще не огонь метод, но если у вас простой фон и нет хаотичного движения кучи объектов, то норм наверное будет

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

В результате будет матрица, где области в которых движение не произошло будут черные (яркость пикселей 0), а там где что-то двигалось яркость будет отличной от нуля… Это вообще не огонь метод

Да, не огонь. Разность будет не 0 уже из-за шума матрицы. Также влияние добавит освещение (например, свет от электрических ламп может пульсировать), автоматический баланс белого, автоматический подбор усиления в камере и т.д.

Как-то будет работать, если предварительно разделить все пиксели на 2 цвета по порогу (например, по средней яркости). Но тут будет работать для контрастных объектов.

Если не выделять контуры, то можно попробовать ещё разделить изображение на кластеры по k-means и следить, чтобы число пикселей в кластерах не сильно менялось. Кластеры можно даже в 3-мерном RGB пространстве сделать. Тогда кроме количества пикселей для каждого кластера будет ещё и какой-то цвет присутствовать.

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

а одноплатный arm как думаете с 512Мб ее вывезет?

зависит от … , в своё время использовал OpenCV для нахождения лиц в потоке на FreeScale imx53, не идеально, но вполне работало

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

по сути это так же на основе размера файла, просто дробление на участки, поэтому не особо подходит, т.к. все камеры у меня уличные и простое изменение времени суток приводит к «движению», хотя в кадре вообще из крупных объектов (авто или люди недалеко от камеры) ничего не перемещается.

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

Плохо. Тогда только декодировать и сравнивать кадры. Но этим можно уложить на лопатки процессор. Лучше рассмотри вариант с покупкой IP камеры. Она по цене будет как вебка, но с детектором движения.

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

А тебе нужен просто факт, что есть движение в кадре или нужно ещё и прямоугольниками обвести области, где есть движение?

У меня есть код детектора движения на opencv. Из коммерческого проекта. Выложить не могу, но могу в общем написать алгоритм.

Кадр переводится в серый цвет. Так же хранится предыдущий кадр, тоже в сером цвете. Дальше просто алгоритм.

cv::absdiff // разница между кадрами
cv::threshold // регулировка чувствительности детектора
cv::motempl::updateMotionHistory
cv::motempl::segmentMotion

Это даст тебе координаты всех областей, в которых есть движение

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

да уже 1.5 тыщи камер куплено

Плохо проработали задачу на этапе планирования. Тут нужны ip камеры. Вебки они для скайпа. Если нужно детектить движение и писать архивы, то лучше купить ip камеры и ip регистратор. Всё будет из коробки. С циклической перезаписью и записью только если в кадре есть движение.

ox55ff ★★★★★
()

Кстати. Вангую тебе ещё нужна фича, чтобы в архив начиналась запись не в момент детектирования движения в кадре, а за несколько секунд до этого — очень полезно, когда потом будешь смотреть архив. Понятнее становится, что произошло в кадре. Это называется предзапись. Есть ещё постзапись — несколько секунд после окончания движения. И в готовых ip регистраторах она есть. А тебе придётся колхозить самим.

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

да из коробки не подходит, архив циклически пишется нормально на карту одноплатником уже и высылается он по запросу пока правда по tcp четко

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

спасибо вам, буду разбираться по описанным вызовам.

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

Если движение удастся идеально детектировать то это выглядит не сложно просто записывая куском заранее и если движа нет - переписывать его

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

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

декодирование мжпег 90-120 мс где то занимает, беда что однопоточная процедура это в ффмпеге

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

проблема в том, что не знаю как в опенсв, но вот например в ффмпеге они дохера поменяли и такие 10 летние статьи становятся не актуальными для текущей версий

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

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

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

вообще я предполагаю 1 раз в секунду сравнивать, ну ок пусть не смена суток - солнце из-за тучи вылезло или спряталось - вот вам куча «движения» в размере как файлов, так и пикселей

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

Можешь попытаться избавиться от ffmpeg в этом месте: просто читать кадры напрямую через v4l2, там достаточно просто, можешь за основу взять: https://gist.github.com/h4tr3d/602e895d6027a4e48031.Loongson готовит мир к своим новым процессорам. Компания выпустила патчи для Linux, внедряющие поддержку ряда функций чипа 3A6000, релиз которого ожидается в ближайшие недели.

А для декодирования libjpeg-turbo или каким другим вариантом, где используется simd или параллелизм.

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

спасибо, интересно! для этой либы указана якобы аппаратная поддержка NEON для армок (в идеале бы конечно аппаратная поддержка на гпу Mali, но то видать мечты)

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

Там есть нюанс по рестарт-маркерам. Как минимум, mjpeg от logitech c910 с ними идёт. Так что будьте готовы. А вот про GPU декодировку и параллельную декодировку я только бумаги видел. До свёртывания проекта, где это нужно было, наиболее оптимальным решением был IP core на FPGA. Но он не умел рестарт маркеры.

Зы скопипастил лишнюю хрень, сорян откорректировать не смогу.

hatred ★★★
()
Последнее исправление: hatred (всего исправлений: 1)

Попробую объяснить на примере. Картинка (разжатая, конечно) является сигналом, типа синусоиды, например, только сложнее. На этот сигнал накладывается случайный шум и усиление от внешних источников света. Это можно смоделировать кодом:

const double PI = acos(-1);

void create_data(vector<int>& values, int startAngle)
{
    values.clear();
    int lastAngle = startAngle + 90;
    int ampl = 100;
    for(int angle = startAngle; angle < lastAngle; ++angle)
    {
        int val = ampl + ampl * sin((double)angle * PI / 180.0);
        values.push_back(val);
    }
}

void add_noise(vector<int>& values, int ampl)
{
    for (int& val: values)
    {
        val += rand() % (ampl);
    }

}

void multiply_percent(vector<int>& values, int percent)
{
    for (int& val: values)
    {
        val = (val * percent) / 100;
    }
}

Первая функция создаёт сигнал. В данном случае, это синусоида от угла startAngle до startAngle + 90. Мы её можем смещать и детектировать это смещение. Остальные функции задают шум и усиление.

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

int get_diff_sum(vector<int>& values1, vector<int>& values2)
{
    if(!values1.size()) return 0;
    int sum = 0;

    int maxValue1 = (*max_element(values1.begin(), values1.end()));
    int maxValue2 = (*max_element(values2.begin(), values2.end()));
    int base = 100;

    for (size_t i = 0; i < values1.size(); ++i)
    {
        sum += abs(base * values2[i] / maxValue2 - base * values1[i] / maxValue1);
    }
    return 100 * sum / values1.size();
}

Здесь мы нормализуем два сигнала, а потом получаем среднюю разницу элементов в процентах. Нормализуем путем деления на максимальное значение для каждого сигнала.

Затем проверяем:

    vector<int> originalValues;
    vector<int> movedValues;
    create_data(originalValues, 90);
    create_data(movedValues, 95);


    vector<int> noiseValues = originalValues;
    add_noise(noiseValues, 10);

    vector<int> bigValues = originalValues;
    multiply_percent(bigValues, 150);

    cout << "5% move diff sum: " << get_diff_sum(originalValues, movedValues) << " %" << endl;
    cout << "10% noise diff sum: " << get_diff_sum(originalValues, noiseValues) << " %" << endl;
    cout << "150% mul diff sum: " << get_diff_sum(originalValues, bigValues) << " %" << endl;

На выходе получаем:

5% move diff sum: 286 %
10% noise diff sum: 165 %
150% mul diff sum: 0 %

То есть в усиленном сигнале движение отбросили нормализацией, а шум в 10% даёт сумму отклонений меньше чем сдвиг на 5 %. Можно задать порог отделения шума (например в 200 %). К сожалению, сдвиг на 1% мы этим способом не выявим при таком шуме. Тут может помочь фильтрация.

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

кароч попробовал этот фильтр ффмпега - декодирую, масштабирую в 8 раз фуллхд и фильтрация по SAD - вроде как то работает, все лучше чем еще опенсв прикручивать.

wolverin ★★★
() автор топика