├── .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 | 
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 |
--------------------------------------------------------------------------------