// 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) { auto diff = 0; if (pixA > pixB) diff = pixA - pixB; if (pixB > pixA) diff = pixB - pixA; if (diff < share->colorThresh) { diff = 0; } return diff != 0; } void secDiff(Mat imgA, Mat imgB, int rows, int cols, int rowOffs, int colOffs, vector *results, mutex *secMutex, shared_t *share) { auto pnts = 0; for (auto y = rowOffs; y < rows; y++) { for (auto x = colOffs; x < cols; x++) { auto pixA = imgA.at(Point(x, y)); auto pixB = imgB.at(Point(x, y)); if (pixDiff(pixA, pixB, share)) { pnts += 1; } } } struct sec_t res; res.x = colOffs; res.y = rowOffs; res.xSize = cols; res.ySize = rows; res.pixDiff = pnts; lock_guard guard(*secMutex); results->push_back(res); } bool imgDiff(Mat prev, Mat next, Rect *block, shared_t *share) { auto numOfXBlocks = prev.cols / share->blockX; auto numOfYBlocks = prev.rows / share->blockY; auto moInBlock = false; vector threads; vector results; mutex secMutex; for (auto x = 0; x < numOfXBlocks; x += share->blockX) { // spawn all of the block motion detection threads. for (auto y = 0; y < numOfYBlocks; y += share->blockY) { threads.push_back(thread(secDiff, prev, next, 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; share->stat += "block_thread:" + string(" x=") + to_string(x) + " y=" + to_string(y) + " pixdiff=" + to_string(diff) + "\n"; if ((results[i].pixDiff >= share->blockThresh) && (results[i].pixDiff > maxPixDiff)) { maxPixDiff = results[i].pixDiff; blockPick = i; } } if (maxPixDiff >= share->blockThresh) { // return true on this function with the block with the // high pixDiff value which should be at or exceeds // the block_threshold set by the conf file. auto res = results[blockPick]; block->x = res.x; block->y = res.y; block->height = res.ySize; block->width = res.xSize; moInBlock = true; } return moInBlock; } bool moDetect(const string &buffFile, Rect *block, Mat *img, 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), block, share)) { *img = next; 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; }