From 605e81389ee3f7a476a5a3e36c4459a83e5d2993 Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Fri, 8 Oct 2021 22:43:55 +0200 Subject: [PATCH] started to work on detection and filter --- filter.cc | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ filter.h | 74 +++++++++++++++++++++++ videoframe.cc | 142 ++++++++++++++++++++++++++++++++++++++++++++ videoframe.h | 51 ++++++++++++++++ 4 files changed, 427 insertions(+) create mode 100644 filter.cc create mode 100644 filter.h create mode 100644 videoframe.cc create mode 100644 videoframe.h diff --git a/filter.cc b/filter.cc new file mode 100644 index 0000000..669ac6b --- /dev/null +++ b/filter.cc @@ -0,0 +1,160 @@ + + +#include + +#include "config.h" +#include "gui.h" +#include "filter.h" + +extern Filter filter; +gboolean cb_filtertemp_thread (gpointer data); +gboolean cb_filterout_thread (gpointer data); + +// +// C / C++ Wrapper for the thread function +// +gpointer _FilterThread (gpointer data) { + filter.Thread (); + return NULL; +}; + + + +Filter::Filter() { // @suppress("Class members should be properly initialized") + g_mutex_init (&mutexin); + g_mutex_init (&mutexout); + g_mutex_init (&mutextmp); + g_mutex_init (&mutex); + running = 1; + inFrame.SetSize(64, 64); + oldFrame.SetSize(64, 64); + temp.SetSize(64, 64); + tempgtk.SetSize(64, 64); + image.SetSize(64, 64); + imagegtk.SetSize(64, 64); + thread = NULL; + thread = g_thread_new("Filter", _FilterThread, NULL); +}; + + + +Filter::~Filter() { + running = 0; + if (thread) { + g_thread_join (thread); + thread = NULL; + } +}; + + + +int Filter::NewFrame(VideoFrame *newframe) { + LockInMutex(); + inFrame.CopyFrom(newframe); + inFrameNew = 1; + UnLockInMutex(); + return -1; +}; + + +// +// NewFrame: will set new frame +// Thread: newFrame |------> Find Object --- not found ---> send gui information +void Filter::Thread() { + while (running) { + // check for new frame + LockInMutex(); + if (inFrameNew == 1) { + inFrameNew = 0; + + // + // do some input detection improvement + InputDetect(); + + oldFrame.CopyFrom(&inFrame); + UnLockInMutex(); + + // copy temporary image for gtk + LockTempMutex(); + tempgtk.CopyFrom(&temp); + UnLockTempMutex(); + gdk_threads_add_idle(cb_filtertemp_thread , &tempgtk); + + // + // do some other stuff use if possible only the oldFrame data + ComposeOutput(); + + // copy output image for gtk + LockOutMutex(); + imagegtk.CopyFrom(&image); + UnLockOutMutex(); + gdk_threads_add_idle(cb_filterout_thread , &imagegtk); + } + else + UnLockInMutex(); + + usleep (10000); + } +} + + +void Filter::InputDetect() { + int x, y; + float vo, v; + unsigned char *pxs, *pxso, *pxstemp; + unsigned char pixel; + int idx; + FloatImage fi;; + float fmin, fmax; + + temp.SetSize (inFrame.w, inFrame.h); + fi.SetSize (inFrame.w, inFrame.h); + pxs = inFrame.data; + pxso = oldFrame.data; + pxstemp = temp.data; + + for (x = 0; x < temp.w && x < inFrame.w && x < oldFrame.w; x++) + for (y = 0; y < temp.h && y < inFrame.h && y < oldFrame.h; y++) { + idx = (inFrame.w * y + x); + vo = pxso[3*idx+0] + pxso[3*idx+1] + pxso[3*idx+2]; + v = pxs[3*idx+0] + pxs[3*idx+1] + pxs[3*idx+2]; + fi.data[idx] = v - vo; + + if (idx == 0 || fmin > fi.data[idx]) fmin = fi.data[idx]; + if (idx == 0 || fmax < fi.data[idx]) fmax = fi.data[idx]; + } + + for (x = 0; x < temp.w && x < inFrame.w && x < oldFrame.w; x++) + for (y = 0; y < temp.h && y < inFrame.h && y < oldFrame.h; y++) { + idx = (inFrame.w * y + x); + pixel = (unsigned char)((float)( (fi.data[idx]-fmin) / (fmax-fmin)) * 256.0); + pxstemp[3*idx+0] = pixel; + pxstemp[3*idx+1] = pixel; + pxstemp[3*idx+2] = pixel; + } +} + + + +#define FACTOR 100.0 +void Filter::ComposeOutput() { + int x, y, idx, i; + float *pixd; // destination + unsigned char *pixs; // source + + image.SetSize(oldFrame.w, oldFrame.h); + pixd = image.data; + pixs = oldFrame.data; + + for (x = 0; x < temp.w && x < inFrame.w && x < oldFrame.w; x++) + for (y = 0; y < temp.h && y < inFrame.h && y < oldFrame.h; y++) { + idx = 3 * (oldFrame.w * y + x); + + for (i = 0; i < 3; i++) + pixd[idx+i] = (FACTOR * pixd[idx+i]/FACTOR) + (pixs[idx+i] / FACTOR); + } +} + + + + diff --git a/filter.h b/filter.h new file mode 100644 index 0000000..dd69aaf --- /dev/null +++ b/filter.h @@ -0,0 +1,74 @@ +/*************************************************************************************** + * + * filter.h is part of SimpleSkyCam. + * + *****************************************************************************************/ + + +#ifndef _FILTER_H_ +#define _FILTER_H_ + +#include "gui.h" +#include "config.h" +#include "video.h" +#include "videoframe.h" + + +class Filter { +private: + int running; + VideoFrame inFrame; // input frame + int inFrameNew; // new input frame; + VideoFrame oldFrame; // oldinput frame + VideoFrame temp; // temporary image + VideoFrame tempgtk; // temp image for gtk + FloatImage image; // output image + VideoFrame imagegtk; // output image -- send to gtk + GMutex mutexout; + GMutex mutexin; + GMutex mutextmp; // for access the temp image + GMutex mutex; // general mutex for changing settings + GThread *thread; + + int objectW; // object Image Size Width + int objectH; // object Image Size Height + + float *fpixels; // + + void InputDetect(); + void ComposeOutput(); + +public: + Filter(); + ~Filter(); + + int NewFrame (VideoFrame *newframe); + + // + // Thread Releated Functions (maybe soon private?) + int TryLockInMutex() { return g_mutex_trylock(&mutextmp); }; + void LockInMutex() { g_mutex_lock(&mutextmp);}; + void UnLockInMutex() { g_mutex_unlock(&mutextmp);}; + + int TryLockTempMutex() { return g_mutex_trylock(&mutextmp); }; + void LockTempMutex() { g_mutex_lock(&mutextmp);}; + void UnLockTempMutex() { g_mutex_unlock(&mutextmp);}; + + int TryLockOutMutex() { return g_mutex_trylock(&mutexout); }; + void LockOutMutex() { g_mutex_lock(&mutexout);}; + void UnLockOutMutex() { g_mutex_unlock(&mutexout);}; + + void LockMutex() { g_mutex_lock(&mutex);}; + void UnLockMutex() { g_mutex_unlock(&mutex);}; + + + // + // Object functions + void SetObjectSize (int neww, int newh); + void SetObject (VideoFrame objFrame, int newx, int newy); + void GetObjectPos (int *x, int *y); + + void Thread(); +}; + +#endif diff --git a/videoframe.cc b/videoframe.cc new file mode 100644 index 0000000..13bafbd --- /dev/null +++ b/videoframe.cc @@ -0,0 +1,142 @@ + +#include "video.h" +#include "config.h" +#include "gui.h" + +#define VIDEOFRAME_DEPTH_BYTES 3 + +VideoFrame::VideoFrame() { + data = NULL; + w = 0; + h = 0; + size = 0; +}; + + +VideoFrame::~VideoFrame() { + if (data) { + free (data); + data = NULL; + } + + w = 0; + h = 0; + size = 0; +}; + + +// +// we will only allocate a new image if the needed size increases +void VideoFrame::SetSize(int nw, int nh) { + uint32_t newsize = VIDEOFRAME_DEPTH_BYTES * h * w; + + if (newsize > size || data == NULL) { + unsigned char *newdata = (unsigned char *) malloc (newsize); + if (data != NULL) free (data); + data = newdata; + size = newsize; + } + w = nw; + h = nh; +}; + + +VideoFrame VideoFrame::operator=(VideoFrame rightside) { + w = rightside.w; + h = rightside.h; + size = rightside.size; + if (size > 0) data = (unsigned char *) malloc (rightside.size); + if (rightside.data != NULL && size > 0) { + memcpy (data, rightside.data, size); + } + return *this; +} + + +void VideoFrame::CopyFrom(VideoFrame *source) { + SetSize (source->w, source->h); + memcpy(data, source->data, VIDEOFRAME_DEPTH_BYTES * w * h); +} + + + +void VideoFrame::CopyFrom(FloatImage *source) { + float min, max; + int x, y, i, idx; + unsigned char v; + + SetSize (source->w, source->h); + + // find min max; + min = source->data[0]; + max = source->data[0]; + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = 3 * (y * w + x); + if (min > source->data[idx+i]) min = source->data[idx+i]; + if (max < source->data[idx+i]) max = source->data[idx+i]; + } + + for (y = 0; y < h; y++) for (x = 0; x < w; x++) + for (i = 0; i < 3; i++) { + idx = 3 * (y * w + x); + v = (float)(256.0 * (source->data[idx+i]-min) / (max-min)); + } +} + + + + +FloatImage::FloatImage() { + data = NULL; + w = 0; + h = 0; + size = 0; +}; + + +FloatImage::~FloatImage() { + if (data) { + free (data); + data = NULL; + } + + w = 0; + h = 0; + size = 0; +}; + + +// +// we will only allocate a new image if the needed size increases +void FloatImage::SetSize(int nw, int nh) { + uint32_t newsize = 3 * h * w * sizeof(float); + + if (newsize > size || data == NULL) { + float *newdata = (float *) malloc (newsize); + if (data != NULL) free (data); + data = newdata; + size = newsize; + } + w = nw; + h = nh; +}; + + +FloatImage FloatImage::operator=(FloatImage rightside) { + w = rightside.w; + h = rightside.h; + size = rightside.size; + if (size > 0) data = (float *) malloc (rightside.size); + if (rightside.data != NULL && size > 0) { + memcpy (data, rightside.data, size); + } + return *this; +} + + +void FloatImage::CopyFrom(FloatImage *source) { + SetSize (source->w, source->h); + memcpy(data, source->data, 3 * w * h); +} + diff --git a/videoframe.h b/videoframe.h new file mode 100644 index 0000000..f697d91 --- /dev/null +++ b/videoframe.h @@ -0,0 +1,51 @@ +#ifndef _VIDEOFRAME_H_ +#define _VIDEOFRAME_H_ + +#include "gui.h" +#include "config.h" + + + + +class FloatImage { +public: + int w; + int h; + uint32_t size; + float *data; + + FloatImage(); + ~FloatImage(); + + FloatImage operator=(FloatImage rightside); + + void SetSize(int nw, int nh); + void SetW(int nw) { SetSize(nw, h); }; + void SetH(int nh) { SetSize(w, nh); }; + void CopyFrom(FloatImage *source); +}; + + +class VideoFrame { +public: + int w; + int h; + uint32_t size; + unsigned char *data; + + VideoFrame(); + ~VideoFrame(); + + VideoFrame operator=(VideoFrame rightside); + + void SetSize(int nw, int nh); + void SetW(int nw) { SetSize(nw, h); }; + void SetH(int nh) { SetSize(w, nh); }; + void CopyFrom(VideoFrame *source); + void CopyFrom(FloatImage *source); +}; + + + +#endif +