• 工程(十四)——ubuntu20.04 PL-VINS


    博主创建了一个科研互助群Q:772356582,欢迎大家加入讨论。这是一个科研互助群,主要围绕机器人,无人驾驶,无人机方面的感知定位,决策规划,以及论文发表经验,以方便大家很好很快的科研,少走弯路。欢迎在群里积极提问与回答,相互交流共同学习。

    一、简介

    PL-VINS是基于最先进的基于点的VINS- mono,开发的一种基于点和线特征的实时、高效优化的单目VINS方法。原始的 PL-VINS 是在ubuntu18.04基于opencv3去开发的。源码的下载地址:https://github.com/cnqiangfu/PL-VINS

    我的配置:ubuntu20.04+opencv4.2+eigen3.3.7

    更改好的代码如下,可直接用,需要修改mage_node_b.cpp的main函数第一行的地址

    huashu996/Ubuntu20.04PL_VINS · GitHub

    二、编译

    如果你使用官方的代码,编译时候可能会遇到如下问题

    1. mkdir -p ~/catkin_plvins/src
    2. cd catkin_plvins/src //进入创建的catkin_plvins/src文件夹下
    3. catkin_init_workspace 进行空间创建
    4. cd ~/catkin_plvins //在文件夹catkin_plvins下建立终端输入
    5. catkin_make //终端输入
    6. source devel/setup.bash
    7. echo $ROS_PACKAGE_PATH
    8. //将代码下载到src目录下 或者执行下面代码
    9. cd ~/catkin_plvins/src
    10. git clone https://github.com/cnqiangfu/PL-VINS.git
    11. //编译
    12. cd .. //回到文件夹catkin_plvins
    13. catkin_make
    14. source devel/setup.bash
    • 将feature_tracker里面的Cmakelist修改一下:主要修改以下2处的路径

    • 打开catkin_plvins/src/PL-VINS/image_node_b文件下的CMakeLists.txt添加
    set(CMAKE_CXX_STANDARD 14)

    如果你配置正确,应该能够编译顺利通过

    三、opencv4适配

    但运行往往会出现如下图问题,对于每个问题我们一次解决

    • [image_node_b-7]  挂掉的原因是linefeature_tracker_node中只发布了归一化坐标,没有发布linefeature的startpoint和endpoint的像素坐标。

    1.mage_node_b.cpp的main函数第一行的地址,修改原绝对地址。

     2.加入project函数

    1. void project(cv::Point2f& pt, cv::Mat const& k)
    2. {
    3. pt.x=k.at<float>(0,0)*pt.x+k.at<float>(0,2);
    4. pt.y=k.at<float>(1,1)*pt.y+k.at<float>(1,2);
    5. }

    3.替换 

    1. 将下面两行
    2. cv::Point startPoint = cv::Point(line_feature_msg->channels[3].values[i], line_feature_msg->channels[4].values[i]);
    3. cv::Point endPoint = cv::Point(line_feature_msg->channels[5].values[i], line_feature_msg->channels[6].values[i]);
    4. 替换
    5. cv::Point2f startPoint = cv::Point2f(line_feature_msg->points[i].x,line_feature_msg->points[i].y );
    6. project (startPoint,K_);
    7. cv::Point2f endPoint = cv::Point2f(line_feature_msg->channels[1].values[i],line_feature_msg->channels[2].values[i]);
    • [linefeature_tracker-4] 

    此问题由于opencv和cv_bridge冲突的问题,因为在ubuntu20.04 cv_bridge是4,如果你使用opencv3那么将产生冲突,如果使用opencv4跑,代码本身又不支持opencv4所以需要更改。相应的解决方式也有两种:

    1)把vins-mono代码全部改成opencv4的版本 或者  2)把cv_bridge改成opencv3版本。参考如下博客修改

    【精选】Ubuntu20.04下成功运行VINS-mono_ubuntu vinsmono-CSDN博客

    1.将所有包含opencv的Cmakelists.txt中opencv引入都换成4,如下

    2.更新头文件使使用opencv4

    1. (1)将camera_model包改成兼容opencv4
    2. 在camera_model包中的头文件Chessboard.h中添加
    3. #include
    4. #include
    5. 在CameraCalibration.h中添加
    6. #include
    7. #include
    8. (2)将包中所有报错的头文件
    9. #include
    10. #include
    11. 替换为
    12. #include
    13. #include

    3.加入线特征检测函数

    imgproc.hpp关于线特征的部分由于opencv4权限的问题无法使用了,这里只需要自己定义一个相同功能的头文件去把opencv3中的实现拷贝过去。在路径

    PL-VINS/src/PL-VINS/feature_tracker/src/line_descriptor/src

    创建一个my_lsd.hpp

    1. //
    2. // Created by fs on 2021/11/3.
    3. // This file is my_lsd.hpp
    4. //
    5. //#include "opencv2/../../src/precomp.hpp"
    6. #include "opencv2/imgproc.hpp"
    7. //#include "opencv2/core/private.hpp"
    8. #include
    9. #define M_3_2_PI (3 * CV_PI) / 2 // 3/2 pi
    10. #define M_2__PI (2 * CV_PI) // 2 pi
    11. #ifndef M_LN10
    12. #define M_LN10 2.30258509299404568402
    13. #endif
    14. #define NOTDEF double(-1024.0) // Label for pixels with undefined gradient.
    15. #define NOTUSED 0 // Label for pixels not used in yet.
    16. #define USED 1 // Label for pixels already used in detection.
    17. #define RELATIVE_ERROR_FACTOR 100.0
    18. const double DEG_TO_RADS = CV_PI / 180;
    19. #define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x))
    20. struct edge
    21. {
    22. cv::Point p;
    23. bool taken;
    24. };
    25. inline double distSq(const double x1, const double y1,
    26. const double x2, const double y2)
    27. {
    28. return (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1);
    29. }
    30. inline double dist(const double x1, const double y1,
    31. const double x2, const double y2)
    32. {
    33. return sqrt(distSq(x1, y1, x2, y2));
    34. }
    35. // Signed angle difference
    36. inline double angle_diff_signed(const double& a, const double& b)
    37. {
    38. double diff = a - b;
    39. while(diff <= -CV_PI) diff += M_2__PI;
    40. while(diff > CV_PI) diff -= M_2__PI;
    41. return diff;
    42. }
    43. // Absolute value angle difference
    44. inline double angle_diff(const double& a, const double& b)
    45. {
    46. return std::fabs(angle_diff_signed(a, b));
    47. }
    48. // Compare doubles by relative error.
    49. inline bool double_equal(const double& a, const double& b)
    50. {
    51. // trivial case
    52. if(a == b) return true;
    53. double abs_diff = fabs(a - b);
    54. double aa = fabs(a);
    55. double bb = fabs(b);
    56. double abs_max = (aa > bb)? aa : bb;
    57. if(abs_max < DBL_MIN) abs_max = DBL_MIN;
    58. return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON);
    59. }
    60. inline bool AsmallerB_XoverY(const edge& a, const edge& b)
    61. {
    62. if (a.p.x == b.p.x) return a.p.y < b.p.y;
    63. else return a.p.x < b.p.x;
    64. }
    65. /**
    66. * Computes the natural logarithm of the absolute value of
    67. * the gamma function of x using Windschitl method.
    68. * See http://www.rskey.org/gamma.htm
    69. */
    70. inline double log_gamma_windschitl(const double& x)
    71. {
    72. return 0.918938533204673 + (x-0.5)*log(x) - x
    73. + 0.5*x*log(x*sinh(1/x) + 1/(810.0*pow(x, 6.0)));
    74. }
    75. /**
    76. * Computes the natural logarithm of the absolute value of
    77. * the gamma function of x using the Lanczos approximation.
    78. * See http://www.rskey.org/gamma.htm
    79. */
    80. inline double log_gamma_lanczos(const double& x)
    81. {
    82. static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477,
    83. 8687.24529705, 1168.92649479, 83.8676043424,
    84. 2.50662827511 };
    85. double a = (x + 0.5) * log(x + 5.5) - (x + 5.5);
    86. double b = 0;
    87. for(int n = 0; n < 7; ++n)
    88. {
    89. a -= log(x + double(n));
    90. b += q[n] * pow(x, double(n));
    91. }
    92. return a + log(b);
    93. }
    94. ///
    95. namespace cv {
    96. class myLineSegmentDetectorImpl CV_FINAL : public LineSegmentDetector
    97. {
    98. public:
    99. /**
    100. * Create a LineSegmentDetectorImpl object. Specifying scale, number of subdivisions for the image, should the lines be refined and other constants as follows:
    101. *
    102. * @param _refine How should the lines found be refined?
    103. * LSD_REFINE_NONE - No refinement applied.
    104. * LSD_REFINE_STD - Standard refinement is applied. E.g. breaking arches into smaller line approximations.
    105. * LSD_REFINE_ADV - Advanced refinement. Number of false alarms is calculated,
    106. * lines are refined through increase of precision, decrement in size, etc.
    107. * @param _scale The scale of the image that will be used to find the lines. Range (0..1].
    108. * @param _sigma_scale Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale.
    109. * @param _quant Bound to the quantization error on the gradient norm.
    110. * @param _ang_th Gradient angle tolerance in degrees.
    111. * @param _log_eps Detection threshold: -log10(NFA) > _log_eps
    112. * @param _density_th Minimal density of aligned region points in rectangle.
    113. * @param _n_bins Number of bins in pseudo-ordering of gradient modulus.
    114. */
    115. myLineSegmentDetectorImpl(int _refine = LSD_REFINE_STD, double _scale = 0.8,
    116. double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5,
    117. double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024);
    118. /**
    119. * Detect lines in the input image.
    120. *
    121. * @param _image A grayscale(CV_8UC1) input image.
    122. * If only a roi needs to be selected, use
    123. * lsd_ptr->detect(image(roi), ..., lines);
    124. * lines += Scalar(roi.x, roi.y, roi.x, roi.y);
    125. * @param _lines Return: A vector of Vec4i or Vec4f elements specifying the beginning and ending point of a line.
    126. * Where Vec4i/Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
    127. * Returned lines are strictly oriented depending on the gradient.
    128. * @param width Return: Vector of widths of the regions, where the lines are found. E.g. Width of line.
    129. * @param prec Return: Vector of precisions with which the lines are found.
    130. * @param nfa Return: Vector containing number of false alarms in the line region, with precision of 10%.
    131. * The bigger the value, logarithmically better the detection.
    132. * * -1 corresponds to 10 mean false alarms
    133. * * 0 corresponds to 1 mean false alarm
    134. * * 1 corresponds to 0.1 mean false alarms
    135. * This vector will be calculated _only_ when the objects type is REFINE_ADV
    136. */
    137. void detect(InputArray _image, OutputArray _lines,
    138. OutputArray width = noArray(), OutputArray prec = noArray(),
    139. OutputArray nfa = noArray()) CV_OVERRIDE;
    140. /**
    141. * Draw lines on the given canvas.
    142. *
    143. * @param image The image, where lines will be drawn.
    144. * Should have the size of the image, where the lines were found
    145. * @param lines The lines that need to be drawn
    146. */
    147. void drawSegments(InputOutputArray _image, InputArray lines) CV_OVERRIDE;
    148. /**
    149. * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2.
    150. *
    151. * @param size The size of the image, where lines1 and lines2 were found.
    152. * @param lines1 The first lines that need to be drawn. Color - Blue.
    153. * @param lines2 The second lines that need to be drawn. Color - Red.
    154. * @param image An optional image, where lines will be drawn.
    155. * Should have the size of the image, where the lines were found
    156. * @return The number of mismatching pixels between lines1 and lines2.
    157. */
    158. int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image = noArray()) CV_OVERRIDE;
    159. private:
    160. Mat image;
    161. Mat scaled_image;
    162. Mat_<double> angles; // in rads
    163. Mat_<double> modgrad;
    164. Mat_ used;
    165. int img_width;
    166. int img_height;
    167. double LOG_NT;
    168. bool w_needed;
    169. bool p_needed;
    170. bool n_needed;
    171. const double SCALE;
    172. const int doRefine;
    173. const double SIGMA_SCALE;
    174. const double QUANT;
    175. const double ANG_TH;
    176. const double LOG_EPS;
    177. const double DENSITY_TH;
    178. const int N_BINS;
    179. struct RegionPoint {
    180. int x;
    181. int y;
    182. uchar* used;
    183. double angle;
    184. double modgrad;
    185. };
    186. struct normPoint
    187. {
    188. Point2i p;
    189. int norm;
    190. };
    191. std::vector ordered_points;
    192. struct rect
    193. {
    194. double x1, y1, x2, y2; // first and second point of the line segment
    195. double width; // rectangle width
    196. double x, y; // center of the rectangle
    197. double theta; // angle
    198. double dx,dy; // (dx,dy) is vector oriented as the line segment
    199. double prec; // tolerance angle
    200. double p; // probability of a point with angle within 'prec'
    201. };
    202. myLineSegmentDetectorImpl& operator= (const myLineSegmentDetectorImpl&); // to quiet MSVC
    203. /**
    204. * Detect lines in the whole input image.
    205. *
    206. * @param lines Return: A vector of Vec4f elements specifying the beginning and ending point of a line.
    207. * Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
    208. * Returned lines are strictly oriented depending on the gradient.
    209. * @param widths Return: Vector of widths of the regions, where the lines are found. E.g. Width of line.
    210. * @param precisions Return: Vector of precisions with which the lines are found.
    211. * @param nfas Return: Vector containing number of false alarms in the line region, with precision of 10%.
    212. * The bigger the value, logarithmically better the detection.
    213. * * -1 corresponds to 10 mean false alarms
    214. * * 0 corresponds to 1 mean false alarm
    215. * * 1 corresponds to 0.1 mean false alarms
    216. */
    217. void flsd(std::vector& lines,
    218. std::vector<double>& widths, std::vector<double>& precisions,
    219. std::vector<double>& nfas);
    220. /**
    221. * Finds the angles and the gradients of the image. Generates a list of pseudo ordered points.
    222. *
    223. * @param threshold The minimum value of the angle that is considered defined, otherwise NOTDEF
    224. * @param n_bins The number of bins with which gradients are ordered by, using bucket sort.
    225. * @param ordered_points Return: Vector of coordinate points that are pseudo ordered by magnitude.
    226. * Pixels would be ordered by norm value, up to a precision given by max_grad/n_bins.
    227. */
    228. void ll_angle(const double& threshold, const unsigned int& n_bins);
    229. /**
    230. * Grow a region starting from point s with a defined precision,
    231. * returning the containing points size and the angle of the gradients.
    232. *
    233. * @param s Starting point for the region.
    234. * @param reg Return: Vector of points, that are part of the region
    235. * @param reg_angle Return: The mean angle of the region.
    236. * @param prec The precision by which each region angle should be aligned to the mean.
    237. */
    238. void region_grow(const Point2i& s, std::vector& reg,
    239. double& reg_angle, const double& prec);
    240. /**
    241. * Finds the bounding rotated rectangle of a region.
    242. *
    243. * @param reg The region of points, from which the rectangle to be constructed from.
    244. * @param reg_angle The mean angle of the region.
    245. * @param prec The precision by which points were found.
    246. * @param p Probability of a point with angle within 'prec'.
    247. * @param rec Return: The generated rectangle.
    248. */
    249. void region2rect(const std::vector& reg, const double reg_angle,
    250. const double prec, const double p, rect& rec) const;
    251. /**
    252. * Compute region's angle as the principal inertia axis of the region.
    253. * @return Regions angle.
    254. */
    255. double get_theta(const std::vector& reg, const double& x,
    256. const double& y, const double& reg_angle, const double& prec) const;
    257. /**
    258. * An estimation of the angle tolerance is performed by the standard deviation of the angle at points
    259. * near the region's starting point. Then, a new region is grown starting from the same point, but using the
    260. * estimated angle tolerance. If this fails to produce a rectangle with the right density of region points,
    261. * 'reduce_region_radius' is called to try to satisfy this condition.
    262. */
    263. bool refine(std::vector& reg, double reg_angle,
    264. const double prec, double p, rect& rec, const double& density_th);
    265. /**
    266. * Reduce the region size, by elimination the points far from the starting point, until that leads to
    267. * rectangle with the right density of region points or to discard the region if too small.
    268. */
    269. bool reduce_region_radius(std::vector& reg, double reg_angle,
    270. const double prec, double p, rect& rec, double density, const double& density_th);
    271. /**
    272. * Try some rectangles variations to improve NFA value. Only if the rectangle is not meaningful (i.e., log_nfa <= log_eps).
    273. * @return The new NFA value.
    274. */
    275. double rect_improve(rect& rec) const;
    276. /**
    277. * Calculates the number of correctly aligned points within the rectangle.
    278. * @return The new NFA value.
    279. */
    280. double rect_nfa(const rect& rec) const;
    281. /**
    282. * Computes the NFA values based on the total number of points, points that agree.
    283. * n, k, p are the binomial parameters.
    284. * @return The new NFA value.
    285. */
    286. double nfa(const int& n, const int& k, const double& p) const;
    287. /**
    288. * Is the point at place 'address' aligned to angle theta, up to precision 'prec'?
    289. * @return Whether the point is aligned.
    290. */
    291. bool isAligned(int x, int y, const double& theta, const double& prec) const;
    292. public:
    293. // Compare norm
    294. static inline bool compare_norm( const normPoint& n1, const normPoint& n2 )
    295. {
    296. return (n1.norm > n2.norm);
    297. }
    298. };
    299. CV_EXPORTS Ptr createLineSegmentDetector(
    300. int _refine, double _scale, double _sigma_scale, double _quant, double _ang_th,
    301. double _log_eps, double _density_th, int _n_bins)
    302. {
    303. return makePtr(
    304. _refine, _scale, _sigma_scale, _quant, _ang_th,
    305. _log_eps, _density_th, _n_bins);
    306. }
    307. myLineSegmentDetectorImpl::myLineSegmentDetectorImpl(int _refine, double _scale, double _sigma_scale, double _quant,
    308. double _ang_th, double _log_eps, double _density_th, int _n_bins)
    309. :img_width(0), img_height(0), LOG_NT(0), w_needed(false), p_needed(false), n_needed(false),
    310. SCALE(_scale), doRefine(_refine), SIGMA_SCALE(_sigma_scale), QUANT(_quant),
    311. ANG_TH(_ang_th), LOG_EPS(_log_eps), DENSITY_TH(_density_th), N_BINS(_n_bins)
    312. {
    313. CV_Assert(_scale > 0 && _sigma_scale > 0 && _quant >= 0 &&
    314. _ang_th > 0 && _ang_th < 180 && _density_th >= 0 && _density_th < 1 &&
    315. _n_bins > 0);
    316. // CV_UNUSED(_refine); CV_UNUSED(_log_eps);
    317. // CV_Error(Error::StsNotImplemented, "Implementation has been removed due original code license issues");
    318. }
    319. void myLineSegmentDetectorImpl::detect(InputArray _image, OutputArray _lines,
    320. OutputArray _width, OutputArray _prec, OutputArray _nfa)
    321. {
    322. // CV_INSTRUMENT_REGION();
    323. image = _image.getMat();
    324. CV_Assert(!image.empty() && image.type() == CV_8UC1);
    325. std::vector lines;
    326. std::vector<double> w, p, n;
    327. w_needed = _width.needed();
    328. p_needed = _prec.needed();
    329. if (doRefine < LSD_REFINE_ADV)
    330. n_needed = false;
    331. else
    332. n_needed = _nfa.needed();
    333. flsd(lines, w, p, n);
    334. Mat(lines).copyTo(_lines);
    335. if(w_needed) Mat(w).copyTo(_width);
    336. if(p_needed) Mat(p).copyTo(_prec);
    337. if(n_needed) Mat(n).copyTo(_nfa);
    338. // Clear used structures
    339. ordered_points.clear();
    340. // CV_UNUSED(_image); CV_UNUSED(_lines);
    341. // CV_UNUSED(_width); CV_UNUSED(_prec); CV_UNUSED(_nfa);
    342. // CV_Error(Error::StsNotImplemented, "Implementation has been removed due original code license issues");
    343. }
    344. void myLineSegmentDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines)
    345. {
    346. // CV_INSTRUMENT_REGION();
    347. CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3));
    348. if (_image.channels() == 1)
    349. {
    350. cvtColor(_image, _image, COLOR_GRAY2BGR);
    351. }
    352. Mat _lines = lines.getMat();
    353. const int N = _lines.checkVector(4);
    354. CV_Assert(_lines.depth() == CV_32F || _lines.depth() == CV_32S);
    355. // Draw segments
    356. if (_lines.depth() == CV_32F)
    357. {
    358. for (int i = 0; i < N; ++i)
    359. {
    360. const Vec4f& v = _lines.at(i);
    361. const Point2f b(v[0], v[1]);
    362. const Point2f e(v[2], v[3]);
    363. line(_image, b, e, Scalar(0, 0, 255), 1);
    364. }
    365. }
    366. else
    367. {
    368. for (int i = 0; i < N; ++i)
    369. {
    370. const Vec4i& v = _lines.at(i);
    371. const Point2i b(v[0], v[1]);
    372. const Point2i e(v[2], v[3]);
    373. line(_image, b, e, Scalar(0, 0, 255), 1);
    374. }
    375. }
    376. }
    377. int myLineSegmentDetectorImpl::compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image)
    378. {
    379. // CV_INSTRUMENT_REGION();
    380. Size sz = size;
    381. if (_image.needed() && _image.size() != size) sz = _image.size();
    382. CV_Assert(!sz.empty());
    383. Mat_ I1 = Mat_::zeros(sz);
    384. Mat_ I2 = Mat_::zeros(sz);
    385. Mat _lines1 = lines1.getMat();
    386. Mat _lines2 = lines2.getMat();
    387. const int N1 = _lines1.checkVector(4);
    388. const int N2 = _lines2.checkVector(4);
    389. CV_Assert(_lines1.depth() == CV_32F || _lines1.depth() == CV_32S);
    390. CV_Assert(_lines2.depth() == CV_32F || _lines2.depth() == CV_32S);
    391. if (_lines1.depth() == CV_32S)
    392. _lines1.convertTo(_lines1, CV_32F);
    393. if (_lines2.depth() == CV_32S)
    394. _lines2.convertTo(_lines2, CV_32F);
    395. // Draw segments
    396. for(int i = 0; i < N1; ++i)
    397. {
    398. const Point2f b(_lines1.at(i)[0], _lines1.at(i)[1]);
    399. const Point2f e(_lines1.at(i)[2], _lines1.at(i)[3]);
    400. line(I1, b, e, Scalar::all(255), 1);
    401. }
    402. for(int i = 0; i < N2; ++i)
    403. {
    404. const Point2f b(_lines2.at(i)[0], _lines2.at(i)[1]);
    405. const Point2f e(_lines2.at(i)[2], _lines2.at(i)[3]);
    406. line(I2, b, e, Scalar::all(255), 1);
    407. }
    408. // Count the pixels that don't agree
    409. Mat Ixor;
    410. bitwise_xor(I1, I2, Ixor);
    411. int N = countNonZero(Ixor);
    412. if (_image.needed())
    413. {
    414. CV_Assert(_image.channels() == 3);
    415. Mat img = _image.getMatRef();
    416. CV_Assert(img.isContinuous() && I1.isContinuous() && I2.isContinuous());
    417. for (unsigned int i = 0; i < I1.total(); ++i)
    418. {
    419. uchar i1 = I1.ptr()[i];
    420. uchar i2 = I2.ptr()[i];
    421. if (i1 || i2)
    422. {
    423. unsigned int base_idx = i * 3;
    424. if (i1) img.ptr()[base_idx] = 255;
    425. else img.ptr()[base_idx] = 0;
    426. img.ptr()[base_idx + 1] = 0;
    427. if (i2) img.ptr()[base_idx + 2] = 255;
    428. else img.ptr()[base_idx + 2] = 0;
    429. }
    430. }
    431. }
    432. return N;
    433. }
    434. void myLineSegmentDetectorImpl::flsd(std::vector& lines,
    435. std::vector<double>& widths, std::vector<double>& precisions,
    436. std::vector<double>& nfas)
    437. {
    438. // Angle tolerance
    439. const double prec = CV_PI * ANG_TH / 180;
    440. const double p = ANG_TH / 180;
    441. const double rho = QUANT / sin(prec); // gradient magnitude threshold
    442. if(SCALE != 1)
    443. {
    444. Mat gaussian_img;
    445. const double sigma = (SCALE < 1)?(SIGMA_SCALE / SCALE):(SIGMA_SCALE);
    446. const double sprec = 3;
    447. const unsigned int h = (unsigned int)(ceil(sigma * sqrt(2 * sprec * log(10.0))));
    448. Size ksize(1 + 2 * h, 1 + 2 * h); // kernel size
    449. GaussianBlur(image, gaussian_img, ksize, sigma);
    450. // Scale image to needed size
    451. resize(gaussian_img, scaled_image, Size(), SCALE, SCALE, INTER_LINEAR_EXACT);
    452. ll_angle(rho, N_BINS);
    453. }
    454. else
    455. {
    456. scaled_image = image;
    457. ll_angle(rho, N_BINS);
    458. }
    459. LOG_NT = 5 * (log10(double(img_width)) + log10(double(img_height))) / 2 + log10(11.0);
    460. const size_t min_reg_size = size_t(-LOG_NT/log10(p)); // minimal number of points in region that can give a meaningful event
    461. // // Initialize region only when needed
    462. // Mat region = Mat::zeros(scaled_image.size(), CV_8UC1);
    463. used = Mat_::zeros(scaled_image.size()); // zeros = NOTUSED
    464. std::vector reg;
    465. // Search for line segments
    466. for(size_t i = 0, points_size = ordered_points.size(); i < points_size; ++i)
    467. {
    468. const Point2i& point = ordered_points[i].p;
    469. if((used.at(point) == NOTUSED) && (angles.at<double>(point) != NOTDEF))
    470. {
    471. double reg_angle;
    472. region_grow(ordered_points[i].p, reg, reg_angle, prec);
    473. // Ignore small regions
    474. if(reg.size() < min_reg_size) { continue; }
    475. // Construct rectangular approximation for the region
    476. rect rec;
    477. region2rect(reg, reg_angle, prec, p, rec);
    478. double log_nfa = -1;
    479. if(doRefine > LSD_REFINE_NONE)
    480. {
    481. // At least REFINE_STANDARD lvl.
    482. if(!refine(reg, reg_angle, prec, p, rec, DENSITY_TH)) { continue; }
    483. if(doRefine >= LSD_REFINE_ADV)
    484. {
    485. // Compute NFA
    486. log_nfa = rect_improve(rec);
    487. if(log_nfa <= LOG_EPS) { continue; }
    488. }
    489. }
    490. // Found new line
    491. // Add the offset
    492. rec.x1 += 0.5; rec.y1 += 0.5;
    493. rec.x2 += 0.5; rec.y2 += 0.5;
    494. // scale the result values if a sub-sampling was performed
    495. if(SCALE != 1)
    496. {
    497. rec.x1 /= SCALE; rec.y1 /= SCALE;
    498. rec.x2 /= SCALE; rec.y2 /= SCALE;
    499. rec.width /= SCALE;
    500. }
    501. //Store the relevant data
    502. lines.push_back(Vec4f(float(rec.x1), float(rec.y1), float(rec.x2), float(rec.y2)));
    503. if(w_needed) widths.push_back(rec.width);
    504. if(p_needed) precisions.push_back(rec.p);
    505. if(n_needed && doRefine >= LSD_REFINE_ADV) nfas.push_back(log_nfa);
    506. }
    507. }
    508. }
    509. void myLineSegmentDetectorImpl::ll_angle(const double& threshold,
    510. const unsigned int& n_bins)
    511. {
    512. //Initialize data
    513. angles = Mat_<double>(scaled_image.size());
    514. modgrad = Mat_<double>(scaled_image.size());
    515. img_width = scaled_image.cols;
    516. img_height = scaled_image.rows;
    517. // Undefined the down and right boundaries
    518. angles.row(img_height - 1).setTo(NOTDEF);
    519. angles.col(img_width - 1).setTo(NOTDEF);
    520. // Computing gradient for remaining pixels
    521. double max_grad = -1;
    522. for(int y = 0; y < img_height - 1; ++y)
    523. {
    524. const uchar* scaled_image_row = scaled_image.ptr(y);
    525. const uchar* next_scaled_image_row = scaled_image.ptr(y+1);
    526. double* angles_row = angles.ptr<double>(y);
    527. double* modgrad_row = modgrad.ptr<double>(y);
    528. for(int x = 0; x < img_width-1; ++x)
    529. {
    530. int DA = next_scaled_image_row[x + 1] - scaled_image_row[x];
    531. int BC = scaled_image_row[x + 1] - next_scaled_image_row[x];
    532. int gx = DA + BC; // gradient x component
    533. int gy = DA - BC; // gradient y component
    534. double norm = std::sqrt((gx * gx + gy * gy) / 4.0); // gradient norm
    535. modgrad_row[x] = norm; // store gradient
    536. if (norm <= threshold) // norm too small, gradient no defined
    537. {
    538. angles_row[x] = NOTDEF;
    539. }
    540. else
    541. {
    542. angles_row[x] = fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS; // gradient angle computation
    543. if (norm > max_grad) { max_grad = norm; }
    544. }
    545. }
    546. }
    547. // Compute histogram of gradient values
    548. double bin_coef = (max_grad > 0) ? double(n_bins - 1) / max_grad : 0; // If all image is smooth, max_grad <= 0
    549. for(int y = 0; y < img_height - 1; ++y)
    550. {
    551. const double* modgrad_row = modgrad.ptr<double>(y);
    552. for(int x = 0; x < img_width - 1; ++x)
    553. {
    554. normPoint _point;
    555. int i = int(modgrad_row[x] * bin_coef);
    556. _point.p = Point(x, y);
    557. _point.norm = i;
    558. ordered_points.push_back(_point);
    559. }
    560. }
    561. // Sort
    562. std::sort(ordered_points.begin(), ordered_points.end(), compare_norm);
    563. }
    564. void myLineSegmentDetectorImpl::region_grow(const Point2i& s, std::vector& reg,
    565. double& reg_angle, const double& prec)
    566. {
    567. reg.clear();
    568. // Point to this region
    569. RegionPoint seed;
    570. seed.x = s.x;
    571. seed.y = s.y;
    572. seed.used = &used.at(s);
    573. reg_angle = angles.at<double>(s);
    574. seed.angle = reg_angle;
    575. seed.modgrad = modgrad.at<double>(s);
    576. reg.push_back(seed);
    577. float sumdx = float(std::cos(reg_angle));
    578. float sumdy = float(std::sin(reg_angle));
    579. *seed.used = USED;
    580. //Try neighboring regions
    581. for (size_t i = 0;isize();i++)
    582. {
    583. const RegionPoint& rpoint = reg[i];
    584. int xx_min = std::max(rpoint.x - 1, 0), xx_max = std::min(rpoint.x + 1, img_width - 1);
    585. int yy_min = std::max(rpoint.y - 1, 0), yy_max = std::min(rpoint.y + 1, img_height - 1);
    586. for(int yy = yy_min; yy <= yy_max; ++yy)
    587. {
    588. uchar* used_row = used.ptr(yy);
    589. const double* angles_row = angles.ptr<double>(yy);
    590. const double* modgrad_row = modgrad.ptr<double>(yy);
    591. for(int xx = xx_min; xx <= xx_max; ++xx)
    592. {
    593. uchar& is_used = used_row[xx];
    594. if(is_used != USED &&
    595. (isAligned(xx, yy, reg_angle, prec)))
    596. {
    597. const double& angle = angles_row[xx];
    598. // Add point
    599. is_used = USED;
    600. RegionPoint region_point;
    601. region_point.x = xx;
    602. region_point.y = yy;
    603. region_point.used = &is_used;
    604. region_point.modgrad = modgrad_row[xx];
    605. region_point.angle = angle;
    606. reg.push_back(region_point);
    607. // Update region's angle
    608. sumdx += cos(float(angle));
    609. sumdy += sin(float(angle));
    610. // reg_angle is used in the isAligned, so it needs to be updates?
    611. reg_angle = fastAtan2(sumdy, sumdx) * DEG_TO_RADS;
    612. }
    613. }
    614. }
    615. }
    616. }
    617. void myLineSegmentDetectorImpl::region2rect(const std::vector& reg,
    618. const double reg_angle, const double prec, const double p, rect& rec) const
    619. {
    620. double x = 0, y = 0, sum = 0;
    621. for(size_t i = 0; i < reg.size(); ++i)
    622. {
    623. const RegionPoint& pnt = reg[i];
    624. const double& weight = pnt.modgrad;
    625. x += double(pnt.x) * weight;
    626. y += double(pnt.y) * weight;
    627. sum += weight;
    628. }
    629. // Weighted sum must differ from 0
    630. CV_Assert(sum > 0);
    631. x /= sum;
    632. y /= sum;
    633. double theta = get_theta(reg, x, y, reg_angle, prec);
    634. // Find length and width
    635. double dx = cos(theta);
    636. double dy = sin(theta);
    637. double l_min = 0, l_max = 0, w_min = 0, w_max = 0;
    638. for(size_t i = 0; i < reg.size(); ++i)
    639. {
    640. double regdx = double(reg[i].x) - x;
    641. double regdy = double(reg[i].y) - y;
    642. double l = regdx * dx + regdy * dy;
    643. double w = -regdx * dy + regdy * dx;
    644. if(l > l_max) l_max = l;
    645. else if(l < l_min) l_min = l;
    646. if(w > w_max) w_max = w;
    647. else if(w < w_min) w_min = w;
    648. }
    649. // Store values
    650. rec.x1 = x + l_min * dx;
    651. rec.y1 = y + l_min * dy;
    652. rec.x2 = x + l_max * dx;
    653. rec.y2 = y + l_max * dy;
    654. rec.width = w_max - w_min;
    655. rec.x = x;
    656. rec.y = y;
    657. rec.theta = theta;
    658. rec.dx = dx;
    659. rec.dy = dy;
    660. rec.prec = prec;
    661. rec.p = p;
    662. // Min width of 1 pixel
    663. if(rec.width < 1.0) rec.width = 1.0;
    664. }
    665. double myLineSegmentDetectorImpl::get_theta(const std::vector& reg, const double& x,
    666. const double& y, const double& reg_angle, const double& prec) const
    667. {
    668. double Ixx = 0.0;
    669. double Iyy = 0.0;
    670. double Ixy = 0.0;
    671. // Compute inertia matrix
    672. for(size_t i = 0; i < reg.size(); ++i)
    673. {
    674. const double& regx = reg[i].x;
    675. const double& regy = reg[i].y;
    676. const double& weight = reg[i].modgrad;
    677. double dx = regx - x;
    678. double dy = regy - y;
    679. Ixx += dy * dy * weight;
    680. Iyy += dx * dx * weight;
    681. Ixy -= dx * dy * weight;
    682. }
    683. // Check if inertia matrix is null
    684. CV_Assert(!(double_equal(Ixx, 0) && double_equal(Iyy, 0) && double_equal(Ixy, 0)));
    685. // Compute smallest eigenvalue
    686. double lambda = 0.5 * (Ixx + Iyy - sqrt((Ixx - Iyy) * (Ixx - Iyy) + 4.0 * Ixy * Ixy));
    687. // Compute angle
    688. double theta = (fabs(Ixx)>fabs(Iyy))?
    689. double(fastAtan2(float(lambda - Ixx), float(Ixy))):
    690. double(fastAtan2(float(Ixy), float(lambda - Iyy))); // in degs
    691. theta *= DEG_TO_RADS;
    692. // Correct angle by 180 deg if necessary
    693. if(angle_diff(theta, reg_angle) > prec) { theta += CV_PI; }
    694. return theta;
    695. }
    696. bool myLineSegmentDetectorImpl::refine(std::vector& reg, double reg_angle,
    697. const double prec, double p, rect& rec, const double& density_th)
    698. {
    699. double density = double(reg.size()) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
    700. if (density >= density_th) { return true; }
    701. // Try to reduce angle tolerance
    702. double xc = double(reg[0].x);
    703. double yc = double(reg[0].y);
    704. const double& ang_c = reg[0].angle;
    705. double sum = 0, s_sum = 0;
    706. int n = 0;
    707. for (size_t i = 0; i < reg.size(); ++i)
    708. {
    709. *(reg[i].used) = NOTUSED;
    710. if (dist(xc, yc, reg[i].x, reg[i].y) < rec.width)
    711. {
    712. const double& angle = reg[i].angle;
    713. double ang_d = angle_diff_signed(angle, ang_c);
    714. sum += ang_d;
    715. s_sum += ang_d * ang_d;
    716. ++n;
    717. }
    718. }
    719. CV_Assert(n > 0);
    720. double mean_angle = sum / double(n);
    721. // 2 * standard deviation
    722. double tau = 2.0 * sqrt((s_sum - 2.0 * mean_angle * sum) / double(n) + mean_angle * mean_angle);
    723. // Try new region
    724. region_grow(Point(reg[0].x, reg[0].y), reg, reg_angle, tau);
    725. if (reg.size() < 2) { return false; }
    726. region2rect(reg, reg_angle, prec, p, rec);
    727. density = double(reg.size()) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
    728. if (density < density_th)
    729. {
    730. return reduce_region_radius(reg, reg_angle, prec, p, rec, density, density_th);
    731. }
    732. else
    733. {
    734. return true;
    735. }
    736. }
    737. bool myLineSegmentDetectorImpl::reduce_region_radius(std::vector& reg, double reg_angle,
    738. const double prec, double p, rect& rec, double density, const double& density_th)
    739. {
    740. // Compute region's radius
    741. double xc = double(reg[0].x);
    742. double yc = double(reg[0].y);
    743. double radSq1 = distSq(xc, yc, rec.x1, rec.y1);
    744. double radSq2 = distSq(xc, yc, rec.x2, rec.y2);
    745. double radSq = radSq1 > radSq2 ? radSq1 : radSq2;
    746. while(density < density_th)
    747. {
    748. radSq *= 0.75*0.75; // Reduce region's radius to 75% of its value
    749. // Remove points from the region and update 'used' map
    750. for (size_t i = 0; i < reg.size(); ++i)
    751. {
    752. if(distSq(xc, yc, double(reg[i].x), double(reg[i].y)) > radSq)
    753. {
    754. // Remove point from the region
    755. *(reg[i].used) = NOTUSED;
    756. std::swap(reg[i], reg[reg.size() - 1]);
    757. reg.pop_back();
    758. --i; // To avoid skipping one point
    759. }
    760. }
    761. if(reg.size() < 2) { return false; }
    762. // Re-compute rectangle
    763. region2rect(reg ,reg_angle, prec, p, rec);
    764. // Re-compute region points density
    765. density = double(reg.size()) /
    766. (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
    767. }
    768. return true;
    769. }
    770. double myLineSegmentDetectorImpl::rect_improve(rect& rec) const
    771. {
    772. double delta = 0.5;
    773. double delta_2 = delta / 2.0;
    774. double log_nfa = rect_nfa(rec);
    775. if(log_nfa > LOG_EPS) return log_nfa; // Good rectangle
    776. // Try to improve
    777. // Finer precision
    778. rect r = rect(rec); // Copy
    779. for(int n = 0; n < 5; ++n)
    780. {
    781. r.p /= 2;
    782. r.prec = r.p * CV_PI;
    783. double log_nfa_new = rect_nfa(r);
    784. if(log_nfa_new > log_nfa)
    785. {
    786. log_nfa = log_nfa_new;
    787. rec = rect(r);
    788. }
    789. }
    790. if(log_nfa > LOG_EPS) return log_nfa;
    791. // Try to reduce width
    792. r = rect(rec);
    793. for(unsigned int n = 0; n < 5; ++n)
    794. {
    795. if((r.width - delta) >= 0.5)
    796. {
    797. r.width -= delta;
    798. double log_nfa_new = rect_nfa(r);
    799. if(log_nfa_new > log_nfa)
    800. {
    801. rec = rect(r);
    802. log_nfa = log_nfa_new;
    803. }
    804. }
    805. }
    806. if(log_nfa > LOG_EPS) return log_nfa;
    807. // Try to reduce one side of rectangle
    808. r = rect(rec);
    809. for(unsigned int n = 0; n < 5; ++n)
    810. {
    811. if((r.width - delta) >= 0.5)
    812. {
    813. r.x1 += -r.dy * delta_2;
    814. r.y1 += r.dx * delta_2;
    815. r.x2 += -r.dy * delta_2;
    816. r.y2 += r.dx * delta_2;
    817. r.width -= delta;
    818. double log_nfa_new = rect_nfa(r);
    819. if(log_nfa_new > log_nfa)
    820. {
    821. rec = rect(r);
    822. log_nfa = log_nfa_new;
    823. }
    824. }
    825. }
    826. if(log_nfa > LOG_EPS) return log_nfa;
    827. // Try to reduce other side of rectangle
    828. r = rect(rec);
    829. for(unsigned int n = 0; n < 5; ++n)
    830. {
    831. if((r.width - delta) >= 0.5)
    832. {
    833. r.x1 -= -r.dy * delta_2;
    834. r.y1 -= r.dx * delta_2;
    835. r.x2 -= -r.dy * delta_2;
    836. r.y2 -= r.dx * delta_2;
    837. r.width -= delta;
    838. double log_nfa_new = rect_nfa(r);
    839. if(log_nfa_new > log_nfa)
    840. {
    841. rec = rect(r);
    842. log_nfa = log_nfa_new;
    843. }
    844. }
    845. }
    846. if(log_nfa > LOG_EPS) return log_nfa;
    847. // Try finer precision
    848. r = rect(rec);
    849. for(unsigned int n = 0; n < 5; ++n)
    850. {
    851. if((r.width - delta) >= 0.5)
    852. {
    853. r.p /= 2;
    854. r.prec = r.p * CV_PI;
    855. double log_nfa_new = rect_nfa(r);
    856. if(log_nfa_new > log_nfa)
    857. {
    858. rec = rect(r);
    859. log_nfa = log_nfa_new;
    860. }
    861. }
    862. }
    863. return log_nfa;
    864. }
    865. double myLineSegmentDetectorImpl::rect_nfa(const rect& rec) const
    866. {
    867. int total_pts = 0, alg_pts = 0;
    868. double half_width = rec.width / 2.0;
    869. double dyhw = rec.dy * half_width;
    870. double dxhw = rec.dx * half_width;
    871. edge ordered_x[4];
    872. edge* min_y = &ordered_x[0];
    873. edge* max_y = &ordered_x[0]; // Will be used for loop range
    874. ordered_x[0].p.x = int(rec.x1 - dyhw); ordered_x[0].p.y = int(rec.y1 + dxhw); ordered_x[0].taken = false;
    875. ordered_x[1].p.x = int(rec.x2 - dyhw); ordered_x[1].p.y = int(rec.y2 + dxhw); ordered_x[1].taken = false;
    876. ordered_x[2].p.x = int(rec.x2 + dyhw); ordered_x[2].p.y = int(rec.y2 - dxhw); ordered_x[2].taken = false;
    877. ordered_x[3].p.x = int(rec.x1 + dyhw); ordered_x[3].p.y = int(rec.y1 - dxhw); ordered_x[3].taken = false;
    878. std::sort(ordered_x, ordered_x + 4, AsmallerB_XoverY);
    879. // Find min y. And mark as taken. find max y.
    880. for(unsigned int i = 1; i < 4; ++i)
    881. {
    882. if(min_y->p.y > ordered_x[i].p.y) {min_y = &ordered_x[i]; }
    883. if(max_y->p.y < ordered_x[i].p.y) {max_y = &ordered_x[i]; }
    884. }
    885. min_y->taken = true;
    886. // Find leftmost untaken point;
    887. edge* leftmost = 0;
    888. for(unsigned int i = 0; i < 4; ++i)
    889. {
    890. if(!ordered_x[i].taken)
    891. {
    892. if(!leftmost) // if uninitialized
    893. {
    894. leftmost = &ordered_x[i];
    895. }
    896. else if (leftmost->p.x > ordered_x[i].p.x)
    897. {
    898. leftmost = &ordered_x[i];
    899. }
    900. }
    901. }
    902. CV_Assert(leftmost != NULL);
    903. leftmost->taken = true;
    904. // Find rightmost untaken point;
    905. edge* rightmost = 0;
    906. for(unsigned int i = 0; i < 4; ++i)
    907. {
    908. if(!ordered_x[i].taken)
    909. {
    910. if(!rightmost) // if uninitialized
    911. {
    912. rightmost = &ordered_x[i];
    913. }
    914. else if (rightmost->p.x < ordered_x[i].p.x)
    915. {
    916. rightmost = &ordered_x[i];
    917. }
    918. }
    919. }
    920. CV_Assert(rightmost != NULL);
    921. rightmost->taken = true;
    922. // Find last untaken point;
    923. edge* tailp = 0;
    924. for(unsigned int i = 0; i < 4; ++i)
    925. {
    926. if(!ordered_x[i].taken)
    927. {
    928. if(!tailp) // if uninitialized
    929. {
    930. tailp = &ordered_x[i];
    931. }
    932. else if (tailp->p.x > ordered_x[i].p.x)
    933. {
    934. tailp = &ordered_x[i];
    935. }
    936. }
    937. }
    938. CV_Assert(tailp != NULL);
    939. tailp->taken = true;
    940. double flstep = (min_y->p.y != leftmost->p.y) ?
    941. (min_y->p.x - leftmost->p.x) / (min_y->p.y - leftmost->p.y) : 0; //first left step
    942. double slstep = (leftmost->p.y != tailp->p.x) ?
    943. (leftmost->p.x - tailp->p.x) / (leftmost->p.y - tailp->p.x) : 0; //second left step
    944. double frstep = (min_y->p.y != rightmost->p.y) ?
    945. (min_y->p.x - rightmost->p.x) / (min_y->p.y - rightmost->p.y) : 0; //first right step
    946. double srstep = (rightmost->p.y != tailp->p.x) ?
    947. (rightmost->p.x - tailp->p.x) / (rightmost->p.y - tailp->p.x) : 0; //second right step
    948. double lstep = flstep, rstep = frstep;
    949. double left_x = min_y->p.x, right_x = min_y->p.x;
    950. // Loop around all points in the region and count those that are aligned.
    951. int min_iter = min_y->p.y;
    952. int max_iter = max_y->p.y;
    953. for(int y = min_iter; y <= max_iter; ++y)
    954. {
    955. if (y < 0 || y >= img_height) continue;
    956. for(int x = int(left_x); x <= int(right_x); ++x)
    957. {
    958. if (x < 0 || x >= img_width) continue;
    959. ++total_pts;
    960. if(isAligned(x, y, rec.theta, rec.prec))
    961. {
    962. ++alg_pts;
    963. }
    964. }
    965. if(y >= leftmost->p.y) { lstep = slstep; }
    966. if(y >= rightmost->p.y) { rstep = srstep; }
    967. left_x += lstep;
    968. right_x += rstep;
    969. }
    970. return nfa(total_pts, alg_pts, rec.p);
    971. }
    972. double myLineSegmentDetectorImpl::nfa(const int& n, const int& k, const double& p) const
    973. {
    974. // Trivial cases
    975. if(n == 0 || k == 0) { return -LOG_NT; }
    976. if(n == k) { return -LOG_NT - double(n) * log10(p); }
    977. double p_term = p / (1 - p);
    978. double log1term = (double(n) + 1) - log_gamma(double(k) + 1)
    979. - log_gamma(double(n-k) + 1)
    980. + double(k) * log(p) + double(n-k) * log(1.0 - p);
    981. double term = exp(log1term);
    982. if(double_equal(term, 0))
    983. {
    984. if(k > n * p) return -log1term / M_LN10 - LOG_NT;
    985. else return -LOG_NT;
    986. }
    987. // Compute more terms if needed
    988. double bin_tail = term;
    989. double tolerance = 0.1; // an error of 10% in the result is accepted
    990. for(int i = k + 1; i <= n; ++i)
    991. {
    992. double bin_term = double(n - i + 1) / double(i);
    993. double mult_term = bin_term * p_term;
    994. term *= mult_term;
    995. bin_tail += term;
    996. if(bin_term < 1)
    997. {
    998. double err = term * ((1 - pow(mult_term, double(n-i+1))) / (1 - mult_term) - 1);
    999. if(err < tolerance * fabs(-log10(bin_tail) - LOG_NT) * bin_tail) break;
    1000. }
    1001. }
    1002. return -log10(bin_tail) - LOG_NT;
    1003. }
    1004. inline bool myLineSegmentDetectorImpl::isAligned(int x, int y, const double& theta, const double& prec) const
    1005. {
    1006. if(x < 0 || y < 0 || x >= angles.cols || y >= angles.rows) { return false; }
    1007. const double& a = angles.at<double>(y, x);
    1008. if(a == NOTDEF) { return false; }
    1009. // It is assumed that 'theta' and 'a' are in the range [-pi,pi]
    1010. double n_theta = theta - a;
    1011. if(n_theta < 0) { n_theta = -n_theta; }
    1012. if(n_theta > M_3_2_PI)
    1013. {
    1014. n_theta -= M_2__PI;
    1015. if(n_theta < 0) n_theta = -n_theta;
    1016. }
    1017. return n_theta <= prec;
    1018. }
    1019. } // namespace cv

     在LSDDetector_custom.cpp文件中引用头文件

    #include "my_lsd.hpp"

    再次编译运行

    四、运行

    1. source devel/setup.bash
    2. roslaunch plvins_estimator plvins_show_linepoint.launch
    3. rosbag play MH_05_difficult.bag

    注意:我们此时需要需要将src/PL-VINSvins_estimator/launch/下的plvins-show-linepoint.launch改为plvins_show_linepoint.launch(注意是下划线)文件名

    数据集下载地址如下:

    kmavvisualinertialdatasets – ASL Datasets

    博主github仓库中的代码全部都修改完毕,适用ubuntu20.04 opencv4

  • 相关阅读:
    HTTP图解基础知识
    c# winform 实际操作XML代码,包括创建、保存、查询、删除窗体演示
    正则表达式
    Pycharm 远程连接服务器(ssh)运行深度学习代码 | 详细步骤
    Web3 的通行证——DID 带来数字身份革命
    【Hello Algorithm】暴力递归到动态规划(一)
    controller接收List入参
    Apollo配置中心-手把手教你搭建Apollo配置中心运行环境
    【logrotate】linux定时文件切割(解决openresty单个日志文件过大问题)
    关于打印输出
  • 原文地址:https://blog.csdn.net/HUASHUDEYANJING/article/details/134254818