├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── P1020171.jpg ├── README.md └── src ├── VPDetection.cpp ├── VPDetection.h ├── lsd.c ├── lsd.h └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set project's name 2 | PROJECT( VanishingPoint ) 3 | 4 | ############################################################################### 5 | # CMake settings 6 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3) 7 | 8 | # OpenCV 9 | FIND_PACKAGE(OpenCV REQUIRED) 10 | 11 | FILE(GLOB_RECURSE HDRS_FILES "src/*.h" "src/*.hpp") 12 | FILE(GLOB_RECURSE SRCS_FILES "src/*.c" "src/*.cpp") 13 | 14 | ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS_FILES} ${HDRS_FILES}) 15 | TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${OpenCV_LIBS}) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /P1020171.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaohulugo/VanishingPointDetection/b8b32a95f6dcec4fc9b9ab2a4443000af8f6cb74/P1020171.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VanishingPointDetection 2 | 3 | 2-Line Exhaustive Searching for Real-Time Vanishing Point Estimation in Manhattan World,Xiaohu Lu, JianYao, Haoang Li, Yahui Liu and Xiaofeng Zhang, WACV2017. 4 | 5 | http://xiaohulugo.github.io/papers/Vanishing_Point_Detection_WACV2017.pdf 6 | 7 | Prerequisites: 8 | --- 9 | OpenCV > 2.4.x 10 | 11 | Usage: 12 | --- 13 | 1. build the project with Cmake 14 | 2. set the internal parameters of the input image (it's ok to use approximate values, for example: pp(cols/2,rows/2), f=1.2*max(cols,rows), but the result will be a little worse) 15 | 16 | Performance: 17 | --- 18 | 40ms on a computer with Intel Core i5-3550p CPU without any optimization and parallel computation in the Release mode. 19 | 20 | ![image](https://github.com/xiaohulugo/images/blob/master/vp_result.bmp) 21 | 22 | Please cite this paper if you use this data or code: 23 | 24 | @InProceedings{Lu_2017_WACV, 25 | author = {Lu, Xiaohu and Yao, Jian and Li, Haoang and Liu, Yahui and Zhang, Xiaofeng}, 26 | title = {2-Line Exhaustive Searching for Real-Time Vanishing Point Estimation in Manhattan World}, 27 | booktitle = {IEEE Winter Conference on Applications of Computer Vision (WACV)}, 28 | month = {March}, 29 | year = {2017} 30 | } 31 | 32 | Feel free to correct my code, if you spotted the mistakes. You are also welcomed to Email me: fangzelu@gmail.com 33 | -------------------------------------------------------------------------------- /src/VPDetection.cpp: -------------------------------------------------------------------------------- 1 | #include "VPDetection.h" 2 | #include "time.h" 3 | #include 4 | 5 | using namespace std; 6 | using namespace cv; 7 | 8 | 9 | VPDetection::VPDetection(void) 10 | { 11 | } 12 | 13 | 14 | VPDetection::~VPDetection(void) 15 | { 16 | } 17 | 18 | void VPDetection::run( std::vector > &lines, cv::Point2d pp, double f, std::vector &vps, std::vector > &clusters ) 19 | { 20 | this->lines = lines; 21 | this->pp = pp; 22 | this->f = f; 23 | this->noiseRatio = 0.5; 24 | 25 | cout<<"get vp hypotheses . . ."< > vpHypo; 27 | getVPHypVia2Lines( vpHypo ); 28 | 29 | cout<<"get sphere grid . . ."< > sphereGrid; 31 | getSphereGrids( sphereGrid ); 32 | 33 | cout<<"test vp hypotheses . . ."< > &vpHypo ) 50 | { 51 | int num = lines.size(); 52 | 53 | double p = 1.0 / 3.0 * pow( 1.0 - noiseRatio, 2 ); 54 | 55 | double confEfficience = 0.9999; 56 | int it = log( 1 - confEfficience ) / log( 1.0 - p ); 57 | 58 | int numVp2 = 360; 59 | double stepVp2 = 2.0 * CV_PI / numVp2; 60 | 61 | // get the parameters of each line 62 | lineInfos.resize( num ); 63 | for ( int i=0; i p1 = ( cv::Mat_(3, 1) << lines[i][0], lines[i][1], 1.0 ); 66 | cv::Mat_ p2 = ( cv::Mat_(3, 1) << lines[i][2], lines[i][3], 1.0 ); 67 | 68 | lineInfos[i].para = p1.cross( p2 ); 69 | 70 | double dx = lines[i][0] - lines[i][2]; 71 | double dy = lines[i][1] - lines[i][3]; 72 | lineInfos[i].length = sqrt( dx * dx + dy * dy ); 73 | 74 | lineInfos[i].orientation = atan2( dy, dx ); 75 | if ( lineInfos[i].orientation < 0 ) 76 | { 77 | lineInfos[i].orientation += CV_PI; 78 | } 79 | } 80 | 81 | // get vp hypothesis for each iteration 82 | vpHypo = std::vector > ( it * numVp2, 3 ); 83 | int count = 0; 84 | srand((unsigned)time(NULL)); 85 | for ( int i = 0; i < it; ++ i ) 86 | { 87 | int idx1 = rand() % num; 88 | int idx2 = rand() % num; 89 | while ( idx2 == idx1 ) 90 | { 91 | idx2 = rand() % num; 92 | } 93 | 94 | // get the vp1 95 | cv::Mat_ vp1_Img = lineInfos[idx1].para.cross( lineInfos[idx2].para ); 96 | if ( vp1_Img(2) == 0 ) 97 | { 98 | i --; 99 | continue; 100 | } 101 | cv::Mat_ vp1 = ( cv::Mat_(3, 1) << vp1_Img(0) / vp1_Img(2) - pp.x, vp1_Img(1) / vp1_Img(2) - pp.y, f ); 102 | if ( vp1(2) == 0 ) { vp1(2) = 0.0011; } 103 | double N = sqrt( vp1(0) * vp1(0) + vp1(1) * vp1(1) + vp1(2) * vp1(2) ); 104 | vp1 *= 1.0 / N; 105 | 106 | // get the vp2 and vp3 107 | cv::Mat_ vp2 = ( cv::Mat_(3, 1) << 0.0, 0.0, 0.0 ); 108 | cv::Mat_ vp3 = ( cv::Mat_(3, 1) << 0.0, 0.0, 0.0 ); 109 | for ( int j = 0; j < numVp2; ++ j ) 110 | { 111 | // vp2 112 | double lambda = j * stepVp2; 113 | 114 | double k1 = vp1(0) * sin( lambda ) + vp1(1) * cos( lambda ); 115 | double k2 = vp1(2); 116 | double phi = atan( - k2 / k1 ); 117 | 118 | double Z = cos( phi ); 119 | double X = sin( phi ) * sin( lambda ); 120 | double Y = sin( phi ) * cos( lambda ); 121 | 122 | vp2(0) = X; vp2(1) = Y; vp2(2) = Z; 123 | if ( vp2(2) == 0.0 ) { vp2(2) = 0.0011; } 124 | N = sqrt( vp2(0) * vp2(0) + vp2(1) * vp2(1) + vp2(2) * vp2(2) ); 125 | vp2 *= 1.0 / N; 126 | if ( vp2(2) < 0 ) { vp2 *= -1.0; } 127 | 128 | // vp3 129 | vp3 = vp1.cross( vp2 ); 130 | if ( vp3(2) == 0.0 ) { vp3(2) = 0.0011; } 131 | N = sqrt( vp3(0) * vp3(0) + vp3(1) * vp3(1) + vp3(2) * vp3(2) ); 132 | vp3 *= 1.0 / N; 133 | if ( vp3(2) < 0 ) { vp3 *= -1.0; } 134 | 135 | // 136 | vpHypo[count][0] = cv::Point3d( vp1(0), vp1(1), vp1(2) ); 137 | vpHypo[count][1] = cv::Point3d( vp2(0), vp2(1), vp2(2) ); 138 | vpHypo[count][2] = cv::Point3d( vp3(0), vp3(1), vp3(2) ); 139 | 140 | count ++; 141 | } 142 | } 143 | } 144 | 145 | 146 | void VPDetection::getSphereGrids( std::vector > &sphereGrid ) 147 | { 148 | // build sphere grid with 1 degree accuracy 149 | double angelAccuracy = 1.0 / 180.0 * CV_PI; 150 | double angleSpanLA = CV_PI / 2.0; 151 | double angleSpanLO = CV_PI * 2.0; 152 | int gridLA = angleSpanLA / angelAccuracy; 153 | int gridLO = angleSpanLO / angelAccuracy; 154 | 155 | sphereGrid = std::vector >( gridLA, gridLO ); 156 | for ( int i=0; i ptIntersect; 167 | double x = 0.0, y = 0.0; 168 | double X = 0.0, Y = 0.0, Z = 0.0, N = 0.0; 169 | double latitude = 0.0, longitude = 0.0; 170 | int LA = 0, LO = 0; 171 | double angleDev = 0.0; 172 | for ( int i=0; i= gridLA ) 196 | { 197 | LA = gridLA - 1; 198 | } 199 | 200 | LO = int( longitude / angelAccuracy ); 201 | if ( LO >= gridLO ) 202 | { 203 | LO = gridLO - 1; 204 | } 205 | 206 | // 207 | angleDev = abs( lineInfos[i].orientation - lineInfos[j].orientation ); 208 | angleDev = min( CV_PI - angleDev, angleDev ); 209 | if ( angleDev > angelTolerance ) 210 | { 211 | continue; 212 | } 213 | 214 | sphereGrid[LA][LO] += sqrt( lineInfos[i].length * lineInfos[j].length ) * ( sin( 2.0 * angleDev ) + 0.2 ); // 0.2 is much robuster 215 | } 216 | } 217 | 218 | // 219 | int halfSize = 1; 220 | int winSize = halfSize * 2 + 1; 221 | int neighNum = winSize * winSize; 222 | 223 | // get the weighted line length of each grid 224 | std::vector > sphereGridNew( gridLA, gridLO ); 225 | for ( int i=halfSize; i > &sphereGrid, std::vector > &vpHypo, std::vector &vps ) 245 | { 246 | int num = vpHypo.size(); 247 | double oneDegree = 1.0 / 180.0 * CV_PI; 248 | 249 | // get the corresponding line length of every hypotheses 250 | std::vector lineLength( num, 0.0 ); 251 | for ( int i = 0; i < num; ++ i ) 252 | { 253 | std::vector vpLALO( 3 ); 254 | for ( int j = 0; j < 3; ++ j ) 255 | { 256 | if ( vpHypo[i][j].z == 0.0 ) 257 | { 258 | continue; 259 | } 260 | 261 | if ( vpHypo[i][j].z > 1.0 || vpHypo[i][j].z < -1.0 ) 262 | { 263 | cout<<1.0000< maxLength ) 290 | { 291 | maxLength = lineLength[i]; 292 | bestIdx = i; 293 | } 294 | } 295 | 296 | vps = vpHypo[bestIdx]; 297 | } 298 | 299 | 300 | void VPDetection::lines2Vps( double thAngle, std::vector &vps, std::vector > &clusters ) 301 | { 302 | clusters.clear(); 303 | clusters.resize( 3 ); 304 | 305 | //get the corresponding vanish points on the image plane 306 | std::vector vp2D( 3 ); 307 | for ( int i = 0; i < 3; ++ i ) 308 | { 309 | vp2D[i].x = vps[i].x * f / vps[i].z + pp.x; 310 | vp2D[i].y = vps[i].y * f / vps[i].z + pp.y; 311 | } 312 | 313 | for ( int i = 0; i < lines.size(); ++ i ) 314 | { 315 | double x1 = lines[i][0]; 316 | double y1 = lines[i][1]; 317 | double x2 = lines[i][2]; 318 | double y2 = lines[i][3]; 319 | double xm = ( x1 + x2 ) / 2.0; 320 | double ym = ( y1 + y2 ) / 2.0; 321 | 322 | double v1x = x1 - x2; 323 | double v1y = y1 - y2; 324 | double N1 = sqrt( v1x * v1x + v1y * v1y ); 325 | v1x /= N1; v1y /= N1; 326 | 327 | double minAngle = 1000.0; 328 | int bestIdx = 0; 329 | for ( int j = 0; j < 3; ++ j ) 330 | { 331 | double v2x = vp2D[j].x - xm; 332 | double v2y = vp2D[j].y - ym; 333 | double N2 = sqrt( v2x * v2x + v2y * v2y ); 334 | v2x /= N2; v2y /= N2; 335 | 336 | double crossValue = v1x * v2x + v1y * v2y; 337 | if ( crossValue > 1.0 ) 338 | { 339 | crossValue = 1.0; 340 | } 341 | if ( crossValue < -1.0 ) 342 | { 343 | crossValue = -1.0; 344 | } 345 | double angle = acos( crossValue ); 346 | angle = min( CV_PI - angle, angle ); 347 | 348 | if ( angle < minAngle ) 349 | { 350 | minAngle = angle; 351 | bestIdx = j; 352 | } 353 | } 354 | 355 | // 356 | if ( minAngle < thAngle ) 357 | { 358 | clusters[bestIdx].push_back( i ); 359 | } 360 | } 361 | } -------------------------------------------------------------------------------- /src/VPDetection.h: -------------------------------------------------------------------------------- 1 | #ifndef _VP_DETECTION_H_ 2 | #define _VP_DETECTION_H_ 3 | #pragma once 4 | 5 | #include 6 | #include 7 | 8 | struct LineInfo 9 | { 10 | cv::Mat_ para; 11 | double length; 12 | double orientation; 13 | }; 14 | 15 | class VPDetection 16 | { 17 | public: 18 | VPDetection(void); 19 | ~VPDetection(void); 20 | 21 | void run( std::vector > &lines, cv::Point2d pp, double f, std::vector &vps, std::vector > &clusters ); 22 | 23 | void getVPHypVia2Lines( std::vector > &vpHypo ); 24 | 25 | void getSphereGrids( std::vector > &sphereGrid ); 26 | 27 | void getBestVpsHyp( std::vector > &sphereGrid, std::vector > &vpHypo, std::vector &vps ); 28 | 29 | void lines2Vps( double thAngle, std::vector &vps, std::vector > &clusters ); 30 | 31 | private: 32 | std::vector > lines; 33 | std::vector lineInfos; 34 | cv::Point2d pp; 35 | double f; 36 | double noiseRatio; 37 | }; 38 | 39 | #endif // _VP_DETECTION_H_ 40 | -------------------------------------------------------------------------------- /src/lsd.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | 3 | LSD - Line Segment Detector on digital images 4 | 5 | Copyright 2007,2008,2009,2010 rafael grompone von gioi (grompone@gmail.com) 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | 20 | ----------------------------------------------------------------------------*/ 21 | 22 | /*---------------------------------------------------------------------------- 23 | 24 | This is an implementation of the Line Segment Detector described in the paper: 25 | 26 | "LSD: A Fast Line Segment Detector with a False Detection Control" 27 | by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, 28 | and Gregory Randall, IEEE Transactions on Pattern Analysis and 29 | Machine Intelligence, vol. 32, no. 4, pp. 722-732, April, 2010. 30 | 31 | and in more details in the CMLA Technical Report: 32 | 33 | "LSD: A Line Segment Detector, Technical Report", 34 | by Rafael Grompone von Gioi, Jeremie Jakubowicz, Jean-Michel Morel, 35 | Gregory Randall, CMLA, ENS Cachan, 2010. 36 | 37 | HISTORY: 38 | version 1.3 - feb 2010: Multiple bug correction and improved code. 39 | version 1.2 - dic 2009: First full Ansi C Language version. 40 | version 1.1 - sep 2009: Systematic subsampling to scale 0.8 41 | and correction to partially handle "angle problem". 42 | version 1.0 - jan 2009: First complete Megawave2 and Ansi C Language version. 43 | 44 | ----------------------------------------------------------------------------*/ 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include "lsd.h" 51 | 52 | #ifndef M_LN10 53 | #define M_LN10 2.30258509299404568402 54 | #endif /* !M_LN10 */ 55 | 56 | #ifndef M_PI 57 | #define M_PI 3.14159265358979323846 58 | #endif /* !M_PI */ 59 | 60 | #ifndef FALSE 61 | #define FALSE 0 62 | #endif /* !FALSE */ 63 | 64 | #ifndef TRUE 65 | #define TRUE 1 66 | #endif /* !TRUE */ 67 | 68 | #define NOTDEF -1024.0 69 | #define M_3_2_PI 4.71238898038 70 | #define M_2__PI 6.28318530718 71 | #define NOTUSED 0 72 | #define USED 1 73 | 74 | /*----------------------------------------------------------------------------*/ 75 | struct coorlist 76 | { 77 | int x,y; 78 | struct coorlist * next; 79 | }; 80 | 81 | /*----------------------------------------------------------------------------*/ 82 | struct point {int x,y;}; 83 | 84 | 85 | /*----------------------------------------------------------------------------*/ 86 | /*------------------------- Miscellaneous functions --------------------------*/ 87 | /*----------------------------------------------------------------------------*/ 88 | 89 | /*----------------------------------------------------------------------------*/ 90 | /* 91 | Fatal error, print a message to standard-error output and exit. 92 | */ 93 | static void error(char * msg) 94 | { 95 | fprintf(stderr,"LSD Error: %s\n",msg); 96 | exit(EXIT_FAILURE); 97 | } 98 | 99 | /*----------------------------------------------------------------------------*/ 100 | /* 101 | Compare doubles by relative error. 102 | 103 | The resulting rounding error after floating point computations 104 | depend on the specific operations done. The same number computed by 105 | different algorithms could present different rounding errors. For a 106 | useful comparison, an estimation of the relative rounding error 107 | should be considered and compared to a factor times EPS. The factor 108 | should be related to the cumulated rounding error in the chain of 109 | computation. Here, as a simplification, a fixed factor is used. 110 | */ 111 | #define RELATIVE_ERROR_FACTOR 100.0 112 | static int double_equal(double a, double b) 113 | { 114 | double abs_diff,aa,bb,abs_max; 115 | 116 | if( a == b ) return TRUE; 117 | 118 | abs_diff = fabs(a-b); 119 | aa = fabs(a); 120 | bb = fabs(b); 121 | abs_max = aa > bb ? aa : bb; 122 | 123 | /* DBL_MIN is the smallest normalized number, thus, the smallest 124 | number whose relative error is bounded by DBL_EPSILON. For 125 | smaller numbers, the same quantization steps as for DBL_MIN 126 | are used. Then, for smaller numbers, a meaningful "relative" 127 | error should be computed by dividing the difference by DBL_MIN. */ 128 | if( abs_max < DBL_MIN ) abs_max = DBL_MIN; 129 | 130 | /* equal if relative error <= factor x eps */ 131 | return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); 132 | } 133 | 134 | /*----------------------------------------------------------------------------*/ 135 | /* 136 | Computes Euclidean distance between point (x1,y1) and point (x2,y2). 137 | */ 138 | static double dist(double x1, double y1, double x2, double y2) 139 | { 140 | return sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ); 141 | } 142 | 143 | 144 | /*----------------------------------------------------------------------------*/ 145 | /*----------------------- 'list of n-tuple' data type ------------------------*/ 146 | /*----------------------------------------------------------------------------*/ 147 | 148 | /*----------------------------------------------------------------------------*/ 149 | /* 150 | Free memory used in n-tuple 'in'. 151 | */ 152 | void free_ntuple_list(ntuple_list in) 153 | { 154 | if( in == NULL || in->values == NULL ) 155 | error("free_ntuple_list: invalid n-tuple input."); 156 | free( (void *) in->values ); 157 | free( (void *) in ); 158 | } 159 | 160 | /*----------------------------------------------------------------------------*/ 161 | /* 162 | Create an n-tuple list and allocate memory for one element. 163 | The parameter 'dim' is the dimension (n) of the n-tuple. 164 | */ 165 | ntuple_list new_ntuple_list(unsigned int dim) 166 | { 167 | ntuple_list n_tuple; 168 | 169 | if( dim <= 0 ) error("new_ntuple_list: 'dim' must be positive."); 170 | 171 | n_tuple = (ntuple_list) malloc( sizeof(struct ntuple_list_s) ); 172 | if( n_tuple == NULL ) error("not enough memory."); 173 | n_tuple->size = 0; 174 | n_tuple->max_size = 1; 175 | n_tuple->dim = dim; 176 | n_tuple->values = (double *) malloc( dim*n_tuple->max_size * sizeof(double) ); 177 | if( n_tuple->values == NULL ) error("not enough memory."); 178 | return n_tuple; 179 | } 180 | 181 | /*----------------------------------------------------------------------------*/ 182 | /* 183 | Enlarge the allocated memory of an n-tuple list. 184 | */ 185 | static void enlarge_ntuple_list(ntuple_list n_tuple) 186 | { 187 | if( n_tuple == NULL || n_tuple->values == NULL || n_tuple->max_size <= 0 ) 188 | error("enlarge_ntuple_list: invalid n-tuple."); 189 | n_tuple->max_size *= 2; 190 | n_tuple->values = 191 | (double *) realloc( (void *) n_tuple->values, 192 | n_tuple->dim * n_tuple->max_size * sizeof(double) ); 193 | if( n_tuple->values == NULL ) error("not enough memory."); 194 | } 195 | 196 | /*----------------------------------------------------------------------------*/ 197 | /* 198 | Add a 5-tuple to an n-tuple list. 199 | */ 200 | static void add_5tuple( ntuple_list out, double v1, double v2, 201 | double v3, double v4, double v5 ) 202 | { 203 | if( out == NULL ) error("add_5tuple: invalid n-tuple input."); 204 | if( out->dim != 5 ) error("add_5tuple: the n-tuple must be a 5-tuple."); 205 | if( out->size == out->max_size ) enlarge_ntuple_list(out); 206 | if( out->values == NULL ) error("add_5tuple: invalid n-tuple input."); 207 | out->values[ out->size * out->dim + 0 ] = v1; 208 | out->values[ out->size * out->dim + 1 ] = v2; 209 | out->values[ out->size * out->dim + 2 ] = v3; 210 | out->values[ out->size * out->dim + 3 ] = v4; 211 | out->values[ out->size * out->dim + 4 ] = v5; 212 | out->size++; 213 | } 214 | 215 | 216 | /*----------------------------------------------------------------------------*/ 217 | /*----------------------------- Image Data Types -----------------------------*/ 218 | /*----------------------------------------------------------------------------*/ 219 | 220 | /*----------------------------------------------------------------------------*/ 221 | /* 222 | Free memory used in image_char 'i'. 223 | */ 224 | void free_image_char(image_char i) 225 | { 226 | if( i == NULL || i->data == NULL ) 227 | error("free_image_char: invalid input image."); 228 | free( (void *) i->data ); 229 | free( (void *) i ); 230 | } 231 | 232 | /*----------------------------------------------------------------------------*/ 233 | /* 234 | Create a new image_char of size 'xsize' times 'ysize'. 235 | */ 236 | image_char new_image_char(unsigned int xsize, unsigned int ysize) 237 | { 238 | image_char image; 239 | 240 | if( xsize == 0 || ysize == 0 ) error("new_image_char: invalid image size."); 241 | 242 | image = (image_char) malloc( sizeof(struct image_char_s) ); 243 | if( image == NULL ) error("not enough memory."); 244 | image->data = (unsigned char *) calloc( xsize*ysize, sizeof(unsigned char) ); 245 | if( image->data == NULL ) error("not enough memory."); 246 | 247 | image->xsize = xsize; 248 | image->ysize = ysize; 249 | 250 | return image; 251 | } 252 | 253 | /*----------------------------------------------------------------------------*/ 254 | /* 255 | Create a new image_char of size 'xsize' times 'ysize', 256 | initialized to the value 'fill_value'. 257 | */ 258 | image_char new_image_char_ini( unsigned int xsize, unsigned int ysize, 259 | unsigned char fill_value ) 260 | { 261 | image_char image = new_image_char(xsize,ysize); 262 | unsigned int N = xsize*ysize; 263 | unsigned int i; 264 | 265 | if( image == NULL || image->data == NULL ) 266 | error("new_image_char_ini: invalid image."); 267 | 268 | for(i=0; idata[i] = fill_value; 269 | 270 | return image; 271 | } 272 | 273 | /*----------------------------------------------------------------------------*/ 274 | /* 275 | Free memory used in image_int 'i'. 276 | */ 277 | void free_image_int(image_int i) 278 | { 279 | if( i == NULL || i->data == NULL ) 280 | error("free_image_int: invalid input image."); 281 | free( (void *) i->data ); 282 | free( (void *) i ); 283 | } 284 | 285 | /*----------------------------------------------------------------------------*/ 286 | /* 287 | Create a new image_int of size 'xsize' times 'ysize'. 288 | */ 289 | image_int new_image_int(unsigned int xsize, unsigned int ysize) 290 | { 291 | image_int image; 292 | 293 | if( xsize == 0 || ysize == 0 ) error("new_image_int: invalid image size."); 294 | 295 | image = (image_int) malloc( sizeof(struct image_int_s) ); 296 | if( image == NULL ) error("not enough memory."); 297 | image->data = (int *) calloc( xsize*ysize, sizeof(int) ); 298 | if( image->data == NULL ) error("not enough memory."); 299 | 300 | image->xsize = xsize; 301 | image->ysize = ysize; 302 | 303 | return image; 304 | } 305 | 306 | /*----------------------------------------------------------------------------*/ 307 | /* 308 | Create a new image_int of size 'xsize' times 'ysize', 309 | initialized to the value 'fill_value'. 310 | */ 311 | image_int new_image_int_ini( unsigned int xsize, unsigned int ysize, 312 | int fill_value ) 313 | { 314 | image_int image = new_image_int(xsize,ysize); 315 | unsigned int N = xsize*ysize; 316 | unsigned int i; 317 | 318 | for(i=0; idata[i] = fill_value; 319 | 320 | return image; 321 | } 322 | 323 | /*----------------------------------------------------------------------------*/ 324 | /* 325 | Free memory used in image_double 'i'. 326 | */ 327 | void free_image_double(image_double i) 328 | { 329 | if( i == NULL || i->data == NULL ) 330 | error("free_image_double: invalid input image."); 331 | free( (void *) i->data ); 332 | free( (void *) i ); 333 | } 334 | 335 | /*----------------------------------------------------------------------------*/ 336 | /* 337 | Create a new image_double of size 'xsize' times 'ysize'. 338 | */ 339 | image_double new_image_double(unsigned int xsize, unsigned int ysize) 340 | { 341 | image_double image; 342 | 343 | if( xsize == 0 || ysize == 0 ) error("new_image_double: invalid image size."); 344 | 345 | image = (image_double) malloc( sizeof(struct image_double_s) ); 346 | if( image == NULL ) error("not enough memory."); 347 | image->data = (double *) calloc( xsize * ysize, sizeof(double) ); 348 | if( image->data == NULL ) error("not enough memory."); 349 | 350 | image->xsize = xsize; 351 | image->ysize = ysize; 352 | 353 | return image; 354 | } 355 | 356 | /*----------------------------------------------------------------------------*/ 357 | /* 358 | Create a new image_double of size 'xsize' times 'ysize', 359 | initialized to the value 'fill_value'. 360 | */ 361 | image_double new_image_double_ini( unsigned int xsize, unsigned int ysize, 362 | double fill_value ) 363 | { 364 | image_double image = new_image_double(xsize,ysize); 365 | unsigned int N = xsize*ysize; 366 | unsigned int i; 367 | 368 | for(i=0; idata[i] = fill_value; 369 | 370 | return image; 371 | } 372 | 373 | 374 | /*----------------------------------------------------------------------------*/ 375 | /*----------------------------- Gaussian filter ------------------------------*/ 376 | /*----------------------------------------------------------------------------*/ 377 | 378 | /*----------------------------------------------------------------------------*/ 379 | /* 380 | Compute a Gaussian kernel of length 'kernel->dim', 381 | standard deviation 'sigma', and centered at value 'mean'. 382 | For example, if mean=0.5, the Gaussian will be centered 383 | in the middle point between values 'kernel->values[0]' 384 | and 'kernel->values[1]'. 385 | */ 386 | static void gaussian_kernel(ntuple_list kernel, double sigma, double mean) 387 | { 388 | double sum = 0.0; 389 | double val; 390 | unsigned int i; 391 | 392 | if( kernel == NULL || kernel->values == NULL ) 393 | error("gaussian_kernel: invalid n-tuple 'kernel'."); 394 | if( sigma <= 0.0 ) error("gaussian_kernel: 'sigma' must be positive."); 395 | 396 | /* compute gaussian kernel */ 397 | if( kernel->max_size < 1 ) enlarge_ntuple_list(kernel); 398 | kernel->size = 1; 399 | for(i=0;idim;i++) 400 | { 401 | val = ( (double) i - mean ) / sigma; 402 | kernel->values[i] = exp( -0.5 * val * val ); 403 | sum += kernel->values[i]; 404 | } 405 | 406 | /* normalization */ 407 | if( sum >= 0.0 ) for(i=0;idim;i++) kernel->values[i] /= sum; 408 | } 409 | 410 | /*----------------------------------------------------------------------------*/ 411 | /* 412 | Subsample image 'in' with Gaussian filtering, to a scale 'scale' 413 | (for example, 0.8 will give a result at 80% of the original size), 414 | using a standard deviation sigma given by: 415 | 416 | sigma = sigma_scale / scale, if scale < 1.0 417 | sigma = sigma_scale, if scale >= 1.0 418 | */ 419 | static image_double gaussian_sampler( image_double in, double scale, 420 | double sigma_scale ) 421 | { 422 | image_double aux,out; 423 | ntuple_list kernel; 424 | unsigned int N,M,h,n,x,y,i; 425 | int xc,yc,j,double_x_size,double_y_size; 426 | double sigma,xx,yy,sum,prec; 427 | 428 | if( in == NULL || in->data == NULL || in->xsize <= 0 || in->ysize <= 0 ) 429 | error("gaussian_sampler: invalid image."); 430 | if( scale <= 0.0 ) error("gaussian_sampler: 'scale' must be positive."); 431 | if( sigma_scale <= 0.0 ) 432 | error("gaussian_sampler: 'sigma_scale' must be positive."); 433 | 434 | /* get memory for images */ 435 | N = (unsigned int) floor( in->xsize * scale ); 436 | M = (unsigned int) floor( in->ysize * scale ); 437 | aux = new_image_double(N,in->ysize); 438 | out = new_image_double(N,M); 439 | 440 | /* sigma, kernel size and memory for the kernel */ 441 | sigma = scale < 1.0 ? sigma_scale / scale : sigma_scale; 442 | /* 443 | The size of the kernel is selected to guarantee that the 444 | the first discarded term is at least 10^prec times smaller 445 | than the central value. For that, h should be larger than x, with 446 | e^(-x^2/2sigma^2) = 1/10^prec. 447 | Then, 448 | x = sigma * sqrt( 2 * prec * ln(10) ). 449 | */ 450 | prec = 3.0; 451 | h = (unsigned int) ceil( sigma * sqrt( 2.0 * prec * log(10.0) ) ); 452 | n = 1+2*h; /* kernel size */ 453 | kernel = new_ntuple_list(n); 454 | 455 | /* auxiliary double image size variables */ 456 | double_x_size = (int) (2 * in->xsize); 457 | double_y_size = (int) (2 * in->ysize); 458 | 459 | /* First subsampling: x axis */ 460 | for(x=0;xxsize;x++) 461 | { 462 | /* 463 | x is the coordinate in the new image. 464 | xx is the corresponding x-value in the original size image. 465 | xc is the integer value, the pixel coordinate of xx. 466 | */ 467 | xx = (double) x / scale; 468 | /* coordinate (0.0,0.0) is in the center of pixel (0,0), 469 | so the pixel with xc=0 get the values of xx from -0.5 to 0.5 */ 470 | xc = (int) floor( xx + 0.5 ); 471 | gaussian_kernel( kernel, sigma, (double) h + xx - (double) xc ); 472 | /* the kernel must be computed for each x because the fine 473 | offset xx-xc is different in each case */ 474 | 475 | for(y=0;yysize;y++) 476 | { 477 | sum = 0.0; 478 | for(i=0;idim;i++) 479 | { 480 | j = xc - h + i; 481 | 482 | /* symmetry boundary condition */ 483 | while( j < 0 ) j += double_x_size; 484 | while( j >= double_x_size ) j -= double_x_size; 485 | if( j >= (int) in->xsize ) j = double_x_size-1-j; 486 | 487 | sum += in->data[ j + y * in->xsize ] * kernel->values[i]; 488 | } 489 | aux->data[ x + y * aux->xsize ] = sum; 490 | } 491 | } 492 | 493 | /* Second subsampling: y axis */ 494 | for(y=0;yysize;y++) 495 | { 496 | /* 497 | y is the coordinate in the new image. 498 | yy is the corresponding x-value in the original size image. 499 | yc is the integer value, the pixel coordinate of xx. 500 | */ 501 | yy = (double) y / scale; 502 | /* coordinate (0.0,0.0) is in the center of pixel (0,0), 503 | so the pixel with yc=0 get the values of yy from -0.5 to 0.5 */ 504 | yc = (int) floor( yy + 0.5 ); 505 | gaussian_kernel( kernel, sigma, (double) h + yy - (double) yc ); 506 | /* the kernel must be computed for each y because the fine 507 | offset yy-yc is different in each case */ 508 | 509 | for(x=0;xxsize;x++) 510 | { 511 | sum = 0.0; 512 | for(i=0;idim;i++) 513 | { 514 | j = yc - h + i; 515 | 516 | /* symmetry boundary condition */ 517 | while( j < 0 ) j += double_y_size; 518 | while( j >= double_y_size ) j -= double_y_size; 519 | if( j >= (int) in->ysize ) j = double_y_size-1-j; 520 | 521 | sum += aux->data[ x + j * aux->xsize ] * kernel->values[i]; 522 | } 523 | out->data[ x + y * out->xsize ] = sum; 524 | } 525 | } 526 | 527 | /* free memory */ 528 | free_ntuple_list(kernel); 529 | free_image_double(aux); 530 | 531 | return out; 532 | } 533 | 534 | 535 | /*----------------------------------------------------------------------------*/ 536 | /*------------------------------ Gradient Angle ------------------------------*/ 537 | /*----------------------------------------------------------------------------*/ 538 | 539 | /*----------------------------------------------------------------------------*/ 540 | /* 541 | Computes the direction of the level line of 'in' at each point. 542 | It returns: 543 | 544 | - an image_double with the angle at each pixel, or NOTDEF if not defined. 545 | - the image_double 'modgrad' (a pointer is passed as argument) 546 | with the gradient magnitude at each point. 547 | - a list of pixels 'list_p' roughly ordered by gradient magnitude. 548 | (the order is made by classing points into bins by gradient magnitude. 549 | the parameters 'n_bins' and 'max_grad' specify the number of 550 | bins and the gradient modulus at the highest bin.) 551 | - a pointer 'mem_p' to the memory used by 'list_p' to be able to 552 | free the memory. 553 | */ 554 | static image_double ll_angle( image_double in, double threshold, 555 | struct coorlist ** list_p, void ** mem_p, 556 | image_double * modgrad, unsigned int n_bins, 557 | double max_grad ) 558 | { 559 | image_double g; 560 | unsigned int n,p,x,y,adr,i; 561 | double com1,com2,gx,gy,norm,norm2; 562 | /* the rest of the variables are used for pseudo-ordering 563 | the gradient magnitude values */ 564 | int list_count = 0; 565 | struct coorlist * list; 566 | struct coorlist ** range_l_s; /* array of pointers to start of bin list */ 567 | struct coorlist ** range_l_e; /* array of pointers to end of bin list */ 568 | struct coorlist * start; 569 | struct coorlist * end; 570 | 571 | /* check parameters */ 572 | if( in == NULL || in->data == NULL || in->xsize <= 0 || in->ysize <= 0 ) 573 | error("ll_angle: invalid image."); 574 | if( threshold < 0.0 ) error("ll_angle: 'threshold' must be positive."); 575 | if( list_p == NULL ) error("ll_angle: NULL pointer 'list_p'."); 576 | if( mem_p == NULL ) error("ll_angle: NULL pointer 'mem_p'."); 577 | if( modgrad == NULL ) error("ll_angle: NULL pointer 'modgrad'."); 578 | if( n_bins <= 0 ) error("ll_angle: 'n_bins' must be positive."); 579 | if( max_grad <= 0.0 ) error("ll_angle: 'max_grad' must be positive."); 580 | 581 | n = in->ysize; 582 | p = in->xsize; 583 | 584 | /* allocate output image */ 585 | g = new_image_double(in->xsize,in->ysize); 586 | 587 | /* get memory for the image of gradient modulus */ 588 | *modgrad = new_image_double(in->xsize,in->ysize); 589 | 590 | /* get memory for "ordered" coordinate list */ 591 | list = (struct coorlist *) calloc(n*p,sizeof(struct coorlist)); 592 | *mem_p = (void *) list; 593 | range_l_s = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *)); 594 | range_l_e = (struct coorlist **) calloc(n_bins,sizeof(struct coorlist *)); 595 | if( list == NULL || range_l_s == NULL || range_l_e == NULL ) 596 | error("not enough memory."); 597 | for(i=0;idata[(n-1)*p+x] = NOTDEF; 601 | for(y=0;ydata[p*y+p-1] = NOTDEF; 602 | 603 | /*** remaining part ***/ 604 | for(x=0;xdata[adr+p+1] - in->data[adr]; 621 | com2 = in->data[adr+1] - in->data[adr+p]; 622 | gx = com1+com2; 623 | gy = com1-com2; 624 | norm2 = gx*gx+gy*gy; 625 | norm = sqrt( norm2 / 4.0 ); 626 | 627 | (*modgrad)->data[adr] = norm; 628 | 629 | if( norm <= threshold ) /* norm too small, gradient no defined */ 630 | g->data[adr] = NOTDEF; 631 | else 632 | { 633 | /* angle computation */ 634 | g->data[adr] = atan2(gx,-gy); 635 | 636 | /* store the point in the right bin according to its norm */ 637 | i = (unsigned int) (norm * (double) n_bins / max_grad); 638 | if( i >= n_bins ) i = n_bins-1; 639 | if( range_l_e[i] == NULL ) 640 | range_l_s[i] = range_l_e[i] = list+list_count++; 641 | else 642 | { 643 | range_l_e[i]->next = list+list_count; 644 | range_l_e[i] = list+list_count++; 645 | } 646 | range_l_e[i]->x = (int) x; 647 | range_l_e[i]->y = (int) y; 648 | range_l_e[i]->next = NULL; 649 | } 650 | } 651 | 652 | /* Make the list of points "ordered" by norm value. 653 | It starts by the larger bin, so the list starts by the 654 | pixels with higher gradient value. 655 | */ 656 | for(i=n_bins-1; i>0 && range_l_s[i]==NULL; i--); 657 | start = range_l_s[i]; 658 | end = range_l_e[i]; 659 | if( start != NULL ) 660 | for(i--;i>0; i--) 661 | if( range_l_s[i] != NULL ) 662 | { 663 | end->next = range_l_s[i]; 664 | end = range_l_e[i]; 665 | } 666 | *list_p = start; 667 | 668 | /* free memory */ 669 | free( (void *) range_l_s ); 670 | free( (void *) range_l_e ); 671 | 672 | return g; 673 | } 674 | 675 | /*----------------------------------------------------------------------------*/ 676 | /* 677 | Is point (x,y) aligned to angle theta, up to precision 'prec'? 678 | */ 679 | static int isaligned( int x, int y, image_double angles, double theta, 680 | double prec ) 681 | { 682 | double a; 683 | 684 | /* check parameters */ 685 | if( angles == NULL || angles->data == NULL ) 686 | error("isaligned: invalid image 'angles'."); 687 | if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) 688 | error("isaligned: (x,y) out of the image."); 689 | if( prec < 0.0 ) error("isaligned: 'prec' must be positive."); 690 | 691 | a = angles->data[ x + y * angles->xsize ]; 692 | 693 | if( a == NOTDEF ) return FALSE; /* there is no risk of double comparison 694 | problem here because we are only 695 | interested in the exact NOTDEF value */ 696 | 697 | /* it is assumed that 'theta' and 'a' are in the range [-pi,pi] */ 698 | theta -= a; 699 | if( theta < 0.0 ) theta = -theta; 700 | if( theta > M_3_2_PI ) 701 | { 702 | theta -= M_2__PI; 703 | if( theta < 0.0 ) theta = -theta; 704 | } 705 | 706 | return theta < prec; 707 | } 708 | 709 | /*----------------------------------------------------------------------------*/ 710 | /* 711 | Absolute value angle difference. 712 | */ 713 | static double angle_diff(double a, double b) 714 | { 715 | a -= b; 716 | while( a <= -M_PI ) a += M_2__PI; 717 | while( a > M_PI ) a -= M_2__PI; 718 | if( a < 0.0 ) a = -a; 719 | return a; 720 | } 721 | 722 | /*----------------------------------------------------------------------------*/ 723 | /* 724 | Signed angle difference. 725 | */ 726 | static double angle_diff_signed(double a, double b) 727 | { 728 | a -= b; 729 | while( a <= -M_PI ) a += M_2__PI; 730 | while( a > M_PI ) a -= M_2__PI; 731 | return a; 732 | } 733 | 734 | 735 | /*----------------------------------------------------------------------------*/ 736 | /*----------------------------- NFA computation ------------------------------*/ 737 | /*----------------------------------------------------------------------------*/ 738 | 739 | /*----------------------------------------------------------------------------*/ 740 | /* 741 | Calculates the natural logarithm of the absolute value of 742 | the gamma function of x using the Lanczos approximation, 743 | see http://www.rskey.org/gamma.htm 744 | 745 | The formula used is 746 | \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) } 747 | (x+5.5)^(x+0.5) e^{-(x+5.5)} 748 | so 749 | \log\Gamma(x) = \log( \sum_{n=0}^{N} q_n x^n ) + (x+0.5) \log(x+5.5) 750 | - (x+5.5) - \sum_{n=0}^{N} \log(x+n) 751 | and 752 | q0 = 75122.6331530 753 | q1 = 80916.6278952 754 | q2 = 36308.2951477 755 | q3 = 8687.24529705 756 | q4 = 1168.92649479 757 | q5 = 83.8676043424 758 | q6 = 2.50662827511 759 | */ 760 | static double log_gamma_lanczos(double x) 761 | { 762 | static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, 763 | 8687.24529705, 1168.92649479, 83.8676043424, 764 | 2.50662827511 }; 765 | double a = (x+0.5) * log(x+5.5) - (x+5.5); 766 | double b = 0.0; 767 | int n; 768 | 769 | for(n=0;n<7;n++) 770 | { 771 | a -= log( x + (double) n ); 772 | b += q[n] * pow( x, (double) n ); 773 | } 774 | return a + log(b); 775 | } 776 | 777 | /*----------------------------------------------------------------------------*/ 778 | /* 779 | Calculates the natural logarithm of the absolute value of 780 | the gamma function of x using Robert H. Windschitl method, 781 | see http://www.rskey.org/gamma.htm 782 | 783 | The formula used is 784 | \Gamma(x) = \sqrt(\frac{2\pi}{x}) ( \frac{x}{e} 785 | \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } )^x 786 | so 787 | \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x 788 | + 0.5x\log( x\sinh(1/x) + \frac{1}{810x^6} ). 789 | 790 | This formula is a good approximation when x > 15. 791 | */ 792 | static double log_gamma_windschitl(double x) 793 | { 794 | return 0.918938533204673 + (x-0.5)*log(x) - x 795 | + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) ); 796 | } 797 | 798 | /*----------------------------------------------------------------------------*/ 799 | /* 800 | Calculates the natural logarithm of the absolute value of 801 | the gamma function of x. When x>15 use log_gamma_windschitl(), 802 | otherwise use log_gamma_lanczos(). 803 | */ 804 | #define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) 805 | 806 | /*----------------------------------------------------------------------------*/ 807 | /* 808 | Computes -log10(NFA) 809 | 810 | NFA stands for Number of False Alarms: 811 | 812 | NFA = NT.b(n,k,p) 813 | 814 | NT - number of tests 815 | b(,,) - tail of binomial distribution with parameters n,k and p 816 | 817 | The value -log10(NFA) is equivalent but more intuitive than NFA: 818 | -1 corresponds to 10 mean false alarms 819 | 0 corresponds to 1 mean false alarm 820 | 1 corresponds to 0.1 mean false alarms 821 | 2 corresponds to 0.01 mean false alarms 822 | ... 823 | 824 | Used this way, the bigger the value, better the detection, 825 | and a logarithmic scale is used. 826 | 827 | Parameters: 828 | n,k,p - binomial parameters. 829 | logNT - logarithm of Number of Tests 830 | */ 831 | #define TABSIZE 100000 832 | static double nfa(int n, int k, double p, double logNT) 833 | { 834 | static double inv[TABSIZE]; /* table to keep computed inverse values */ 835 | double tolerance = 0.1; /* an error of 10% in the result is accepted */ 836 | double log1term,term,bin_term,mult_term,bin_tail,err,p_term; 837 | int i; 838 | 839 | if( n<0 || k<0 || k>n || p<=0.0 || p>=1.0 ) 840 | error("nfa: wrong n, k or p values."); 841 | 842 | if( n==0 || k==0 ) return -logNT; 843 | if( n==k ) return -logNT - (double) n * log10(p); 844 | 845 | p_term = p / (1.0-p); 846 | 847 | /* compute the first term of the series */ 848 | /* 849 | binomial_tail(n,k,p) = sum_{i=k}^n bincoef(n,i) * p^i * (1-p)^{n-i} 850 | where bincoef(n,i) are the binomial coefficients. 851 | But 852 | bincoef(n,k) = gamma(n+1) / ( gamma(k+1) * gamma(n-k+1) ). 853 | We use this to compute the first term. Actually the log of it. 854 | */ 855 | log1term = log_gamma( (double) n + 1.0 ) - log_gamma( (double) k + 1.0 ) 856 | - log_gamma( (double) (n-k) + 1.0 ) 857 | + (double) k * log(p) + (double) (n-k) * log(1.0-p); 858 | term = exp(log1term); 859 | 860 | /* in some cases no more computations are needed */ 861 | if( double_equal(term,0.0) ) /* the first term is almost zero */ 862 | { 863 | if( (double) k > (double) n * p ) /* at begin or end of the tail? */ 864 | return -log1term / M_LN10 - logNT; /* end: use just the first term */ 865 | else 866 | return -logNT; /* begin: the tail is roughly 1 */ 867 | } 868 | 869 | /* compute more terms if needed */ 870 | bin_tail = term; 871 | for(i=k+1;i<=n;i++) 872 | { 873 | /* 874 | As 875 | term_i = bincoef(n,i) * p^i * (1-p)^(n-i) 876 | and 877 | bincoef(n,i)/bincoef(n,i-1) = n-1+1 / i, 878 | then, 879 | term_i / term_i-1 = (n-i+1)/i * p/(1-p) 880 | and 881 | term_i = term_i-1 * (n-i+1)/i * p/(1-p). 882 | 1/i is stored in a table as they are computed, 883 | because divisions are expensive. 884 | p/(1-p) is computed only once and stored in 'p_term'. 885 | */ 886 | bin_term = (double) (n-i+1) * ( ii. 896 | Then, the error on the binomial tail when truncated at 897 | the i term can be bounded by a geometric series of form 898 | term_i * sum mult_term_i^j. */ 899 | err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) / 900 | (1.0-mult_term) - 1.0 ); 901 | 902 | /* One wants an error at most of tolerance*final_result, or: 903 | tolerance * abs(-log10(bin_tail)-logNT). 904 | Now, the error that can be accepted on bin_tail is 905 | given by tolerance*final_result divided by the derivative 906 | of -log10(x) when x=bin_tail. that is: 907 | tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail) 908 | Finally, we truncate the tail if the error is less than: 909 | tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */ 910 | if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break; 911 | } 912 | } 913 | return -log10(bin_tail) - logNT; 914 | } 915 | 916 | 917 | /*----------------------------------------------------------------------------*/ 918 | /*--------------------------- Rectangle structure ----------------------------*/ 919 | /*----------------------------------------------------------------------------*/ 920 | 921 | /*----------------------------------------------------------------------------*/ 922 | struct rect /* line segment with width */ 923 | { 924 | double x1,y1,x2,y2; /* first and second point of the line segment */ 925 | double width; /* rectangle width */ 926 | double x,y; /* center of the rectangle */ 927 | double theta; /* angle */ 928 | double dx,dy; /* vector with the line segment angle */ 929 | double prec; /* tolerance angle */ 930 | double p; /* probability of a point with angle within 'prec' */ 931 | }; 932 | 933 | /*----------------------------------------------------------------------------*/ 934 | /* 935 | Copy one rectangle structure to another. 936 | */ 937 | static void rect_copy(struct rect * in, struct rect * out) 938 | { 939 | if( in == NULL || out == NULL ) error("rect_copy: invalid 'in' or 'out'."); 940 | out->x1 = in->x1; 941 | out->y1 = in->y1; 942 | out->x2 = in->x2; 943 | out->y2 = in->y2; 944 | out->width = in->width; 945 | out->x = in->x; 946 | out->y = in->y; 947 | out->theta = in->theta; 948 | out->dx = in->dx; 949 | out->dy = in->dy; 950 | out->prec = in->prec; 951 | out->p = in->p; 952 | } 953 | 954 | /*----------------------------------------------------------------------------*/ 955 | /* 956 | Rectangle points iterator. 957 | */ 958 | typedef struct 959 | { 960 | double vx[4]; 961 | double vy[4]; 962 | double ys,ye; 963 | int x,y; 964 | } rect_iter; 965 | 966 | /*----------------------------------------------------------------------------*/ 967 | /* 968 | Rectangle points iterator auxiliary function. 969 | */ 970 | static double inter_low(double x, double x1, double y1, double x2, double y2) 971 | { 972 | if( x1 > x2 || x < x1 || x > x2 ) 973 | { 974 | fprintf(stderr,"inter_low: x %g x1 %g x2 %g.\n",x,x1,x2); 975 | error("impossible situation."); 976 | } 977 | if( double_equal(x1,x2) && y1y2 ) return y2; 979 | return y1 + (x-x1) * (y2-y1) / (x2-x1); 980 | } 981 | 982 | /*----------------------------------------------------------------------------*/ 983 | /* 984 | Rectangle points iterator auxiliary function. 985 | */ 986 | static double inter_hi(double x, double x1, double y1, double x2, double y2) 987 | { 988 | if( x1 > x2 || x < x1 || x > x2 ) 989 | { 990 | fprintf(stderr,"inter_hi: x %g x1 %g x2 %g.\n",x,x1,x2); 991 | error("impossible situation."); 992 | } 993 | if( double_equal(x1,x2) && y1y2 ) return y1; 995 | return y1 + (x-x1) * (y2-y1) / (x2-x1); 996 | } 997 | 998 | /*----------------------------------------------------------------------------*/ 999 | /* 1000 | Free memory used by a rectangle iterator. 1001 | */ 1002 | static void ri_del(rect_iter * iter) 1003 | { 1004 | if( iter == NULL ) error("ri_del: NULL iterator."); 1005 | free( (void *) iter ); 1006 | } 1007 | 1008 | /*----------------------------------------------------------------------------*/ 1009 | /* 1010 | Check if the iterator finished the full iteration. 1011 | */ 1012 | static int ri_end(rect_iter * i) 1013 | { 1014 | if( i == NULL ) error("ri_end: NULL iterator."); 1015 | return (double)(i->x) > i->vx[2]; 1016 | } 1017 | 1018 | /*----------------------------------------------------------------------------*/ 1019 | /* 1020 | Increment a rectangle iterator. 1021 | */ 1022 | static void ri_inc(rect_iter * i) 1023 | { 1024 | if( i == NULL ) error("ri_inc: NULL iterator."); 1025 | 1026 | if( (double) (i->x) <= i->vx[2] ) i->y++; 1027 | 1028 | while( (double) (i->y) > i->ye && (double) (i->x) <= i->vx[2] ) 1029 | { 1030 | /* new x */ 1031 | i->x++; 1032 | 1033 | if( (double) (i->x) > i->vx[2] ) return; /* end of iteration */ 1034 | 1035 | /* update lower y limit for the line */ 1036 | if( (double) i->x < i->vx[3] ) 1037 | i->ys = inter_low((double)i->x,i->vx[0],i->vy[0],i->vx[3],i->vy[3]); 1038 | else i->ys = inter_low((double)i->x,i->vx[3],i->vy[3],i->vx[2],i->vy[2]); 1039 | 1040 | /* update upper y limit for the line */ 1041 | if( (double)i->x < i->vx[1] ) 1042 | i->ye = inter_hi((double)i->x,i->vx[0],i->vy[0],i->vx[1],i->vy[1]); 1043 | else i->ye = inter_hi((double)i->x,i->vx[1],i->vy[1],i->vx[2],i->vy[2]); 1044 | 1045 | /* new y */ 1046 | i->y = (int) ceil(i->ys); 1047 | } 1048 | } 1049 | 1050 | /*----------------------------------------------------------------------------*/ 1051 | /* 1052 | Create and initialize a rectangle iterator. 1053 | */ 1054 | static rect_iter * ri_ini(struct rect * r) 1055 | { 1056 | double vx[4],vy[4]; 1057 | int n,offset; 1058 | rect_iter * i; 1059 | 1060 | if( r == NULL ) error("ri_ini: invalid rectangle."); 1061 | 1062 | i = (rect_iter *) malloc(sizeof(rect_iter)); 1063 | if( i == NULL ) error("ri_ini: Not enough memory."); 1064 | 1065 | vx[0] = r->x1 - r->dy * r->width / 2.0; 1066 | vy[0] = r->y1 + r->dx * r->width / 2.0; 1067 | vx[1] = r->x2 - r->dy * r->width / 2.0; 1068 | vy[1] = r->y2 + r->dx * r->width / 2.0; 1069 | vx[2] = r->x2 + r->dy * r->width / 2.0; 1070 | vy[2] = r->y2 - r->dx * r->width / 2.0; 1071 | vx[3] = r->x1 + r->dy * r->width / 2.0; 1072 | vy[3] = r->y1 - r->dx * r->width / 2.0; 1073 | 1074 | if( r->x1 < r->x2 && r->y1 <= r->y2 ) offset = 0; 1075 | else if( r->x1 >= r->x2 && r->y1 < r->y2 ) offset = 1; 1076 | else if( r->x1 > r->x2 && r->y1 >= r->y2 ) offset = 2; 1077 | else offset = 3; 1078 | 1079 | for(n=0; n<4; n++) 1080 | { 1081 | i->vx[n] = vx[(offset+n)%4]; 1082 | i->vy[n] = vy[(offset+n)%4]; 1083 | } 1084 | 1085 | /* starting point */ 1086 | i->x = (int) ceil(i->vx[0]) - 1; 1087 | i->y = (int) ceil(i->vy[0]); 1088 | i->ys = i->ye = -DBL_MAX; 1089 | 1090 | /* advance to the first point */ 1091 | ri_inc(i); 1092 | 1093 | return i; 1094 | } 1095 | 1096 | /*----------------------------------------------------------------------------*/ 1097 | /* 1098 | Compute a rectangle's NFA value. 1099 | */ 1100 | static double rect_nfa(struct rect * rec, image_double angles, double logNT) 1101 | { 1102 | rect_iter * i; 1103 | int pts = 0; 1104 | int alg = 0; 1105 | 1106 | if( rec == NULL ) error("rect_nfa: invalid rectangle."); 1107 | if( angles == NULL ) error("rect_nfa: invalid 'angles'."); 1108 | 1109 | for(i=ri_ini(rec); !ri_end(i); ri_inc(i)) 1110 | if( i->x >= 0 && i->y >= 0 && 1111 | i->x < (int) angles->xsize && i->y < (int) angles->ysize ) 1112 | { 1113 | ++pts; 1114 | if( isaligned(i->x, i->y, angles, rec->theta, rec->prec) ) ++alg; 1115 | } 1116 | ri_del(i); 1117 | 1118 | return nfa(pts,alg,rec->p,logNT); 1119 | } 1120 | 1121 | 1122 | /*----------------------------------------------------------------------------*/ 1123 | /*---------------------------------- Regions ---------------------------------*/ 1124 | /*----------------------------------------------------------------------------*/ 1125 | 1126 | /*----------------------------------------------------------------------------*/ 1127 | /* 1128 | Compute a region's angle. 1129 | */ 1130 | static double get_theta( struct point * reg, int reg_size, double x, double y, 1131 | image_double modgrad, double reg_angle, double prec ) 1132 | { 1133 | double lambda1,lambda2,tmp,theta,weight,sum; 1134 | double Ixx = 0.0; 1135 | double Iyy = 0.0; 1136 | double Ixy = 0.0; 1137 | int i; 1138 | 1139 | /* check parameters */ 1140 | if( reg == NULL ) error("get_theta: invalid region."); 1141 | if( reg_size <= 1 ) error("get_theta: region size <= 1."); 1142 | if( modgrad == NULL || modgrad->data == NULL ) 1143 | error("get_theta: invalid 'modgrad'."); 1144 | if( prec < 0.0 ) error("get_theta: 'prec' must be positive."); 1145 | 1146 | /*----------- theta ---------------------------------------------------*/ 1147 | /* 1148 | Region inertia matrix A: 1149 | Ixx Ixy 1150 | Ixy Iyy 1151 | where 1152 | Ixx = \sum_i y_i^2 1153 | Iyy = \sum_i x_i^2 1154 | Ixy = -\sum_i x_i y_i 1155 | 1156 | lambda1 and lambda2 are the eigenvalues, with lambda1 >= lambda2. 1157 | They are found by solving the characteristic polynomial 1158 | det(\lambda I - A) = 0. 1159 | 1160 | To get the line segment direction we want to get the eigenvector of 1161 | the smaller eigenvalue. We have to solve a,b in: 1162 | a.Ixx + b.Ixy = a.lambda2 1163 | a.Ixy + b.Iyy = b.lambda2 1164 | We want the angle theta = atan(b/a). I can be computed with 1165 | any of the two equations: 1166 | theta = atan( (lambda2-Ixx) / Ixy ) 1167 | or 1168 | theta = atan( Ixy / (lambda2-Iyy) ) 1169 | 1170 | When |Ixx| > |Iyy| we use the first, otherwise the second 1171 | (just to get better numeric precision). 1172 | */ 1173 | sum = 0.0; 1174 | for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; 1177 | Ixx += ( (double) reg[i].y - y ) * ( (double) reg[i].y - y ) * weight; 1178 | Iyy += ( (double) reg[i].x - x ) * ( (double) reg[i].x - x ) * weight; 1179 | Ixy -= ( (double) reg[i].x - x ) * ( (double) reg[i].y - y ) * weight; 1180 | sum += weight; 1181 | } 1182 | if( sum <= 0.0 ) error("get_theta: weights sum less or equal to zero."); 1183 | Ixx /= sum; 1184 | Iyy /= sum; 1185 | Ixy /= sum; 1186 | lambda1 = ( Ixx + Iyy + sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4.0*Ixy*Ixy ) ) / 2.0; 1187 | lambda2 = ( Ixx + Iyy - sqrt( (Ixx-Iyy)*(Ixx-Iyy) + 4.0*Ixy*Ixy ) ) / 2.0; 1188 | if( fabs(lambda1) < fabs(lambda2) ) 1189 | { 1190 | fprintf(stderr,"Ixx %g Iyy %g Ixy %g lamb1 %g lamb2 %g - lamb1 < lamb2\n", 1191 | Ixx,Iyy,Ixy,lambda1,lambda2); 1192 | tmp = lambda1; 1193 | lambda1 = lambda2; 1194 | lambda2 = tmp; 1195 | } 1196 | 1197 | if( fabs(Ixx) > fabs(Iyy) ) 1198 | theta = atan2( lambda2-Ixx, Ixy ); 1199 | else 1200 | theta = atan2( Ixy, lambda2-Iyy ); 1201 | 1202 | /* The previous procedure don't cares about orientation, 1203 | so it could be wrong by 180 degrees. Here is corrected if necessary. */ 1204 | if( angle_diff(theta,reg_angle) > prec ) theta += M_PI; 1205 | 1206 | return theta; 1207 | } 1208 | 1209 | /*----------------------------------------------------------------------------*/ 1210 | /* 1211 | Computes a rectangle that covers a region of points. 1212 | */ 1213 | static void region2rect( struct point * reg, int reg_size, 1214 | image_double modgrad, double reg_angle, 1215 | double prec, double p, struct rect * rec ) 1216 | { 1217 | double x,y,dx,dy,l,w,theta,weight,sum,l_min,l_max,w_min,w_max; 1218 | int i; 1219 | 1220 | /* check parameters */ 1221 | if( reg == NULL ) error("region2rect: invalid region."); 1222 | if( reg_size <= 1 ) error("region2rect: region size <= 1."); 1223 | if( modgrad == NULL || modgrad->data == NULL ) 1224 | error("region2rect: invalid image 'modgrad'."); 1225 | if( rec == NULL ) error("region2rect: invalid 'rec'."); 1226 | 1227 | /* center */ 1228 | x = y = sum = 0.0; 1229 | for(i=0; idata[ reg[i].x + reg[i].y * modgrad->xsize ]; 1232 | x += (double) reg[i].x * weight; 1233 | y += (double) reg[i].y * weight; 1234 | sum += weight; 1235 | } 1236 | if( sum <= 0.0 ) error("region2rect: weights sum equal to zero."); 1237 | x /= sum; 1238 | y /= sum; 1239 | 1240 | /* theta */ 1241 | theta = get_theta(reg,reg_size,x,y,modgrad,reg_angle,prec); 1242 | 1243 | /* length and width */ 1244 | dx = cos(theta); 1245 | dy = sin(theta); 1246 | l_min = l_max = w_min = w_max = 0.0; 1247 | for(i=0; i l_max ) l_max = l; 1253 | if( l < l_min ) l_min = l; 1254 | if( w > w_max ) w_max = w; 1255 | if( w < w_min ) w_min = w; 1256 | } 1257 | 1258 | /* store values */ 1259 | rec->x1 = x + l_min * dx; 1260 | rec->y1 = y + l_min * dy; 1261 | rec->x2 = x + l_max * dx; 1262 | rec->y2 = y + l_max * dy; 1263 | rec->width = w_max - w_min; 1264 | rec->x = x; 1265 | rec->y = y; 1266 | rec->theta = theta; 1267 | rec->dx = dx; 1268 | rec->dy = dy; 1269 | rec->prec = prec; 1270 | rec->p = p; 1271 | 1272 | if( rec->width < 1.0 ) rec->width = 1.0; 1273 | } 1274 | 1275 | /*----------------------------------------------------------------------------*/ 1276 | /* 1277 | Found a region of points that share the same angle, up to a tolerance 'prec', 1278 | starting at point (x,y). 1279 | */ 1280 | static void region_grow( int x, int y, image_double angles, struct point * reg, 1281 | int * reg_size, double * reg_angle, image_char used, 1282 | double prec ) 1283 | { 1284 | double sumdx,sumdy; 1285 | int xx,yy,i; 1286 | 1287 | /* check parameters */ 1288 | if( x < 0 || y < 0 || x >= (int) angles->xsize || y >= (int) angles->ysize ) 1289 | error("region_grow: (x,y) out of the image."); 1290 | if( angles == NULL || angles->data == NULL ) 1291 | error("region_grow: invalid image 'angles'."); 1292 | if( reg == NULL ) error("region_grow: invalid 'reg'."); 1293 | if( reg_size == NULL ) error("region_grow: invalid pointer 'reg_size'."); 1294 | if( reg_angle == NULL ) error("region_grow: invalid pointer 'reg_angle'."); 1295 | if( used == NULL || used->data == NULL ) 1296 | error("region_grow: invalid image 'used'."); 1297 | 1298 | /* first point of the region */ 1299 | *reg_size = 1; 1300 | reg[0].x = x; 1301 | reg[0].y = y; 1302 | *reg_angle = angles->data[x+y*angles->xsize]; 1303 | sumdx = cos(*reg_angle); 1304 | sumdy = sin(*reg_angle); 1305 | used->data[x+y*used->xsize] = USED; 1306 | 1307 | /* try neighbors as new region points */ 1308 | for(i=0; i<*reg_size; i++) 1309 | for(xx=reg[i].x-1; xx<=reg[i].x+1; xx++) 1310 | for(yy=reg[i].y-1; yy<=reg[i].y+1; yy++) 1311 | if( xx>=0 && yy>=0 && xx<(int)used->xsize && yy<(int)used->ysize && 1312 | used->data[xx+yy*used->xsize] != USED && 1313 | isaligned(xx,yy,angles,*reg_angle,prec) ) 1314 | { 1315 | /* add point */ 1316 | used->data[xx+yy*used->xsize] = USED; 1317 | reg[*reg_size].x = xx; 1318 | reg[*reg_size].y = yy; 1319 | ++(*reg_size); 1320 | 1321 | /* update region's angle */ 1322 | sumdx += cos( angles->data[xx+yy*angles->xsize] ); 1323 | sumdy += sin( angles->data[xx+yy*angles->xsize] ); 1324 | *reg_angle = atan2(sumdy,sumdx); 1325 | } 1326 | } 1327 | 1328 | /*----------------------------------------------------------------------------*/ 1329 | /* 1330 | Try some rectangles variations to improve NFA value. 1331 | Only if the rectangle is not meaningful (i.e., log_nfa <= eps). 1332 | */ 1333 | static double rect_improve( struct rect * rec, image_double angles, 1334 | double logNT, double eps ) 1335 | { 1336 | struct rect r; 1337 | double log_nfa,log_nfa_new; 1338 | double delta = 0.5; 1339 | double delta_2 = delta / 2.0; 1340 | int n; 1341 | 1342 | log_nfa = rect_nfa(rec,angles,logNT); 1343 | 1344 | if( log_nfa > eps ) return log_nfa; 1345 | 1346 | /* try finer precisions */ 1347 | rect_copy(rec,&r); 1348 | for(n=0; n<5; n++) 1349 | { 1350 | r.p /= 2.0; 1351 | r.prec = r.p * M_PI; 1352 | log_nfa_new = rect_nfa(&r,angles,logNT); 1353 | if( log_nfa_new > log_nfa ) 1354 | { 1355 | log_nfa = log_nfa_new; 1356 | rect_copy(&r,rec); 1357 | } 1358 | } 1359 | 1360 | if( log_nfa > eps ) return log_nfa; 1361 | 1362 | /* try to reduce width */ 1363 | rect_copy(rec,&r); 1364 | for(n=0; n<5; n++) 1365 | { 1366 | if( (r.width - delta) >= 0.5 ) 1367 | { 1368 | r.width -= delta; 1369 | log_nfa_new = rect_nfa(&r,angles,logNT); 1370 | if( log_nfa_new > log_nfa ) 1371 | { 1372 | rect_copy(&r,rec); 1373 | log_nfa = log_nfa_new; 1374 | } 1375 | } 1376 | } 1377 | 1378 | if( log_nfa > eps ) return log_nfa; 1379 | 1380 | /* try to reduce one side of the rectangle */ 1381 | rect_copy(rec,&r); 1382 | for(n=0; n<5; n++) 1383 | { 1384 | if( (r.width - delta) >= 0.5 ) 1385 | { 1386 | r.x1 += -r.dy * delta_2; 1387 | r.y1 += r.dx * delta_2; 1388 | r.x2 += -r.dy * delta_2; 1389 | r.y2 += r.dx * delta_2; 1390 | r.width -= delta; 1391 | log_nfa_new = rect_nfa(&r,angles,logNT); 1392 | if( log_nfa_new > log_nfa ) 1393 | { 1394 | rect_copy(&r,rec); 1395 | log_nfa = log_nfa_new; 1396 | } 1397 | } 1398 | } 1399 | 1400 | if( log_nfa > eps ) return log_nfa; 1401 | 1402 | /* try to reduce the other side of the rectangle */ 1403 | rect_copy(rec,&r); 1404 | for(n=0; n<5; n++) 1405 | { 1406 | if( (r.width - delta) >= 0.5 ) 1407 | { 1408 | r.x1 -= -r.dy * delta_2; 1409 | r.y1 -= r.dx * delta_2; 1410 | r.x2 -= -r.dy * delta_2; 1411 | r.y2 -= r.dx * delta_2; 1412 | r.width -= delta; 1413 | log_nfa_new = rect_nfa(&r,angles,logNT); 1414 | if( log_nfa_new > log_nfa ) 1415 | { 1416 | rect_copy(&r,rec); 1417 | log_nfa = log_nfa_new; 1418 | } 1419 | } 1420 | } 1421 | 1422 | if( log_nfa > eps ) return log_nfa; 1423 | 1424 | /* try even finer precisions */ 1425 | rect_copy(rec,&r); 1426 | for(n=0; n<5; n++) 1427 | { 1428 | r.p /= 2.0; 1429 | r.prec = r.p * M_PI; 1430 | log_nfa_new = rect_nfa(&r,angles,logNT); 1431 | if( log_nfa_new > log_nfa ) 1432 | { 1433 | log_nfa = log_nfa_new; 1434 | rect_copy(&r,rec); 1435 | } 1436 | } 1437 | 1438 | return log_nfa; 1439 | } 1440 | 1441 | /*----------------------------------------------------------------------------*/ 1442 | /* 1443 | Reduce the region size, by elimination the points far from the 1444 | starting point, until that leads to rectangle with the right 1445 | density of region points or to discard the region if too small. 1446 | */ 1447 | static int reduce_region_radius( struct point * reg, int * reg_size, 1448 | image_double modgrad, double reg_angle, 1449 | double prec, double p, struct rect * rec, 1450 | image_char used, image_double angles, 1451 | double density_th, double logNT, double eps ) 1452 | { 1453 | double density,rad1,rad2,rad,xc,yc,log_nfa; 1454 | int i; 1455 | 1456 | /* check parameters */ 1457 | if( reg == NULL ) error("refine: invalid pointer 'reg'."); 1458 | if( reg_size == NULL ) error("refine: invalid pointer 'reg_size'."); 1459 | if( prec < 0.0 ) error("refine: 'prec' must be positive."); 1460 | if( rec == NULL ) error("refine: invalid pointer 'rec'."); 1461 | if( used == NULL || used->data == NULL ) 1462 | error("refine: invalid image 'used'."); 1463 | if( angles == NULL || angles->data == NULL ) 1464 | error("refine: invalid image 'angles'."); 1465 | 1466 | /* compute region points density */ 1467 | density = (double) *reg_size / 1468 | ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); 1469 | 1470 | if( density >= density_th ) return TRUE; 1471 | 1472 | /* compute region radius */ 1473 | xc = (double) reg[0].x; 1474 | yc = (double) reg[0].y; 1475 | rad1 = dist( xc, yc, rec->x1, rec->y1 ); 1476 | rad2 = dist( xc, yc, rec->x2, rec->y2 ); 1477 | rad = rad1 > rad2 ? rad1 : rad2; 1478 | 1479 | while( density < density_th ) 1480 | { 1481 | rad *= 0.75; 1482 | 1483 | /* remove points from the region and update 'used' map */ 1484 | for(i=0; i<*reg_size; i++) 1485 | if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) > rad ) 1486 | { 1487 | /* point not kept, mark it as NOTUSED */ 1488 | used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; 1489 | /* remove point from the region */ 1490 | reg[i].x = reg[*reg_size-1].x; /* if i==*reg_size-1 copy itself */ 1491 | reg[i].y = reg[*reg_size-1].y; 1492 | --(*reg_size); 1493 | --i; /* to avoid skipping one point */ 1494 | } 1495 | 1496 | /* reject if the region is too small. 1497 | 2 is the minimal region size for 'region2rect' to work. */ 1498 | if( *reg_size < 2 ) return FALSE; 1499 | 1500 | /* re-compute rectangle */ 1501 | region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); 1502 | 1503 | /* try to improve the rectangle and compute NFA */ 1504 | log_nfa = rect_improve(rec,angles,logNT,eps); 1505 | 1506 | /* re-compute region points density */ 1507 | density = (double) *reg_size / 1508 | ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); 1509 | } 1510 | 1511 | /* if the final rectangle is meaningful accept, otherwise reject */ 1512 | if( log_nfa > eps ) return TRUE; 1513 | else return FALSE; 1514 | } 1515 | 1516 | /*----------------------------------------------------------------------------*/ 1517 | /* 1518 | Refine a rectangle. For that, an estimation of the angle tolerance is 1519 | performed by the standard deviation of the angle at points near the 1520 | region's starting point. Then, a new region is grown starting from the 1521 | same point, but using the estimated angle tolerance. 1522 | If this fails to produce a rectangle with the right density of 1523 | region points, 'reduce_region_radius' is called to try to 1524 | satisfy this condition. 1525 | */ 1526 | static int refine( struct point * reg, int * reg_size, image_double modgrad, 1527 | double reg_angle, double prec, double p, struct rect * rec, 1528 | image_char used, image_double angles, double density_th, 1529 | double logNT, double eps ) 1530 | { 1531 | double angle,ang_d,mean_angle,tau,density,xc,yc,ang_c,sum,s_sum,log_nfa; 1532 | int i,n; 1533 | 1534 | /* check parameters */ 1535 | if( reg == NULL ) error("refine: invalid pointer 'reg'."); 1536 | if( reg_size == NULL ) error("refine: invalid pointer 'reg_size'."); 1537 | if( prec < 0.0 ) error("refine: 'prec' must be positive."); 1538 | if( rec == NULL ) error("refine: invalid pointer 'rec'."); 1539 | if( used == NULL || used->data == NULL ) 1540 | error("refine: invalid image 'used'."); 1541 | if( angles == NULL || angles->data == NULL ) 1542 | error("refine: invalid image 'angles'."); 1543 | 1544 | /* compute region points density */ 1545 | density = (double) *reg_size / 1546 | ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); 1547 | 1548 | if( density >= density_th ) return TRUE; 1549 | 1550 | /*------ First try: reduce angle tolerance ------*/ 1551 | 1552 | /* compute the new mean angle and tolerance */ 1553 | xc = (double) reg[0].x; 1554 | yc = (double) reg[0].y; 1555 | ang_c = angles->data[ reg[0].x + reg[0].y * angles->xsize ]; 1556 | sum = s_sum = 0.0; 1557 | n = 0; 1558 | for(i=0; i<*reg_size; i++) 1559 | { 1560 | used->data[ reg[i].x + reg[i].y * used->xsize ] = NOTUSED; 1561 | if( dist( xc, yc, (double) reg[i].x, (double) reg[i].y ) < rec->width ) 1562 | { 1563 | angle = angles->data[ reg[i].x + reg[i].y * angles->xsize ]; 1564 | ang_d = angle_diff_signed(angle,ang_c); 1565 | sum += ang_d; 1566 | s_sum += ang_d * ang_d; 1567 | ++n; 1568 | } 1569 | } 1570 | mean_angle = sum / (double) n; 1571 | tau = 2.0 * sqrt( (s_sum - 2.0 * mean_angle * sum) / (double) n 1572 | + mean_angle*mean_angle ); /* 2 * standard deviation */ 1573 | 1574 | /* find a new region from the same starting point and new angle tolerance */ 1575 | region_grow(reg[0].x,reg[0].y,angles,reg,reg_size,®_angle,used,tau); 1576 | 1577 | /* if the region is too small, reject */ 1578 | if( *reg_size < 2 ) return FALSE; 1579 | 1580 | /* re-compute rectangle */ 1581 | region2rect(reg,*reg_size,modgrad,reg_angle,prec,p,rec); 1582 | 1583 | /* try to improve the rectangle and compute NFA */ 1584 | log_nfa = rect_improve(rec,angles,logNT,eps); 1585 | 1586 | /* re-compute region points density */ 1587 | density = (double) *reg_size / 1588 | ( dist(rec->x1,rec->y1,rec->x2,rec->y2) * rec->width ); 1589 | 1590 | /*------ Second try: reduce region radius ------*/ 1591 | if( density < density_th ) 1592 | return reduce_region_radius( reg, reg_size, modgrad, reg_angle, prec, p, 1593 | rec, used, angles, density_th, logNT, eps ); 1594 | 1595 | /* if the final rectangle is meaningful accept, otherwise reject */ 1596 | if( log_nfa > eps ) return TRUE; 1597 | else return FALSE; 1598 | } 1599 | 1600 | 1601 | /*----------------------------------------------------------------------------*/ 1602 | /*-------------------------- Line Segment Detector ---------------------------*/ 1603 | /*----------------------------------------------------------------------------*/ 1604 | 1605 | /*----------------------------------------------------------------------------*/ 1606 | /* 1607 | LSD full interface 1608 | */ 1609 | ntuple_list LineSegmentDetection( image_double image, double scale, 1610 | double sigma_scale, double quant, 1611 | double ang_th, double eps, double density_th, 1612 | int n_bins, double max_grad, 1613 | image_int * region ) 1614 | { 1615 | ntuple_list out = new_ntuple_list(5); 1616 | image_double scaled_image,angles,modgrad; 1617 | image_char used; 1618 | struct coorlist * list_p; 1619 | void * mem_p; 1620 | struct rect rec; 1621 | struct point * reg; 1622 | int reg_size,min_reg_size,i; 1623 | unsigned int xsize,ysize; 1624 | double rho,reg_angle,prec,p,log_nfa,logNT; 1625 | int ls_count = 0; /* line segments are numbered 1,2,3,... */ 1626 | 1627 | 1628 | /* check parameters */ 1629 | if( image==NULL || image->data==NULL || image->xsize<=0 || image->ysize<=0 ) 1630 | error("invalid image input."); 1631 | if( scale <= 0.0 ) error("'scale' value must be positive."); 1632 | if( sigma_scale <= 0.0 ) error("'sigma_scale' value must be positive."); 1633 | if( quant < 0.0 ) error("'quant' value must be positive."); 1634 | if( ang_th <= 0.0 || ang_th >= 180.0 ) 1635 | error("'ang_th' value must be in the range (0,180)."); 1636 | if( density_th < 0.0 || density_th > 1.0 ) 1637 | error("'density_th' value must be in the range [0,1]."); 1638 | if( n_bins <= 0 ) error("'n_bins' value must be positive."); 1639 | if( max_grad <= 0.0 ) error("'max_grad' value must be positive."); 1640 | 1641 | 1642 | /* angle tolerance */ 1643 | prec = M_PI * ang_th / 180.0; 1644 | p = ang_th / 180.0; 1645 | rho = quant / sin(prec); /* gradient magnitude threshold */ 1646 | 1647 | 1648 | /* scale image (if necessary) and compute angle at each pixel */ 1649 | if( scale != 1.0 ) 1650 | { 1651 | scaled_image = gaussian_sampler( image, scale, sigma_scale ); 1652 | angles = ll_angle( scaled_image, rho, &list_p, &mem_p, 1653 | &modgrad, (unsigned int) n_bins, max_grad ); 1654 | free_image_double(scaled_image); 1655 | } 1656 | else 1657 | angles = ll_angle( image, rho, &list_p, &mem_p, &modgrad, 1658 | (unsigned int) n_bins, max_grad ); 1659 | xsize = angles->xsize; 1660 | ysize = angles->ysize; 1661 | logNT = 5.0 * ( log10( (double) xsize ) + log10( (double) ysize ) ) / 2.0; 1662 | min_reg_size = (int) (-logNT/log10(p)); /* minimal number of points in region 1663 | that can give a meaningful event */ 1664 | 1665 | 1666 | /* initialize some structures */ 1667 | if( region != NULL ) /* image to output pixel region number, if asked */ 1668 | *region = new_image_int_ini(angles->xsize,angles->ysize,0); 1669 | used = new_image_char_ini(xsize,ysize,NOTUSED); 1670 | reg = (struct point *) calloc(xsize * ysize, sizeof(struct point)); 1671 | if( reg == NULL ) error("not enough memory!"); 1672 | 1673 | 1674 | /* search for line segments */ 1675 | for(;list_p; list_p = list_p->next ) 1676 | if( used->data[ list_p->x + list_p->y * used->xsize ] == NOTUSED && 1677 | angles->data[ list_p->x + list_p->y * angles->xsize ] != NOTDEF ) 1678 | /* there is no risk of double comparison problem here 1679 | because we are only interested in the exact NOTDEF value */ 1680 | { 1681 | /* find the region of connected point and ~equal angle */ 1682 | region_grow( list_p->x, list_p->y, angles, reg, ®_size, 1683 | ®_angle, used, prec ); 1684 | 1685 | /* reject small regions */ 1686 | if( reg_size < min_reg_size ) continue; 1687 | 1688 | /* construct rectangular approximation for the region */ 1689 | region2rect(reg,reg_size,modgrad,reg_angle,prec,p,&rec); 1690 | 1691 | /* Check if the rectangle exceeds the minimal density of 1692 | region points. If not, try to improve the region. 1693 | The rectangle will be rejected if the final one does 1694 | not fulfill the minimal density condition. 1695 | This is an addition to the original LSD algorithm published in 1696 | "LSD: A Fast Line Segment Detector with a False Detection Control" 1697 | by R. Grompone von Gioi, J. Jakubowicz, J.M. Morel, and G. Randall. 1698 | The original algorithm is obtained with density_th = 0.0. 1699 | */ 1700 | if( !refine( reg, ®_size, modgrad, reg_angle, prec, p, 1701 | &rec, used, angles, density_th, logNT, eps ) ) continue; 1702 | 1703 | /* compute NFA value */ 1704 | log_nfa = rect_improve(&rec,angles,logNT,eps); 1705 | if( log_nfa <= eps ) continue; 1706 | 1707 | /* A New Line Segment was found! */ 1708 | ++ls_count; /* increase line segment counter */ 1709 | 1710 | /* 1711 | The gradient was computed with a 2x2 mask, its value corresponds to 1712 | points with an offset of (0.5,0.5), that should be added to output. 1713 | The coordinates origin is at the center of pixel (0,0). 1714 | */ 1715 | rec.x1 += 0.5; rec.y1 += 0.5; 1716 | rec.x2 += 0.5; rec.y2 += 0.5; 1717 | 1718 | /* scale the result values if a subsampling was performed */ 1719 | if( scale != 1.0 ) 1720 | { 1721 | rec.x1 /= scale; rec.y1 /= scale; 1722 | rec.x2 /= scale; rec.y2 /= scale; 1723 | rec.width /= scale; 1724 | } 1725 | 1726 | /* add line segment found to output */ 1727 | add_5tuple(out, rec.x1, rec.y1, rec.x2, rec.y2, rec.width); 1728 | 1729 | /* add region number to 'region' image if needed */ 1730 | if( region != NULL ) 1731 | for(i=0; idata[reg[i].x+reg[i].y*(*region)->xsize] = ls_count; 1733 | } 1734 | 1735 | 1736 | /* free memory */ 1737 | free_image_double(angles); 1738 | free_image_double(modgrad); 1739 | free_image_char(used); 1740 | free( (void *) reg ); 1741 | free( (void *) mem_p ); 1742 | 1743 | return out; 1744 | } 1745 | 1746 | /*----------------------------------------------------------------------------*/ 1747 | /* 1748 | LSD Simple Interface 1749 | */ 1750 | ntuple_list lsd(image_double image) 1751 | { 1752 | /* LSD parameters */ 1753 | double scale = 0.8; /* Scale the image by Gaussian filter to 'scale'. */ 1754 | double sigma_scale = 0.6; /* Sigma for Gaussian filter is computed as 1755 | sigma = sigma_scale/scale. */ 1756 | double quant = 2.0; /* Bound to the quantization error on the 1757 | gradient norm. */ 1758 | double ang_th = 22.5; /* Gradient angle tolerance in degrees. */ 1759 | double eps = 0.0; /* Detection threshold, -log10(NFA). */ 1760 | double density_th = 0.7; /* Minimal density of region points in rectangle. */ 1761 | int n_bins = 1024; /* Number of bins in pseudo-ordering of gradient 1762 | modulus. */ 1763 | double max_grad = 255.0; /* Gradient modulus in the highest bin. The 1764 | default value corresponds to the highest 1765 | gradient modulus on images with gray 1766 | levels in [0,255]. */ 1767 | 1768 | return LineSegmentDetection( image, scale, sigma_scale, quant, ang_th, eps, 1769 | density_th, n_bins, max_grad, NULL ); 1770 | } 1771 | /*----------------------------------------------------------------------------*/ 1772 | -------------------------------------------------------------------------------- /src/lsd.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------- 2 | 3 | LSD - Line Segment Detector on digital images 4 | 5 | Copyright 2007,2008,2009,2010 rafael grompone von gioi (grompone@gmail.com) 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU Affero General Public License as 9 | published by the Free Software Foundation, either version 3 of the 10 | License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU Affero General Public License for more details. 16 | 17 | You should have received a copy of the GNU Affero General Public License 18 | along with this program. If not, see . 19 | 20 | ----------------------------------------------------------------------------*/ 21 | #ifndef LSD_HEADER 22 | #define LSD_HEADER 23 | 24 | 25 | /*----------------------------------------------------------------------------*/ 26 | /*----------------------- 'list of n-tuple' data type ------------------------*/ 27 | /*----------------------------------------------------------------------------*/ 28 | 29 | /* 30 | The i component, of the n-tuple number j, of an n-tuple list 'ntl' 31 | is accessed with: 32 | 33 | ntl->values[ i + j * ntl->dim ] 34 | 35 | The dimension of the n-tuple (n) is: 36 | 37 | ntl->dim 38 | 39 | The number of number of n-tuples in the list is: 40 | 41 | ntl->size 42 | 43 | The maximum number of n-tuples that can be stored in the 44 | list with the allocated memory at a given time is given by: 45 | 46 | ntl->max_size 47 | */ 48 | typedef struct ntuple_list_s 49 | { 50 | unsigned int size; 51 | unsigned int max_size; 52 | unsigned int dim; 53 | double * values; 54 | } * ntuple_list; 55 | 56 | void free_ntuple_list(ntuple_list in); 57 | ntuple_list new_ntuple_list(unsigned int dim); 58 | 59 | 60 | /*----------------------------------------------------------------------------*/ 61 | /*----------------------------- Image Data Types -----------------------------*/ 62 | /*----------------------------------------------------------------------------*/ 63 | /* 64 | The pixel value at (x,y) is accessed by: 65 | 66 | image->data[ x + y * image->xsize ] 67 | 68 | with x and y integer. 69 | */ 70 | 71 | /*----------------------------------------------------------------------------*/ 72 | /* 73 | char image data type 74 | */ 75 | typedef struct image_char_s 76 | { 77 | unsigned char * data; 78 | unsigned int xsize,ysize; 79 | } * image_char; 80 | 81 | void free_image_char(image_char i); 82 | image_char new_image_char(unsigned int xsize, unsigned int ysize); 83 | image_char new_image_char_ini( unsigned int xsize, unsigned int ysize, 84 | unsigned char fill_value ); 85 | 86 | /*----------------------------------------------------------------------------*/ 87 | /* 88 | int image data type 89 | */ 90 | typedef struct image_int_s 91 | { 92 | int * data; 93 | unsigned int xsize,ysize; 94 | } * image_int; 95 | 96 | void free_image_int(image_int i); 97 | image_int new_image_int(unsigned int xsize, unsigned int ysize); 98 | image_int new_image_int_ini( unsigned int xsize, unsigned int ysize, 99 | int fill_value ); 100 | 101 | /*----------------------------------------------------------------------------*/ 102 | /* 103 | double image data type 104 | */ 105 | typedef struct image_double_s 106 | { 107 | double * data; 108 | unsigned int xsize,ysize; 109 | } * image_double; 110 | 111 | void free_image_double(image_double i); 112 | image_double new_image_double(unsigned int xsize, unsigned int ysize); 113 | image_double new_image_double_ini( unsigned int xsize, unsigned int ysize, 114 | double fill_value ); 115 | 116 | 117 | /*----------------------------------------------------------------------------*/ 118 | /*-------------------------- Line Segment Detector ---------------------------*/ 119 | /*----------------------------------------------------------------------------*/ 120 | 121 | /*----------------------------------------------------------------------------*/ 122 | /* LSD Full Interface */ 123 | /*----------------------------------------------------------------------------*/ 124 | /* 125 | Input: 126 | 127 | image: Input image 128 | 129 | scale: When different than 1.0, LSD will scale the image by 130 | Gaussian filtering. 131 | Example: is scale=0.8, the input image will be subsampled 132 | to 80% of its size, and then the line segment detector 133 | will be applied. 134 | Suggested value: 0.8 135 | 136 | sigma_scale: When scale!=1.0, the sigma of the Gaussian filter is: 137 | sigma = sigma_scale / scale, if scale < 1.0 138 | sigma = sigma_scale, if scale >= 1.0 139 | Suggested value: 0.6 140 | 141 | quant: Bound to the quantization error on the gradient norm. 142 | Example: if gray level is quantized to integer steps, 143 | the gradient (computed by finite differences) error 144 | due to quantization will be bounded by 2.0, as the 145 | worst case is when the error are 1 and -1, that 146 | gives an error of 2.0. 147 | Suggested value: 2.0 148 | 149 | ang_th: Gradient angle tolerance in the region growing 150 | algorithm, in degrees. 151 | Suggested value: 22.5 152 | 153 | eps: Detection threshold, -log10(NFA). 154 | The bigger, the more strict the detector is, 155 | and will result in less detections. 156 | (Note that the 'minus sign' makes that this 157 | behavior is opposite to the one of NFA.) 158 | The value -log10(NFA) is equivalent but more 159 | intuitive than NFA: 160 | -1.0 corresponds to 10 mean false alarms 161 | 0.0 corresponds to 1 mean false alarm 162 | 1.0 corresponds to 0.1 mean false alarms 163 | 2.0 corresponds to 0.01 mean false alarms 164 | Suggested value: 0.0 165 | 166 | density_th: Minimal proportion of region points in a rectangle. 167 | Suggested value: 0.7 168 | 169 | n_bins: Number of bins used in the pseudo-ordering of gradient 170 | modulus. 171 | Suggested value: 1024 172 | 173 | max_grad: Gradient modulus in the highest bin. For example, 174 | for images with integer gray levels in [0,255], 175 | the maximum possible gradient value is 255.0. 176 | Suggested value: 255.0 177 | 178 | region: Optional output: an int image where the pixels used 179 | in some line support region are marked. Unused pixels 180 | have the value '0' while the used ones have the 181 | number of the line segment, numbered 1,2,3,... If desired, 182 | a non NULL pointer to an image_int should be used. 183 | The resulting image has the size of the image used 184 | for the processing, that is, the size of the input 185 | image scaled by the given factor 'scale'. 186 | Suggested value: NULL 187 | 188 | Return value: A 5-tuple list, where each 5-tuple corresponds to a 189 | detected line segment. The five values are: 190 | x1,y1,x2,y2,width 191 | for a line segment from (x1,y1) to (x2,y2) and 192 | a width 'width'. 193 | */ 194 | ntuple_list LineSegmentDetection( image_double image, double scale, 195 | double sigma_scale, double quant, 196 | double ang_th, double eps, double density_th, 197 | int n_bins, double max_grad, 198 | image_int * region ); 199 | 200 | /*----------------------------------------------------------------------------*/ 201 | /* LSD Simple Interface */ 202 | /*----------------------------------------------------------------------------*/ 203 | /* 204 | input: an image 205 | output: a 5-tuple list of detected line segments. 206 | */ 207 | ntuple_list lsd(image_double image); 208 | 209 | 210 | #endif /* !LSD_HEADER */ 211 | /*----------------------------------------------------------------------------*/ 212 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | extern "C" 2 | { 3 | #include "lsd.h" 4 | }; 5 | #include "VPDetection.h" 6 | 7 | using namespace std; 8 | using namespace cv; 9 | 10 | 11 | // LSD line segment detection 12 | void LineDetect( cv::Mat image, double thLength, std::vector > &lines ) 13 | { 14 | cv::Mat grayImage; 15 | if ( image.channels() == 1 ) 16 | grayImage = image; 17 | else 18 | cv::cvtColor(image, grayImage, CV_BGR2GRAY); 19 | 20 | image_double imageLSD = new_image_double( grayImage.cols, grayImage.rows ); 21 | unsigned char* im_src = (unsigned char*) grayImage.data; 22 | 23 | int xsize = grayImage.cols; 24 | int ysize = grayImage.rows; 25 | for ( int y = 0; y < ysize; ++y ) 26 | { 27 | for ( int x = 0; x < xsize; ++x ) 28 | { 29 | imageLSD->data[y * xsize + x] = im_src[y * xsize + x]; 30 | } 31 | } 32 | 33 | ntuple_list linesLSD = lsd( imageLSD ); 34 | free_image_double( imageLSD ); 35 | 36 | int nLines = linesLSD->size; 37 | int dim = linesLSD->dim; 38 | std::vector lineTemp( 4 ); 39 | for ( int i = 0; i < nLines; ++i ) 40 | { 41 | double x1 = linesLSD->values[i * dim + 0]; 42 | double y1 = linesLSD->values[i * dim + 1]; 43 | double x2 = linesLSD->values[i * dim + 2]; 44 | double y2 = linesLSD->values[i * dim + 3]; 45 | 46 | double l = sqrt( ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ) ); 47 | if ( l > thLength ) 48 | { 49 | lineTemp[0] = x1; 50 | lineTemp[1] = y1; 51 | lineTemp[2] = x2; 52 | lineTemp[3] = y2; 53 | 54 | lines.push_back( lineTemp ); 55 | } 56 | } 57 | 58 | free_ntuple_list(linesLSD); 59 | } 60 | 61 | void drawClusters( cv::Mat &img, std::vector > &lines, std::vector > &clusters ) 62 | { 63 | int cols = img.cols; 64 | int rows = img.rows; 65 | 66 | //draw lines 67 | std::vector lineColors( 3 ); 68 | lineColors[0] = cv::Scalar( 0, 0, 255 ); 69 | lineColors[1] = cv::Scalar( 0, 255, 0 ); 70 | lineColors[2] = cv::Scalar( 255, 0, 0 ); 71 | 72 | for ( int i=0; i > lines; 110 | LineDetect( image, thLength, lines ); 111 | 112 | // Camera internal parameters 113 | cv::Point2d pp( 307, 251 ); // Principle point (in pixel) 114 | double f = 6.053 / 0.009; // Focal length (in pixel) 115 | 116 | // Vanishing point detection 117 | std::vector vps; // Detected vanishing points (in pixel) 118 | std::vector > clusters; // Line segment clustering results of each vanishing point 119 | VPDetection detector; 120 | detector.run( lines, pp, f, vps, clusters ); 121 | 122 | drawClusters( image, lines, clusters ); 123 | imshow("",image); 124 | cv::waitKey( 0 ); 125 | } 126 | --------------------------------------------------------------------------------