Changed post motion detection conditioning
The app will now count the amount of secs to record post motion detection instead of the amount of frames. Split the main loop timer with the motion timer in separate threads to make that happen. The parameter was added to the config file. Recording fps is now adjustable.
This commit is contained in:
parent
072cbe269c
commit
c054356541
14
README.md
14
README.md
|
@ -40,7 +40,7 @@ detection_stream = rtsp://1.2.3.4:554/h264cif
|
||||||
output_dir = /path/to/footage/directory
|
output_dir = /path/to/footage/directory
|
||||||
# this is the output directory that will be used to store recorded footage
|
# this is the output directory that will be used to store recorded footage
|
||||||
# from the camera. the file naming convention uses date codes. it creates
|
# from the camera. the file naming convention uses date codes. it creates
|
||||||
# a subfolder for the date if it needs to and then stores the video file
|
# a sub-folder for the date if it needs to and then stores the video file
|
||||||
# using the time.
|
# using the time.
|
||||||
#
|
#
|
||||||
diff_threshold = 210
|
diff_threshold = 210
|
||||||
|
@ -68,14 +68,12 @@ pixel_size = 3
|
||||||
# this is the pixel size of the detected object or movement. this can
|
# this is the pixel size of the detected object or movement. this can
|
||||||
# prevent false positives due small moves in grass/plants or insects.
|
# prevent false positives due small moves in grass/plants or insects.
|
||||||
#
|
#
|
||||||
frames_post_motion = 60
|
secs_post_motion = 3
|
||||||
# this is the amount frames to capture after motion was detected.
|
# this is the minimum amount of seconds to capture after motion was
|
||||||
|
# detected.
|
||||||
#
|
#
|
||||||
minimum_recording_frames = 90
|
recording_fps = 25
|
||||||
# this is the minimum amount of frames needed before video footage is
|
# recording fps to use when recording footage to storage.
|
||||||
# recorded to storage. this prevents video files that are too small to
|
|
||||||
# be of any use and reduces clutter. warning: setting this value too
|
|
||||||
# high could cause the application to use too much memory.
|
|
||||||
#
|
#
|
||||||
section_size = 100
|
section_size = 100
|
||||||
# detection frames are read in y axis sections and then runs gray level
|
# detection frames are read in y axis sections and then runs gray level
|
||||||
|
|
138
src/main.cpp
138
src/main.cpp
|
@ -27,13 +27,13 @@ struct shared_t
|
||||||
string conf;
|
string conf;
|
||||||
bool wrRunning;
|
bool wrRunning;
|
||||||
bool ffRunning;
|
bool ffRunning;
|
||||||
int motion;
|
bool motion;
|
||||||
|
int fps;
|
||||||
int secs;
|
int secs;
|
||||||
int thrWithMotion;
|
int thrWithMotion;
|
||||||
int thresh;
|
int thresh;
|
||||||
int pixSize;
|
int pixSize;
|
||||||
int postMoIncr;
|
int postMoIncr;
|
||||||
int minRecFrames;
|
|
||||||
int sectionSize;
|
int sectionSize;
|
||||||
int retCode;
|
int retCode;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ bool createDirTree(const string &full_path)
|
||||||
|
|
||||||
void vidCap(shared_t *share)
|
void vidCap(shared_t *share)
|
||||||
{
|
{
|
||||||
if (share->buff.size() >= share->minRecFrames)
|
if (!share->buff.empty())
|
||||||
{
|
{
|
||||||
share->wrRunning = true;
|
share->wrRunning = true;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ void vidCap(shared_t *share)
|
||||||
|
|
||||||
VideoWriter writer;
|
VideoWriter writer;
|
||||||
|
|
||||||
writer.open(dstPath, codec, 30.0, share->buff[0].size(), true);
|
writer.open(dstPath, codec, (double) share->fps, share->buff[0].size(), true);
|
||||||
|
|
||||||
if (!writer.isOpened())
|
if (!writer.isOpened())
|
||||||
{
|
{
|
||||||
|
@ -205,11 +205,11 @@ bool grayDiff(Mat imgA, Mat imgB, shared_t *share)
|
||||||
return share->thrWithMotion != 0;
|
return share->thrWithMotion != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer(shared_t *share)
|
void loopTimer(shared_t *share)
|
||||||
{
|
{
|
||||||
sleep(share->secs);
|
sleep(share->secs);
|
||||||
|
|
||||||
if (share->motion == 0)
|
if (!share->motion)
|
||||||
{
|
{
|
||||||
share->ffRunning = false;
|
share->ffRunning = false;
|
||||||
}
|
}
|
||||||
|
@ -220,6 +220,13 @@ void timer(shared_t *share)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void motionTimer(shared_t *share)
|
||||||
|
{
|
||||||
|
sleep(share->postMoIncr);
|
||||||
|
|
||||||
|
share->motion = false;
|
||||||
|
}
|
||||||
|
|
||||||
Mat toGray(const Mat &src)
|
Mat toGray(const Mat &src)
|
||||||
{
|
{
|
||||||
Mat ret;
|
Mat ret;
|
||||||
|
@ -238,11 +245,11 @@ void moDetect(shared_t *share)
|
||||||
|
|
||||||
while (share->ffRunning)
|
while (share->ffRunning)
|
||||||
{
|
{
|
||||||
if (share->motion == 0) dCap >> dFrame;
|
if (!share->motion) dCap >> dFrame;
|
||||||
|
|
||||||
rCap >> rFrame;
|
rCap >> rFrame;
|
||||||
|
|
||||||
if (dFrame.empty() && (share->motion == 0))
|
if (dFrame.empty() && (!share->motion))
|
||||||
{
|
{
|
||||||
// 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
|
||||||
|
@ -254,11 +261,9 @@ void moDetect(shared_t *share)
|
||||||
{
|
{
|
||||||
rCap.open(share->recordUrl, CAP_FFMPEG);
|
rCap.open(share->recordUrl, CAP_FFMPEG);
|
||||||
}
|
}
|
||||||
else if (share->motion > 0)
|
else if (share->motion)
|
||||||
{
|
{
|
||||||
share->buff.push_back(rFrame.clone());
|
share->buff.push_back(rFrame.clone());
|
||||||
|
|
||||||
share->motion -= 1;
|
|
||||||
}
|
}
|
||||||
else if (dPrev.empty() || rPrev.empty())
|
else if (dPrev.empty() || rPrev.empty())
|
||||||
{
|
{
|
||||||
|
@ -270,7 +275,9 @@ void moDetect(shared_t *share)
|
||||||
share->buff.push_back(rPrev);
|
share->buff.push_back(rPrev);
|
||||||
share->buff.push_back(rFrame.clone());
|
share->buff.push_back(rFrame.clone());
|
||||||
|
|
||||||
share->motion += share->postMoIncr;
|
share->motion = true;
|
||||||
|
|
||||||
|
thread(motionTimer, share);
|
||||||
|
|
||||||
rPrev.release();
|
rPrev.release();
|
||||||
dPrev.release();
|
dPrev.release();
|
||||||
|
@ -303,7 +310,7 @@ string parseForParam(const string &arg, int argc, char** argv, bool argOnly)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return string("true")
|
return string("true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,19 +318,28 @@ string parseForParam(const string &arg, int argc, char** argv, bool argOnly)
|
||||||
return string();
|
return string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rdLine(const string ¶m, const string &line, string *value)
|
||||||
|
{
|
||||||
|
if (line.rfind(param.c_str(), 0) == 0)
|
||||||
|
{
|
||||||
|
*value = line.substr(param.size());
|
||||||
|
|
||||||
|
cout << param << *value << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rdLine(const string ¶m, const string &line, int *value)
|
||||||
|
{
|
||||||
|
if (line.rfind(param.c_str(), 0) == 0)
|
||||||
|
{
|
||||||
|
*value = strtol(line.substr(param.size()).c_str(), NULL, 10);
|
||||||
|
|
||||||
|
cout << param << *value << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool rdConf(shared_t *share)
|
bool rdConf(shared_t *share)
|
||||||
{
|
{
|
||||||
// recording_stream
|
|
||||||
// detection_stream
|
|
||||||
// output_dir
|
|
||||||
// diff_threshold
|
|
||||||
// post_cmd
|
|
||||||
// duration
|
|
||||||
// pixel_size
|
|
||||||
// frames_post_motion
|
|
||||||
// minimum_recording_frames
|
|
||||||
// section_size
|
|
||||||
|
|
||||||
auto ret = false;
|
auto ret = false;
|
||||||
|
|
||||||
share->retCode = ENOENT;
|
share->retCode = ENOENT;
|
||||||
|
@ -344,66 +360,16 @@ bool rdConf(shared_t *share)
|
||||||
|
|
||||||
if (line.rfind("#", 0) != 0)
|
if (line.rfind("#", 0) != 0)
|
||||||
{
|
{
|
||||||
if (line.rfind("recording_stream = ", 0) == 0)
|
rdLine("recording_stream = ", line, &share->recordUrl);
|
||||||
{
|
rdLine("detection_stream = ", line, &share->detectUrl);
|
||||||
share->recordUrl = line.substr(19);
|
rdLine("output_dir = ", line, &share->outDir);
|
||||||
|
rdLine("post_cmd = ", line, &share->postCmd);
|
||||||
cout << "recording_stream = " << share->recordUrl << endl;
|
rdLine("diff_threshold = ", line, &share->thresh);
|
||||||
}
|
rdLine("duration = ", line, &share->secs);
|
||||||
else if (line.rfind("detection_stream = ", 0) == 0)
|
rdLine("pixel_size = ", line, &share->pixSize);
|
||||||
{
|
rdLine("secs_post_motion = ", line, &share->postMoIncr);
|
||||||
share->detectUrl = line.substr(19);
|
rdLine("section_size = ", line, &share->sectionSize);
|
||||||
|
rdLine("recording_fps = ", line, &share->fps);
|
||||||
cout << "detection_stream = " << share->detectUrl << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("output_dir = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->outDir = line.substr(13);
|
|
||||||
|
|
||||||
cout << "output_dir = " << share->outDir << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("post_cmd = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->postCmd = line.substr(11);
|
|
||||||
|
|
||||||
cout << "post_cmd = " << share->postCmd << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("diff_threshold = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->thresh = strtol(line.substr(17).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "diff_threshold = " << share->thresh << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("duration = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->secs = strtol(line.substr(11).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "duration = " << share->secs << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("pixel_size = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->pixSize = strtol(line.substr(13).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "pixel_size = " << share->pixSize << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("frames_post_motion = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->postMoIncr = strtol(line.substr(21).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "frames_post_motion = " << share->postMoIncr << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("minimum_recording_frames = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->minRecFrames = strtol(line.substr(27).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "minimum_recording_frames = " << share->minRecFrames << endl;
|
|
||||||
}
|
|
||||||
else if (line.rfind("section_size = ", 0) == 0)
|
|
||||||
{
|
|
||||||
share->sectionSize = strtol(line.substr(15).c_str(), NULL, 10);
|
|
||||||
|
|
||||||
cout << "section_size = " << share->sectionSize << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(!line.empty());
|
} while(!line.empty());
|
||||||
|
@ -441,14 +407,14 @@ int main(int argc, char** argv)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sharedRes.retCode = 0;
|
sharedRes.retCode = 0;
|
||||||
sharedRes.motion = 0;
|
sharedRes.motion = false;
|
||||||
sharedRes.wrRunning = false;
|
sharedRes.wrRunning = false;
|
||||||
|
|
||||||
while (rdConf(&sharedRes))
|
while (rdConf(&sharedRes))
|
||||||
{
|
{
|
||||||
sharedRes.ffRunning = true;
|
sharedRes.ffRunning = true;
|
||||||
|
|
||||||
thread th1(timer, &sharedRes);
|
thread th1(loopTimer, &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