diff --git a/ChangeLog b/ChangeLog index c1b3d20..f8e4e95 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ +2021-10-25: +- adding position/movement vector in the top left corner +- saving/loading the default config is working now +- saving and recalling presetbuttons are working +- some code cleanup + 2021-10-10: - basic object detection and image filter added - save image works diff --git a/configuration.cc b/configuration.cc index f34b0f8..76596da 100644 --- a/configuration.cc +++ b/configuration.cc @@ -110,8 +110,6 @@ void Configuration::SaveConfig(std::string filename) { void Configuration::LoadConfig(std::string filename) { JSONParse jp; string vstr; - float vf; - int vi; int i; JSONElement je; @@ -121,7 +119,6 @@ void Configuration::LoadConfig(std::string filename) { } else { printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__); - // config in jp loaded, setup all the GUI fields // // set resolution and video stream mode diff --git a/detect.cc b/detect.cc index 5b4d909..17c0d61 100644 --- a/detect.cc +++ b/detect.cc @@ -74,7 +74,6 @@ int Detect::NewFrame(VideoFrame *newframe) { // Thread: newFrame |------> Find Object --- not found ---> send gui information void Detect::Thread() { DetectOutput output; - int errorinputtype = -1, x, y; objectX = -1; objectY = -1; @@ -176,11 +175,6 @@ void Detect::InputDetect(int *posx, int *posy) { int x, y, i, dx, dy, sy; unsigned char *pxs, *pxi; int idx, didx; - struct timeval t1, t2; - float f; - - f = get_cycletime(&t1); - t2 = t1; image.SetSize (objectW, objectH); SetInputSize(inFrame.w, inFrame.h); @@ -189,10 +183,6 @@ void Detect::InputDetect(int *posx, int *posy) { *posx = 0; *posy = 0; -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d setup memory time needed:%f\n", __FILE__, __LINE__, f); -#endif // // maximum brightness for (x = 0; x < posmaxx; x++) maxx[x] = 0.0; @@ -203,17 +193,8 @@ void Detect::InputDetect(int *posx, int *posy) { maxx[x] += pow(pxs[idx+0] + pxs[idx+1] + pxs[idx+2], POWERVAL); maxy[y] += pow(pxs[idx+0] + pxs[idx+1] + pxs[idx+2], POWERVAL); } -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d calculated maximum:%f\n", __FILE__, __LINE__, f); - // select maximum -#endif for (x = 1; x < inFrame.w; x++) if (maxx[x] > maxx[*posx]) *posx = x; for (y = 1; y < inFrame.h; y++) if (maxy[y] > maxy[*posy]) *posy = y; -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d selected maximum:%f\n", __FILE__, __LINE__, f); -#endif // select start corner if (*posx < (objectW / 2)) x = 0; @@ -228,18 +209,8 @@ void Detect::InputDetect(int *posx, int *posy) { for (dy = 0, y = sy; dy < image.h && y < inFrame.h; y++, dy++) { idx = 3* (inFrame.w * y + x); didx = 3* (image.w * dy + dx); - // printf ("[%d , %d] --> [%d, %d] idx: %d --> %d Value:%d\n", x, y, dx, dy, idx, didx, pxs[idx+i]); for (i = 0; i < 3; i++) pxi[didx+i] = pxs[idx+i]; } - -// printf ("%s:%d %s pos: %d,%d \n", __FILE__, __LINE__, __FUNCTION__, *posx, *posy); - -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d copy output:%f\n", __FILE__, __LINE__, f); - f = get_cycletime(&t2); - printf ("%s:%d time needed:%f\n", __FILE__, __LINE__, f); -#endif } inline float calc_vector(uint8_t a1, uint8_t a2, uint8_t b1, uint8_t b2, uint8_t c1, uint8_t c2, uint8_t d1, uint8_t d2) { @@ -254,15 +225,12 @@ inline float calc_vector(uint8_t a1, uint8_t a2, uint8_t b1, uint8_t b2, uint8_t #define OBJSIZE 50 #define MAXSHIFT 20 -// #define DEBUGTIMES 1 void Detect::InputDetectCrossC(int *posx, int *posy) { unsigned char *pxi; // input image - unsigned char *pxd; // destination image unsigned char *pxo; // old image int inx, iny, oldx, oldy; - struct timeval t1, t2; - int shiftx, shifty, x, y, ini, oldi, desti, mxi, mxx, mxy; + int shiftx, shifty, x, y, ini, oldi, mxi, mxx, mxy; float f; if (oldFrame.h != inFrame.h || oldFrame.w != inFrame.w || *posx == -1 || *posy == -1) { @@ -271,10 +239,6 @@ void Detect::InputDetectCrossC(int *posx, int *posy) { return; } -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - t2 = t1; -#endif if (objectW > inFrame.w || objectH > inFrame.h) { printf ("%s:%d %s objectW,H (%d,%d) > inFrame.W,H (%d, %d)\n", __FILE__, __LINE__, __FUNCTION__, @@ -288,19 +252,11 @@ void Detect::InputDetectCrossC(int *posx, int *posy) { SetInputSize(inFrame.w, inFrame.h); pxi = inFrame.data; pxo = oldFrame.data; - pxd = image.data; - -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d setup memory time needed:%f\n", __FILE__, __LINE__, f); -#endif mxx = mxy = 0; for (shifty = 0; shifty < MAXSHIFT; shifty++) { - // printf ("%s:%d %s shift (%d)\n", __FILE__, __LINE__, __FUNCTION__, shifty); mxi = shifty * objectW; for (shiftx = 0; shiftx < MAXSHIFT; shiftx++, mxi++) { - // fixme: help help f = 0.0; for (y = 0; y < OBJSIZE; y++) { @@ -315,7 +271,6 @@ void Detect::InputDetectCrossC(int *posx, int *posy) { for (x = 0; x < OBJSIZE; x++, oldi += 3, ini += 3, oldx++, inx++) { if (oldx >= 0 && oldy >= 0 && oldx < oldFrame.w && oldy <= oldFrame.h && inx >= 0 && inx < inFrame.w && iny >= 0 && iny < inFrame.h) { - //f += (float)(pxo[oldi+0])*(float)(pxi[ini+0]); f += calc_vector( pxo[oldi+0], pxi[ini+0], pxo[oldi+3], pxi[ini+3], pxo[oldi+6], pxi[ini+6], @@ -332,19 +287,9 @@ void Detect::InputDetectCrossC(int *posx, int *posy) { } } -// printf ("%s:%d %s pos (%d,%d) dpos (%d,%d) newpos (%d,%d)\n", __FILE__, __LINE__, __FUNCTION__, -// *posx, *posy, (mxx-MAXSHIFT/2), (mxy-MAXSHIFT/2), *posx - (mxx-MAXSHIFT/2), *posy - (mxy-MAXSHIFT/2)); - *posx += (mxx-MAXSHIFT/2); *posy += (mxy-MAXSHIFT/2); CopyObjectImage (*posx, *posy); - -#ifdef DEBUGTIMES - f = get_cycletime(&t1); - printf ("%s:%d copy output:%f\n", __FILE__, __LINE__, f); - f = get_cycletime(&t2); - printf ("%s:%d time needed:%f\n", __FILE__, __LINE__, f); -#endif } diff --git a/gui.cc b/gui.cc index 8f58edf..8dcdfc9 100644 --- a/gui.cc +++ b/gui.cc @@ -10,6 +10,7 @@ #endif #include #include +#include #include "gui.h" #include "config.h" #include "video.h" @@ -25,6 +26,7 @@ extern Detect detect; // defines what should happen on clicking a point on the input videodata int video_enterdata = VID_ENTERDATA_NONE; // see VID_ENTERDATA_xxxxx position_2d video_enterdata_pos; +detect_movement detectedpos_data = {0}; GtkWidget *detect_da = NULL; GdkPixbuf *detect_pixbuf = NULL; @@ -139,7 +141,7 @@ gboolean cb_thread_detect (gpointer data) { GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx")); GtkWidget *e_y = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posy")); DetectOutput *dout = (DetectOutput *) data; - int pix_h, pix_w; + int pix_h, pix_w, x, y; if (detect_da == NULL) detect_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "temp-da")); @@ -147,10 +149,12 @@ gboolean cb_thread_detect (gpointer data) { if (dout == NULL) return false; if (dout->image == NULL) return false; + detect.LockImageMutex(); + gtk_entry_set_text(GTK_ENTRY(e_x), std::to_string(dout->posx).c_str()); gtk_entry_set_text(GTK_ENTRY(e_y), std::to_string(dout->posy).c_str()); - - detect.LockImageMutex(); + x = dout->posx; // save value for later use (unlocked image data) + y = dout->posy; if (detect_pixbuf) { pix_h = gdk_pixbuf_get_height(detect_pixbuf); @@ -172,6 +176,34 @@ gboolean cb_thread_detect (gpointer data) { detect.UnLockImageMutex(); + // + // detect movements, by creating a ring buffer and we comptare the current + // position with the one DETECT_MOVEMENT_SAMPLES frames ago. + // + struct timeval tv = detectedpos_data.samples[0].ts; + float ftime = get_cycletime(&tv); + float fdist = sqrtf ( (x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) * + (x-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x) + + (y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y) * + (y-detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y)); + if (fdist > 20.0) { + for (int i = 0; i < DETECT_MOVEMENT_SAMPLES; i++) { + detectedpos_data.samples[i].x = x; + detectedpos_data.samples[i].y = y; + detectedpos_data.samples[i].ts = tv; + } + } + + detectedpos_data.dx = (float)(x-detectedpos_data.samples[0].x) / ftime; + detectedpos_data.dy = (float)(y-detectedpos_data.samples[0].y) / ftime; + + for (int i = 1; i < DETECT_MOVEMENT_SAMPLES; i++) + detectedpos_data.samples[i-1] = detectedpos_data.samples[i]; + + detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].ts = tv; + detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].x = x; + detectedpos_data.samples[DETECT_MOVEMENT_SAMPLES-1].y = y; + return false; }; @@ -180,7 +212,6 @@ gboolean cb_thread_detect (gpointer data) { void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { int clientw, clienth, pixbufw, pixbufh; float clientar, pixbufar; - GdkRGBA color; GdkPixbuf *pixbuf = NULL; GdkPixbuf *src = NULL; @@ -279,7 +310,6 @@ void cb_image_btnsave (GtkWidget *widget, gpointer data) { void cb_detect_bright (GtkRange *range, gpointer data) { -// GtkWidget *scale = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-adj-bright")); double value; value = gtk_range_get_value(range); diff --git a/gui.h b/gui.h index 0afff5e..b109e7c 100644 --- a/gui.h +++ b/gui.h @@ -27,6 +27,18 @@ struct { int y; } typedef position_2d; + +#define DETECT_MOVEMENT_SAMPLES 50 +struct { + struct { + struct timeval ts; + int x; + int y; + } samples[DETECT_MOVEMENT_SAMPLES]; + float dx; + float dy; +} typedef detect_movement; + void displayerror (std::string error); #ifdef __cplusplus diff --git a/json.cc b/json.cc index 25c37cd..a788aba 100644 --- a/json.cc +++ b/json.cc @@ -48,9 +48,8 @@ int JSONParse::Set(string json) { Clear(); // find start and read until end - for (step = STEP_NONE, i = 0, ignorenext = false; i < json.length(); i++) { + for (step = STEP_NONE, i = 0, ignorenext = false; (unsigned int)i < json.length(); i++) { // need to copy next character -// debug (0, "JSONParse: step:%d i:%d name:'%s' value:'%s'", step, i, jelement.name.c_str(), jelement.value.c_str()); if (ignorenext) { ignorenext = false; if (step == STEP_NAME) jelement.name += json[i]; @@ -160,9 +159,7 @@ int JSONParse::Set(string json) { // another element? if (step == STEP_END) { if (json[i] == ',') { -// debug (0, "* JSON.Set Add name:%s", jelement.name.c_str()); if (jelement.type != JSON_T_NONE) { -// debug (0, "%s:%d json add element type:%d", __FILE__, __LINE__, jelement.type); names.push_back (jelement); } jelement.Clear(); @@ -171,9 +168,7 @@ int JSONParse::Set(string json) { continue; } } -// debug (0, "* JSON.Set Add name:%s", jelement.name.c_str()); if (jelement.type != JSON_T_NONE) { -// debug (0, "%s:%d json add element type:%d", __FILE__, __LINE__, jelement.type); names.push_back (jelement); } @@ -242,12 +237,9 @@ int JSONParse::GetIdx(string src, int idx, string *dest) { int i = 0, rcnt = 0, cnt = 0; (*dest) = ""; -// printf("\n***************************************idx:%d\n", idx); for (i = 0; i < MAXRECURSIVE; i++) recursive[i] = 0; - for (i = 0; i < src.length() && rcnt < MAXRECURSIVE && cnt <= idx; i++) { -// printf ("i:%d rcnt:%d['%c'] cnt:%d char:'%c' ous:'%s'\n", -// i, rcnt, recursive[rcnt], cnt, src[i], dest->c_str()); + for (i = 0; (unsigned int) i < src.length() && rcnt < MAXRECURSIVE && cnt <= idx; i++) { if (src[i] == '[') { recursive[rcnt++] = src[i]; continue; @@ -273,9 +265,6 @@ int JSONParse::GetIdx(string src, int idx, string *dest) { } } -// printf("\n***************************************idx:%d cnt:%d\n", idx, cnt); -// printf("in:'%s'\n***\nout:'%s'\n\n*****\n", src.c_str(), dest->c_str()); - // // final checks if (cnt == 0 && idx == 0 && // empty source/array? diff --git a/main.cc b/main.cc index d04364d..6f6cc44 100644 --- a/main.cc +++ b/main.cc @@ -38,12 +38,6 @@ int main (int argc, char **argv) { gtk_builder_add_from_file (builder, BUILDER_FILE, NULL); gtk_builder_connect_signals(builder, builder); - // - // #if defined _WIN32 || defined _WIN64 || defined __CYGWIN__ - // #else - // #endif - // - window = gtk_builder_get_object (builder, "window-main"); if(window == NULL) { printf("ERROR: gtk_builder_get_object() failed\n"); diff --git a/video.cc b/video.cc index ef27d28..58a58b7 100644 --- a/video.cc +++ b/video.cc @@ -22,6 +22,7 @@ extern GtkBuilder *_builder_; // work around for threads extern Detect detect; extern int video_enterdata; extern position_2d video_enterdata_pos; +extern detect_movement detectedpos_data; extern Configuration config; gboolean videoctrl_update(gpointer data) { @@ -75,6 +76,8 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) int clientw, clienth, pixbufw, pixbufh; float clientar, pixbufar; GdkPixbuf *pixbuf = NULL; + char txt1[255]; + char txt2[255]; GdkRGBA color; GtkWidget *e_x = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-posx")); @@ -101,9 +104,6 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) pixbuf = gdk_pixbuf_scale_simple (video_pixbuf, clientw, clienth, GDK_INTERP_NEAREST); - //cairo_move_to(cr, 30, 30); - //cairo_set_font_size(cr,15); - //cairo_show_text(cr, "hello world"); gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); cairo_paint(cr); cairo_fill (cr); @@ -186,6 +186,47 @@ void cb_videoda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) cairo_stroke(cr); } } + + // draw movement vector to screen + snprintf (txt1, 255, "%f", detectedpos_data.dx); + snprintf (txt2, 255, "%f", detectedpos_data.dy); + for (int i = 0; i < 5; i++) { + int dx, dy; + + switch (i) { + case 0: + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + dx = -1; + dy = 0; + break; + case 1: + dx = +1; + dy = 0; + break; + case 2: + dx = 0; + dy = -1; + break; + case 3: + dx = 0; + dy = +1; + break; + case 4: + cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); + dx = 0; + dy = 0; + break; + } + + cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, 12); + cairo_move_to (cr, 10+dx, 15+dy); + cairo_show_text(cr, txt1); + cairo_stroke(cr); + cairo_move_to (cr, 10+dx, 30+dy); + cairo_show_text(cr, txt2); + cairo_stroke(cr); + } }; diff --git a/videodev.cc b/videodev.cc index 2a65321..f1597c3 100644 --- a/videodev.cc +++ b/videodev.cc @@ -469,8 +469,8 @@ int VideoDev::OpenInit() { fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 1920; fmt.fmt.pix.height = 1080; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; -// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; +// fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; fmt.fmt.pix.field = V4L2_FIELD_NONE; if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) {