Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project-sd-card by
lsd.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2013, OpenCV Foundation, all rights reserved. 00014 // Third party copyrights are property of their respective owners. 00015 // 00016 // Redistribution and use in source and binary forms, with or without modification, 00017 // are permitted provided that the following conditions are met: 00018 // 00019 // * Redistributions of source code must retain the above copyright notice, 00020 // this list of conditions and the following disclaimer. 00021 // 00022 // * Redistributions in binary form must reproduce the above copyright notice, 00023 // this list of conditions and the following disclaimer in the documentation 00024 // and/or other materials provided with the distribution. 00025 // 00026 // * The name of the copyright holders may not be used to endorse or promote products 00027 // derived from this software without specific prior written permission. 00028 // 00029 // This software is provided by the copyright holders and contributors "as is" and 00030 // any express or implied warranties, including, but not limited to, the implied 00031 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00032 // In no event shall the Intel Corporation or contributors be liable for any direct, 00033 // indirect, incidental, special, exemplary, or consequential damages 00034 // (including, but not limited to, procurement of substitute goods or services; 00035 // loss of use, data, or profits; or business interruption) however caused 00036 // and on any theory of liability, whether in contract, strict liability, 00037 // or tort (including negligence or otherwise) arising in any way out of 00038 // the use of this software, even if advised of the possibility of such damage. 00039 // 00040 //M*/ 00041 00042 #include "precomp.hpp" 00043 #include <vector> 00044 00045 ///////////////////////////////////////////////////////////////////////////////////////// 00046 // Default LSD parameters 00047 // SIGMA_SCALE 0.6 - Sigma for Gaussian filter is computed as sigma = sigma_scale/scale. 00048 // QUANT 2.0 - Bound to the quantization error on the gradient norm. 00049 // ANG_TH 22.5 - Gradient angle tolerance in degrees. 00050 // LOG_EPS 0.0 - Detection threshold: -log10(NFA) > log_eps 00051 // DENSITY_TH 0.7 - Minimal density of region points in rectangle. 00052 // N_BINS 1024 - Number of bins in pseudo-ordering of gradient modulus. 00053 00054 #define M_3_2_PI (3 * CV_PI) / 2 // 3/2 pi 00055 #define M_2__PI (2 * CV_PI) // 2 pi 00056 00057 #ifndef M_LN10 00058 #define M_LN10 2.30258509299404568402 00059 #endif 00060 00061 #define NOTDEF double(-1024.0) // Label for pixels with undefined gradient. 00062 00063 #define NOTUSED 0 // Label for pixels not used in yet. 00064 #define USED 1 // Label for pixels already used in detection. 00065 00066 #define RELATIVE_ERROR_FACTOR 100.0 00067 00068 const double DEG_TO_RADS = CV_PI / 180; 00069 00070 #define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) 00071 00072 struct edge 00073 { 00074 cv::Point p; 00075 bool taken; 00076 }; 00077 00078 ///////////////////////////////////////////////////////////////////////////////////////// 00079 00080 inline double distSq(const double x1, const double y1, 00081 const double x2, const double y2) 00082 { 00083 return (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1); 00084 } 00085 00086 inline double dist(const double x1, const double y1, 00087 const double x2, const double y2) 00088 { 00089 return sqrt(distSq(x1, y1, x2, y2)); 00090 } 00091 00092 // Signed angle difference 00093 inline double angle_diff_signed(const double& a, const double& b) 00094 { 00095 double diff = a - b; 00096 while(diff <= -CV_PI) diff += M_2__PI; 00097 while(diff > CV_PI) diff -= M_2__PI; 00098 return diff; 00099 } 00100 00101 // Absolute value angle difference 00102 inline double angle_diff(const double& a, const double& b) 00103 { 00104 return std::fabs(angle_diff_signed(a, b)); 00105 } 00106 00107 // Compare doubles by relative error. 00108 inline bool double_equal(const double& a, const double& b) 00109 { 00110 // trivial case 00111 if(a == b) return true; 00112 00113 double abs_diff = fabs(a - b); 00114 double aa = fabs(a); 00115 double bb = fabs(b); 00116 double abs_max = (aa > bb)? aa : bb; 00117 00118 if(abs_max < DBL_MIN) abs_max = DBL_MIN; 00119 00120 return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); 00121 } 00122 00123 inline bool AsmallerB_XoverY(const edge& a, const edge& b) 00124 { 00125 if (a.p.x == b.p.x) return a.p.y < b.p.y; 00126 else return a.p.x < b.p.x; 00127 } 00128 00129 /** 00130 * Computes the natural logarithm of the absolute value of 00131 * the gamma function of x using Windschitl method. 00132 * See http://www.rskey.org/gamma.htm 00133 */ 00134 inline double log_gamma_windschitl(const double& x) 00135 { 00136 return 0.918938533204673 + (x-0.5)*log(x) - x 00137 + 0.5*x*log(x*sinh(1/x) + 1/(810.0*pow(x, 6.0))); 00138 } 00139 00140 /** 00141 * Computes the natural logarithm of the absolute value of 00142 * the gamma function of x using the Lanczos approximation. 00143 * See http://www.rskey.org/gamma.htm 00144 */ 00145 inline double log_gamma_lanczos(const double& x) 00146 { 00147 static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, 00148 8687.24529705, 1168.92649479, 83.8676043424, 00149 2.50662827511 }; 00150 double a = (x + 0.5) * log(x + 5.5) - (x + 5.5); 00151 double b = 0; 00152 for(int n = 0; n < 7; ++n) 00153 { 00154 a -= log(x + double(n)); 00155 b += q[n] * pow(x, double(n)); 00156 } 00157 return a + log(b); 00158 } 00159 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// 00160 00161 namespace cv{ 00162 00163 class LineSegmentDetectorImpl : public LineSegmentDetector 00164 { 00165 public: 00166 00167 /** 00168 * Create a LineSegmentDetectorImpl object. Specifying scale, number of subdivisions for the image, should the lines be refined and other constants as follows: 00169 * 00170 * @param _refine How should the lines found be refined? 00171 * LSD_REFINE_NONE - No refinement applied. 00172 * LSD_REFINE_STD - Standard refinement is applied. E.g. breaking arches into smaller line approximations. 00173 * LSD_REFINE_ADV - Advanced refinement. Number of false alarms is calculated, 00174 * lines are refined through increase of precision, decrement in size, etc. 00175 * @param _scale The scale of the image that will be used to find the lines. Range (0..1]. 00176 * @param _sigma_scale Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale. 00177 * @param _quant Bound to the quantization error on the gradient norm. 00178 * @param _ang_th Gradient angle tolerance in degrees. 00179 * @param _log_eps Detection threshold: -log10(NFA) > _log_eps 00180 * @param _density_th Minimal density of aligned region points in rectangle. 00181 * @param _n_bins Number of bins in pseudo-ordering of gradient modulus. 00182 */ 00183 LineSegmentDetectorImpl(int _refine = LSD_REFINE_STD, double _scale = 0.8, 00184 double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, 00185 double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); 00186 00187 /** 00188 * Detect lines in the input image. 00189 * 00190 * @param _image A grayscale(CV_8UC1) input image. 00191 * If only a roi needs to be selected, use 00192 * lsd_ptr->detect(image(roi), ..., lines); 00193 * lines += Scalar(roi.x, roi.y, roi.x, roi.y); 00194 * @param _lines Return: A vector of Vec4i or Vec4f elements specifying the beginning and ending point of a line. 00195 * Where Vec4i/Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. 00196 * Returned lines are strictly oriented depending on the gradient. 00197 * @param width Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. 00198 * @param prec Return: Vector of precisions with which the lines are found. 00199 * @param nfa Return: Vector containing number of false alarms in the line region, with precision of 10%. 00200 * The bigger the value, logarithmically better the detection. 00201 * * -1 corresponds to 10 mean false alarms 00202 * * 0 corresponds to 1 mean false alarm 00203 * * 1 corresponds to 0.1 mean false alarms 00204 * This vector will be calculated _only_ when the objects type is REFINE_ADV 00205 */ 00206 void detect(InputArray _image, OutputArray _lines, 00207 OutputArray width = noArray(), OutputArray prec = noArray(), 00208 OutputArray nfa = noArray()); 00209 00210 /** 00211 * Draw lines on the given canvas. 00212 * 00213 * @param image The image, where lines will be drawn. 00214 * Should have the size of the image, where the lines were found 00215 * @param lines The lines that need to be drawn 00216 */ 00217 void drawSegments(InputOutputArray _image, InputArray lines); 00218 00219 /** 00220 * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. 00221 * 00222 * @param size The size of the image, where lines1 and lines2 were found. 00223 * @param lines1 The first lines that need to be drawn. Color - Blue. 00224 * @param lines2 The second lines that need to be drawn. Color - Red. 00225 * @param image An optional image, where lines will be drawn. 00226 * Should have the size of the image, where the lines were found 00227 * @return The number of mismatching pixels between lines1 and lines2. 00228 */ 00229 int compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image = noArray()); 00230 00231 private: 00232 Mat image; 00233 Mat_<double> scaled_image; 00234 double *scaled_image_data; 00235 Mat_<double> angles; // in rads 00236 double *angles_data; 00237 Mat_<double> modgrad; 00238 double *modgrad_data; 00239 Mat_<uchar> used; 00240 00241 int img_width; 00242 int img_height; 00243 double LOG_NT; 00244 00245 bool w_needed; 00246 bool p_needed; 00247 bool n_needed; 00248 00249 const double SCALE; 00250 const int doRefine; 00251 const double SIGMA_SCALE; 00252 const double QUANT; 00253 const double ANG_TH; 00254 const double LOG_EPS; 00255 const double DENSITY_TH; 00256 const int N_BINS; 00257 00258 struct RegionPoint { 00259 int x; 00260 int y; 00261 uchar* used; 00262 double angle; 00263 double modgrad; 00264 }; 00265 00266 00267 struct coorlist 00268 { 00269 Point2i p; 00270 struct coorlist* next; 00271 }; 00272 00273 struct rect 00274 { 00275 double x1, y1, x2, y2; // first and second point of the line segment 00276 double width; // rectangle width 00277 double x, y; // center of the rectangle 00278 double theta; // angle 00279 double dx,dy; // (dx,dy) is vector oriented as the line segment 00280 double prec; // tolerance angle 00281 double p; // probability of a point with angle within 'prec' 00282 }; 00283 00284 LineSegmentDetectorImpl& operator= (const LineSegmentDetectorImpl&); // to quiet MSVC 00285 00286 /** 00287 * Detect lines in the whole input image. 00288 * 00289 * @param lines Return: A vector of Vec4f elements specifying the beginning and ending point of a line. 00290 * Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end. 00291 * Returned lines are strictly oriented depending on the gradient. 00292 * @param widths Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. 00293 * @param precisions Return: Vector of precisions with which the lines are found. 00294 * @param nfas Return: Vector containing number of false alarms in the line region, with precision of 10%. 00295 * The bigger the value, logarithmically better the detection. 00296 * * -1 corresponds to 10 mean false alarms 00297 * * 0 corresponds to 1 mean false alarm 00298 * * 1 corresponds to 0.1 mean false alarms 00299 */ 00300 void flsd(std::vector<Vec4f>& lines, 00301 std::vector<double>& widths, std::vector<double>& precisions, 00302 std::vector<double>& nfas); 00303 00304 /** 00305 * Finds the angles and the gradients of the image. Generates a list of pseudo ordered points. 00306 * 00307 * @param threshold The minimum value of the angle that is considered defined, otherwise NOTDEF 00308 * @param n_bins The number of bins with which gradients are ordered by, using bucket sort. 00309 * @param list Return: Vector of coordinate points that are pseudo ordered by magnitude. 00310 * Pixels would be ordered by norm value, up to a precision given by max_grad/n_bins. 00311 */ 00312 void ll_angle(const double& threshold, const unsigned int& n_bins, std::vector<coorlist>& list); 00313 00314 /** 00315 * Grow a region starting from point s with a defined precision, 00316 * returning the containing points size and the angle of the gradients. 00317 * 00318 * @param s Starting point for the region. 00319 * @param reg Return: Vector of points, that are part of the region 00320 * @param reg_size Return: The size of the region. 00321 * @param reg_angle Return: The mean angle of the region. 00322 * @param prec The precision by which each region angle should be aligned to the mean. 00323 */ 00324 void region_grow(const Point2i& s, std::vector<RegionPoint>& reg, 00325 int& reg_size, double& reg_angle, const double& prec); 00326 00327 /** 00328 * Finds the bounding rotated rectangle of a region. 00329 * 00330 * @param reg The region of points, from which the rectangle to be constructed from. 00331 * @param reg_size The number of points in the region. 00332 * @param reg_angle The mean angle of the region. 00333 * @param prec The precision by which points were found. 00334 * @param p Probability of a point with angle within 'prec'. 00335 * @param rec Return: The generated rectangle. 00336 */ 00337 void region2rect(const std::vector<RegionPoint>& reg, const int reg_size, const double reg_angle, 00338 const double prec, const double p, rect& rec) const; 00339 00340 /** 00341 * Compute region's angle as the principal inertia axis of the region. 00342 * @return Regions angle. 00343 */ 00344 double get_theta(const std::vector<RegionPoint>& reg, const int& reg_size, const double& x, 00345 const double& y, const double& reg_angle, const double& prec) const; 00346 00347 /** 00348 * An estimation of the angle tolerance is performed by the standard deviation of the angle at points 00349 * near the region's starting point. Then, a new region is grown starting from the same point, but using the 00350 * estimated angle tolerance. If this fails to produce a rectangle with the right density of region points, 00351 * 'reduce_region_radius' is called to try to satisfy this condition. 00352 */ 00353 bool refine(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle, 00354 const double prec, double p, rect& rec, const double& density_th); 00355 00356 /** 00357 * Reduce the region size, by elimination the points far from the starting point, until that leads to 00358 * rectangle with the right density of region points or to discard the region if too small. 00359 */ 00360 bool reduce_region_radius(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle, 00361 const double prec, double p, rect& rec, double density, const double& density_th); 00362 00363 /** 00364 * Try some rectangles variations to improve NFA value. Only if the rectangle is not meaningful (i.e., log_nfa <= log_eps). 00365 * @return The new NFA value. 00366 */ 00367 double rect_improve(rect& rec) const; 00368 00369 /** 00370 * Calculates the number of correctly aligned points within the rectangle. 00371 * @return The new NFA value. 00372 */ 00373 double rect_nfa(const rect& rec) const; 00374 00375 /** 00376 * Computes the NFA values based on the total number of points, points that agree. 00377 * n, k, p are the binomial parameters. 00378 * @return The new NFA value. 00379 */ 00380 double nfa(const int& n, const int& k, const double& p) const; 00381 00382 /** 00383 * Is the point at place 'address' aligned to angle theta, up to precision 'prec'? 00384 * @return Whether the point is aligned. 00385 */ 00386 bool isAligned(const int& address, const double& theta, const double& prec) const; 00387 }; 00388 00389 ///////////////////////////////////////////////////////////////////////////////////////// 00390 00391 CV_EXPORTS Ptr<LineSegmentDetector> createLineSegmentDetector( 00392 int _refine, double _scale, double _sigma_scale, double _quant, double _ang_th, 00393 double _log_eps, double _density_th, int _n_bins) 00394 { 00395 return makePtr<LineSegmentDetectorImpl>( 00396 _refine, _scale, _sigma_scale, _quant, _ang_th, 00397 _log_eps, _density_th, _n_bins); 00398 } 00399 00400 ///////////////////////////////////////////////////////////////////////////////////////// 00401 00402 LineSegmentDetectorImpl::LineSegmentDetectorImpl(int _refine, double _scale, double _sigma_scale, double _quant, 00403 double _ang_th, double _log_eps, double _density_th, int _n_bins) 00404 :SCALE(_scale), doRefine(_refine), SIGMA_SCALE(_sigma_scale), QUANT(_quant), 00405 ANG_TH(_ang_th), LOG_EPS(_log_eps), DENSITY_TH(_density_th), N_BINS(_n_bins) 00406 { 00407 CV_Assert(_scale > 0 && _sigma_scale > 0 && _quant >= 0 && 00408 _ang_th > 0 && _ang_th < 180 && _density_th >= 0 && _density_th < 1 && 00409 _n_bins > 0); 00410 } 00411 00412 void LineSegmentDetectorImpl::detect(InputArray _image, OutputArray _lines, 00413 OutputArray _width, OutputArray _prec, OutputArray _nfa) 00414 { 00415 Mat_<double> img = _image.getMat(); 00416 CV_Assert(!img.empty() && img.channels() == 1); 00417 00418 // Convert image to double 00419 img.convertTo(image, CV_64FC1); 00420 00421 std::vector<Vec4f> lines; 00422 std::vector<double> w, p, n; 00423 w_needed = _width.needed(); 00424 p_needed = _prec.needed(); 00425 if (doRefine < LSD_REFINE_ADV) 00426 n_needed = false; 00427 else 00428 n_needed = _nfa.needed(); 00429 00430 flsd(lines, w, p, n); 00431 00432 Mat(lines).copyTo(_lines); 00433 if(w_needed) Mat(w).copyTo(_width); 00434 if(p_needed) Mat(p).copyTo(_prec); 00435 if(n_needed) Mat(n).copyTo(_nfa); 00436 } 00437 00438 void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines, 00439 std::vector<double>& widths, std::vector<double>& precisions, 00440 std::vector<double>& nfas) 00441 { 00442 // Angle tolerance 00443 const double prec = CV_PI * ANG_TH / 180; 00444 const double p = ANG_TH / 180; 00445 const double rho = QUANT / sin(prec); // gradient magnitude threshold 00446 00447 std::vector<coorlist> list; 00448 if(SCALE != 1) 00449 { 00450 Mat gaussian_img; 00451 const double sigma = (SCALE < 1)?(SIGMA_SCALE / SCALE):(SIGMA_SCALE); 00452 const double sprec = 3; 00453 const unsigned int h = (unsigned int)(ceil(sigma * sqrt(2 * sprec * log(10.0)))); 00454 Size ksize(1 + 2 * h, 1 + 2 * h); // kernel size 00455 GaussianBlur(image, gaussian_img, ksize, sigma); 00456 // Scale image to needed size 00457 resize(gaussian_img, scaled_image, Size(), SCALE, SCALE); 00458 ll_angle(rho, N_BINS, list); 00459 } 00460 else 00461 { 00462 scaled_image = image; 00463 ll_angle(rho, N_BINS, list); 00464 } 00465 00466 LOG_NT = 5 * (log10(double(img_width)) + log10(double(img_height))) / 2 + log10(11.0); 00467 const int min_reg_size = int(-LOG_NT/log10(p)); // minimal number of points in region that can give a meaningful event 00468 00469 // // Initialize region only when needed 00470 // Mat region = Mat::zeros(scaled_image.size(), CV_8UC1); 00471 used = Mat_<uchar>::zeros(scaled_image.size()); // zeros = NOTUSED 00472 std::vector<RegionPoint> reg(img_width * img_height); 00473 00474 // Search for line segments 00475 unsigned int ls_count = 0; 00476 for(size_t i = 0, list_size = list.size(); i < list_size; ++i) 00477 { 00478 unsigned int adx = list[i].p.x + list[i].p.y * img_width; 00479 if((used.ptr()[adx] == NOTUSED) && (angles_data[adx] != NOTDEF)) 00480 { 00481 int reg_size; 00482 double reg_angle; 00483 region_grow(list[i].p, reg, reg_size, reg_angle, prec); 00484 00485 // Ignore small regions 00486 if(reg_size < min_reg_size) { continue; } 00487 00488 // Construct rectangular approximation for the region 00489 rect rec; 00490 region2rect(reg, reg_size, reg_angle, prec, p, rec); 00491 00492 double log_nfa = -1; 00493 if(doRefine > LSD_REFINE_NONE) 00494 { 00495 // At least REFINE_STANDARD lvl. 00496 if(!refine(reg, reg_size, reg_angle, prec, p, rec, DENSITY_TH)) { continue; } 00497 00498 if(doRefine >= LSD_REFINE_ADV) 00499 { 00500 // Compute NFA 00501 log_nfa = rect_improve(rec); 00502 if(log_nfa <= LOG_EPS) { continue; } 00503 } 00504 } 00505 // Found new line 00506 ++ls_count; 00507 00508 // Add the offset 00509 rec.x1 += 0.5; rec.y1 += 0.5; 00510 rec.x2 += 0.5; rec.y2 += 0.5; 00511 00512 // scale the result values if a sub-sampling was performed 00513 if(SCALE != 1) 00514 { 00515 rec.x1 /= SCALE; rec.y1 /= SCALE; 00516 rec.x2 /= SCALE; rec.y2 /= SCALE; 00517 rec.width /= SCALE; 00518 } 00519 00520 //Store the relevant data 00521 lines.push_back(Vec4f(float(rec.x1), float(rec.y1), float(rec.x2), float(rec.y2))); 00522 if(w_needed) widths.push_back(rec.width); 00523 if(p_needed) precisions.push_back(rec.p); 00524 if(n_needed && doRefine >= LSD_REFINE_ADV) nfas.push_back(log_nfa); 00525 00526 00527 // //Add the linesID to the region on the image 00528 // for(unsigned int el = 0; el < reg_size; el++) 00529 // { 00530 // region.data[reg[i].x + reg[i].y * width] = ls_count; 00531 // } 00532 } 00533 } 00534 } 00535 00536 void LineSegmentDetectorImpl::ll_angle(const double& threshold, 00537 const unsigned int& n_bins, 00538 std::vector<coorlist>& list) 00539 { 00540 //Initialize data 00541 angles = Mat_<double>(scaled_image.size()); 00542 modgrad = Mat_<double>(scaled_image.size()); 00543 00544 angles_data = angles.ptr<double>(0); 00545 modgrad_data = modgrad.ptr<double>(0); 00546 scaled_image_data = scaled_image.ptr<double>(0); 00547 00548 img_width = scaled_image.cols; 00549 img_height = scaled_image.rows; 00550 00551 // Undefined the down and right boundaries 00552 angles.row(img_height - 1).setTo(NOTDEF); 00553 angles.col(img_width - 1).setTo(NOTDEF); 00554 00555 // Computing gradient for remaining pixels 00556 CV_Assert(scaled_image.isContinuous() && 00557 modgrad.isContinuous() && 00558 angles.isContinuous()); // Accessing image data linearly 00559 00560 double max_grad = -1; 00561 for(int y = 0; y < img_height - 1; ++y) 00562 { 00563 for(int addr = y * img_width, addr_end = addr + img_width - 1; addr < addr_end; ++addr) 00564 { 00565 double DA = scaled_image_data[addr + img_width + 1] - scaled_image_data[addr]; 00566 double BC = scaled_image_data[addr + 1] - scaled_image_data[addr + img_width]; 00567 double gx = DA + BC; // gradient x component 00568 double gy = DA - BC; // gradient y component 00569 double norm = std::sqrt((gx * gx + gy * gy) / 4); // gradient norm 00570 00571 modgrad_data[addr] = norm; // store gradient 00572 00573 if (norm <= threshold) // norm too small, gradient no defined 00574 { 00575 angles_data[addr] = NOTDEF; 00576 } 00577 else 00578 { 00579 angles_data[addr] = fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS; // gradient angle computation 00580 if (norm > max_grad) { max_grad = norm; } 00581 } 00582 00583 } 00584 } 00585 00586 // Compute histogram of gradient values 00587 list = std::vector<coorlist>(img_width * img_height); 00588 std::vector<coorlist*> range_s(n_bins); 00589 std::vector<coorlist*> range_e(n_bins); 00590 unsigned int count = 0; 00591 double bin_coef = (max_grad > 0) ? double(n_bins - 1) / max_grad : 0; // If all image is smooth, max_grad <= 0 00592 00593 for(int y = 0; y < img_height - 1; ++y) 00594 { 00595 const double* norm = modgrad_data + y * img_width; 00596 for(int x = 0; x < img_width - 1; ++x, ++norm) 00597 { 00598 // Store the point in the right bin according to its norm 00599 int i = int((*norm) * bin_coef); 00600 if(!range_e[i]) 00601 { 00602 range_e[i] = range_s[i] = &list[count]; 00603 ++count; 00604 } 00605 else 00606 { 00607 range_e[i]->next = &list[count]; 00608 range_e[i] = &list[count]; 00609 ++count; 00610 } 00611 range_e[i]->p = Point(x, y); 00612 range_e[i]->next = 0; 00613 } 00614 } 00615 00616 // Sort 00617 int idx = n_bins - 1; 00618 for(;idx > 0 && !range_s[idx]; --idx); 00619 coorlist* start = range_s[idx]; 00620 coorlist* end = range_e[idx]; 00621 if(start) 00622 { 00623 while(idx > 0) 00624 { 00625 --idx; 00626 if(range_s[idx]) 00627 { 00628 end->next = range_s[idx]; 00629 end = range_e[idx]; 00630 } 00631 } 00632 } 00633 } 00634 00635 void LineSegmentDetectorImpl::region_grow(const Point2i& s, std::vector<RegionPoint>& reg, 00636 int& reg_size, double& reg_angle, const double& prec) 00637 { 00638 // Point to this region 00639 reg_size = 1; 00640 reg[0].x = s.x; 00641 reg[0].y = s.y; 00642 int addr = s.x + s.y * img_width; 00643 reg[0].used = used.ptr() + addr; 00644 reg_angle = angles_data[addr]; 00645 reg[0].angle = reg_angle; 00646 reg[0].modgrad = modgrad_data[addr]; 00647 00648 float sumdx = float(std::cos(reg_angle)); 00649 float sumdy = float(std::sin(reg_angle)); 00650 *reg[0].used = USED; 00651 00652 //Try neighboring regions 00653 for(int i = 0; i < reg_size; ++i) 00654 { 00655 const RegionPoint& rpoint = reg[i]; 00656 int xx_min = std::max(rpoint.x - 1, 0), xx_max = std::min(rpoint.x + 1, img_width - 1); 00657 int yy_min = std::max(rpoint.y - 1, 0), yy_max = std::min(rpoint.y + 1, img_height - 1); 00658 for(int yy = yy_min; yy <= yy_max; ++yy) 00659 { 00660 int c_addr = xx_min + yy * img_width; 00661 for(int xx = xx_min; xx <= xx_max; ++xx, ++c_addr) 00662 { 00663 if((used.ptr()[c_addr] != USED) && 00664 (isAligned(c_addr, reg_angle, prec))) 00665 { 00666 // Add point 00667 used.ptr()[c_addr] = USED; 00668 RegionPoint& region_point = reg[reg_size]; 00669 region_point.x = xx; 00670 region_point.y = yy; 00671 region_point.used = &(used.ptr()[c_addr]); 00672 region_point.modgrad = modgrad_data[c_addr]; 00673 const double& angle = angles_data[c_addr]; 00674 region_point.angle = angle; 00675 ++reg_size; 00676 00677 // Update region's angle 00678 sumdx += cos(float(angle)); 00679 sumdy += sin(float(angle)); 00680 // reg_angle is used in the isAligned, so it needs to be updates? 00681 reg_angle = fastAtan2(sumdy, sumdx) * DEG_TO_RADS; 00682 } 00683 } 00684 } 00685 } 00686 } 00687 00688 void LineSegmentDetectorImpl::region2rect(const std::vector<RegionPoint>& reg, const int reg_size, 00689 const double reg_angle, const double prec, const double p, rect& rec) const 00690 { 00691 double x = 0, y = 0, sum = 0; 00692 for(int i = 0; i < reg_size; ++i) 00693 { 00694 const RegionPoint& pnt = reg[i]; 00695 const double& weight = pnt.modgrad; 00696 x += double(pnt.x) * weight; 00697 y += double(pnt.y) * weight; 00698 sum += weight; 00699 } 00700 00701 // Weighted sum must differ from 0 00702 CV_Assert(sum > 0); 00703 00704 x /= sum; 00705 y /= sum; 00706 00707 double theta = get_theta(reg, reg_size, x, y, reg_angle, prec); 00708 00709 // Find length and width 00710 double dx = cos(theta); 00711 double dy = sin(theta); 00712 double l_min = 0, l_max = 0, w_min = 0, w_max = 0; 00713 00714 for(int i = 0; i < reg_size; ++i) 00715 { 00716 double regdx = double(reg[i].x) - x; 00717 double regdy = double(reg[i].y) - y; 00718 00719 double l = regdx * dx + regdy * dy; 00720 double w = -regdx * dy + regdy * dx; 00721 00722 if(l > l_max) l_max = l; 00723 else if(l < l_min) l_min = l; 00724 if(w > w_max) w_max = w; 00725 else if(w < w_min) w_min = w; 00726 } 00727 00728 // Store values 00729 rec.x1 = x + l_min * dx; 00730 rec.y1 = y + l_min * dy; 00731 rec.x2 = x + l_max * dx; 00732 rec.y2 = y + l_max * dy; 00733 rec.width = w_max - w_min; 00734 rec.x = x; 00735 rec.y = y; 00736 rec.theta = theta; 00737 rec.dx = dx; 00738 rec.dy = dy; 00739 rec.prec = prec; 00740 rec.p = p; 00741 00742 // Min width of 1 pixel 00743 if(rec.width < 1.0) rec.width = 1.0; 00744 } 00745 00746 double LineSegmentDetectorImpl::get_theta(const std::vector<RegionPoint>& reg, const int& reg_size, const double& x, 00747 const double& y, const double& reg_angle, const double& prec) const 00748 { 00749 double Ixx = 0.0; 00750 double Iyy = 0.0; 00751 double Ixy = 0.0; 00752 00753 // Compute inertia matrix 00754 for(int i = 0; i < reg_size; ++i) 00755 { 00756 const double& regx = reg[i].x; 00757 const double& regy = reg[i].y; 00758 const double& weight = reg[i].modgrad; 00759 double dx = regx - x; 00760 double dy = regy - y; 00761 Ixx += dy * dy * weight; 00762 Iyy += dx * dx * weight; 00763 Ixy -= dx * dy * weight; 00764 } 00765 00766 // Check if inertia matrix is null 00767 CV_Assert(!(double_equal(Ixx, 0) && double_equal(Iyy, 0) && double_equal(Ixy, 0))); 00768 00769 // Compute smallest eigenvalue 00770 double lambda = 0.5 * (Ixx + Iyy - sqrt((Ixx - Iyy) * (Ixx - Iyy) + 4.0 * Ixy * Ixy)); 00771 00772 // Compute angle 00773 double theta = (fabs(Ixx)>fabs(Iyy))? 00774 double(fastAtan2(float(lambda - Ixx), float(Ixy))): 00775 double(fastAtan2(float(Ixy), float(lambda - Iyy))); // in degs 00776 theta *= DEG_TO_RADS; 00777 00778 // Correct angle by 180 deg if necessary 00779 if(angle_diff(theta, reg_angle) > prec) { theta += CV_PI; } 00780 00781 return theta; 00782 } 00783 00784 bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle, 00785 const double prec, double p, rect& rec, const double& density_th) 00786 { 00787 double density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); 00788 00789 if (density >= density_th) { return true; } 00790 00791 // Try to reduce angle tolerance 00792 double xc = double(reg[0].x); 00793 double yc = double(reg[0].y); 00794 const double& ang_c = reg[0].angle; 00795 double sum = 0, s_sum = 0; 00796 int n = 0; 00797 00798 for (int i = 0; i < reg_size; ++i) 00799 { 00800 *(reg[i].used) = NOTUSED; 00801 if (dist(xc, yc, reg[i].x, reg[i].y) < rec.width) 00802 { 00803 const double& angle = reg[i].angle; 00804 double ang_d = angle_diff_signed(angle, ang_c); 00805 sum += ang_d; 00806 s_sum += ang_d * ang_d; 00807 ++n; 00808 } 00809 } 00810 double mean_angle = sum / double(n); 00811 // 2 * standard deviation 00812 double tau = 2.0 * sqrt((s_sum - 2.0 * mean_angle * sum) / double(n) + mean_angle * mean_angle); 00813 00814 // Try new region 00815 region_grow(Point(reg[0].x, reg[0].y), reg, reg_size, reg_angle, tau); 00816 00817 if (reg_size < 2) { return false; } 00818 00819 region2rect(reg, reg_size, reg_angle, prec, p, rec); 00820 density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); 00821 00822 if (density < density_th) 00823 { 00824 return reduce_region_radius(reg, reg_size, reg_angle, prec, p, rec, density, density_th); 00825 } 00826 else 00827 { 00828 return true; 00829 } 00830 } 00831 00832 bool LineSegmentDetectorImpl::reduce_region_radius(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle, 00833 const double prec, double p, rect& rec, double density, const double& density_th) 00834 { 00835 // Compute region's radius 00836 double xc = double(reg[0].x); 00837 double yc = double(reg[0].y); 00838 double radSq1 = distSq(xc, yc, rec.x1, rec.y1); 00839 double radSq2 = distSq(xc, yc, rec.x2, rec.y2); 00840 double radSq = radSq1 > radSq2 ? radSq1 : radSq2; 00841 00842 while(density < density_th) 00843 { 00844 radSq *= 0.75*0.75; // Reduce region's radius to 75% of its value 00845 // Remove points from the region and update 'used' map 00846 for(int i = 0; i < reg_size; ++i) 00847 { 00848 if(distSq(xc, yc, double(reg[i].x), double(reg[i].y)) > radSq) 00849 { 00850 // Remove point from the region 00851 *(reg[i].used) = NOTUSED; 00852 std::swap(reg[i], reg[reg_size - 1]); 00853 --reg_size; 00854 --i; // To avoid skipping one point 00855 } 00856 } 00857 00858 if(reg_size < 2) { return false; } 00859 00860 // Re-compute rectangle 00861 region2rect(reg, reg_size ,reg_angle, prec, p, rec); 00862 00863 // Re-compute region points density 00864 density = double(reg_size) / 00865 (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); 00866 } 00867 00868 return true; 00869 } 00870 00871 double LineSegmentDetectorImpl::rect_improve(rect& rec) const 00872 { 00873 double delta = 0.5; 00874 double delta_2 = delta / 2.0; 00875 00876 double log_nfa = rect_nfa(rec); 00877 00878 if(log_nfa > LOG_EPS) return log_nfa; // Good rectangle 00879 00880 // Try to improve 00881 // Finer precision 00882 rect r = rect(rec); // Copy 00883 for(int n = 0; n < 5; ++n) 00884 { 00885 r.p /= 2; 00886 r.prec = r.p * CV_PI; 00887 double log_nfa_new = rect_nfa(r); 00888 if(log_nfa_new > log_nfa) 00889 { 00890 log_nfa = log_nfa_new; 00891 rec = rect(r); 00892 } 00893 } 00894 if(log_nfa > LOG_EPS) return log_nfa; 00895 00896 // Try to reduce width 00897 r = rect(rec); 00898 for(unsigned int n = 0; n < 5; ++n) 00899 { 00900 if((r.width - delta) >= 0.5) 00901 { 00902 r.width -= delta; 00903 double log_nfa_new = rect_nfa(r); 00904 if(log_nfa_new > log_nfa) 00905 { 00906 rec = rect(r); 00907 log_nfa = log_nfa_new; 00908 } 00909 } 00910 } 00911 if(log_nfa > LOG_EPS) return log_nfa; 00912 00913 // Try to reduce one side of rectangle 00914 r = rect(rec); 00915 for(unsigned int n = 0; n < 5; ++n) 00916 { 00917 if((r.width - delta) >= 0.5) 00918 { 00919 r.x1 += -r.dy * delta_2; 00920 r.y1 += r.dx * delta_2; 00921 r.x2 += -r.dy * delta_2; 00922 r.y2 += r.dx * delta_2; 00923 r.width -= delta; 00924 double log_nfa_new = rect_nfa(r); 00925 if(log_nfa_new > log_nfa) 00926 { 00927 rec = rect(r); 00928 log_nfa = log_nfa_new; 00929 } 00930 } 00931 } 00932 if(log_nfa > LOG_EPS) return log_nfa; 00933 00934 // Try to reduce other side of rectangle 00935 r = rect(rec); 00936 for(unsigned int n = 0; n < 5; ++n) 00937 { 00938 if((r.width - delta) >= 0.5) 00939 { 00940 r.x1 -= -r.dy * delta_2; 00941 r.y1 -= r.dx * delta_2; 00942 r.x2 -= -r.dy * delta_2; 00943 r.y2 -= r.dx * delta_2; 00944 r.width -= delta; 00945 double log_nfa_new = rect_nfa(r); 00946 if(log_nfa_new > log_nfa) 00947 { 00948 rec = rect(r); 00949 log_nfa = log_nfa_new; 00950 } 00951 } 00952 } 00953 if(log_nfa > LOG_EPS) return log_nfa; 00954 00955 // Try finer precision 00956 r = rect(rec); 00957 for(unsigned int n = 0; n < 5; ++n) 00958 { 00959 if((r.width - delta) >= 0.5) 00960 { 00961 r.p /= 2; 00962 r.prec = r.p * CV_PI; 00963 double log_nfa_new = rect_nfa(r); 00964 if(log_nfa_new > log_nfa) 00965 { 00966 rec = rect(r); 00967 log_nfa = log_nfa_new; 00968 } 00969 } 00970 } 00971 00972 return log_nfa; 00973 } 00974 00975 double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const 00976 { 00977 int total_pts = 0, alg_pts = 0; 00978 double half_width = rec.width / 2.0; 00979 double dyhw = rec.dy * half_width; 00980 double dxhw = rec.dx * half_width; 00981 00982 std::vector<edge> ordered_x(4); 00983 edge* min_y = &ordered_x[0]; 00984 edge* max_y = &ordered_x[0]; // Will be used for loop range 00985 00986 ordered_x[0].p.x = int(rec.x1 - dyhw); ordered_x[0].p.y = int(rec.y1 + dxhw); ordered_x[0].taken = false; 00987 ordered_x[1].p.x = int(rec.x2 - dyhw); ordered_x[1].p.y = int(rec.y2 + dxhw); ordered_x[1].taken = false; 00988 ordered_x[2].p.x = int(rec.x2 + dyhw); ordered_x[2].p.y = int(rec.y2 - dxhw); ordered_x[2].taken = false; 00989 ordered_x[3].p.x = int(rec.x1 + dyhw); ordered_x[3].p.y = int(rec.y1 - dxhw); ordered_x[3].taken = false; 00990 00991 std::sort(ordered_x.begin(), ordered_x.end(), AsmallerB_XoverY); 00992 00993 // Find min y. And mark as taken. find max y. 00994 for(unsigned int i = 1; i < 4; ++i) 00995 { 00996 if(min_y->p.y > ordered_x[i].p.y) {min_y = &ordered_x[i]; } 00997 if(max_y->p.y < ordered_x[i].p.y) {max_y = &ordered_x[i]; } 00998 } 00999 min_y->taken = true; 01000 01001 // Find leftmost untaken point; 01002 edge* leftmost = 0; 01003 for(unsigned int i = 0; i < 4; ++i) 01004 { 01005 if(!ordered_x[i].taken) 01006 { 01007 if(!leftmost) // if uninitialized 01008 { 01009 leftmost = &ordered_x[i]; 01010 } 01011 else if (leftmost->p.x > ordered_x[i].p.x) 01012 { 01013 leftmost = &ordered_x[i]; 01014 } 01015 } 01016 } 01017 leftmost->taken = true; 01018 01019 // Find rightmost untaken point; 01020 edge* rightmost = 0; 01021 for(unsigned int i = 0; i < 4; ++i) 01022 { 01023 if(!ordered_x[i].taken) 01024 { 01025 if(!rightmost) // if uninitialized 01026 { 01027 rightmost = &ordered_x[i]; 01028 } 01029 else if (rightmost->p.x < ordered_x[i].p.x) 01030 { 01031 rightmost = &ordered_x[i]; 01032 } 01033 } 01034 } 01035 rightmost->taken = true; 01036 01037 // Find last untaken point; 01038 edge* tailp = 0; 01039 for(unsigned int i = 0; i < 4; ++i) 01040 { 01041 if(!ordered_x[i].taken) 01042 { 01043 if(!tailp) // if uninitialized 01044 { 01045 tailp = &ordered_x[i]; 01046 } 01047 else if (tailp->p.x > ordered_x[i].p.x) 01048 { 01049 tailp = &ordered_x[i]; 01050 } 01051 } 01052 } 01053 tailp->taken = true; 01054 01055 double flstep = (min_y->p.y != leftmost->p.y) ? 01056 (min_y->p.x - leftmost->p.x) / (min_y->p.y - leftmost->p.y) : 0; //first left step 01057 double slstep = (leftmost->p.y != tailp->p.x) ? 01058 (leftmost->p.x - tailp->p.x) / (leftmost->p.y - tailp->p.x) : 0; //second left step 01059 01060 double frstep = (min_y->p.y != rightmost->p.y) ? 01061 (min_y->p.x - rightmost->p.x) / (min_y->p.y - rightmost->p.y) : 0; //first right step 01062 double srstep = (rightmost->p.y != tailp->p.x) ? 01063 (rightmost->p.x - tailp->p.x) / (rightmost->p.y - tailp->p.x) : 0; //second right step 01064 01065 double lstep = flstep, rstep = frstep; 01066 01067 double left_x = min_y->p.x, right_x = min_y->p.x; 01068 01069 // Loop around all points in the region and count those that are aligned. 01070 int min_iter = min_y->p.y; 01071 int max_iter = max_y->p.y; 01072 for(int y = min_iter; y <= max_iter; ++y) 01073 { 01074 if (y < 0 || y >= img_height) continue; 01075 01076 int adx = y * img_width + int(left_x); 01077 for(int x = int(left_x); x <= int(right_x); ++x, ++adx) 01078 { 01079 if (x < 0 || x >= img_width) continue; 01080 01081 ++total_pts; 01082 if(isAligned(adx, rec.theta, rec.prec)) 01083 { 01084 ++alg_pts; 01085 } 01086 } 01087 01088 if(y >= leftmost->p.y) { lstep = slstep; } 01089 if(y >= rightmost->p.y) { rstep = srstep; } 01090 01091 left_x += lstep; 01092 right_x += rstep; 01093 } 01094 01095 return nfa(total_pts, alg_pts, rec.p); 01096 } 01097 01098 double LineSegmentDetectorImpl::nfa(const int& n, const int& k, const double& p) const 01099 { 01100 // Trivial cases 01101 if(n == 0 || k == 0) { return -LOG_NT; } 01102 if(n == k) { return -LOG_NT - double(n) * log10(p); } 01103 01104 double p_term = p / (1 - p); 01105 01106 double log1term = (double(n) + 1) - log_gamma(double(k) + 1) 01107 - log_gamma(double(n-k) + 1) 01108 + double(k) * log(p) + double(n-k) * log(1.0 - p); 01109 double term = exp(log1term); 01110 01111 if(double_equal(term, 0)) 01112 { 01113 if(k > n * p) return -log1term / M_LN10 - LOG_NT; 01114 else return -LOG_NT; 01115 } 01116 01117 // Compute more terms if needed 01118 double bin_tail = term; 01119 double tolerance = 0.1; // an error of 10% in the result is accepted 01120 for(int i = k + 1; i <= n; ++i) 01121 { 01122 double bin_term = double(n - i + 1) / double(i); 01123 double mult_term = bin_term * p_term; 01124 term *= mult_term; 01125 bin_tail += term; 01126 if(bin_term < 1) 01127 { 01128 double err = term * ((1 - pow(mult_term, double(n-i+1))) / (1 - mult_term) - 1); 01129 if(err < tolerance * fabs(-log10(bin_tail) - LOG_NT) * bin_tail) break; 01130 } 01131 01132 } 01133 return -log10(bin_tail) - LOG_NT; 01134 } 01135 01136 inline bool LineSegmentDetectorImpl::isAligned(const int& address, const double& theta, const double& prec) const 01137 { 01138 if(address < 0) { return false; } 01139 const double& a = angles_data[address]; 01140 if(a == NOTDEF) { return false; } 01141 01142 // It is assumed that 'theta' and 'a' are in the range [-pi,pi] 01143 double n_theta = theta - a; 01144 if(n_theta < 0) { n_theta = -n_theta; } 01145 if(n_theta > M_3_2_PI) 01146 { 01147 n_theta -= M_2__PI; 01148 if(n_theta < 0) n_theta = -n_theta; 01149 } 01150 01151 return n_theta <= prec; 01152 } 01153 01154 01155 void LineSegmentDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines) 01156 { 01157 CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3)); 01158 01159 Mat gray; 01160 if (_image.channels() == 1) 01161 { 01162 gray = _image.getMatRef(); 01163 } 01164 else if (_image.channels() == 3) 01165 { 01166 cvtColor(_image, gray, CV_BGR2GRAY); 01167 } 01168 01169 // Create a 3 channel image in order to draw colored lines 01170 std::vector<Mat> planes; 01171 planes.push_back(gray); 01172 planes.push_back(gray); 01173 planes.push_back(gray); 01174 01175 merge(planes, _image); 01176 01177 Mat _lines; 01178 _lines = lines.getMat(); 01179 int N = _lines.checkVector(4); 01180 01181 // Draw segments 01182 for(int i = 0; i < N; ++i) 01183 { 01184 const Vec4f& v = _lines.at<Vec4f>(i); 01185 Point2f b(v[0], v[1]); 01186 Point2f e(v[2], v[3]); 01187 line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1); 01188 } 01189 } 01190 01191 01192 int LineSegmentDetectorImpl::compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image) 01193 { 01194 Size sz = size; 01195 if (_image.needed() && _image.size() != size) sz = _image.size(); 01196 CV_Assert(sz.area()); 01197 01198 Mat_<uchar> I1 = Mat_<uchar>::zeros(sz); 01199 Mat_<uchar> I2 = Mat_<uchar>::zeros(sz); 01200 01201 Mat _lines1; 01202 Mat _lines2; 01203 _lines1 = lines1.getMat(); 01204 _lines2 = lines2.getMat(); 01205 int N1 = _lines1.checkVector(4); 01206 int N2 = _lines2.checkVector(4); 01207 01208 // Draw segments 01209 for(int i = 0; i < N1; ++i) 01210 { 01211 Point2f b(_lines1.at<Vec4f>(i)[0], _lines1.at<Vec4f>(i)[1]); 01212 Point2f e(_lines1.at<Vec4f>(i)[2], _lines1.at<Vec4f>(i)[3]); 01213 line(I1, b, e, Scalar::all(255), 1); 01214 } 01215 for(int i = 0; i < N2; ++i) 01216 { 01217 Point2f b(_lines2.at<Vec4f>(i)[0], _lines2.at<Vec4f>(i)[1]); 01218 Point2f e(_lines2.at<Vec4f>(i)[2], _lines2.at<Vec4f>(i)[3]); 01219 line(I2, b, e, Scalar::all(255), 1); 01220 } 01221 01222 // Count the pixels that don't agree 01223 Mat Ixor; 01224 bitwise_xor(I1, I2, Ixor); 01225 int N = countNonZero(Ixor); 01226 01227 if (_image.needed()) 01228 { 01229 CV_Assert(_image.channels() == 3); 01230 Mat img = _image.getMatRef(); 01231 CV_Assert(img.isContinuous() && I1.isContinuous() && I2.isContinuous()); 01232 01233 for (unsigned int i = 0; i < I1.total(); ++i) 01234 { 01235 uchar i1 = I1.ptr()[i]; 01236 uchar i2 = I2.ptr()[i]; 01237 if (i1 || i2) 01238 { 01239 unsigned int base_idx = i * 3; 01240 if (i1) img.ptr()[base_idx] = 255; 01241 else img.ptr()[base_idx] = 0; 01242 img.ptr()[base_idx + 1] = 0; 01243 if (i2) img.ptr()[base_idx + 2] = 255; 01244 else img.ptr()[base_idx + 2] = 0; 01245 } 01246 } 01247 } 01248 01249 return N; 01250 } 01251 01252 } // namespace cv 01253
Generated on Tue Jul 12 2022 14:47:15 by
