コード例 #1
0
bool compute()
{
    bool waiting_for_image_set = false;
    updated = false;
    ++frame_count;

    if (image_current_frame.cols == 0)
    {
        console_log("bad frame");
        return false;
    }

    Mat image_flipped;
    flip(image_current_frame, image_flipped, 0);

    Mat image0 = image_flipped(Rect(0, 0, 640, 480));
    Mat image1 = image_flipped(Rect(640, 0, 640, 480));

    if (frame_count == 1)
        setup_on_first_frame();

    if (!play || settings.touch_control != "1")
    {
        if (enable_imshow)
            waitKey(1);

        return false;
    }

    int x_accel;
    int y_accel;
    int z_accel;
    camera->getAccelerometerValues(&x_accel, &y_accel, &z_accel);
    imu.compute(x_accel, y_accel, z_accel);

    //----------------------------------------core algorithm----------------------------------------

    Mat image_small0;
    Mat image_small1;
    resize(image0, image_small0, Size(160, 120), 0, 0, INTER_LINEAR);
    resize(image1, image_small1, Size(160, 120), 0, 0, INTER_LINEAR);

    Mat image_preprocessed0;
    Mat image_preprocessed1;

    static bool exposure_set = false;

    bool normalized = compute_channel_diff_image(image_small0, image_preprocessed0, exposure_set, "image_preprocessed0", true, exposure_set);
                      compute_channel_diff_image(image_small1, image_preprocessed1, exposure_set, "image_preprocessed1");

    GaussianBlur(image_preprocessed0, image_preprocessed0, Size(3, 9), 0, 0);
    GaussianBlur(image_preprocessed1, image_preprocessed1, Size(3, 9), 0, 0);

    if (!CameraInitializerNew::adjust_exposure(camera, image_preprocessed0))
    {
        static int step_count = 0;
        if (step_count == 3)
            surface_computer.init(image0);

        ++step_count;
        return false;
    }

    exposure_set = true;

#if 0
    {
        Mat image_remapped0 = reprojector.remap(&image_small0, 0, true);
        Mat image_remapped1 = reprojector.remap(&image_small1, 1, true);

        reprojector.y_align(image_remapped0, image_remapped1, false);

        GaussianBlur(image_remapped0, image_remapped0, Size(9, 9), 0, 0);
        GaussianBlur(image_remapped1, image_remapped1, Size(9, 9), 0, 0);


        Mat image_disparity;

        static StereoSGBM stereo_sgbm(0, 32, 21, 0, 0, 0, 0, 20, 0, 0, false);
        stereo_sgbm(image_remapped0, image_remapped1, image_disparity);

        Mat image_disparity_8u;
        double minVal, maxVal;
        minMaxLoc(image_disparity, &minVal, &maxVal);
        image_disparity.convertTo(image_disparity_8u, CV_8UC1, 255 / (maxVal - minVal));

        imshow("image_remapped0", image_remapped0);
        imshow("image_remapped1", image_remapped1);
        imshow("image_disparity_8u", image_disparity_8u);
    }
#endif

    /*static bool show_wiggle_sent = false;
    if (!show_wiggle_sent)
    {
        if (child_module_name != "")
          ipc->open_udp_channel(child_module_name);
        
        ipc->send_message("menu_plus", "show window", "");
        ipc->send_message("menu_plus", "show wiggle", "");//todo
    }
    show_wiggle_sent = true;*/

    if (enable_imshow)
    {
        imshow("image_small1", image_small1);
        // imshow("image_preprocessed1", image_preprocessed1);

        // setMouseCallback("image_preprocessed1", left_mouse_cb, NULL);
        // waitKey(1);
        // return false;
    }

    algo_name_vec_old = algo_name_vec;
    algo_name_vec.clear();

    static bool motion_processor_proceed = false;
    static bool construct_background = false;
    static bool first_pass = true;

    bool proceed0;
    bool proceed1;

    if (normalized)
    {
        proceed0 = motion_processor0.compute(image_preprocessed0,  image_small0, surface_computer.y_reflection, imu.pitch,
                                             construct_background, "0",          true);
        proceed1 = motion_processor1.compute(image_preprocessed1,  image_small1, surface_computer.y_reflection, imu.pitch,
                                             construct_background, "1",          false);
    }

    if (first_pass && motion_processor0.both_moving && motion_processor1.both_moving)
    {
        console_log("readjusting exposure");

        first_pass = false;
        exposure_set = false;
        mat_functions_low_pass_filter.reset();

        CameraInitializerNew::adjust_exposure(camera, image_preprocessed0, true);
    }
    else if (!first_pass)
        construct_background = true;

    if (!construct_background)
    {
        proceed0 = false;
        proceed1 = false;            
    }

    if (proceed0 && proceed1)
        motion_processor_proceed = true;

    bool proceed = motion_processor_proceed;

    static bool menu_plus_signal0 = false;
    if (!menu_plus_signal0)
    {
        menu_plus_signal0 = true;
        // ipc->send_message("menu_plus", "hide window", "");
    }

    if (proceed)
    {
        proceed0 = foreground_extractor0.compute(image_preprocessed0, motion_processor0, "0", true);
        proceed1 = foreground_extractor1.compute(image_preprocessed1, motion_processor1, "1", false);
        proceed = proceed0 && proceed1;
    }

    if (proceed)
    {
        proceed0 = hand_splitter0.compute(foreground_extractor0, motion_processor0, "0", false);
        proceed1 = hand_splitter1.compute(foreground_extractor1, motion_processor1, "1", false);
        proceed = proceed0 && proceed1;
    }

    if (proceed)
    {
        waiting_for_image = true;
        waiting_for_image_set = true;

        proceed1 = scopa1.compute_mono0(hand_splitter1, pose_estimator, "1", false);
        proceed0 = scopa0.compute_mono0(hand_splitter0, pose_estimator, "0", false);
        proceed = proceed0 && proceed1;
    }

    if (proceed)
    {
        motion_processor0.target_frame = 10;
        motion_processor1.target_frame = 10;

        SCOPA::compute_stereo();
        scopa1.compute_mono1("1");
        scopa0.compute_mono1("0");
    }

    if (enable_imshow)
        waitKey(1);

    return waiting_for_image_set;
}
コード例 #2
0
void compute()
{
	updated = false;

	ipc->update();

	if (wait_for_device_bool)
		wait_for_device();

	if (first_frame)
	{
		on_first_frame();
		first_frame = false;
	}

	if (!play || settings.touch_control != "1")
	{
		hide_cursors();

		if (enable_imshow)
			waitKey(1);

		return;
	}

	int x_accel;
	int y_accel;
	int z_accel;
	camera->getAccelerometerValues(&x_accel, &y_accel, &z_accel);
	imu.compute(x_accel, y_accel, z_accel);

	if ((mode == "surface" && imu.pitch > 60) || (mode == "tool" && imu.pitch < 60))
	{
		COUT << "exit 1" << endl;

		if (child_module_name != "")
			ipc->send_message(child_module_name, "exit", "");

		exit(0);
	}

	//----------------------------------------core algorithm----------------------------------------

	Mat image_flipped;
	if (mode == "surface")
		flip(image_current_frame, image_flipped, 0);
	else
		flip(image_current_frame, image_flipped, 0);
		// image_flipped = image_current_frame.clone();

	Mat image0 = image_flipped(Rect(0, 0, 640, 480));
	Mat image1 = image_flipped(Rect(640, 0, 640, 480));

	Mat image_small0;
	Mat image_small1;
	resize(image0, image_small0, Size(160, 120), 0, 0, INTER_LINEAR);
	resize(image1, image_small1, Size(160, 120), 0, 0, INTER_LINEAR);

	Mat image_preprocessed0;
	Mat image_preprocessed1;
	compute_channel_diff_image(image_small0, image_preprocessed0, exposure_adjusted, "image_preprocessed0");
	compute_channel_diff_image(image_small1, image_preprocessed1, exposure_adjusted, "image_preprocessed1");

	Mat image_preprocessed_smoothed0;
	Mat image_preprocessed_smoothed1;
	GaussianBlur(image_preprocessed0, image_preprocessed_smoothed0, Size(1, 19), 0, 0);
	GaussianBlur(image_preprocessed1, image_preprocessed_smoothed1, Size(1, 19), 0, 0);

	if (!CameraInitializerNew::adjust_exposure(camera, image_preprocessed0))
		return;

	exposure_adjusted = true;

	// imshow("image_small0", image_small0);
	// imshow("image_preprocessed0", image_preprocessed0);

	bool proceed0 = motion_processor0.compute(image_preprocessed_smoothed0, "0", false);
	bool proceed1 = motion_processor1.compute(image_preprocessed_smoothed1, "1", false);
	bool proceed = proceed0 && proceed1;

	if (proceed)
	{
		proceed0 = foreground_extractor0.compute(image_preprocessed0, image_preprocessed_smoothed0, motion_processor0, "0", true);
		proceed1 = foreground_extractor1.compute(image_preprocessed1, image_preprocessed_smoothed1, motion_processor1, "1", true);
		proceed = proceed0 && proceed1;
	}
	else
		hide_cursors();

	if (proceed)
	{
		proceed0 = hand_splitter0.compute(foreground_extractor0, motion_processor0, "0");
		proceed1 = hand_splitter1.compute(foreground_extractor1, motion_processor1, "1");
		proceed = proceed0 && proceed1;
	}
	else
		hide_cursors();

	if (mode == "surface" && proceed)
	{
		proceed0 = mono_processor0.compute(hand_splitter0, "0", false);
		proceed1 = mono_processor1.compute(hand_splitter1, "1", false);
		proceed = false;
		proceed = proceed0 && proceed1;

		if (proceed)
		{
			// stereo_processor.compute(mono_processor0, mono_processor1, motion_processor0, motion_processor1);

			points_pool[points_pool_count] = mono_processor0.points_unwrapped_result;
			points_ptr = &(points_pool[points_pool_count]);

			++points_pool_count;
			if (points_pool_count == points_pool_count_max)
				points_pool_count = 0;

			initialized = true;

			if (!show_point_sent)
			{
				ipc->send_message("menu_plus", "show point", "");
				show_point_sent = true;
			}

			if (pose_name == "point")
			{
				if (!show_calibration_sent)
				{
					ipc->send_message("menu_plus", "show calibration", "");
					show_calibration_sent = true;
				}

				hand_resolver.compute(mono_processor0, mono_processor1, motion_processor0, motion_processor1, image0, image1, reprojector);
				pointer_mapper.compute(hand_resolver, reprojector);

				if (pointer_mapper.calibrated)
				{
					if (enable_imshow)
					{
						enable_imshow = false;
						destroyAllWindows();
					}
					show_cursor_index = true;
				}

				if (show_cursor_index && pointer_mapper.thumb_down && pointer_mapper.index_down)
					show_cursor_thumb = true;
				else
					show_cursor_thumb = false;
			}
			else
			{
				pointer_mapper.reset();

				if (pose_name != "point")
				{
					show_cursor_index = false;
					show_cursor_thumb = false;
				}
			}
		}
		else
			hide_cursors();

		if (!pinch_to_zoom)
		{
			if (show_cursor_index)
			{
				ipc->send_udp_message("win_cursor_plus", to_string(pointer_mapper.pt_cursor_index.x) + "!" +
														 to_string(pointer_mapper.pt_cursor_index.y) + "!" +
														 to_string(pointer_mapper.dist_cursor_index_plane) + "!" +
														 to_string(pointer_mapper.index_down) + "!index");
			}
			else
				ipc->send_udp_message("win_cursor_plus", "hide_cursor_index");

			ipc->send_udp_message("win_cursor_plus", "hide_cursor_thumb");
		}
		else
		{
			ipc->send_udp_message("win_cursor_plus", to_string(pointer_mapper.pt_pinch_to_zoom_index.x) + "!" +
													 to_string(pointer_mapper.pt_pinch_to_zoom_index.y) + "!0!1!index");

			ipc->send_udp_message("win_cursor_plus", to_string(pointer_mapper.pt_pinch_to_zoom_thumb.x) + "!" +
													 to_string(pointer_mapper.pt_pinch_to_zoom_thumb.y) + "!0!1!thumb");
		}

		ipc->send_udp_message("win_cursor_plus", "update!" + to_string(frame_num));
	}
	else if (mode == "tool" && proceed)
	{
		enable_imshow = true;

		Mat image_active_light0;
		Mat image_active_light1;
		compute_active_light_image(image_small0, image_preprocessed0, image_active_light0);
		compute_active_light_image(image_small1, image_preprocessed1, image_active_light1);

		proceed0 = tool_mono_processor0.compute(image_active_light0, image_preprocessed0, "0");
		proceed1 = tool_mono_processor1.compute(image_active_light1, image_preprocessed1, "1");
		proceed = proceed0 && proceed1;

		if (proceed)
		{
			proceed0 = tool_stereo_processor.compute(tool_mono_processor0, tool_mono_processor1);
			proceed1 = tool_stereo_processor.matches.size() >= 4;
			proceed = proceed0 && proceed1;

			if (proceed)
			{
				tool_pointer_mapper.compute(reprojector, tool_stereo_processor, image0, image1);

				string data = "";
				data += to_string(tool_pointer_mapper.pt0.x) + "!" +
						to_string(tool_pointer_mapper.pt0.y) + "!" +
						to_string(tool_pointer_mapper.pt0.z) + "!";
				data += to_string(tool_pointer_mapper.pt1.x) + "!" +
						to_string(tool_pointer_mapper.pt1.y) + "!" +
						to_string(tool_pointer_mapper.pt1.z) + "!";
				data += to_string(tool_pointer_mapper.pt2.x) + "!" +
						to_string(tool_pointer_mapper.pt2.y) + "!" +
						to_string(tool_pointer_mapper.pt2.z) + "!";
				data += to_string(tool_pointer_mapper.pt3.x) + "!" +
						to_string(tool_pointer_mapper.pt3.y) + "!" +
						to_string(tool_pointer_mapper.pt3.z) + "!";
				data += to_string(tool_pointer_mapper.pt_center.x) + "!" +
						to_string(tool_pointer_mapper.pt_center.y) + "!" +
						to_string(tool_pointer_mapper.pt_center.z);

				ipc->send_udp_message("unity_demo", data);
			}
		}
	}

	++frame_num;

	if (increment_keypress_count)
	{
		if (keypress_count == calibration_points_count)
		{
			ipc->send_message("menu_plus", "show calibration next", "");

			COUT << "step " << calibration_step << " complete" << endl; 

			++calibration_step;
		}
		else if (keypress_count < calibration_points_count)
		{
			float percentage = (keypress_count * 100.0 / calibration_points_count);
			COUT << percentage << endl;
			pointer_mapper.add_calibration_point(calibration_step);
		}

		if (calibration_step == 4)
		{
			ipc->send_message("menu_plus", "show stage", "");

			pointer_mapper.compute_calibration_points();
			calibrating = false;
			increment_keypress_count = false;

			COUT << "calibration finished" << endl;
		}

		++keypress_count;
	}

	if (enable_imshow)
		waitKey(1);
}
コード例 #3
0
ファイル: main.cpp プロジェクト: roijo/touch_plus_source_code
void compute()
{
    updated = false;

    if (image_current_frame.cols == 0)
    {
        COUT << "bad frame" << endl;
        return;
    }

    Mat image_flipped;
    flip(image_current_frame, image_flipped, 0);

    Mat image0 = image_flipped(Rect(0, 0, 640, 480));
    Mat image1 = image_flipped(Rect(640, 0, 640, 480));

    if (first_frame)
    {
        on_first_frame();
        first_frame = false;
    }

    if (!play || settings.touch_control != "1")
    {
        hide_cursors();

        if (enable_imshow)
            waitKey(1);

        return;
    }

    int x_accel;
    int y_accel;
    int z_accel;
    camera->getAccelerometerValues(&x_accel, &y_accel, &z_accel);
    imu.compute(x_accel, y_accel, z_accel);

    //----------------------------------------core algorithm----------------------------------------

    Mat image_small0;
    Mat image_small1;
    resize(image0, image_small0, Size(160, 120), 0, 0, INTER_LINEAR);
    resize(image1, image_small1, Size(160, 120), 0, 0, INTER_LINEAR);

    Mat image_preprocessed0;
    Mat image_preprocessed1;

    bool normalized = compute_channel_diff_image(image_small0, image_preprocessed0, exposure_adjusted, "image_preprocessed0", true);
                      compute_channel_diff_image(image_small1, image_preprocessed1, exposure_adjusted, "image_preprocessed1", false);

    GaussianBlur(image_preprocessed0, image_preprocessed0, Size(3, 9), 0, 0);
    GaussianBlur(image_preprocessed1, image_preprocessed1, Size(3, 9), 0, 0);

    if (!CameraInitializerNew::adjust_exposure(camera, image_preprocessed0))
    {
        static int step_count = 0;
        if (step_count == 3)
        {
            surface_computer.init(image0);
        }
        ++step_count;
        return;
    }

    exposure_adjusted = true;

#ifdef false
    {
        Mat image_remapped0 = reprojector.remap(&image_small0, 0, true);
        Mat image_remapped1 = reprojector.remap(&image_small1, 1, true);

        reprojector.y_align(image_remapped0, image_remapped1, false);

        GaussianBlur(image_remapped0, image_remapped0, Size(9, 9), 0, 0);
        GaussianBlur(image_remapped1, image_remapped1, Size(9, 9), 0, 0);


		Mat image_disparity;

		static StereoSGBM stereo_sgbm(0, 32, 21, 0, 0, 0, 0, 20, 0, 0, false);
		stereo_sgbm(image_remapped0, image_remapped1, image_disparity);

        Mat image_disparity_8u;
        double minVal, maxVal;
        minMaxLoc(image_disparity, &minVal, &maxVal);
        image_disparity.convertTo(image_disparity_8u, CV_8UC1, 255 / (maxVal - minVal));

		imshow("image_remapped0", image_remapped0);
		imshow("image_remapped1", image_remapped1);
		imshow("image_disparity_8u", image_disparity_8u);
    }
#endif

	/*static bool show_wiggle_sent = false;
	if (!show_wiggle_sent)
	{
        if (child_module_name != "")
		  ipc->open_udp_channel(child_module_name);
        
		ipc->send_message("menu_plus", "show window", "");
		ipc->send_message("menu_plus", "show wiggle", "");//todo
	}
	show_wiggle_sent = true;*/

    if (enable_imshow)
    {
        imshow("image_small1", image_small1);
        imshow("image_preprocessed1", image_preprocessed1);

        // setMouseCallback("image_preprocessed1", left_mouse_cb, NULL);
        // waitKey(1);
        // return;
    }

    algo_name_vec_old = algo_name_vec;
	algo_name_vec.clear();

    static bool motion_processor_proceed = false;
    static bool construct_background = false;
    static bool first_pass = true;

    bool proceed0;
    bool proceed1;

    if (normalized)
    {
        proceed0 = motion_processor0.compute(image_preprocessed0,  image_small0, surface_computer.y_reflection, imu.pitch,
                                             construct_background, "0",          true);
        proceed1 = motion_processor1.compute(image_preprocessed1,  image_small1, surface_computer.y_reflection, imu.pitch,
                                             construct_background, "1",          true);
    }

    if (first_pass && motion_processor0.both_moving)
    {
        COUT << "readjusting exposure" << endl;

        first_pass = false;
        exposure_adjusted = false;
        CameraInitializerNew::adjust_exposure(camera, image_preprocessed0, true);
    }
    else if (!first_pass)
        construct_background = true;

    if (!construct_background)
    {
        proceed0 = false;
        proceed1 = false;            
    }

    if (proceed0 && proceed1)
        motion_processor_proceed = true;

    bool proceed = motion_processor_proceed;

    if (proceed)
    {
        proceed0 = foreground_extractor0.compute(image_preprocessed0, motion_processor0, "0", false);
        proceed1 = foreground_extractor1.compute(image_preprocessed1, motion_processor1, "1", false);
        proceed = proceed0 && proceed1;
    }

    if (proceed)
    {
        proceed0 = hand_splitter0.compute(foreground_extractor0, motion_processor0, "0");
        proceed1 = hand_splitter1.compute(foreground_extractor1, motion_processor1, "1");
        proceed = proceed0 && proceed1;
    }

    proceed = false;

    if (proceed)
    {
        proceed0 = mono_processor0.compute(hand_splitter0, "0", false);
        proceed1 = mono_processor1.compute(hand_splitter1, "1", false);
        proceed = proceed0 && proceed1;
    }

    if (proceed)
    {
        stereo_processor.compute(mono_processor0, mono_processor1, point_resolver, pointer_mapper, image0, image1);
    }

    ++frame_num;

    if (increment_keypress_count)
    {
        if (keypress_count == calibration_points_count)
        {
            COUT << "step " << calibration_step << " complete" << endl; 

            // ipc->send_message("menu_plus", "show calibration next", "");//todo
            ++calibration_step;
        }
        else if (keypress_count < calibration_points_count)
        {
            float percentage = (keypress_count * 100.0 / calibration_points_count);
            COUT << percentage << endl;

            pointer_mapper.add_calibration_point(calibration_step);
        }

        if (calibration_step == 4)
        {
            pointer_mapper.compute_calibration_points();
            calibrating = false;
            increment_keypress_count = false;

            COUT << "calibration finished" << endl;
        }

        ++keypress_count;
    }

    if (enable_imshow)
        waitKey(1);
}
コード例 #4
0
bool HandSplitterNew::compute(ForegroundExtractorNew& foreground_extractor, MotionProcessorNew& motion_processor, string name, bool visualize)
{
	if (value_store.get_bool("first_pass", false) == false)
	{
		value_store.set_bool("first_pass", true);
		algo_name += name;
	}

	bool algo_name_found = false;
	for (String& algo_name_current : algo_name_vec_old)
		if (algo_name_current == algo_name)
		{
			algo_name_found = true;
			break;
		}

	LowPassFilter* low_pass_filter = value_store.get_low_pass_filter("low_pass_filter");

	//------------------------------------------------------------------------------------------------------------------------

	Mat image_find_contours = Mat::zeros(HEIGHT_SMALL, WIDTH_SMALL, CV_8UC1);
	for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
		if (blob.active)
			blob.fill(image_find_contours, 254);

	vector<vector<Point>> contours = legacyFindContours(image_find_contours);
	
	if (contours.size() == 0)
		return false;

	int complexity = 0;
	for (vector<Point>& contour : contours)
	{
		vector<Point> contour_approximated;
		approxPolyDP(Mat(contour), contour_approximated, 10, false);
		complexity += contour_approximated.size();
	}

	//------------------------------------------------------------------------------------------------------------------------

	int x_min = foreground_extractor.x_min_result;
	int x_max = foreground_extractor.x_max_result;
	int y_min = foreground_extractor.y_min_result;
	int y_max = foreground_extractor.y_max_result;

	float x_seed_vec0_max = value_store.get_float("x_seed_vec0_max");
	float x_seed_vec1_min = value_store.get_float("x_seed_vec1_min");

	int intensity_array[WIDTH_SMALL] { 0 };
	for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
		if (blob.active)
			for (Point& pt : blob.data)
				++intensity_array[pt.x];

	vector<Point> hist_pt_vec;
	for (int i = 0; i < WIDTH_SMALL; ++i)
	{
		int j = intensity_array[i];
		low_pass_filter->compute(j, 0.5, "histogram_j");

		if (j < 10)
			continue;

		for (int j_current = 0; j_current < j; ++j_current)
			hist_pt_vec.push_back(Point(i, j_current));
	}

	Point seed0 = Point(x_min, 0);
	Point seed1 = Point(x_max, 0);

	vector<Point> seed_vec0;
	vector<Point> seed_vec1;

	while (true)
	{
		seed_vec0.clear();
		seed_vec1.clear();

		for (Point& pt : hist_pt_vec)
		{
			float dist0 = get_distance(pt, seed0, false);
			float dist1 = get_distance(pt, seed1, false);

			if (dist0 < dist1)
				seed_vec0.push_back(pt);
			else
				seed_vec1.push_back(pt);
		}

		if (seed_vec0.size() == 0 || seed_vec1.size() == 0)
			break;

		Point seed0_new = Point(0, 0);
		for (Point& pt : seed_vec0)
		{
			seed0_new.x += pt.x;
			seed0_new.y += pt.y;
		}
		seed0_new.x /= seed_vec0.size();
		seed0_new.y /= seed_vec0.size();

		Point seed1_new = Point(0, 0);
		for (Point& pt : seed_vec1)
		{
			seed1_new.x += pt.x;
			seed1_new.y += pt.y;
		}
		seed1_new.x /= seed_vec1.size();
		seed1_new.y /= seed_vec1.size();

		if (seed0 == seed0_new && seed1 == seed1_new)
			break;

		seed0 = seed0_new;
		seed1 = seed1_new;
	}

	bool dual = false;
	if (seed_vec0.size() > 0 && seed_vec1.size() > 0)
	{
		x_seed_vec0_max = seed_vec0[seed_vec0.size() - 1].x;
		x_seed_vec1_min = seed_vec1[0].x;

		low_pass_filter->compute_if_smaller(x_seed_vec0_max, 0.5, "x_seed_vec0_max");
		low_pass_filter->compute_if_larger(x_seed_vec1_min, 0.5, "x_seed_vec1_min");

		value_store.set_float("x_seed_vec0_max", x_seed_vec0_max);
		value_store.set_float("x_seed_vec1_min", x_seed_vec1_min);

		value_store.set_bool("x_min_max_set", true);

		//------------------------------------------------------------------------------------------------------------------------

		int width0 = x_seed_vec0_max - x_min;
		int width1 = x_max - x_seed_vec1_min;
		int width_min = min(width0, width1);

		float gap_size = x_seed_vec1_min - x_seed_vec0_max;
		low_pass_filter->compute_if_larger(gap_size, 0.1, "gap_size");

		//------------------------------------------------------------------------------------------------------------------------

		bool bool_complexity = complexity >= 15;
		bool bool_width_min = width_min >= 20;
		bool bool_gap_size = gap_size >= 5;
		bool bool_gap_order = x_seed_vec0_max < x_seed_vec1_min;

		dual = bool_gap_order && bool_width_min && (bool_gap_size || bool_complexity);
	}

	//------------------------------------------------------------------------------------------------------------------------

	BlobNew* blob_max_size_left = NULL;
	BlobNew* blob_max_size_right = NULL;
	BlobNew* blob_max_size = NULL;

	for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
	{
		if (blob.x <= motion_processor.x_separator_middle && (blob_max_size_left == NULL || blob.count > blob_max_size_left->count))
			blob_max_size_left = &blob;
		else if (blob.x > motion_processor.x_separator_middle && (blob_max_size_right == NULL || blob.count > blob_max_size_right->count))
			blob_max_size_right = &blob;

		if (blob_max_size == NULL || blob.count > blob_max_size->count)
			blob_max_size = &blob;
	}

	//------------------------------------------------------------------------------------------------------------------------

	int count_left = 0;
	int count_right = 0;

	int x_min_left = 9999;
	int x_max_left = 0;
	int x_min_right = 9999;
	int x_max_right = 0;

	for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
		if (blob.active)
		{
			for (Point& pt : blob.data)
				if (pt.x < motion_processor.x_separator_middle)
				{
					++count_left;
					if (pt.x < x_min_left)
						x_min_left = pt.x;
					if (pt.x > x_max_left)
						x_max_left = pt.x;
				}
				else
				{
					++count_right;
					if (pt.x < x_min_right)
						x_min_right = pt.x;
					if (pt.x > x_max_right)
						x_max_right = pt.x;
				}
		}

	int width_left = x_max_left - x_min_left;
	int width_right = x_max_right - x_min_right;

	//------------------------------------------------------------------------------------------------------------------------

	bool reference_is_left = value_store.get_bool("reference_is_left", false);
	bool dual_old = value_store.get_bool("dual_old", dual);
	bool merge = value_store.get_bool("merge", false);

	if (!dual && dual_old)
	{
		float count_small = reference_is_left ? count_right : count_left;
		float count_large = reference_is_left ? count_left : count_right;

		if (count_small / count_large > 0.5)
		{
			merge = true;
			value_store.set_bool("merge", merge);
		}
	}

	dual_old = dual;
	value_store.set_bool("dual_old", dual_old);

	//------------------------------------------------------------------------------------------------------------------------

	int reference_x_offset = value_store.get_int("reference_x_offset", 0);
	int reference_x_offset_blob = value_store.get_int("reference_x_offset_blob", 0);

	bool do_reset = value_store.get_bool("do_reset", false);

	if (dual || !algo_name_found || do_reset)
	{
		if (dual)
		{
			motion_processor.compute_x_separator_middle = false;
			set_value(&motion_processor.x_separator_middle, (x_seed_vec1_min + x_seed_vec0_max) / 2, 0, WIDTH_SMALL_MINUS);
		}

		reference_is_left = count_left > count_right;
		value_store.set_bool("reference_is_left", reference_is_left);

		if (!algo_name_found || do_reset)
			set_value(&motion_processor.x_separator_middle, motion_processor.x_separator_middle_median, 0, WIDTH_SMALL_MINUS);

		int reference_x = reference_is_left ? foreground_extractor.x_min_result : foreground_extractor.x_max_result;
		reference_x_offset = reference_x - motion_processor.x_separator_middle;
		value_store.set_int("reference_x_offset", reference_x_offset);

		int reference_x_blob = -1;
		if (reference_is_left && blob_max_size_left != NULL)
			reference_x_blob = blob_max_size_left->x_max;
		else if (!reference_is_left && blob_max_size_right != NULL)
			reference_x_blob = blob_max_size_right->x_min;

		if (reference_x_blob != -1)
		{
			reference_x_offset_blob = reference_x_blob - motion_processor.x_separator_middle;
			value_store.set_int("reference_x_offset_blob", reference_x_offset_blob);
		}

		merge = false;
		value_store.set_bool("merge", merge);

		do_reset = false;
		value_store.set_bool("do_reset", do_reset);
	}

	//------------------------------------------------------------------------------------------------------------------------

	if (!dual && !merge)
	{
		int reference_x = reference_is_left ? foreground_extractor.x_min_result : foreground_extractor.x_max_result;
		int reference_x_blob = reference_is_left ? blob_max_size->x_max : blob_max_size->x_min;

		const int x_separator_middle_target = reference_x_blob - reference_x_offset_blob;
		const int x_separator_middle = motion_processor.x_separator_middle;
		const int i_increment = x_separator_middle_target > motion_processor.x_separator_middle ? 1 : -1;

		int cost = 0;
		for (int i = x_separator_middle; i != x_separator_middle_target; i += i_increment)
			for (int j = 0; j < HEIGHT_SMALL; ++j)
				if (foreground_extractor.image_foreground.ptr<uchar>(j, i)[0] > 0)
					++cost;

		if ((float)cost / blob_max_size->count < 0.5)
			set_value(&motion_processor.x_separator_middle, x_separator_middle_target, 0, WIDTH_SMALL_MINUS);
		else
		{
			do_reset = true;
			value_store.set_bool("do_reset", do_reset);
		}
	}

	//------------------------------------------------------------------------------------------------------------------------

	Point seed_left = value_store.get_point("seed_left", Point(x_min, 0));
	Point seed_right = value_store.get_point("seed_right", Point(x_max, 0));

	if (merge || dual)
	{
		seed_left = Point(0, 0);
		int seed_left_count = 0;
		for (BlobNew& blob : blobs_left)
			for (Point& pt : blob.data)
			{
				seed_left.x += pt.x;
				seed_left.y += pt.y;
				++seed_left_count;
			}
		
		seed_right = Point(0, 0);
		int seed_right_count = 0;
		for (BlobNew& blob : blobs_right)
			for (Point& pt : blob.data)
			{
				seed_right.x += pt.x;
				seed_right.y += pt.y;
				++seed_right_count;
			}

		if (seed_left_count > 0 && seed_right_count > 0)
		{
			seed_left.x /= seed_left_count;
			seed_left.y /= seed_left_count;

			seed_right.x /= seed_right_count;
			seed_right.y /= seed_right_count;

			vector<Point> seed_left_vec;
			vector<Point> seed_right_vec;

			while (true)
			{
				seed_left_vec.clear();
				seed_right_vec.clear();				

				for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
					if (blob.active)
						for (Point& pt : blob.data)
						{
							float dist_left = get_distance(pt, seed_left, false);
							float dist_right = get_distance(pt, seed_right, false);
							if (dist_left < dist_right)
								seed_left_vec.push_back(pt);
							else
								seed_right_vec.push_back(pt);
						}

				if (seed_left_vec.size() > 0 && seed_right_vec.size() > 0)
				{
					Point seed_left_new = Point(0, 0);
					for (Point& pt : seed_left_vec)
					{
						seed_left_new.x += pt.x;
						seed_left_new.y += pt.y;
					}
					seed_left_new.x /= seed_left_vec.size();
					seed_left_new.y /= seed_left_vec.size();

					Point seed_right_new = Point(0, 0);
					for (Point& pt : seed_right_vec)
					{
						seed_right_new.x += pt.x;
						seed_right_new.y += pt.y;
					}
					seed_right_new.x /= seed_right_vec.size();
					seed_right_new.y /= seed_right_vec.size();

					if (seed_left.x == seed_left_new.x && seed_left.y == seed_left_new.y &&
						seed_right.x == seed_right_new.x && seed_right.y == seed_right_new.y)
					{
						break;
					}

					seed_left = seed_left_new;
					seed_right = seed_right_new;
				}
				else
					break;
			}

			if (merge)
				set_value(&motion_processor.x_separator_middle, (seed_left.x + seed_right.x) / 2, 0, WIDTH_SMALL_MINUS);
		}
	}

	value_store.set_point("seed_left", seed_left);
	value_store.set_point("seed_right", seed_right);

	//------------------------------------------------------------------------------------------------------------------------

	const int x_separator_middle = motion_processor.x_separator_middle;
	const int x_separator_middle_median = motion_processor.x_separator_middle_median;
	const int x_separator_left_median = motion_processor.x_separator_left_median;
	const int x_separator_right_median = motion_processor.x_separator_right_median;
	const int y_separator_down_median = motion_processor.y_separator_down_median;
	const int y_separator_up_median = motion_processor.y_separator_up_median;

	while (dual)
	{
		const int i_min = seed_left.x;
		const int i_max = seed_right.x;
		const int j_min = 0;
		const int j_max = y_separator_up_median;

		if (!(i_max > i_min && i_min >= 0 && i_max <= WIDTH_SMALL_MINUS))
			break;

		Point pt0 = Point(i_min, 0);
		Point pt1 = Point(i_max, 0);
		Point pt2 = Point(x_separator_middle, j_max);    //tip point

		if (pt2.y < 2 || i_max - i_min < 2)
			break;

		Mat image_triangle_fill = Mat::zeros(j_max + 1, WIDTH_SMALL, CV_8UC1);

		line(image_triangle_fill, pt0, pt2, Scalar(254), 1);
		line(image_triangle_fill, pt1, pt2, Scalar(254), 1);
		floodFill(image_triangle_fill, Point(x_separator_middle, 0), Scalar(254));

		for (int i = i_min; i <= i_max; ++i)
			for (int j = j_min; j <= j_max; ++j)
				if (image_triangle_fill.ptr<uchar>(j, i)[0] > 0)
					motion_processor.fill_image_background_static(i, j, motion_processor.image_ptr);

		break;
	}

	//------------------------------------------------------------------------------------------------------------------------

	x_min_result_right = 9999;
	x_max_result_right = -1;
	y_min_result_right = 9999;
	y_max_result_right = -1;

	x_min_result_left = 9999;
	x_max_result_left = -1;
	y_min_result_left = 9999;
	y_max_result_left = -1;

	blobs_right.clear();
	blobs_left.clear();

	for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
		if (blob.active)
		{
			if (blob.x > motion_processor.x_separator_middle)
			{
				if (blob.x_min < x_min_result_right)
					x_min_result_right = blob.x_min;
				if (blob.x_max > x_max_result_right)
					x_max_result_right = blob.x_max;
				if (blob.y_min < y_min_result_right)
					y_min_result_right = blob.y_min;
				if (blob.y_max > y_max_result_right)
					y_max_result_right = blob.y_max;

				blobs_right.push_back(blob);
			}
			else
			{
				if (blob.x_min < x_min_result_left)
					x_min_result_left = blob.x_min;
				if (blob.x_max > x_max_result_left)
					x_max_result_left = blob.x_max;
				if (blob.y_min < y_min_result_left)
					y_min_result_left = blob.y_min;
				if (blob.y_max > y_max_result_left)
					y_max_result_left = blob.y_max;

				blobs_left.push_back(blob);
			}
		}

	//------------------------------------------------------------------------------------------------------------------------

	if (visualize)
	{
		Mat image_visualization = Mat::zeros(HEIGHT_SMALL, WIDTH_SMALL, CV_8UC1);
		for (BlobNew& blob : *foreground_extractor.blob_detector.blobs)
			if (blob.active)
				blob.fill(image_visualization, 254);

		line(image_visualization, Point(x_separator_left_median, 0), Point(x_separator_left_median, 999), Scalar(254), 1);
		line(image_visualization, Point(x_separator_right_median, 0), Point(x_separator_right_median, 999), Scalar(254), 1);
		line(image_visualization, Point(x_separator_middle, 0), Point(x_separator_middle, 999), Scalar(254), 1);
		line(image_visualization, Point(0, y_separator_down_median), Point(999, y_separator_down_median), Scalar(254), 1);
		line(image_visualization, Point(0, y_separator_up_median), Point(999, y_separator_up_median), Scalar(254), 1);

		imshow("image_visualizationsdlkfjhasdf" + name, image_visualization);
	}

	if (blobs_right.size() > 0 || blobs_left.size() > 0)
	{
		algo_name_vec.push_back(algo_name);
		return true;
	}

	return false;
}