Adjust secondary detection

This commit is contained in:
MrDave
2019-11-20 20:34:50 -07:00
committed by Mr-Dave
parent 1cffc3c39c
commit 0533da7d3b
10 changed files with 269 additions and 334 deletions

View File

@@ -29,24 +29,47 @@
using namespace cv;
static void myltrim(std::string &vstr){
vstr.erase(
vstr.begin()
, std::find_if( vstr.begin() , vstr.end() , [](int ch)
{ return !std::isspace(ch);}
)
);
}
static void myrtrim(std::string &vstr){
vstr.erase(
std::find_if(vstr.rbegin(), vstr.rend(), [](int ch)
{return !std::isspace(ch);}
).base()
, vstr.end()
);
}
static void mytrim(std::string &vstr){
myltrim(vstr);
myrtrim(vstr);
}
static void algsec_img_show(ctx_cam *cam, Mat &mat_src
, std::vector<Rect> &src_pos, std::vector<double> &src_weights
, std::string algmethod, float min_weight ){
, std::string algmethod, ctx_algsec_model &algmdl){
std::vector<Rect> fltr_pos;
std::vector<double> fltr_weights;
std::string testdir;
std::size_t indx0, indx1;
std::vector<uchar> buff;//buffer for coding
std::vector<uchar> buff; //buffer for coding
std::vector<int> param(2);
bool isdetected;
char wstr[10];
float min_weight;
min_weight = algmdl.threshold_motion/100;
testdir = cam->conf->target_dir;
imwrite(testdir + "/src_" + algmethod + ".jpg", mat_src);
isdetected = false;
algmdl.isdetected = false;
for (indx0=0; indx0<src_pos.size(); indx0++) {
Rect r = src_pos[indx0];
double w = src_weights[indx0];
@@ -57,11 +80,11 @@ static void algsec_img_show(ctx_cam *cam, Mat &mat_src
if ((indx1==src_pos.size()) && (w > min_weight)){
fltr_pos.push_back(r);
fltr_weights.push_back(w);
isdetected = true;
algmdl.isdetected = true;
}
}
if (isdetected){
if (algmdl.isdetected){
for (indx0=0; indx0<fltr_pos.size(); indx0++) {
Rect r = fltr_pos[indx0];
r.x += cvRound(r.width*0.1);
@@ -75,14 +98,20 @@ static void algsec_img_show(ctx_cam *cam, Mat &mat_src
imwrite(testdir + "/detect_" + algmethod + ".jpg", mat_src);
}
param[0] = cv::IMWRITE_JPEG_QUALITY;
param[1] = 75;
cv::imencode(".jpg", mat_src, buff, param);
pthread_mutex_lock(&cam->algsec->mutex);
std::copy(buff.begin(), buff.end(), cam->imgs.image_secondary);
cam->imgs.size_secondary = (int)buff.size();
pthread_mutex_unlock(&cam->algsec->mutex);
/* We check the size so that we at least fill in the first image so the
* web stream will have something to start with. After feeding in at least
* the first image, we rely upon the connection count to tell us whether we
* need to expend the CPU to compress and load the secondary images */
if ((cam->stream.secondary.cnct_count >0) ||
(cam->imgs.size_secondary == 0)){
param[0] = cv::IMWRITE_JPEG_QUALITY;
param[1] = 75;
cv::imencode(".jpg", mat_src, buff, param);
pthread_mutex_lock(&cam->algsec->mutex);
std::copy(buff.begin(), buff.end(), cam->imgs.image_secondary);
cam->imgs.size_secondary = (int)buff.size();
pthread_mutex_unlock(&cam->algsec->mutex);
}
}
static void algsec_img_roi(ctx_cam *cam, Mat &mat_src, Mat &mat_dst){
@@ -127,13 +156,6 @@ static void algsec_img_roi(ctx_cam *cam, Mat &mat_src, Mat &mat_dst){
}
static void algsec_detect_yolo(ctx_cam *cam, ctx_algsec_model &algmdl){
(void)cam;
(void)algmdl;
}
static void algsec_detect_hog(ctx_cam *cam, ctx_algsec_model &algmdl){
std::vector<double> detect_weights;
@@ -142,13 +164,13 @@ static void algsec_detect_hog(ctx_cam *cam, ctx_algsec_model &algmdl){
Mat mat_dst;
try {
if (algmdl.parms[0][0] == "color"){
if (algmdl.imagetype == "color"){
/* AFAIK, the detector uses grey so users shouldn't really use this*/
Mat mat_src = Mat(cam->imgs.height*3/2, cam->imgs.width
, CV_8UC1, (void*)cam->algsec->image_norm);
cvtColor(mat_src, mat_dst, COLOR_YUV2RGB_YV12);
} else if (algmdl.parms[0][0] == "full"){
} else if (algmdl.imagetype == "full"){
mat_dst = Mat(cam->imgs.height, cam->imgs.width
, CV_8UC1, (void*)cam->algsec->image_norm);
@@ -170,24 +192,15 @@ static void algsec_detect_hog(ctx_cam *cam, ctx_algsec_model &algmdl){
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
hog.detectMultiScale(mat_dst, detect_pos, detect_weights, 0
,Size(algmdl.parms_int[0][2], algmdl.parms_int[0][2])
,Size(algmdl.parms_int[0][3], algmdl.parms_int[0][3])
,algmdl.parms_float[0][4]
,algmdl.parms_int[0][5]
,Size(algmdl.hog_winstride, algmdl.hog_winstride)
,Size(algmdl.hog_padding, algmdl.hog_padding)
,algmdl.scalefactor
,algmdl.threshold_model
,false);
MOTION_LOG(INF, TYPE_ALL, NO_ERRNO
, _("Parms: winstride %d,%d padding %d,%d scale %.2f theshold %d")
,algmdl.parms_int[0][2], algmdl.parms_int[0][2]
,algmdl.parms_int[0][3], algmdl.parms_int[0][3]
,algmdl.parms_float[0][4]
,algmdl.parms_int[0][5]);
algsec_img_show(cam, mat_dst, detect_pos, detect_weights, "hog",algmdl);
algsec_img_show(cam, mat_dst, detect_pos, detect_weights, "hog"
,algmdl.parms_float[0][1]);
}
catch ( cv::Exception& e ) {
} catch ( cv::Exception& e ) {
const char* err_msg = e.what();
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error %s"),err_msg);
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Disabling secondary detection"));
@@ -208,11 +221,14 @@ static void algsec_detect_haar(ctx_cam *cam, ctx_algsec_model &algmdl){
equalizeHist(mat_src, mat_src);
algmdl.haar_cascade.detectMultiScale(
mat_src, detect_pos, levels, detect_weights, 1.1, 1, 0, Size(), Size(), true);
mat_src, detect_pos, levels, detect_weights
,algmdl.scalefactor, algmdl.haar_minneighbors,algmdl.haar_flags
, Size(algmdl.haar_minsize,algmdl.haar_minsize)
, Size(algmdl.haar_maxsize,algmdl.haar_maxsize), true);
algsec_img_show(cam, mat_src, detect_pos, detect_weights, "haar", 0.6);
}
catch ( cv::Exception& e ) {
algsec_img_show(cam, mat_src, detect_pos, detect_weights, "haar", algmdl);
} catch ( cv::Exception& e ) {
const char* err_msg = e.what();
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error %s"),err_msg);
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Disabling secondary detection"));
@@ -220,72 +236,52 @@ static void algsec_detect_haar(ctx_cam *cam, ctx_algsec_model &algmdl){
}
}
static void algsec_load_yolo(ctx_algsec_model &algmdl){
/* Placeholder for implementation of yolo classifier */
algmdl.method = 0;
}
static void algsec_load_haar(ctx_algsec_model &algsec){
static void algsec_load_haar(ctx_algsec_model &algmdl){
/* If loading fails, reset the method to invalidate detection */
try {
if (!algsec.haar_cascade.load(algsec.modelfile)){
if (!algmdl.haar_cascade.load(algmdl.modelfile)){
/* Loading failed, reset method*/
algsec.method = 0;
algmdl.method = 0;
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Failed loading model %s")
,algsec.modelfile.c_str());
,algmdl.modelfile.c_str());
};
}
catch ( cv::Exception& e ) {
} catch ( cv::Exception& e ) {
const char* err_msg = e.what();
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Error %s"),err_msg);
MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO, _("Failed loading model %s")
,algsec.modelfile.c_str());
algsec.method = 0;
,algmdl.modelfile.c_str());
algmdl.method = 0;
}
}
static void algsec_parms_hog(ctx_algsec_model &model){
/* These conversions put the applicable parms into int or float variables
* This is done once here upon parsing the parms so that we do not have to
* do the conversion upon every single image being processed and we can directly
* reference the converted parameter
*/
int indx0, indx1;
for (indx0=0;indx0<3;indx0++){
for (indx1=0;indx1<10;indx1++){
model.parms_int[indx0][indx1] = 0;
model.parms_float[indx0][indx1] = 0;
if (model.parms[indx0][indx1] != ""){
model.parms_int[indx0][indx1] = std::atoi(model.parms[indx0][indx1].c_str());
model.parms_float[indx0][indx1] = std::atof(model.parms[indx0][indx1].c_str());
}
}
/*parm[0] is color/full/area */
if (model.parms_float[indx0][1] <= 0) model.parms_int[indx0][1] = 0.6; /*Min weigtht */
if (model.parms_int[indx0][2] <= 0) model.parms_int[indx0][2] = 8; /* */
if (model.parms_int[indx0][3] <= 0) model.parms_int[indx0][3] = 32; /* */
if (model.parms_float[indx0][4] <= 0.01) model.parms_float[indx0][4] = 1.05; /* */
if (model.parms_int[indx0][5] <= 0) model.parms_int[indx0][5] = 2; /* */
}
static void algsec_parms_default_hog(ctx_algsec_model &algmdl){
algmdl.hog_padding = 8;
algmdl.scalefactor = 1.05;
algmdl.threshold_model = 1.4;
algmdl.hog_winstride = 8;
algmdl.threshold_motion = 50;
}
static void algsec_parms_default_haar(ctx_algsec_model &algmdl){
algmdl.scalefactor = 1.1;
algmdl.threshold_model = 2;
algmdl.haar_flags = 0;
algmdl.haar_maxsize = 8;
algmdl.haar_minsize = 8;
algmdl.haar_minneighbors = 8;
algmdl.threshold_motion = 50;
}
/**Parse parm based upon colons*/
static void algsec_parms_parse_detail(
std::string &vin, ctx_algsec_model &model,int indx0) {
static void algsec_parms_parse_microdetail(std::string &vin, ctx_algsec_model &algmdl) {
/* This is a place holder for now. It is thought that we will need some subparameters
* associated with the configuration in the future...*/
std::size_t st_colon, en_colon;
std::string tmp;
int indx1;
for (indx1=0;indx1<10;indx1++){
if (model.parms[indx0][indx1] != "") model.parms[indx0][indx1].clear();
}
return;
if (vin == "") return;
en_colon = -1;
@@ -293,58 +289,116 @@ static void algsec_parms_parse_detail(
st_colon = en_colon+1;
en_colon = vin.find(':',st_colon);
tmp = vin.substr(st_colon,en_colon-st_colon);
model.parms[indx0][indx1] = tmp;
//algmdl???? = tmp;
if (en_colon == std::string::npos) return;
}
return;
}
/* modelfile=/home/whatever/model.xml,threshold_motion=50
/**Parse parm based upon equals*/
static void algsec_parms_parse_detail(std::string &vin, ctx_algsec_model &algmdl){
std::size_t stpos;
std::string tmpvar, tmpparm;
int indx1;
if (vin == "") return;
stpos = vin.find('=');
if (stpos != std::string::npos){
tmpvar = vin.substr(0, stpos-1);
tmpparm = vin.substr(stpos+1);
mytrim(tmpvar);
mytrim(tmpparm);
if (tmpvar == "modelfile"){
algmdl.modelfile = tmpparm;
} else if (tmpvar == "config"){
algsec_parms_parse_microdetail(tmpparm, algmdl);
} else if (tmpvar == "imagetype"){
algmdl.imagetype = tmpparm;
} else if (tmpvar == "rotate"){
algmdl.rotate = std::atoi(tmpparm.c_str());
} else if (tmpvar == "scale"){
algmdl.scalefactor = std::atof(tmpparm.c_str());
} else if (tmpvar == "threshold_model"){
algmdl.threshold_model= std::atoi(tmpparm.c_str());
} else if (tmpvar == "threshold_motion"){
algmdl.threshold_motion= std::atoi(tmpparm.c_str());
}
/* Hog specific parms below */
/* These need edits on acceptable values. Is this full list?*/
if (tmpvar == "winstride"){
algmdl.hog_winstride = std::atoi(tmpparm.c_str());
} else if (tmpvar == "padding"){
algmdl.hog_padding= std::atoi(tmpparm.c_str());
}
/* Haar specific parms below */
/* These need edits on acceptable values. Is this full list?*/
if (tmpvar == "minneighbors"){
algmdl.haar_minneighbors = std::atoi(tmpparm.c_str());
} else if (tmpvar == "flags"){
algmdl.haar_flags = std::atoi(tmpparm.c_str());
} else if (tmpvar == "minsize"){
algmdl.haar_minsize = std::atoi(tmpparm.c_str());
} else if (tmpvar == "maxsize"){
algmdl.haar_maxsize= std::atoi(tmpparm.c_str());
}
}
return;
}
/**Parse parms based upon commas */
static void algsec_parms_parse(ctx_cam *cam){
/* Parse out the comma separated parms
* exampe source config line: human:75:25,car:60:30,dog:90:70
*/
int indx1, indx2;
std::size_t st_comma, en_comma;
std::string tmp;
for (indx1=0;indx1<3;indx1++){
if (cam->algsec->models[indx1].config != ""){
indx2=0;
st_comma = 0;
en_comma = cam->algsec->models[indx1].config.find(',', st_comma);
while ((en_comma != std::string::npos) && (indx2 < 2)){
tmp = cam->algsec->models[indx1].config.substr(st_comma, en_comma - st_comma);
algsec_parms_parse_detail(tmp, cam->algsec->models[indx1],indx2);
st_comma = en_comma + 1;
en_comma = cam->algsec->models[indx1].config.find(',', st_comma);
indx2++;
}
tmp = cam->algsec->models[indx1].config.substr(
st_comma, cam->algsec->models[indx1].config.length());
algsec_parms_parse_detail(tmp, cam->algsec->models[indx1], indx2);
}
switch (cam->algsec->models[indx1].method) {
case 1: //Haar Method
break;
case 2: //HoG Method
algsec_parms_hog(cam->algsec->models[indx1]);
break;
case 3: //YoLo Method
break;
}
cam->algsec->models.method = cam->conf->secondary_method;
cam->algsec->models.config = cam->conf->secondary_config;
switch (cam->algsec->models.method) {
case 1: //Haar Method
algsec_parms_default_haar(cam->algsec->models);
break;
case 2: //HoG Method
algsec_parms_default_hog(cam->algsec->models);
break;
default:
cam->algsec->models.method = 0;
break;
}
if (cam->algsec->models.config != ""){
st_comma = 0;
en_comma = cam->algsec->models.config.find(',', st_comma);
while (en_comma != std::string::npos){
tmp = cam->algsec->models.config.substr(st_comma, en_comma - st_comma);
algsec_parms_parse_detail(tmp, cam->algsec->models);
st_comma = en_comma + 1;
en_comma = cam->algsec->models.config.find(',', st_comma);
}
tmp = cam->algsec->models.config.substr(st_comma);
algsec_parms_parse_detail(tmp, cam->algsec->models);
}
}
/**Load the parms from the config to algsec struct */
static void algsec_load_parms(ctx_cam *cam){
static int algsec_load_parms(ctx_cam *cam){
/* Copy the model file names and config into the ctx_cam
* For "simplicity", these are all fixed size arrays for
* both the models and parms. If there is a need later
* they can be changed to vectors
*/
if (cam->conf->secondary_method == 0){
cam->algsec->models.method = 0;
return -1;
}
cam->algsec->height = cam->imgs.height;
cam->algsec->width = cam->imgs.width;
@@ -361,44 +415,9 @@ static void algsec_load_parms(ctx_cam *cam){
*/
cam->algsec->closing = true;
if (cam->conf->secondary_method != 0) {
cam->algsec->models[0].method = cam->conf->secondary_method;
if (cam->conf->secondary_model != NULL){
cam->algsec->models[0].modelfile = cam->conf->secondary_model;
}
if (cam->conf->secondary_config != NULL) {
cam->algsec->models[0].config = cam->conf->secondary_config;
}
} else {
cam->algsec->models[0].method = 0;
}
if (cam->conf->secondary_method2 != 0) {
cam->algsec->models[1].method = cam->conf->secondary_method2;
if (cam->conf->secondary_model2 != NULL){
cam->algsec->models[1].modelfile = cam->conf->secondary_model2;
}
if (cam->conf->secondary_config2 != NULL) {
cam->algsec->models[1].config = cam->conf->secondary_config2;
}
} else {
cam->algsec->models[1].method = 0;
}
if (cam->conf->secondary_method3 != 0) {
cam->algsec->models[2].method = cam->conf->secondary_method3;
if (cam->conf->secondary_model3 != NULL) {
cam->algsec->models[2].modelfile = cam->conf->secondary_model3;
}
if (cam->conf->secondary_config3 != NULL) {
cam->algsec->models[2].config = cam->conf->secondary_config3;
}
} else {
cam->algsec->models[2].method = 0;
}
algsec_parms_parse(cam);
return 0;
}
/**If possible preload the models and initialize them */
@@ -406,25 +425,21 @@ static int algsec_load_models(ctx_cam *cam){
int indx;
for (indx=0;indx<3;indx++){
if (cam->algsec->models[indx].method != 0){
switch (cam->algsec->models[indx].method) {
case 1: //Haar Method
algsec_load_haar(cam->algsec->models[indx]);
break;
case 2: //HoG Method
break;
case 3: //YoLo Method
algsec_load_yolo(cam->algsec->models[indx]);
break;
default:
cam->algsec->models[indx].method = 0;
}
if (cam->algsec->models.method != 0){
switch (cam->algsec->models.method) {
case 1: //Haar Method
algsec_load_haar(cam->algsec->models);
break;
case 2: //HoG Method
//algsec_load_hog(cam->algsec->models);
break;
default:
cam->algsec->models.method = 0;
}
}
/* If model fails to load, it sets method to zero*/
if (cam->algsec->models[0].method != 0){
if (cam->algsec->models.method != 0){
cam->algsec_inuse = TRUE;
return 0;
} else {
@@ -448,20 +463,17 @@ static void *algsec_handler(void *arg) {
while (!cam->algsec->closing){
if (cam->algsec->detecting){
for (indx=0;indx<3;indx++){
switch (cam->algsec->models[indx].method) {
case 1: //Haar Method
algsec_detect_haar(cam, cam->algsec->models[indx]);
break;
case 2: //HoG Method
algsec_detect_hog(cam, cam->algsec->models[indx]);
break;
case 3: //YoLo Method
algsec_detect_yolo(cam, cam->algsec->models[indx]);
break;
}
switch (cam->algsec->models.method) {
case 1: //Haar Method
algsec_detect_haar(cam, cam->algsec->models);
break;
case 2: //HoG Method
algsec_detect_hog(cam, cam->algsec->models);
break;
}
cam->algsec->detecting = false;
/*Set the event based isdetected bool */
if (cam->algsec->models.isdetected) cam->algsec->isdetected = true;
} else {
SLEEP(0,interval)
}
@@ -485,9 +497,7 @@ static void algsec_start_handler(ctx_cam *cam){
if (retcd < 0) {
MOTION_LOG(ALR, TYPE_NETCAM, SHOW_ERRNO
,_("Error starting algsec handler thread"));
for (indx=0;indx<3;indx++){
cam->algsec->models[indx].method = 0;
}
cam->algsec->models.method = 0;
}
pthread_attr_destroy(&handler_attribute);
return;
@@ -511,10 +521,8 @@ void algsec_init(ctx_cam *cam){
pthread_mutex_init(&cam->algsec->mutex, NULL);
algsec_load_parms(cam);
retcd = algsec_load_models(cam);
retcd = algsec_load_parms(cam);
if (retcd == 0) retcd = algsec_load_models(cam);
if (retcd == 0) algsec_start_handler(cam);
mythreadname_set("ml",cam->threadnr,cam->conf->camera_name.c_str());