From a225aac16f8ed9047792597c9993c24e0a20031b Mon Sep 17 00:00:00 2001 From: usrusr Date: Tue, 10 Dec 2013 01:59:06 +0100 Subject: fork info --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index fbbead33..8475ecfe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + Windows binary builds are available at Source code access available at @@ -56,3 +57,9 @@ compatible with it unless resides in separate address space. It's recommended to submit new code under ISC license, it's a shorter boilerplate header than MIT/X11 or new BSD. + +# this fork/branch: usrusr/opentrack feature/pt-hysteresis + +Per pixel hysteresis for point tracker: sacrifice some precision, cpu and sensitivity to minor movements for greatly reduced jitter from pixel noise at full responsivity (usable without postprocessing filters!) +-- Ulf Schreiber +Ulf Schreiber -- cgit v1.2.3 From 28fcbb913ed0969b22fd07c32c63c2a54568b6c6 Mon Sep 17 00:00:00 2001 From: usrusr Date: Tue, 10 Dec 2013 01:52:43 +0100 Subject: add an optional per-pixel hysteresis to remove pixel noise at the expense of a moderate movement threshold (but no lag) --- FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui | 32 ++++++++++ FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp | 1 + FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp | 2 + FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h | 1 + FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp | 2 + FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h | 2 + FTNoIR_Tracker_PT/point_extractor.cpp | 80 +++++++++++++++++++++--- FTNoIR_Tracker_PT/point_extractor.h | 6 ++ 8 files changed, 117 insertions(+), 9 deletions(-) diff --git a/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui b/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui index 1495249a..9ad4f83c 100644 --- a/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui +++ b/FTNoIR_Tracker_PT/FTNoIR_PT_Controls.ui @@ -848,6 +848,38 @@ + + + + + + + Hysteresis + + + threshold_secondary_slider + + + + + + + Per pixel hysteresis width (leave left if there is little difference between dot and non-dot, move right for increased stability against pixel noise) + + + 255 + + + 100 + + + Qt::Horizontal + + + + + + diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp index 5cb7bdf3..dcf28f04 100644 --- a/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt.cpp @@ -113,6 +113,7 @@ void Tracker::apply(const TrackerSettings& settings) camera.set_f(settings.cam_f); frame_rotation.rotation = static_cast(settings.cam_roll); point_extractor.threshold_val = settings.threshold; + point_extractor.threshold_secondary_val = settings.threshold_secondary; point_extractor.min_size = settings.min_point_size; point_extractor.max_size = settings.max_point_size; point_tracker.point_model = boost::shared_ptr(new PointModel(settings.M01, settings.M02)); diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp index fe995163..f8afa790 100644 --- a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.cpp @@ -63,6 +63,7 @@ TrackerDialog::TrackerDialog() ui.campitch_spin->setValue(settings.cam_pitch); ui.camyaw_spin->setValue(settings.cam_yaw); ui.threshold_slider->setValue(settings.threshold); + ui.threshold_secondary_slider->setValue(settings.threshold_secondary); ui.chkEnableRoll->setChecked(settings.bEnableRoll); ui.chkEnablePitch->setChecked(settings.bEnablePitch); @@ -105,6 +106,7 @@ TrackerDialog::TrackerDialog() connect( ui.campitch_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_pitch(int)) ); connect( ui.camyaw_spin,SIGNAL(valueChanged(int)), this,SLOT(set_cam_yaw(int)) ); connect( ui.threshold_slider,SIGNAL(sliderMoved(int)), this,SLOT(set_threshold(int)) ); + connect( ui.threshold_secondary_slider,SIGNAL(sliderMoved(int)), this,SLOT(set_threshold_secondary(int)) ); connect( ui.chkEnableRoll,SIGNAL(toggled(bool)), this,SLOT(set_ena_roll(bool)) ); connect( ui.chkEnablePitch,SIGNAL(toggled(bool)), this,SLOT(set_ena_pitch(bool)) ); diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h index 3e1af50a..de743ad8 100644 --- a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_dialog.h @@ -54,6 +54,7 @@ protected slots: void set_min_point_size(int val) { settings.min_point_size = val; settings_changed(); } void set_max_point_size(int val) { settings.max_point_size = val; settings_changed(); } void set_threshold(int val) { settings.threshold = val; settings_changed(); } + void set_threshold_secondary(int val) { settings.threshold_secondary = val; settings_changed(); } void set_ena_roll(bool val) { settings.bEnableRoll = val; settings_changed(); } void set_ena_pitch(bool val) { settings.bEnablePitch = val; settings_changed(); } void set_ena_yaw(bool val) { settings.bEnableYaw = val; settings_changed(); } diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp index 62ba1e3e..50835cb8 100644 --- a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.cpp @@ -29,6 +29,7 @@ void TrackerSettings::load_ini() cam_pitch = iniFile.value("CameraPitch", 0).toInt(); cam_yaw = iniFile.value("CameraYaw", 0).toInt(); threshold = iniFile.value("PointExtractThreshold", 128).toInt(); + threshold_secondary = iniFile.value("PointExtractThresholdSecondary", 128).toInt(); min_point_size = iniFile.value("PointExtractMinSize", 2).toInt(); max_point_size = iniFile.value("PointExtractMaxSize", 50).toInt(); M01[0] = iniFile.value("PointModelM01x", 0).toFloat(); @@ -74,6 +75,7 @@ void TrackerSettings::save_ini() const iniFile.setValue("CameraPitch", cam_pitch); iniFile.setValue("CameraYaw", cam_yaw); iniFile.setValue("PointExtractThreshold", threshold); + iniFile.setValue("PointExtractThresholdSecondary", threshold_secondary); iniFile.setValue("PointExtractMinSize", min_point_size); iniFile.setValue("PointExtractMaxSize", max_point_size); iniFile.setValue("PointModelM01x", M01[0]); diff --git a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h index 1cf60853..91a7a8d5 100644 --- a/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h +++ b/FTNoIR_Tracker_PT/ftnoir_tracker_pt_settings.h @@ -28,6 +28,8 @@ struct TrackerSettings // point extraction int threshold; + int threshold_secondary; + int min_point_size; int max_point_size; diff --git a/FTNoIR_Tracker_PT/point_extractor.cpp b/FTNoIR_Tracker_PT/point_extractor.cpp index 261de60f..27a14713 100644 --- a/FTNoIR_Tracker_PT/point_extractor.cpp +++ b/FTNoIR_Tracker_PT/point_extractor.cpp @@ -8,15 +8,27 @@ #include "point_extractor.h" #include + using namespace cv; using namespace std; + +PointExtractor::PointExtractor(){ + first = true; + + + //if (!AllocConsole()){} + //else SetConsoleTitle("debug"); + //freopen("CON", "w", stdout); + //freopen("CON", "w", stderr); +} // ---------------------------------------------------------------------------- const vector& PointExtractor::extract_points(Mat frame, float dt, bool draw_output) { const int W = frame.cols; const int H = frame.rows; + // clear old points points.clear(); @@ -24,10 +36,41 @@ const vector& PointExtractor::extract_points(Mat frame, float dt, bool dr Mat frame_gray; cvtColor(frame, frame_gray, CV_RGB2GRAY); - // convert to binary + int secondary = threshold_secondary_val; + + // mask for everything that passes the threshold (or: the upper threshold of the hysteresis) Mat frame_bin; - threshold(frame_gray, frame_bin, threshold_val, 255, THRESH_BINARY); + // only used if draw_output + Mat frame_bin_copy; + // mask for everything that passes + Mat frame_bin_low; + // mask for lower-threshold && combined result of last, needs to remain in scope until drawing, but is only used if secondary != 0 + Mat frame_last_and_low; + if(secondary==0){ + threshold(frame_gray, frame_bin, threshold_val, 255, THRESH_BINARY); + }else{ + // we recombine a number of buffers, this might be slower than a single loop of per-pixel logic + // but it might as well be faster if openCV makes good use of SIMD + float t = threshold_val; + //float hyst = float(threshold_secondary_val)/512.; + //threshold(frame_gray, frame_bin, (t + ((255.-t)*hyst)), 255, THRESH_BINARY); + float hyst = float(threshold_secondary_val)/256.; + threshold(frame_gray, frame_bin, t, 255, THRESH_BINARY); + threshold(frame_gray, frame_bin_low,std::max(float(1), t - (t*hyst)), 255, THRESH_BINARY); + + if(draw_output) frame_bin.copyTo(frame_bin_copy); + if(first){ + frame_bin.copyTo(frame_last); + first = false; + }else{ + // keep pixels from last if they are above lower threshold + bitwise_and(frame_last, frame_bin_low, frame_last_and_low); + // union of pixels >= higher threshold and pixels >= lower threshold + bitwise_or(frame_bin, frame_last_and_low, frame_last); + frame_last.copyTo(frame_bin); + } + } unsigned int region_size_min = 3.14*min_size*min_size/4.0; unsigned int region_size_max = 3.14*max_size*max_size/4.0; @@ -42,6 +85,7 @@ const vector& PointExtractor::extract_points(Mat frame, float dt, bool dr // find connected components with floodfill if (frame_bin.at(y,x) != 255) continue; Rect rect; + floodFill(frame_bin, Point(x,y), Scalar(blob_index), &rect, Scalar(0), Scalar(0), FLOODFILL_FIXED_RANGE); blob_index++; @@ -70,9 +114,17 @@ const vector& PointExtractor::extract_points(Mat frame, float dt, bool dr for (int j=rect.x; j < (rect.x+rect.width); j++) { if (frame_bin.at(i,j) != blob_index-1) continue; - float val = frame_gray.at(i,j); - val = float(val - threshold_val)/(256 - threshold_val); - val = val*val; // makes it more stable (less emphasis on low values, more on the peak) + float val; + + if(secondary==0){ + val = frame_gray.at(i,j); + val = float(val - threshold_val)/(256 - threshold_val); + val = val*val; // makes it more stable (less emphasis on low values, more on the peak) + }else{ + //hysteresis point detection gets stability from ignoring pixel noise so we decidedly leave the actual pixel values out of the picture + val = frame_last.at(i,j) / 256.; + } + m += val; mx += j * val; my += i * val; @@ -83,6 +135,7 @@ const vector& PointExtractor::extract_points(Mat frame, float dt, bool dr Vec2f c; c[0] = (mx/m - W/2)/W; c[1] = -(my/m - H/2)/W; + //qDebug()< "<& PointExtractor::extract_points(Mat frame, float dt, bool dr // draw output image if (draw_output) { vector channels; - frame_bin.setTo(170, frame_bin); - channels.push_back(frame_gray + frame_bin); - channels.push_back(frame_gray - frame_bin); - channels.push_back(frame_gray - frame_bin); + if(secondary==0){ + frame_bin.setTo(170, frame_bin); + channels.push_back(frame_gray + frame_bin); + channels.push_back(frame_gray - frame_bin); + channels.push_back(frame_gray - frame_bin); + }else{ + frame_bin_copy.setTo(120, frame_bin_copy); + frame_bin_low.setTo(90, frame_bin_low); + channels.push_back(frame_gray + frame_bin_copy); + channels.push_back(frame_gray + frame_last_and_low); + channels.push_back(frame_gray + frame_bin_low); + //channels.push_back(frame_gray + frame_bin); + } merge(channels, frame); } diff --git a/FTNoIR_Tracker_PT/point_extractor.h b/FTNoIR_Tracker_PT/point_extractor.h index c62d34f9..b9f46666 100644 --- a/FTNoIR_Tracker_PT/point_extractor.h +++ b/FTNoIR_Tracker_PT/point_extractor.h @@ -21,12 +21,18 @@ public: // WARNING: returned reference is valid as long as object const std::vector& extract_points(cv::Mat frame, float dt, bool draw_output); const std::vector& get_points() { return points; } + PointExtractor(); int threshold_val; + int threshold_secondary_val; int min_size, max_size; protected: std::vector points; + cv::Mat frame_last; + + + bool first; }; #endif //POINTEXTRACTOR_H -- cgit v1.2.3