JustMotion/src/mo_detect.cpp

136 lines
3.6 KiB
C++
Raw Normal View History

// This file is part of Motion Watch.
// Motion Watch is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Motion Watch is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "mo_detect.h"
bool pixDiff(const uchar &pixA, const uchar &pixB, shared_t *share)
{
if (pixA > pixB) return true;
if (pixB > pixA) return true;
return false;
}
void secDiff(const Mat &imgA, const Mat &imgB, int id, int rows, int cols, int rowOffs, int colOffs, vector<sec_t> *results, mutex *secMutex, shared_t *share)
{
auto diff = 0;
auto pnts = 0;
for (auto y = rowOffs; y < (rowOffs + rows); y++)
{
for (auto x = colOffs; x < (colOffs + cols); x++)
{
auto pixA = imgA.at<uchar>(Point(x, y));
auto pixB = imgB.at<uchar>(Point(x, y));
if (pixDiff(pixA, pixB, share)) pnts += 1;
else pnts = 0;
if (pnts >= share->consecThresh)
{
diff += 1;
}
}
}
struct sec_t res;
res.x = colOffs;
res.y = rowOffs;
res.xSize = cols;
res.ySize = rows;
res.pixDiff = diff;
res.id = id;
lock_guard<mutex> guard(*secMutex);
results->push_back(res);
}
bool imgDiff(const Mat &prev, const Mat &next, shared_t *share)
{
vector<thread> threads;
vector<sec_t> results;
mutex secMutex;
auto id = 0;
for (auto x = 0; x < prev.cols; x += share->blockX)
{
// spawn all of the block motion detection threads.
for (auto y = 0; y < prev.rows; y += share->blockY, id += 1)
{
threads.push_back(thread(secDiff, prev, next, id, share->blockY, share->blockX, y, x, &results, &secMutex, share));
}
}
for (auto &&thr : threads)
{
// wait for all of the threads to finish.
thr.join();
}
auto maxPixDiff = 0;
auto blockPick = 0;
for (auto i = 0; i < results.size(); ++i)
{
// out of all of the results returned form the threads, pick
// the block with the highest amount of pixDiff.
auto x = results[i].x;
auto y = results[i].y;
auto diff = results[i].pixDiff;
auto id = results[i].id;
if (diff > 0)
{
share->stat += string("block_thread:") + " id=" + to_string(id) + " diff=" + to_string(diff) + "\n";
}
if ((results[i].pixDiff >= share->blockThresh) && (results[i].pixDiff > maxPixDiff))
{
maxPixDiff = results[i].pixDiff;
blockPick = i;
}
}
return maxPixDiff >= share->blockThresh;
}
bool moDetect(const string &buffFile, shared_t *share)
{
auto mod = false;
VideoCapture capture(buffFile.c_str(), CAP_FFMPEG);
if (capture.isOpened())
{
Mat prev;
Mat next;
while (capPair(prev, next, capture, share))
{
if (imgDiff(toGray(prev), toGray(next), share))
{
mod = true; break;
}
}
}
else
{
cerr << "err: Could not open buff file: " << buffFile << " for reading. check formatting/permissions." << endl;
cerr << " Also check if opencv was compiled with FFMPEG encoding enabled." << endl;
}
return mod;
}