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:
Maurice ONeal 2022-07-14 10:19:37 -04:00
parent 072cbe269c
commit c054356541
2 changed files with 58 additions and 94 deletions

View File

@ -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

View File

@ -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 &param, 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 &param, 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