Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define NOMAXMIN
- #define _USE_MATH_DEFINES
- #include <iostream>
- #include <opencv2/opencv.hpp>
- #include <vector>
- #include <set>
- #include <cerrno>
- #include <cmath>
- #include <numeric>
- #include <limits>
- #include "lsd.h"
- #include "dlib/geometry.h"
- #include "dlib/optimization.h"
- #define WIN_TITLE_INPUT "Input"
- #define WIN_TTILE_OUTPUT "Output"
- typedef std::pair<double, int> mypair;
- template<typename Iter_T>
- float vectorNorm(Iter_T first, Iter_T last)
- {
- return sqrt(inner_product(first, last, first, 0.0L));
- }
- float lsd_angle(std::vector<int>& ls_compared);
- bool similarAngle(std::vector<std::vector<int>>& ls12, float athreshold);
- //std::vector<int> similarAngle(std::vector<std::vector<int>> &ls12, float athreshold);
- void resize_image_length(cv::Mat& srcImg, cv::Mat& dstImg, int maxSize);
- void lsd_extend(ntuple_list& lsd_out, std::vector<std::vector<float>>& L, dlib::vector<float> center);
- bool isEqual(const cv::Vec4i& _l1, const cv::Vec4i& _l2);
- void lsd_detection(cv::Mat& srcImg, ntuple_list& lsd_out);
- #if 1
- int main(void)
- {
- // Variables define here
- cv::Mat img, img_gray; // Color and gray input image
- cv::Mat img_result; // Showing result image after lsd
- ntuple_list lsd_out; // Line segments vector
- ntuple_list lsd_selected; // Selected dominant line segments vector
- // Create windows to show reuslt
- cv::namedWindow(WIN_TTILE_OUTPUT, cv::WINDOW_NORMAL);
- cv::namedWindow(WIN_TITLE_INPUT, cv::WINDOW_NORMAL);
- cv::VideoCapture cap(0);
- //cv::VideoCapture cap("http://172.19.127.160:8080/videofeed?dummy=param.mjpg");
- if (!cap.isOpened())
- {
- std::cerr << "cannot open camera during initialisation\n";
- return -1;
- }
- // Configure VideoCapture properties
- cap.set(cv::CAP_PROP_FRAME_WIDTH, 640);
- cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
- cap.set(cv::CAP_PROP_FPS, 30);
- cv::waitKey(1000);
- dlib::vector<float, 2> center(static_cast<float>(640 / 2), static_cast<float>(360 / 2));
- for (;;)
- {
- // Read image and conver to B&W
- cap >> img;
- cv::cvtColor(img, img_gray, cv::COLOR_RGB2GRAY);
- // Line segment detection
- lsd_detection(img_gray, lsd_out);
- int no_of_lines = std::min(lsd_out->size, uint(700));
- lsd_selected = new_ntuple_list(5);
- std::vector<std::vector<float>> L;
- // Draw lsd result
- cv::Point pt1, pt2;
- int line_width;
- img.copyTo(img_result);
- const unsigned int lsd_dim = lsd_out->dim;
- std::vector<cv::Vec4i> lsd_vec;
- std::vector<int> labels;
- for (int i = 0; i < no_of_lines; i++)
- {
- cv::Vec4i lsd_tmp;
- lsd_tmp[0] = (int)lsd_out->values[0 + i * lsd_dim];
- lsd_tmp[1] = (int)lsd_out->values[1 + i * lsd_dim];
- lsd_tmp[2] = (int)lsd_out->values[2 + i * lsd_dim];
- lsd_tmp[3] = (int)lsd_out->values[3 + i * lsd_dim];
- lsd_vec.push_back(lsd_tmp);
- // The first four elements in ntuple_list are [x1 y1 x2 y2] point that define the location of line segment
- pt1.x = (int)lsd_out->values[0 + i * lsd_dim];
- pt1.y = (int)lsd_out->values[1 + i * lsd_dim];
- pt2.x = (int)lsd_out->values[2 + i * lsd_dim];
- pt2.y = (int)lsd_out->values[3 + i * lsd_dim];
- // The 5th element is the width of line segment
- line_width = 2;// (int)lsd_out->values[4 + i * lsd_dim];
- //cv::line(img_result, pt1, pt2, cv::Scalar(0, 255, 255), line_width, CV_AA);
- }
- // Label out the unique subset ID for each the line segment belings to
- int numberOfLines = cv::partition(lsd_vec, labels, isEqual);
- std::vector<std::pair<int, std::vector<int>>> lsd_label_table;
- std::vector<std::pair<int, int>> lsd_label;
- // Construct a LUT for each line segment w.r.t. its belonging set index.
- for (int i = 0; i < labels.size(); i++)
- {
- std::pair<int, int> freq_count_tmp;
- freq_count_tmp = std::make_pair(labels.at(i), i);
- lsd_label.push_back(freq_count_tmp);
- }
- std::sort(lsd_label.begin(), lsd_label.end());
- if (lsd_label.size() > 2)
- {
- // Sort out the set index w.r.t. its corresponding line segment index
- int current = lsd_label.at(0).first;
- std::vector<int> freq_sorted;
- std::pair<int, std::vector<int>> freq_pushed;
- std::vector<std::pair<int, int>> freq_count;
- int size = lsd_label.size();
- int set_idx = 0;
- for (int i = 0; i < size - 1; i++)
- {
- freq_sorted.push_back(lsd_label.at(i).second);
- current = lsd_label.at(i).first;
- if (current != lsd_label.at(i + 1).first)
- {
- freq_pushed.first = set_idx;
- freq_pushed.second.swap(freq_sorted);
- lsd_label_table.push_back(freq_pushed);
- freq_sorted.clear();
- set_idx++;
- }
- }
- for (int i = 0; i < lsd_label_table.size(); i++)
- {
- std::pair<int, int> tmp = std::make_pair(lsd_label_table.at(i).second.size(), lsd_label_table.at(i).first);
- freq_count.push_back(tmp);
- }
- std::sort(freq_count.rbegin(), freq_count.rend());
- // Select the most dominant line segment: pick the most the the second most dominant inedex.
- int lsd_select_threshold = static_cast<int>(freq_count.at(0).first * 0.8f);
- std::cout << "selection threshold: " << lsd_select_threshold << '\n';
- std::vector<int> lsd_selected_idx;
- bool isDone = false;
- lsd_selected_idx.push_back(freq_count.at(0).second);
- lsd_selected_idx.push_back(freq_count.at(1).second);
- #if 0
- // In some cases, we can also select the thrid and preceeding ones if the count is above some threshold
- int selected_idx = 2;
- while (!isDone)
- {
- int count_tmp = freq_count.at(selected_idx).first;
- if (count_tmp > lsd_select_threshold)
- {
- lsd_selected_idx.push_back(freq_count.at(selected_idx).second);
- }
- else
- {
- isDone = true;
- }
- selected_idx++;
- }
- #endif
- lsd_vec.clear();
- // For all selected line segments
- for (int i = 0; i < lsd_selected_idx.size(); i++)
- {
- int idxx = lsd_selected_idx.at(i);
- for (int j = 0; j < lsd_label_table.at(idxx).second.size(); j++)
- {
- int idx = lsd_label_table.at(idxx).second.at(j);
- cv::Vec4i lsd_tmp;
- lsd_tmp[0] = (int)lsd_out->values[0 + idx * lsd_dim];
- lsd_tmp[1] = (int)lsd_out->values[1 + idx * lsd_dim];
- lsd_tmp[2] = (int)lsd_out->values[2 + idx * lsd_dim];
- lsd_tmp[3] = (int)lsd_out->values[3 + idx * lsd_dim];
- lsd_vec.push_back(lsd_tmp);
- struct rect
- {
- double x1, y1, x2, y2; /* first and second point of the line segment */
- double width; /* rectangle width */
- }rec;
- rec.x1 = lsd_out->values[0 + idx * lsd_dim];
- rec.y1 = lsd_out->values[1 + idx * lsd_dim];
- rec.x2 = lsd_out->values[2 + idx * lsd_dim];
- rec.y2 = lsd_out->values[3 + idx * lsd_dim];
- rec.width = lsd_out->values[4 + idx * lsd_dim];
- add_5tuple(lsd_selected, rec.x1, rec.y1, rec.x2, rec.y2, rec.width);
- #if 0
- pt1.x = (int)lsd_out->values[0 + idx * lsd_dim];
- pt1.y = (int)lsd_out->values[1 + idx * lsd_dim];
- pt2.x = (int)lsd_out->values[2 + idx * lsd_dim];
- pt2.y = (int)lsd_out->values[3 + idx * lsd_dim];
- // The 5th element is the width of line segment
- line_width = 2;// (int)lsd_out->values[4 + i * lsd_dim];
- cv::line(img_result, pt1, pt2, cv::Scalar(0, 0, 255), 5, CV_AA);
- #endif
- }
- }
- #if 1
- // Draw the all line segments
- for (int i = 0; i < labels.size(); i++)
- {
- // The first four elements in ntuple_list are [x1 y1 x2 y2] point that define the location of line segment
- pt1.x = (int)lsd_out->values[0 + i * lsd_dim];
- pt1.y = (int)lsd_out->values[1 + i * lsd_dim];
- pt2.x = (int)lsd_out->values[2 + i * lsd_dim];
- pt2.y = (int)lsd_out->values[3 + i * lsd_dim];
- // The 5th element is the width of line segment
- line_width = 2;// (int)lsd_out->values[4 + i * lsd_dim];
- cv::line(img_result, pt1, pt2, cv::Scalar(0, 255, 0), line_width, cv::LINE_AA);
- }
- #endif
- // Line selection is done!!!
- // Line gap filling
- std::vector<int> lsd_mergelist;
- std::vector<std::vector<int>> ls12;
- float athreshold = 2;
- float dthreshold = 10;
- ls12.resize(2);
- for (int i = 0; i < 2; i++)
- ls12[i].resize(4);
- for (int i = 0; i < lsd_selected->size - 1; i++)
- {
- // ls1 pt1
- ls12[0][0] = (int)lsd_selected->values[0 + i * lsd_dim];
- ls12[1][0] = (int)lsd_selected->values[1 + i * lsd_dim];
- // ls1 pt2
- ls12[0][1] = (int)lsd_selected->values[2 + i * lsd_dim];
- ls12[1][1] = (int)lsd_selected->values[3 + i * lsd_dim];
- for (int j = i + 1; j < lsd_selected->size; j++)
- {
- // ls2 pt1
- ls12[0][2] = (int)lsd_selected->values[0 + j * lsd_dim];
- ls12[1][2] = (int)lsd_selected->values[1 + j * lsd_dim];
- // ls2 pt2
- ls12[0][3] = (int)lsd_selected->values[2 + j * lsd_dim];
- ls12[1][3] = (int)lsd_selected->values[3 + j * lsd_dim];
- bool test = similarAngle(ls12, athreshold);
- if (test)
- {
- lsd_mergelist.push_back(j);
- }
- }
- bool mergelist = static_cast<bool>(std::accumulate(lsd_mergelist.begin(), lsd_mergelist.end(), 0));
- if (mergelist)
- {
- int maxx, maxy, minx, miny = 0;
- // 1. grab the corresponding merge ls. First one is the current ls followed by a set of potential merging ones.
- ls12.resize(4);
- for (int i = 0; i < 4; i++)
- ls12[i].resize(1 + lsd_mergelist.size());
- ls12[0][0] = (int)lsd_selected->values[0 + i * lsd_dim]; // x1
- ls12[1][0] = (int)lsd_selected->values[1 + i * lsd_dim]; // y1
- ls12[2][0] = (int)lsd_selected->values[2 + i * lsd_dim]; // x2
- ls12[3][0] = (int)lsd_selected->values[3 + i * lsd_dim]; // y2
- int idx = 1;
- for (int i = 0; i < lsd_mergelist.size(); i++)
- {
- int idxx = lsd_mergelist.at(i);
- ls12[0][idx] = (int)lsd_selected->values[0 + idxx * lsd_dim];
- ls12[1][idx] = (int)lsd_selected->values[1 + idxx * lsd_dim];
- ls12[2][idx] = (int)lsd_selected->values[2 + idxx * lsd_dim];
- ls12[3][idx] = (int)lsd_selected->values[3 + idxx * lsd_dim];
- idx++;
- }
- // 2. sort the segments on the line, by their "left" endpoint
- for (int i = 0; i < ls12[0].size(); i++)
- {
- }
- //std::cout << "merging\n";
- }
- // TODO: Update lsd_selected ()
- //std::cout << '[';
- //for (int i = 0; i < lsd_mergelist.size(); i++)
- //{
- // std::cout << lsd_mergelist.at(i) << ", ";
- //}
- //std::cout << "\b\b]\n";
- lsd_mergelist.clear();
- //cv::waitKey(1);
- }
- //std::cout << "\n------------------------------\n";
- lsd_extend(lsd_selected, L, center);
- int no_of_lines = static_cast<int>(lsd_selected->size);
- for (int j = 0; j < no_of_lines; j++)
- {
- float x1 = L[0][j];
- float y1 = L[1][j];
- float x2 = L[2][j];
- float y2 = L[3][j];
- pt1.x = int(x1);
- pt1.y = int(y1);
- pt2.x = int(x2);
- pt2.y = int(y2);
- float width = 2;// int(lsd_out->values[4 + j * lsd_out->dim]);
- cv::line(img, pt1, pt2, cv::Scalar(0, 255, 255), width, cv::LINE_AA);
- }
- }
- // Show result
- cv::imshow(WIN_TITLE_INPUT, img);
- cv::imshow(WIN_TTILE_OUTPUT, img_result);
- // Free up memory
- L.clear();
- free_ntuple_list(lsd_out);
- free_ntuple_list(lsd_selected);
- if (cv::waitKey(1) == 27)
- break;
- }
- return 0;
- }
- #endif
- bool similarAngle(std::vector<std::vector<int>>& ls12, float athreshold)
- {
- bool rtn = true;
- std::vector<int> chk_book;
- std::vector<std::vector<int>> comb{ { 0, 1, 2, 3 },
- { 0, 1, 0, 2 },
- { 0, 1, 0, 3 },
- { 0, 1, 1, 2 },
- { 0, 1, 1, 3 },
- { 2, 3, 2, 0 },
- { 2, 3, 2, 1 },
- { 2, 3, 3, 0 },
- { 2, 3, 3, 1 } };
- std::vector<int> ls_compared;
- ls_compared.resize(8);
- for (int i = 0; i < comb.size(); i++)
- {
- bool tmp;
- // ls1
- ls_compared[0] = ls12[0][comb[i][0]]; // x1
- ls_compared[1] = ls12[1][comb[i][0]]; // y1
- ls_compared[2] = ls12[0][comb[i][1]]; // x2
- ls_compared[3] = ls12[1][comb[i][1]]; // y2
- // ls2
- ls_compared[4] = ls12[0][comb[i][2]]; // x1
- ls_compared[5] = ls12[1][comb[i][2]]; // y1
- ls_compared[6] = ls12[0][comb[i][3]]; // x2
- ls_compared[7] = ls12[1][comb[i][3]]; // y2
- // measure cos similarity
- float theta = lsd_angle(ls_compared);
- float threshold = std::cos(athreshold * M_PI / 180);
- threshold *= threshold;
- //std::cout << "theta: " << theta << '\t' << threshold << '\n';
- if (theta < threshold) return false;
- //chk_book.push_back(tmp);
- }
- return true;
- }
- float lsd_angle(std::vector<int>& ls_compared)
- {
- std::vector<float> ls1_vector;
- std::vector<float> ls2_vector;
- float theta = 0.0f;
- ls1_vector.resize(2);
- ls2_vector.resize(2);
- // convert points to vector form
- // (x2 - x1, y2 - y1) / norm((x2 - x1, y2 - y1))
- ls1_vector[0] = std::abs((ls_compared[2] - ls_compared[0]));
- ls1_vector[1] = std::abs((ls_compared[3] - ls_compared[1]));
- ls2_vector[0] = std::abs((ls_compared[6] - ls_compared[4]));
- ls2_vector[1] = std::abs((ls_compared[7] - ls_compared[5]));
- float norm = std::sqrt(ls1_vector[0] * ls1_vector[0] + ls1_vector[1] * ls1_vector[1]);
- ls1_vector[0] /= norm;
- ls1_vector[1] /= norm;
- norm = std::sqrt(ls2_vector[0] * ls2_vector[0] + ls2_vector[1] * ls2_vector[1]);
- ls2_vector[0] /= norm;
- ls2_vector[1] /= norm;
- for (int k = 0; k < 2; k++)
- {
- theta += ls1_vector[k] * ls2_vector[k];
- }
- theta *= theta;
- return theta;
- }
- void resize_image_length(cv::Mat& srcImg, cv::Mat& dstImg, int maxSize)
- {
- //cv::Mat myImg = srcImg;
- if (std::max(srcImg.rows, srcImg.cols) > 1000)
- {
- std::cout << "over sized frame, scale down needed" << std::endl;
- float s = float(1000) / std::max(srcImg.rows, srcImg.cols);
- cv::resize(srcImg, dstImg, cv::Size(srcImg.cols * s, srcImg.rows * s), 0, 0, cv::INTER_LINEAR);
- //std::cout << my_image_copy.cols << " x " << my_image_copy.rows << std::endl;
- //my_image_copy.copyTo(output_image);
- }
- else
- {
- srcImg.copyTo(dstImg);
- }
- }
- void lsd_extend(ntuple_list& lsd_out, std::vector<std::vector<float>>& L, dlib::vector<float> center)
- {
- float extension_fac = 0.5f; // Line Extension factor, the larger the number the longer LSD extend.
- bool talk = false;
- std::vector<mypair> line_lengths;
- float sqd_distance;
- float x1, x2, y1, y2;
- int size = lsd_out->size;
- int dim = lsd_out->dim;
- //for (int j = 0; j < (size * dim); j = j + 5)
- //{
- // x1 = lsd_out->values[j];
- // x2 = lsd_out->values[j + 1];
- // y1 = lsd_out->values[j + 2];
- // y2 = lsd_out->values[j + 3];
- // sqd_distance = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1);
- // line_lengths.push_back(std::make_pair(sqd_distance, j));
- //}
- //std::sort(line_lengths.begin(), line_lengths.end());
- //std::reverse(line_lengths.begin(), line_lengths.end());
- //if (talk) std::cout << line_lengths[0].first << " " << line_lengths[0].second << " " << line_lengths[1].first << " " << line_lengths[1].second << std::endl;
- ////cv::waitKey(1000);
- uint no_of_lines = std::min((uint)size, uint(700));
- //std::cout << "Number of lines: " << no_of_lines << std::endl;
- L.resize(4);
- int lsd_dim = lsd_out->dim;
- for (int i = 0; i < 4; i++)
- L[i].resize(no_of_lines);
- for (int j = 0; j < no_of_lines; j++)
- {
- //mypair tmp = line_lengths[j];
- //L[0][j] = lsd_out->values[tmp.second];
- //L[1][j] = lsd_out->values[tmp.second + 1];
- //L[2][j] = lsd_out->values[tmp.second + 2];
- //L[3][j] = lsd_out->values[tmp.second + 3];
- L[0][j] = (int)lsd_out->values[0 + j * lsd_dim];
- L[1][j] = (int)lsd_out->values[1 + j * lsd_dim];
- L[2][j] = (int)lsd_out->values[2 + j * lsd_dim];
- L[3][j] = (int)lsd_out->values[3 + j * lsd_dim];
- }
- // LINE EXTNESION
- float line_length;
- float line_gradient;
- float rise_angle;
- float delta_x;
- float delta_y;
- for (int j = 0; j < no_of_lines; j++) {
- x1 = L[0][j];
- y1 = L[1][j];
- x2 = L[2][j];
- y2 = L[3][j];
- line_length = std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
- line_gradient = (y2 - y1) / (x2 - x1);
- rise_angle = std::atan(std::abs(line_gradient));
- delta_x = std::cos(rise_angle) * (line_length * extension_fac);
- delta_y = std::sin(rise_angle) * (line_length * extension_fac);
- if (line_gradient < 0)
- {
- if (x1 > x2)
- {
- L[0][j] += delta_x;
- L[1][j] -= delta_y;
- L[2][j] -= delta_x;
- L[3][j] += delta_y;
- }
- else
- {
- L[2][j] += delta_x;
- L[3][j] -= delta_y;
- L[0][j] -= delta_x;
- L[1][j] += delta_y;
- }
- }
- else
- {
- if (x1 > x2)
- {
- L[0][j] += delta_x;
- L[1][j] += delta_y;
- L[2][j] -= delta_x;
- L[3][j] -= delta_y;
- }
- else
- {
- L[2][j] += delta_x;
- L[3][j] += delta_y;
- L[0][j] -= delta_x;
- L[1][j] -= delta_y;
- }
- }
- x1 = L[0][j];
- y1 = L[1][j];
- x2 = L[2][j];
- y2 = L[3][j];
- //L[2][j] -= center.x(); //Move Origin to the Principle Point
- //L[3][j] -= center.y();
- //L[0][j] -= center.x();
- //L[1][j] -= center.y();
- }
- line_lengths.clear();
- }
- bool isEqual(const cv::Vec4i& _l1, const cv::Vec4i& _l2)
- {
- cv::Vec4i l1(_l1), l2(_l2);
- float length1 = sqrtf((l1[2] - l1[0]) * (l1[2] - l1[0]) + (l1[3] - l1[1]) * (l1[3] - l1[1]));
- float length2 = sqrtf((l2[2] - l2[0]) * (l2[2] - l2[0]) + (l2[3] - l2[1]) * (l2[3] - l2[1]));
- float product = (l1[2] - l1[0]) * (l2[2] - l2[0]) + (l1[3] - l1[1]) * (l2[3] - l2[1]);
- if (fabs(product / (length1 * length2)) < cos(CV_PI / 180))
- return false;
- float mx1 = (l1[0] + l1[2]) * 0.5f;
- float mx2 = (l2[0] + l2[2]) * 0.5f;
- float my1 = (l1[1] + l1[3]) * 0.5f;
- float my2 = (l2[1] + l2[3]) * 0.5f;
- float dist = sqrtf((mx1 - mx2) * (mx1 - mx2) + (my1 - my2) * (my1 - my2));
- if (dist > std::max(length1, length2) * 0.9f)
- return false;
- return true;
- }
- void lsd_detection(cv::Mat& srcImg, ntuple_list& lsd_out)
- {
- bool talk = false;
- bool verbose = false;
- // Converting image to image double
- image_double dub_image;
- uint w = srcImg.cols;
- uint h = srcImg.rows;
- uchar* imgP = srcImg.data;
- // All parameters defined here
- // 1.LSD parameters
- double scale = 0.8; // Scale the image by Gaussian filter to 'scale'.
- double sigma_scale = 0.6; // Sigma for Gaussian filter is computed as sigma = sigma_scale/scale.
- double quant = 2.0; // Bound to the quantization error on the gradient norm.
- double ang_th = 22.5; // Gradient angle tolerance in degrees.
- double eps = 0.0; // Detection threshold, -log10(NFA).
- double density_th = 0.7; // Minimal density of region points in rectangle.
- int n_bins = 1024; // Number of bins in pseudo-ordering of gradient modulus.
- double max_grad = 255.0; // Gradient modulus in the highest bin. The default value corresponds to the highest
- // gradient modulus on images with gray levels in [0,255].
- // 2. Other flags and parameters
- double athreshadj = 10; // Threshold defining whether a pair of lsd are potentially orthogonal.
- float extension_fac = 0.5f; // Line Extension factor, the larger the number the longer LSD extend.
- dub_image = new_image_double(w, h);
- double px = 0;
- if (talk) std::cout << "\n-----------\nInput data being written to image buffer" << std::endl;
- for (int j = 0; j < (w * h); j++)
- {
- px = imgP[j];
- dub_image->data[j] = px;
- if (verbose) std::cout << " " << dub_image->data[j];
- }
- lsd_out = LineSegmentDetection(dub_image, scale, sigma_scale, quant, ang_th, eps, density_th, n_bins, max_grad, nullptr);
- free_image_double(dub_image);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement