You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
458 lines
14 KiB
458 lines
14 KiB
/***************************************************************************************
|
|
*
|
|
* main.cc is part of SimpleSkyCam.
|
|
*
|
|
*****************************************************************************************/
|
|
|
|
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
|
|
#else
|
|
#include <unistd.h> /* close() */
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <list>
|
|
#include <math.h>
|
|
#include "gui.h"
|
|
#include "config.h"
|
|
#include "video.h"
|
|
#include "output.h"
|
|
#include "detect.h"
|
|
#include "configuration.h"
|
|
|
|
extern GtkBuilder *_builder_; // work around for threads
|
|
extern Output output;
|
|
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;
|
|
|
|
GtkWidget *image_da = NULL;
|
|
GdkPixbuf *image_pixbuf = NULL;
|
|
std::string filename = "";
|
|
extern Configuration config;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// call back functions
|
|
//
|
|
|
|
gboolean cb_window_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) {
|
|
config.SaveDefault();
|
|
gtk_main_quit();
|
|
return FALSE;
|
|
};
|
|
|
|
|
|
//
|
|
// setup default values
|
|
//
|
|
void cb_window_show (GtkWidget *widget, gpointer data) {
|
|
GtkWidget *btnstart = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-rec"));
|
|
GtkWidget *btnstop = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "btn-video-stop"));
|
|
GtkWidget *w = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
|
|
GtkWidget *h = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
|
|
GtkWidget *rbdefdetect = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright"));
|
|
GtkWidget *rbdeffolow = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2"));
|
|
|
|
// changing the value, will cause the 'change' event to be triggered
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdefdetect), true);
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rbdeffolow), true);
|
|
|
|
|
|
gtk_widget_set_sensitive(btnstart, true);
|
|
gtk_widget_set_sensitive(btnstop, false);
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(w),"300");
|
|
gtk_entry_set_text(GTK_ENTRY(h),"300");
|
|
|
|
detect.SetObjectSize(300, 300);
|
|
cb_video_btnrefreshlist (NULL, NULL);
|
|
|
|
//
|
|
// load config and setup elements
|
|
config.LoadDefault();
|
|
GtkWidget *cfg_rgbenc = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "menu-settings-bilinearrgb"));
|
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(cfg_rgbenc), (config.debayer_mode != 0));
|
|
|
|
//
|
|
// update the input video controls every 2 seconds.
|
|
g_timeout_add(2000, videoctrl_update, NULL);
|
|
};
|
|
|
|
|
|
void cb_menu_set_rgbenc (GtkCheckMenuItem *checkmenuitem, gpointer user_data) {
|
|
if (gtk_check_menu_item_get_active(checkmenuitem) == TRUE) config.debayer_mode = 1;
|
|
else config.debayer_mode = 0;
|
|
}
|
|
|
|
|
|
//data
|
|
// callback from filter thread. Data will point to the output VideoFrame.
|
|
// Access to this data must be Locked before use.
|
|
gboolean cb_thread_filter (gpointer data) {
|
|
VideoFrame *vf = (VideoFrame *) data;
|
|
int pix_h, pix_w;
|
|
|
|
if (image_da == NULL)
|
|
image_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "image-da"));
|
|
|
|
if (vf == NULL) {
|
|
return false;
|
|
}
|
|
|
|
output.LockImageMutex();
|
|
|
|
if (image_pixbuf) {
|
|
pix_h = gdk_pixbuf_get_height(image_pixbuf);
|
|
pix_w = gdk_pixbuf_get_width(image_pixbuf);
|
|
}
|
|
else pix_h = 0;
|
|
|
|
if (image_pixbuf == NULL || pix_h != vf->h || pix_w != vf->w) {
|
|
if (image_pixbuf != NULL) g_object_unref (image_pixbuf);
|
|
|
|
printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, vf->w, vf->h);
|
|
image_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, vf->w, vf->h);
|
|
pix_w = vf->w;
|
|
pix_h = vf->h;
|
|
}
|
|
vf->ToPixbuf(image_pixbuf);
|
|
gdk_window_invalidate_rect(gtk_widget_get_window(image_da), NULL, true);
|
|
|
|
output.UnLockImageMutex();
|
|
return false;
|
|
};
|
|
|
|
|
|
//
|
|
// callback from detect thread. Data will point to the temp VideoFrame.
|
|
// this is propabely the object detection
|
|
// Access to this data must be Locked before use and pointers must be looked to
|
|
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, x, y;
|
|
|
|
if (detect_da == NULL)
|
|
detect_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "temp-da"));
|
|
|
|
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());
|
|
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);
|
|
pix_w = gdk_pixbuf_get_width(detect_pixbuf);
|
|
}
|
|
else pix_h = 0;
|
|
|
|
if (detect_pixbuf == NULL || pix_h != dout->image->h || pix_w != dout->image->w) {
|
|
if (detect_pixbuf != NULL) g_object_unref (detect_pixbuf);
|
|
|
|
printf ("%s:%d %s New Pixbuf: %d x %d\n", __FILE__, __LINE__, __FUNCTION__, dout->image->w, dout->image->h);
|
|
detect_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, dout->image->w, dout->image->h);
|
|
pix_w = dout->image->w;
|
|
pix_h = dout->image->h;
|
|
}
|
|
dout->image->ToPixbuf(detect_pixbuf);
|
|
gdk_window_invalidate_rect(gtk_widget_get_window(detect_da), NULL, true);
|
|
output.NewFrame(dout->image, dout->posx, dout->posy);
|
|
|
|
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;
|
|
};
|
|
|
|
|
|
|
|
void cb_imagetempda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) {
|
|
int clientw, clienth, pixbufw, pixbufh;
|
|
float clientar, pixbufar;
|
|
|
|
GdkPixbuf *pixbuf = NULL;
|
|
GdkPixbuf *src = NULL;
|
|
|
|
if (area == image_da) src = image_pixbuf;
|
|
else if (area == detect_da) src = detect_pixbuf;
|
|
else return;
|
|
|
|
clienth = gtk_widget_get_allocated_height(area);
|
|
clientw = gtk_widget_get_allocated_width(area);
|
|
clientar = (float)clientw/(float)clienth;
|
|
pixbufh = gdk_pixbuf_get_height(src);
|
|
pixbufw = gdk_pixbuf_get_width(src);
|
|
pixbufar = (float)pixbufw/(float)pixbufh;
|
|
|
|
if (pixbufar < clientar) {
|
|
clientw = (pixbufar * (float) clienth);
|
|
}
|
|
else {
|
|
clienth = ((float) clientw / pixbufar);
|
|
}
|
|
|
|
pixbuf = gdk_pixbuf_scale_simple (src, clientw, clienth, GDK_INTERP_NEAREST);
|
|
|
|
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
|
|
cairo_paint(cr);
|
|
cairo_fill (cr);
|
|
|
|
g_object_unref (pixbuf);
|
|
};
|
|
|
|
|
|
void cb_detect_btnsetsize (GtkWidget *widget, gpointer data) {
|
|
GtkWidget *txtw = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-w"));
|
|
GtkWidget *txth = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-entry-h"));
|
|
|
|
detect.SetObjectSize( atoi(gtk_entry_get_text(GTK_ENTRY(txtw))),
|
|
atoi(gtk_entry_get_text(GTK_ENTRY(txth))));
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
void cb_output_btnsave (GtkWidget *widget, gpointer data) {
|
|
GtkBuilder *builder = (GtkBuilder *) data;
|
|
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "window-main"));
|
|
GtkWidget *dialog;
|
|
GtkFileChooser *chooser;
|
|
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
|
|
GtkFileFilter *filter;
|
|
gint res;
|
|
|
|
if (image_pixbuf == NULL) return;
|
|
|
|
dialog = gtk_file_chooser_dialog_new ("Save File",
|
|
window,
|
|
action,
|
|
"_Cancel",
|
|
GTK_RESPONSE_CANCEL,
|
|
"_Save",
|
|
GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
chooser = GTK_FILE_CHOOSER (dialog);
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_add_pattern(filter, "*.png");
|
|
gtk_file_filter_set_name(filter, "PNG File");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_add_pattern(filter, "*.*");
|
|
gtk_file_filter_set_name(filter, "All Files");
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
|
|
if (filename.length () == 0)
|
|
gtk_file_chooser_set_current_name (chooser, "capture-001.png");
|
|
else
|
|
gtk_file_chooser_set_filename (chooser, filename.c_str());
|
|
|
|
res = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
if (res == GTK_RESPONSE_ACCEPT) {
|
|
char *filename;
|
|
|
|
filename = gtk_file_chooser_get_filename (chooser);
|
|
|
|
gdk_pixbuf_save(image_pixbuf, filename, "png", NULL, "quality", "100", NULL);
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
};
|
|
*/
|
|
|
|
|
|
void cb_detect_bright (GtkRange *range, gpointer data) {
|
|
double value;
|
|
|
|
value = gtk_range_get_value(range);
|
|
detect.SetMinBrightness(value);
|
|
};
|
|
|
|
|
|
void cb_detect_followtype (GtkWidget *widget, gpointer data) {
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) {
|
|
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet0")))
|
|
detect.SetFollowType(AUTOFOLLOW_OFF);
|
|
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet1")))
|
|
detect.SetFollowType(AUTOFOLLOW_BRIGHT);
|
|
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-type-indet2")))
|
|
detect.SetFollowType(AUTOFOLLOW_CROSSC);
|
|
}
|
|
};
|
|
|
|
|
|
void cb_detect_detecttype (GtkWidget *widget, gpointer data) {
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget)) == 1) {
|
|
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff")))
|
|
detect.SetDetectType(AUTODETECT_OFF);
|
|
if (widget == GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cbbright")))
|
|
detect.SetDetectType(AUTODETECT_BRIGHT);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
void cb_detect_btnsetpos (GtkWidget *widget, gpointer data) {
|
|
GtkWidget *rboff = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "detect-pos-cboff"));
|
|
|
|
// changing the value, will cause the 'change' event to be triggered
|
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rboff), true);
|
|
|
|
video_enterdata = VID_ENTERDATA_POS;
|
|
};
|
|
|
|
|
|
void cb_output_show_window (GtkWidget *widget, gpointer data) {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-output"));
|
|
gtk_widget_show(wnd);
|
|
};
|
|
|
|
|
|
void cb_detect_show_window (GtkWidget *widget, gpointer data) {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-detect"));
|
|
gtk_widget_show(wnd);
|
|
};
|
|
|
|
|
|
/*
|
|
* setup destination path
|
|
*/
|
|
void cb_input_btnsetdestpath (GtkWidget *widget, gpointer data) {
|
|
GtkBuilder *builder = (GtkBuilder *) data;
|
|
GtkWindow *window = GTK_WINDOW (gtk_builder_get_object (builder, "windows-input"));
|
|
GtkWidget *dialog;
|
|
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
|
|
gint res;
|
|
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
dialog = gtk_file_chooser_dialog_new ("Open Folder",
|
|
window,
|
|
action,
|
|
"_Cancel",
|
|
GTK_RESPONSE_CANCEL,
|
|
"_Open",
|
|
GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
res = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
if (res == GTK_RESPONSE_ACCEPT) {
|
|
char *filename;
|
|
GtkFileChooser *chooser = GTK_FILE_CHOOSER (dialog);
|
|
filename = gtk_file_chooser_get_filename (chooser);
|
|
config.SetDestPath(filename);
|
|
GtkWidget *entry = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "input_entry_destpath"));
|
|
gtk_entry_set_text(GTK_ENTRY(entry), filename);
|
|
|
|
g_free (filename);
|
|
}
|
|
gtk_widget_destroy (dialog);
|
|
};
|
|
|
|
void cb_input_show_window (GtkWidget *widget, gpointer data) {
|
|
printf ("%s:%d %s\n", __FILE__, __LINE__, __FUNCTION__);
|
|
|
|
GtkWidget *wnd = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input"));
|
|
gtk_widget_show(wnd);
|
|
};
|
|
|
|
|
|
void draw_text (cairo_t *cr, int x, int y, float border, std::string text) {
|
|
cairo_pattern_t *t = NULL;
|
|
double r, g, b, a;
|
|
|
|
t = cairo_get_source(cr);
|
|
cairo_pattern_get_rgba(t, &r, &g, &b, &a);
|
|
|
|
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_rgba(cr, r, g, b, a);
|
|
dx = 0;
|
|
dy = 0;
|
|
break;
|
|
}
|
|
cairo_move_to (cr, x+dx, y+dy);
|
|
cairo_show_text(cr, text.c_str());
|
|
cairo_stroke(cr);
|
|
}
|
|
};
|
|
|
|
#define DRAW_PRINTF_LEN 512
|
|
void draw_printf(cairo_t *cr, int x, int y, float border, char *fmt,...) {
|
|
va_list args;
|
|
char buffer[DRAW_PRINTF_LEN];
|
|
|
|
va_start (args, fmt);
|
|
vsnprintf (buffer, (DRAW_PRINTF_LEN-1), fmt, args);
|
|
va_end (args);
|
|
buffer[DRAW_PRINTF_LEN-1] = 0;
|
|
draw_text (cr, x, y, border, buffer);
|
|
};
|
|
|
|
|