update change the motion detection to optical flow calculations
This commit is contained in:
parent
91b950df74
commit
8cfa1fccde
|
@ -1,7 +1,7 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
project( MotionWatch )
|
project( MotionWatch )
|
||||||
find_package( OpenCV REQUIRED )
|
find_package( OpenCV REQUIRED )
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread")
|
||||||
include_directories( ${OpenCV_INCLUDE_DIRS} )
|
include_directories( ${OpenCV_INCLUDE_DIRS} )
|
||||||
add_executable( mow src/main.cpp )
|
add_executable( mow src/main.cpp )
|
||||||
target_link_libraries( mow ${OpenCV_LIBS} )
|
target_link_libraries( mow ${OpenCV_LIBS} )
|
||||||
|
|
118
src/main.cpp
118
src/main.cpp
|
@ -17,17 +17,17 @@ using namespace std;
|
||||||
|
|
||||||
struct shared_t
|
struct shared_t
|
||||||
{
|
{
|
||||||
|
vector<Mat> buff;
|
||||||
|
vector<thread> writers;
|
||||||
string detectUrl;
|
string detectUrl;
|
||||||
string recordUrl;
|
string recordUrl;
|
||||||
string outDir;
|
string outDir;
|
||||||
string postMoCmd;
|
string postMoCmd;
|
||||||
string postNoMoCmd;
|
string postNoMoCmd;
|
||||||
string secsStr;
|
string secsStr;
|
||||||
string camId;
|
bool wrRunning;
|
||||||
bool ffRunning;
|
bool ffRunning;
|
||||||
bool motion;
|
|
||||||
int secs;
|
int secs;
|
||||||
int ignore;
|
|
||||||
|
|
||||||
} sharedRes;
|
} sharedRes;
|
||||||
|
|
||||||
|
@ -73,6 +73,10 @@ bool createDirTree(const string &full_path)
|
||||||
|
|
||||||
void vidCap(shared_t *share)
|
void vidCap(shared_t *share)
|
||||||
{
|
{
|
||||||
|
if (share->buff.size() >= 30)
|
||||||
|
{
|
||||||
|
share->wrRunning = true;
|
||||||
|
|
||||||
time_t rawtime;
|
time_t rawtime;
|
||||||
|
|
||||||
time(&rawtime);
|
time(&rawtime);
|
||||||
|
@ -83,41 +87,35 @@ void vidCap(shared_t *share)
|
||||||
char fileName[20];
|
char fileName[20];
|
||||||
|
|
||||||
strftime(dirName, 20, "%Y%m%d", timeinfo);
|
strftime(dirName, 20, "%Y%m%d", timeinfo);
|
||||||
strftime(fileName, 20, "%H%M%S.ts", timeinfo);
|
strftime(fileName, 20, "%H%M%S.avi", timeinfo);
|
||||||
|
|
||||||
auto tmpFile = string("/tmp/mow/") + share->camId + ".ts";
|
|
||||||
auto ffmpegCmd = string("ffmpeg -hide_banner -loglevel error -i ") + share->recordUrl + string(" -t ") + share->secsStr + string(" -y -vcodec copy ") + tmpFile;
|
|
||||||
|
|
||||||
createDirTree(string("/tmp/mow"));
|
|
||||||
system(ffmpegCmd.c_str());
|
|
||||||
|
|
||||||
share->ffRunning = false;
|
|
||||||
|
|
||||||
if (share->motion)
|
|
||||||
{
|
|
||||||
if (!share->postMoCmd.empty())
|
|
||||||
{
|
|
||||||
system(share->postMoCmd.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
createDirTree(cleanDir(share->outDir) + string("/") + string(dirName));
|
createDirTree(cleanDir(share->outDir) + string("/") + string(dirName));
|
||||||
|
|
||||||
auto dstPath = cleanDir(share->outDir) + string("/") + string(dirName) + string("/") + string(fileName);
|
auto dstPath = cleanDir(share->outDir) + string("/") + string(dirName) + string("/") + string(fileName);
|
||||||
|
auto codec = VideoWriter::fourcc('M', 'J', 'P', 'G');
|
||||||
|
auto fps = 25.0;
|
||||||
|
|
||||||
system(string("mv " + tmpFile + " " + dstPath).c_str());
|
VideoWriter writer;
|
||||||
|
|
||||||
|
writer.open(dstPath, codec, fps, share->buff[0].size(), true);
|
||||||
|
|
||||||
|
if (!writer.isOpened())
|
||||||
|
{
|
||||||
|
cerr << "could not open the output video file for writing: " << dstPath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!share->postNoMoCmd.empty())
|
for (; !share->buff.empty(); share->buff.erase(share->buff.begin()))
|
||||||
{
|
{
|
||||||
system(share->postNoMoCmd.c_str());
|
writer.write(share->buff[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
system(string("rm " + tmpFile).c_str());
|
share->wrRunning = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void detectDiff(const Mat &prev, const Mat &next, shared_t *share)
|
bool detectDiff(const Mat &prev, const Mat &next, shared_t *share)
|
||||||
{
|
{
|
||||||
// optical flow calculations are used to detect motion.
|
// optical flow calculations are used to detect motion.
|
||||||
// reference: https://docs.opencv.org/3.4/d4/dee/tutorial_optical_flow.html
|
// reference: https://docs.opencv.org/3.4/d4/dee/tutorial_optical_flow.html
|
||||||
|
@ -135,14 +133,14 @@ void detectDiff(const Mat &prev, const Mat &next, shared_t *share)
|
||||||
goodFeaturesToTrack(prev, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);
|
goodFeaturesToTrack(prev, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);
|
||||||
calcOpticalFlowPyrLK(prev, next, p0, p1, status, err, Size(10, 10), 2, criteria);
|
calcOpticalFlowPyrLK(prev, next, p0, p1, status, err, Size(10, 10), 2, criteria);
|
||||||
|
|
||||||
for(uint i = 0; (i < p0.size()) && !share->motion; i++)
|
for(uint i = 0; i < p0.size(); i++)
|
||||||
{
|
{
|
||||||
// select good points
|
// select good points
|
||||||
if(status[i] == 1)
|
if(status[i] == 1)
|
||||||
{
|
{
|
||||||
if (count == 5)
|
if (count == 5)
|
||||||
{
|
{
|
||||||
share->motion = true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (norm(p0[i] - p1[i]) > distance)
|
else if (norm(p0[i] - p1[i]) > distance)
|
||||||
{
|
{
|
||||||
|
@ -156,36 +154,72 @@ void detectDiff(const Mat &prev, const Mat &next, shared_t *share)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer(shared_t *share)
|
||||||
|
{
|
||||||
|
sleep(share->secs);
|
||||||
|
|
||||||
|
share->ffRunning = false;
|
||||||
|
|
||||||
|
if (!share->wrRunning)
|
||||||
|
{
|
||||||
|
new thread(vidCap, share);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void moDetect(shared_t *share)
|
void moDetect(shared_t *share)
|
||||||
{
|
{
|
||||||
auto cap = VideoCapture(share->detectUrl, CAP_FFMPEG);
|
auto dCap = VideoCapture(share->detectUrl, CAP_FFMPEG);
|
||||||
|
auto rCap = VideoCapture(share->recordUrl, CAP_FFMPEG);
|
||||||
|
auto mod = false;
|
||||||
|
|
||||||
Mat firstFrame, currentFrame, frame;
|
Mat dPrevFrame, dNextFrame, dFrame, rFrame;
|
||||||
|
|
||||||
while (share->ffRunning && !share->motion)
|
while (share->ffRunning)
|
||||||
{
|
{
|
||||||
cap >> frame;
|
dCap >> dFrame;
|
||||||
|
rCap >> rFrame;
|
||||||
|
|
||||||
if (frame.empty())
|
if (dFrame.empty())
|
||||||
{
|
{
|
||||||
// broken frames returned from the cameras i've tested this with would cause
|
// broken frames returned from the cameras i've tested this with would cause
|
||||||
// the entire capture connection to drop, hence why this bit of code is here
|
// the entire capture connection to drop, hence why this bit of code is here
|
||||||
// to detect empty frames (signs of a dropped connection) and attempt
|
// to detect empty frames (signs of a dropped connection) and attempt
|
||||||
// re-connect to the cammera.
|
// re-connect to the cammera.
|
||||||
cap.open(share->detectUrl, CAP_FFMPEG);
|
dCap.open(share->detectUrl, CAP_FFMPEG);
|
||||||
}
|
}
|
||||||
else if (firstFrame.empty())
|
else if (rFrame.empty())
|
||||||
{
|
{
|
||||||
cvtColor(frame, firstFrame, COLOR_BGR2GRAY);
|
rCap.open(share->recordUrl, CAP_FFMPEG);
|
||||||
|
}
|
||||||
|
else if (dPrevFrame.empty())
|
||||||
|
{
|
||||||
|
cvtColor(dFrame, dPrevFrame, COLOR_BGR2GRAY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cvtColor(frame, currentFrame, COLOR_BGR2GRAY);
|
cvtColor(dFrame, dNextFrame, COLOR_BGR2GRAY);
|
||||||
detectDiff(firstFrame, currentFrame, share);
|
|
||||||
|
if (detectDiff(dPrevFrame, dNextFrame, share))
|
||||||
|
{
|
||||||
|
mod = true;
|
||||||
|
|
||||||
|
share->buff.push_back(rFrame.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod)
|
||||||
|
{
|
||||||
|
system(share->postMoCmd.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
system(share->postNoMoCmd.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string parseForParam(const string &arg, int argc, char** argv)
|
string parseForParam(const string &arg, int argc, char** argv)
|
||||||
|
@ -217,7 +251,6 @@ int main(int argc, char** argv)
|
||||||
auto outDir = parseForParam("-dir", argc, argv);
|
auto outDir = parseForParam("-dir", argc, argv);
|
||||||
auto moCmd = parseForParam("-mc", argc, argv);
|
auto moCmd = parseForParam("-mc", argc, argv);
|
||||||
auto noMocmd = parseForParam("-nmc", argc, argv);
|
auto noMocmd = parseForParam("-nmc", argc, argv);
|
||||||
auto camId = parseForParam("-id", argc, argv);
|
|
||||||
auto secs = strtol(secsStr.c_str(), NULL, 10);
|
auto secs = strtol(secsStr.c_str(), NULL, 10);
|
||||||
|
|
||||||
if (lowUrl.empty())
|
if (lowUrl.empty())
|
||||||
|
@ -232,16 +265,14 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
cerr << "the output directory is empty." << endl;
|
cerr << "the output directory is empty." << endl;
|
||||||
}
|
}
|
||||||
else if (camId.empty())
|
|
||||||
{
|
|
||||||
cerr << "the camera id is empty." << endl;
|
|
||||||
}
|
|
||||||
else if (secs == 0)
|
else if (secs == 0)
|
||||||
{
|
{
|
||||||
cerr << "the amount of seconds in -sec cannot be 0 or an invalid number was given." << endl;
|
cerr << "the amount of seconds in -sec cannot be 0 or an invalid number was given." << endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
sharedRes.wrRunning = false;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
sharedRes.recordUrl = highUrl;
|
sharedRes.recordUrl = highUrl;
|
||||||
|
@ -251,12 +282,9 @@ int main(int argc, char** argv)
|
||||||
sharedRes.secsStr = secsStr;
|
sharedRes.secsStr = secsStr;
|
||||||
sharedRes.secs = secs;
|
sharedRes.secs = secs;
|
||||||
sharedRes.outDir = outDir;
|
sharedRes.outDir = outDir;
|
||||||
sharedRes.camId = camId;
|
|
||||||
sharedRes.ffRunning = true;
|
sharedRes.ffRunning = true;
|
||||||
sharedRes.motion = false;
|
|
||||||
sharedRes.ignore = 0;
|
|
||||||
|
|
||||||
thread th1(vidCap, &sharedRes);
|
thread th1(timer, &sharedRes);
|
||||||
thread th2(moDetect, &sharedRes);
|
thread th2(moDetect, &sharedRes);
|
||||||
|
|
||||||
// Wait for the threads to finish
|
// Wait for the threads to finish
|
||||||
|
|
Loading…
Reference in New Issue
Block a user