Compare commits
788 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae4cb571ab | |||
| 4f2aeeffaa | |||
| d58cadc1ea | |||
| 47838a4a22 | |||
| 80a985c894 | |||
| 9b13b07639 | |||
| 569a95e9e1 | |||
| fe4e1913f0 | |||
| 573be75f50 | |||
| 1abc26905d | |||
| 7c8789dc12 | |||
| 0692bf5f34 | |||
| 7c870014fb | |||
| f50f249f80 | |||
| ff095bbbfc | |||
| 7dd059c084 | |||
| 462c3c25a9 | |||
| 0ec0aeb7d0 | |||
| 5044e0f590 | |||
| cf0cc00547 | |||
| 1d804bc695 | |||
| e4fa217a62 | |||
| 4eb16122c0 | |||
| 4046f0398a | |||
| da6898f758 | |||
| c91b0e7ac4 | |||
| 46ac0048f8 | |||
| 91a8ea5e60 | |||
| 7de4e0496c | |||
| 5efad375e0 | |||
| 72419c3778 | |||
| c4906c7f43 | |||
| e181c76d21 | |||
| 914b78b8bb | |||
| d052d863eb | |||
| 957e5ef8eb | |||
| 58e054a003 | |||
| 1c9f590f0d | |||
| 5d213582f7 | |||
| e1bb844475 | |||
| 21227ba092 | |||
| 9cd08c662c | |||
| 9e3a2cbab2 | |||
| c2cb3b515d | |||
| 1fe5441185 | |||
| aa11e102fd | |||
| 8d0383180c | |||
| 15af3f7114 | |||
| a4dd2162f2 | |||
| 1b01e1fe68 | |||
| 4ed696d770 | |||
| 5ca25ab8f0 | |||
| ccdc71286c | |||
| d5f006eee5 | |||
| fb97273b3c | |||
| 7e6fb668ed | |||
| 46faf592fc | |||
| 85a814f748 | |||
| dce629d0e2 | |||
| e19a12f655 | |||
| 5de5f26223 | |||
| cae89a7a88 | |||
| fd59551ff0 | |||
| efebd83bc8 | |||
| 4a9cfbf806 | |||
| 967a88759f | |||
| d88fdd0378 | |||
| 643c906f3d | |||
| fae2eb8a1a | |||
| 30222c7be8 | |||
| 539acaf348 | |||
| 1466621f99 | |||
| ebfaf4c5d8 | |||
| 0aab779532 | |||
| 65b8a1cb37 | |||
| c5a2879ce0 | |||
| 2d89df1804 | |||
| d78bc3c321 | |||
| dee56598e9 | |||
| 83ccdabe7e | |||
| 1f08d8cb6f | |||
| 1fbad26fe3 | |||
| 8466911ad0 | |||
| caba92f2b8 | |||
| 63383ef1d8 | |||
| 237cb93143 | |||
| 579a7fff6d | |||
| 071e78d02e | |||
| 21ad8e92d4 | |||
| 3a263c6326 | |||
| e85ae5f2f0 | |||
| 5b1fd739d9 | |||
| 62d4393883 | |||
| ba5f343c38 | |||
| f83a76cdeb | |||
| e40567eaee | |||
| a8aa6381d9 | |||
| 60367907fe | |||
| 5aa9ac9a77 | |||
| c8707b891b | |||
| 8c91604f5a | |||
| 1cc17a7186 | |||
| 85b60ee3cb | |||
| 8ab6852927 | |||
| 54b59c3cfb | |||
| 070e5ec042 | |||
| 322593e89f | |||
| 8dd213c829 | |||
| 2b52bb092a | |||
| 4de9605b7b | |||
| d767c9df58 | |||
| 926b64fff7 | |||
| 7452eef6e9 | |||
| 55f490485b | |||
| dcbe797980 | |||
| dcee883961 | |||
| e4418e186e | |||
| c45d2642ca | |||
| b37a641cc9 | |||
| d2b9dc5530 | |||
| cb95d1df35 | |||
| 11ebaf673f | |||
| 3787388eac | |||
| c5a1650ac0 | |||
| 276bed3e4a | |||
| 571ebb2373 | |||
| ef3d02214b | |||
| d3821e8cd7 | |||
| 420737e098 | |||
| 630eddf25a | |||
| f379bcc6d3 | |||
| 22ff1e8826 | |||
| 4038beb67e | |||
| 3f37e034a0 | |||
| 8d9e619412 | |||
| 1a809ca89b | |||
| cc11a8d183 | |||
| 54e65598bd | |||
| 1176d4ef84 | |||
| d36b546df8 | |||
| 9c9ecc22e2 | |||
| fa76c634ec | |||
| 01d3848f17 | |||
| 162384a838 | |||
| 06d4aa6060 | |||
| 09df1a286b | |||
| 2e915026a0 | |||
| f6f839eb3c | |||
| c5292c2549 | |||
| c422bdc3f8 | |||
| 48a860a335 | |||
| 61cddd8b63 | |||
| 25a7d023dd | |||
| c5261ea3d2 | |||
| af1d29db83 | |||
| 97a5dd0ead | |||
| d017faa06c | |||
| 4525a5f2be | |||
| b30ad42609 | |||
| c54ef78220 | |||
| ae81006eab | |||
| 5e667ee53a | |||
| a10a7279a8 | |||
| 968fe91c8e | |||
| 18ef0cfe81 | |||
| 45958eaabc | |||
| 5442de7d99 | |||
| 82a5ff8540 | |||
| 9972059476 | |||
| 53d11f490d | |||
| 5c98209127 | |||
| ee210afc44 | |||
| cb76d00f5f | |||
| 419450689b | |||
| b4504639c8 | |||
| 6bfea73716 | |||
| 4a5ea85094 | |||
| df312a4ffa | |||
| 5a16de2ef6 | |||
| 980496bb0e | |||
| d2719ea92f | |||
| 1c75fa7297 | |||
| c6ffa5059d | |||
| 0f0bda9722 | |||
| 11d89ad7c1 | |||
| 53f4f06a15 | |||
| c69016467d | |||
| 89e7860572 | |||
| ed9f6a3cb4 | |||
| e46810eabe | |||
| 47b01be0a4 | |||
| b04d06938d | |||
| a14bfb331d | |||
| a361cc9479 | |||
| 61fe623cf1 | |||
| d46c466e20 | |||
| 89be83e5be | |||
| b3ddc2b9a7 | |||
| 33c15d6309 | |||
| 1f6acc23fa | |||
| e8c2f2ee3e | |||
| 2f046ae873 | |||
| 63715a899e | |||
| ed0eb139cb | |||
| 0a3aab288a | |||
| 1796a26fc7 | |||
| 69c82b4c2b | |||
| 67b2380d19 | |||
| 96cd0d82e5 | |||
| 83ef276697 | |||
| 3b250d6e9c | |||
| a798386660 | |||
| 1edefac4dc | |||
| 8b7c0a7893 | |||
| c37acef077 | |||
| b4c3f465fb | |||
| faf91a466c | |||
| 4071c4e7c9 | |||
| af04a85303 | |||
| ec93d103b7 | |||
| a3916113b9 | |||
| 5f23d99918 | |||
| f6b1c2a0b6 | |||
| c54928e003 | |||
| efd237b8b8 | |||
| de0b46a765 | |||
| ca5e73a9d0 | |||
| 397870d7a5 | |||
| 263fd81bbc | |||
| 9575a82a9e | |||
| 6fa6e3d3d5 | |||
| bc7ab6c2df | |||
| 0c1b405964 | |||
| f238c69511 | |||
| 4babecf3b0 | |||
| 1d280352f4 | |||
| a8169f08fc | |||
| 75601ccf9e | |||
| 183e378bd0 | |||
| 00b8f0dec1 | |||
| 48a9905f5d | |||
| 4f48a05906 | |||
| dfff9a8125 | |||
| ac730d9f53 | |||
| 7166b7b640 | |||
| 1c1c41d3be | |||
| 06461b401a | |||
| 71c3e67cb2 | |||
| c173d9fa18 | |||
| 8d367d4b4d | |||
| eb3046f7d3 | |||
| 66a8acfd3d | |||
| 56fcc41d70 | |||
| 14d5358982 | |||
| 21a27687d0 | |||
| 9698cc93d9 | |||
| 88aed15ffa | |||
| 022ec106f0 | |||
| f317d1277f | |||
| f91e461ea0 | |||
| a84c4ac197 | |||
| b9f57bda05 | |||
| 28ee84b731 | |||
| 2494e028c0 | |||
| 1709421c2c | |||
| 71dd9a6f1b | |||
| 478dd01c91 | |||
| 862b675bee | |||
| f328f9a10d | |||
| a54f6bb08b | |||
| 72fb85f6a0 | |||
| 4d54f35a96 | |||
| d6bf209bb3 | |||
| c87af333b3 | |||
| 92efe4534b | |||
| 4c08581e48 | |||
| 7cb3f3def7 | |||
| 00f16e9178 | |||
| dc76ca5fc9 | |||
| 7520544840 | |||
| ea893bf9d9 | |||
| 7429454171 | |||
| a5b3a205d9 | |||
| 84475ef1de | |||
| 71f4894d87 | |||
| b8457be394 | |||
| ee6835492c | |||
| 3a0b375104 | |||
| 6f05a250be | |||
| af6a64d76b | |||
| be3efdf274 | |||
| a3e56114d1 | |||
| 7e8846b81e | |||
| 4d63362206 | |||
| 9d13c7b1e2 | |||
| 81548a30aa | |||
| 4880dd0cd6 | |||
| 037f27c882 | |||
| 2411556242 | |||
| 8e1ccfae3d | |||
| 1c491c42cd | |||
| eaf5a163b1 | |||
| 148e64d4bc | |||
| 3695a31606 | |||
| 34533dc569 | |||
| 655b22e050 | |||
| bbc161e1cb | |||
| f50f0ba63e | |||
| 44ea50f1c4 | |||
| 34a571d37f | |||
| e46332a183 | |||
| 74e60e44ad | |||
| 857a2d5bfd | |||
| 797143d515 | |||
| e6f653af44 | |||
| f187fd99da | |||
| 01a883df0c | |||
| 8d95c91805 | |||
| d090fcf2fe | |||
| 09fbc78a97 | |||
| b4fc87c380 | |||
| 6377f5a458 | |||
| 4dd6148646 | |||
| c0b702a994 | |||
| 12001a42f9 | |||
| d30ce2b9ac | |||
| 047abb0050 | |||
| 23456d67e5 | |||
| 15251056ba | |||
| cc6e6aa028 | |||
| 302b138aa7 | |||
| b91bd6716c | |||
| 8f334b4e41 | |||
| 7c00b17085 | |||
| 25cf51637d | |||
| 6ad3427426 | |||
| 345b1369be | |||
| 120594163f | |||
| 541b627d21 | |||
| d7418fc9ec | |||
| 5d018c090f | |||
| 4b3f2c1972 | |||
| 450734cc32 | |||
| ecbec7235f | |||
| 0518455163 | |||
| aa57634213 | |||
| 7752483486 | |||
| a419b64347 | |||
| 281ce441a8 | |||
| a75807354d | |||
| 71348651eb | |||
| 55c799a474 | |||
| ec03d6e6fc | |||
| 1007c06d44 | |||
| c8ede7c9ea | |||
| f32a6fb9a1 | |||
| fb9bbf99c4 | |||
| 1c0b9469f5 | |||
| 515be70867 | |||
| 488920168a | |||
| d391a6d49f | |||
| 27b933ba5a | |||
| 0d7b44db50 | |||
| 6337fd0650 | |||
| 892999c40c | |||
| 5e3e438edb | |||
| 2992e3a1b6 | |||
| cff5e3ee88 | |||
| d1fba0686e | |||
| 0c988f00bc | |||
| dc49e11527 | |||
| d1afa0e370 | |||
| 1578dd1027 | |||
| 06e55ddf38 | |||
| 470f427a95 | |||
| aa6ba149bc | |||
| 1162f0ed63 | |||
| f610c88103 | |||
| 458bde5e24 | |||
| 3bc174f1bb | |||
| c5552788c5 | |||
| 60a1cc34b8 | |||
| 5884e4039f | |||
| 4a0364ded5 | |||
| d14d4bc110 | |||
| 550bd24ca8 | |||
| 9bba2443b7 | |||
| aa4a80defc | |||
| 0319120adc | |||
| 9ac0b06ff1 | |||
| 68fe45b594 | |||
| 81b9be1623 | |||
| 4689426a91 | |||
| 38887e6ea9 | |||
| 3ea8be7292 | |||
| c445ce6125 | |||
| 65744cd87d | |||
| ad20feaca0 | |||
| 4057e27539 | |||
| f8254a1011 | |||
| e5ab0ac294 | |||
| e810f3052d | |||
| 46718cae28 | |||
| 8d61ecbc4d | |||
| 87f0010f42 | |||
| 8fe18fefdd | |||
| ad9f9e2ce7 | |||
| 5d0467e769 | |||
| a6b29be55b | |||
| ee0da48bd2 | |||
| 88aea1d52f | |||
| 79f593a429 | |||
| 8c08714b8c | |||
| b0bf8478e5 | |||
| 39874ef742 | |||
| ac206ccb05 | |||
| b5a4159efc | |||
| 71edf1b5f1 | |||
| 2e950eb41b | |||
| 56091bae1f | |||
| d3ad26926d | |||
| ed402c5be6 | |||
| 4d45a2c43f | |||
| 74827c35ff | |||
| 62c704d1e9 | |||
| f03b11d271 | |||
| aeda3d2d69 | |||
| a8db3df8f6 | |||
| c42424f2db | |||
| 93c03ef05b | |||
| b3bae170ed | |||
| 43714b9d03 | |||
| cc7aa5890d | |||
| 0b53ca2848 | |||
| eac4042ed5 | |||
| c942c6539a | |||
| ad00e0dd43 | |||
| dfaf75f502 | |||
| e7b3a73b62 | |||
| 39b27a19be | |||
| d59a6fa518 | |||
| fb0c0eaa7c | |||
| 618c75fe3d | |||
| 26c284b225 | |||
| 5f9d5c483c | |||
| fee8f29f48 | |||
| 2c2cdcf789 | |||
| ffd1df0cb5 | |||
| 64a53de27d | |||
| 98e7d4ceec | |||
| 9fe11db7e2 | |||
| e7af509c86 | |||
| 07d57db91c | |||
| 97ab91dcc9 | |||
| 7d91b8efcd | |||
| f57a4bf87b | |||
| 0276cc90c2 | |||
| 0fd21baaa2 | |||
| 7dd666e444 | |||
| ec827bed8e | |||
| a48c1c8248 | |||
| 214dab39f6 | |||
| a125cd6c6d | |||
| 6c3dd4984c | |||
| 5d3a128cd3 | |||
| 3bafe64666 | |||
| 3e574cd26a | |||
| 1f85ffa11b | |||
| 6abce51481 | |||
| c1032b6232 | |||
| 040ff7993f | |||
| acc2efab50 | |||
| 66ed9ddbe3 | |||
| 43c2c119e9 | |||
| 5f3ee657ce | |||
| 5d4bd700a7 | |||
| e310added4 | |||
| 3334c06e8b | |||
| d9db950c0e | |||
| db391fdfdd | |||
| fbf28bcc63 | |||
| 653bca8b74 | |||
| f739990f4c | |||
| 51311779b3 | |||
| e0c8721830 | |||
| 8908b22c9d | |||
| eb3cb77296 | |||
| 4d474d40e7 | |||
| 4c404cb4cc | |||
| 71ec6144bd | |||
| d4e6812be2 | |||
| 31ac73c315 | |||
| 57fec2f2da | |||
| 6ccb7e169d | |||
| 491bf41356 | |||
| d27e440b2a | |||
| 21f1a0ee49 | |||
| 83a0f0ddb1 | |||
| b332152bef | |||
| 6b6c7ccfea | |||
| f7aadd07f6 | |||
| d66815978a | |||
| 4d9d7e6ded | |||
| 9dc5c58f62 | |||
| a89ff402fc | |||
| 2811d40840 | |||
| b5d073ad3f | |||
| 7189112308 | |||
| 89605fac04 | |||
| 46b6a095a2 | |||
| 9ee0789174 | |||
| a0e4600364 | |||
| 6d253a2068 | |||
| 564a8ed208 | |||
| d06c73861d | |||
| b1d01dc757 | |||
| 5301fe729e | |||
| 2211cfe783 | |||
| e95c33dd18 | |||
| 3ae95150c7 | |||
| e75cd74f5a | |||
| 30742d21d8 | |||
| 3b59a10584 | |||
| 038bfb98ec | |||
| 7017b1250a | |||
| 2c6b7a52e9 | |||
| a350b76738 | |||
| 2f46cf5ddb | |||
| 9b1136518c | |||
| 9ddb23e025 | |||
| 92826a0436 | |||
| 5c1f71de51 | |||
| 4b84d5d2c1 | |||
| e7539bd2c8 | |||
| f624f92e7a | |||
| 6ed168d3af | |||
| decebeea0e | |||
| 887a950243 | |||
| 0eb1c7edb1 | |||
| b56933d9dc | |||
| 1efc3cff36 | |||
| 7ad6b47bc9 | |||
| 17e8d51124 | |||
| 703921e2fd | |||
| 552bda92a9 | |||
| 9a7673f950 | |||
| d47a2988a9 | |||
| c23d6b67ee | |||
| 2a9e252f77 | |||
| 3d222d313b | |||
| 5302e56071 | |||
| 74c77d826f | |||
| de2a8d3706 | |||
| 0ae89fe2be | |||
| 5afaa6b1e7 | |||
| 7b2a1d15cc | |||
| a218bdb0d7 | |||
| 44e04da79c | |||
| 1118a7d15a | |||
| b2cd954f24 | |||
| cb0ab87646 | |||
| 57a1343f10 | |||
| a223479107 | |||
| 04b2d9a453 | |||
| 40d0f853d6 | |||
| c4c731c0aa | |||
| c22dcb04af | |||
| e74cddfbd1 | |||
| 6d1c02ffed | |||
| 4a519a25f3 | |||
| 5ad7f9910f | |||
| e85e83f491 | |||
| 886319c81d | |||
| e09adc4fde | |||
| 8658aef3bf | |||
| 24163eb929 | |||
| 70679b49fc | |||
| bfacad1a99 | |||
| 2f077fcd99 | |||
| f38ebba34d | |||
| deec233519 | |||
| 15704c384e | |||
| 2653d745fd | |||
| 6ea73a5bff | |||
| 7e2bb63378 | |||
| 211a8d31d5 | |||
| 620387fbe1 | |||
| 8fc1848918 | |||
| d3d9b538c7 | |||
| d7a8166720 | |||
| 37b1a7560c | |||
| 108caae216 | |||
| 4667e18831 | |||
| 3e26086f82 | |||
| 71770eb790 | |||
| a23836231f | |||
| d20b2a5a97 | |||
| ae02ecec60 | |||
| f20db35b78 | |||
| 21de04b4a2 | |||
| 65eb52a247 | |||
| e7f14f3d0e | |||
| 3622de2621 | |||
| e4ef0e0ca8 | |||
| 7c97dbc196 | |||
| aa35835cfc | |||
| 8995921cc5 | |||
| a9df50eefc | |||
| b3b4e83aed | |||
| 95ea09c3dc | |||
| bf2ee3c58a | |||
| 3a6deb3ed3 | |||
| 3cdd2b2761 | |||
| af88f0c067 | |||
| 1652b2a443 | |||
| 5bb43f69ab | |||
| 50031ffb15 | |||
| 78f3b0ad1f | |||
| 56d715b091 | |||
| e4a90c19cc | |||
| 64aaa6e1ae | |||
| d5ad4f3255 | |||
| 0e13f33193 | |||
| b8ea21b2e5 | |||
| 6c74439d56 | |||
| 7612e7af05 | |||
| 3a6466d2e1 | |||
| 6ae43a2243 | |||
| fcfeb2451b | |||
| 3039ed7682 | |||
| 3bf6c3c2aa | |||
| b9902f39b7 | |||
| 8355293306 | |||
| 62470d8a33 | |||
| cf1ae3513f | |||
| a37640cdd0 | |||
| fa818d03b8 | |||
| 6207d338dd | |||
| 0ffc53bafe | |||
| fae69df9a9 | |||
| 6ca893be23 | |||
| dea40e5e99 | |||
| 5febdae36a | |||
| 7f8e1f480a | |||
| e9729a9601 | |||
| 90905fb1e2 | |||
| 740c5234b1 | |||
| 1b0f0d7ead | |||
| daaa5a1824 | |||
| b70a391e6c | |||
| dfbeaddc72 | |||
| dbb0fcdc7a | |||
| 2222393b0a | |||
| de806330fd | |||
| b81dcbdf2a | |||
| 3c3d695d4d | |||
| 301ed34142 | |||
| 7da9800694 | |||
| 4a214c08e5 | |||
| 12f8d8069d | |||
| 1dec1645e5 | |||
| de2861e7a9 | |||
| d1f4f6f4b8 | |||
| 58b3bc2d7e | |||
| dccc10ff12 | |||
| 2666da892f | |||
| cc81b4a5cd | |||
| afdb67b462 | |||
| 90b3086f4a | |||
| 6c8b11afee | |||
| b7a19a9a5f | |||
| d7f0b9de25 | |||
| c7f6c0cb9f | |||
| 213241c06a | |||
| 2d26f60192 | |||
| 3780de9d98 | |||
| e2edfecb80 | |||
| 67eb6dde75 | |||
| 591355d2c8 | |||
| 9547110533 | |||
| bc250c2e3f | |||
| 80b4f99b1e | |||
| d09b404178 | |||
| 7ecad71ab0 | |||
| 8c4b8cc0b4 | |||
| 3f5d3b2d40 | |||
| f8c5acee4c | |||
| 7d8a16ae39 | |||
| 8b732e086d | |||
| c07cd007eb | |||
| e5a91a8be8 | |||
| 8c08258cf2 | |||
| 3a2cf37115 | |||
| 837f001789 | |||
| 381574bdb7 | |||
| f1b6809eee | |||
| 2881f2a096 | |||
| d2665b655e | |||
| e14f91dd37 | |||
| ddf5c86f3a | |||
| 57d2cb8962 | |||
| 43301096d3 | |||
| 7b0be9cf8f | |||
| 0d2bc9b0a1 | |||
| 2353436cb5 | |||
| 4447dbe265 | |||
| e3afc32693 | |||
| 55819ae464 | |||
| 23785faf02 | |||
| 16e750dd37 | |||
| 1727e0acf6 | |||
| dfa3ccdea9 | |||
| a3e74ec521 | |||
| 6594d52185 | |||
| 3e2a57ff35 | |||
| 7b8bb4248b | |||
| ae26368e78 | |||
| 917107e635 | |||
| 56704b5e95 | |||
| 08e8f9ca45 | |||
| 9a25cb012d | |||
| 85ccac2633 | |||
| 4a86900761 | |||
| 69f1ee8732 | |||
| 6ff58f02e2 | |||
| 94968c81e0 | |||
| b58979d057 | |||
| 38c2cc8521 | |||
| 31bec45998 | |||
| b33a2f24fa | |||
| 9d18f5c458 | |||
| 6f5876f8f7 | |||
| 2848f43acc | |||
| 319dbd2eb7 | |||
| 924e062426 | |||
| 3b24aa2441 | |||
| be4c1afb0b | |||
| 550e3721ae | |||
| 64c164c111 | |||
| 74e52df3cd | |||
| 7334e54a63 | |||
| 0ac84755a0 | |||
| b6b0c2aa8e | |||
| 5623701acb | |||
| 4ddc6a4a77 | |||
| 0427b70a2f | |||
| df8f1a4355 | |||
| 5f35bed5c5 | |||
| 9cad1dfa0d | |||
| 5980613317 | |||
| 5f54a22d29 | |||
| a4e21c8fa8 | |||
| a3f065c409 | |||
| 48c4a79d2e | |||
| 730fe9e582 | |||
| b1b9a29e48 | |||
| 40f6d320c2 | |||
| 42ab7fd876 | |||
| fb67ab1257 | |||
| 9abcd88435 | |||
| a5d40d7674 | |||
| 89246e1a45 | |||
| ba5a8ee299 | |||
| ce07024a44 | |||
| e395e03040 | |||
| b74cfe8c2c | |||
| ac8cce3963 | |||
| 747c6a2bd2 | |||
| 62fed8b7b2 | |||
| 3d8e05d711 | |||
| 5c8e679bdc | |||
| ca6fb27ea6 | |||
| eb6c598678 | |||
| dd52d1b526 | |||
| 062e1cbe06 | |||
| 4bd55c6f73 | |||
| 693c4e5741 | |||
| 32707317fa | |||
| 3e577b090e | |||
| e0c4936c99 | |||
| 1ea1cafa00 | |||
| b66a13183e | |||
| 6eb1426ea2 | |||
| afb9b9540c | |||
| f2e09d048c | |||
| c45e645d6c | |||
| 5101a7fc00 | |||
| 6a6f24b170 |
@@ -8,21 +8,21 @@
|
||||
function(_icv_downloader)
|
||||
# Define actual ICV versions
|
||||
if(APPLE)
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_macosx_20140429.tgz")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "f2195a60829899983acd4a45794e1717")
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_macosx_20141027.tgz")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "9662fe0694a67e59491a0dcc82fa26e0")
|
||||
set(OPENCV_ICV_PLATFORM "macosx")
|
||||
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_osx")
|
||||
elseif(UNIX)
|
||||
if(ANDROID AND (NOT ANDROID_ABI STREQUAL x86))
|
||||
return()
|
||||
endif()
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_linux_20140513.tgz")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "d80cb24f3a565113a9d6dc56344142f6")
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_linux_20141027.tgz")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "8b449a536a2157bcad08a2b9f266828b")
|
||||
set(OPENCV_ICV_PLATFORM "linux")
|
||||
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_lnx")
|
||||
elseif(WIN32 AND NOT ARM)
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_windows_20140429.zip")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "b5028a92224ec1fbc554010c52eb3ec8")
|
||||
set(OPENCV_ICV_PACKAGE_NAME "ippicv_windows_20141027.zip")
|
||||
set(OPENCV_ICV_PACKAGE_HASH "b59f865d1ba16e8c84124e19d78eec57")
|
||||
set(OPENCV_ICV_PLATFORM "windows")
|
||||
set(OPENCV_ICV_PACKAGE_SUBDIR "/ippicv_win")
|
||||
else()
|
||||
@@ -45,7 +45,7 @@ function(_icv_downloader)
|
||||
endif()
|
||||
endif()
|
||||
unset(OPENCV_ICV_PACKAGE_DOWNLOADED CACHE)
|
||||
|
||||
|
||||
set(OPENCV_ICV_PACKAGE_ARCHIVE "${CMAKE_CURRENT_LIST_DIR}/downloads/${OPENCV_ICV_PLATFORM}-${OPENCV_ICV_PACKAGE_HASH}/${OPENCV_ICV_PACKAGE_NAME}")
|
||||
get_filename_component(OPENCV_ICV_PACKAGE_ARCHIVE_DIR "${OPENCV_ICV_PACKAGE_ARCHIVE}" PATH)
|
||||
if(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
|
||||
@@ -56,7 +56,7 @@ function(_icv_downloader)
|
||||
file(REMOVE_RECURSE "${OPENCV_ICV_PACKAGE_ARCHIVE_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(NOT EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
|
||||
if(NOT DEFINED OPENCV_ICV_URL)
|
||||
if(DEFINED ENV{OPENCV_ICV_URL})
|
||||
@@ -65,7 +65,7 @@ function(_icv_downloader)
|
||||
set(OPENCV_ICV_URL "http://sourceforge.net/projects/opencvlibrary/files/3rdparty/ippicv")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
file(MAKE_DIRECTORY ${OPENCV_ICV_PACKAGE_ARCHIVE_DIR})
|
||||
message(STATUS "ICV: Downloading ${OPENCV_ICV_PACKAGE_NAME}...")
|
||||
file(DOWNLOAD "${OPENCV_ICV_URL}/${OPENCV_ICV_PACKAGE_NAME}" "${OPENCV_ICV_PACKAGE_ARCHIVE}"
|
||||
@@ -82,12 +82,12 @@ function(_icv_downloader)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
ocv_assert(EXISTS "${OPENCV_ICV_PACKAGE_ARCHIVE}")
|
||||
ocv_assert(NOT EXISTS "${OPENCV_ICV_UNPACK_PATH}")
|
||||
file(MAKE_DIRECTORY ${OPENCV_ICV_UNPACK_PATH})
|
||||
ocv_assert(EXISTS "${OPENCV_ICV_UNPACK_PATH}")
|
||||
|
||||
|
||||
message(STATUS "ICV: Unpacking ${OPENCV_ICV_PACKAGE_NAME} to ${OPENCV_ICV_UNPACK_PATH}...")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${OPENCV_ICV_PACKAGE_ARCHIVE}"
|
||||
WORKING_DIRECTORY "${OPENCV_ICV_UNPACK_PATH}"
|
||||
@@ -100,7 +100,7 @@ function(_icv_downloader)
|
||||
ocv_assert(EXISTS "${OPENCV_ICV_PATH}")
|
||||
|
||||
set(OPENCV_ICV_PACKAGE_DOWNLOADED "${OPENCV_ICV_PACKAGE_HASH}" CACHE INTERNAL "ICV package hash")
|
||||
|
||||
|
||||
message(STATUS "ICV: Package successfully downloaded")
|
||||
set(OPENCV_ICV_PATH "${OPENCV_ICV_PATH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -82,7 +82,7 @@ if(UNIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ocv_warnings_disable(CMAKE_C_FLAGS -Wattributes -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations)
|
||||
ocv_warnings_disable(CMAKE_C_FLAGS -Wshorten-64-to-32 -Wattributes -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations)
|
||||
|
||||
set_target_properties(${ZLIB_LIBRARY} PROPERTIES
|
||||
OUTPUT_NAME ${ZLIB_LIBRARY}
|
||||
|
||||
@@ -130,7 +130,7 @@ OCV_OPTION(WITH_GSTREAMER "Include Gstreamer support" ON
|
||||
OCV_OPTION(WITH_GSTREAMER_0_10 "Enable Gstreamer 0.10 support (instead of 1.x)" OFF )
|
||||
OCV_OPTION(WITH_GTK "Include GTK support" ON IF (UNIX AND NOT APPLE AND NOT ANDROID) )
|
||||
OCV_OPTION(WITH_GTK_2_X "Use GTK version 2" OFF IF (UNIX AND NOT APPLE AND NOT ANDROID) )
|
||||
OCV_OPTION(WITH_IPP "Include Intel IPP support" ON IF (NOT IOS) )
|
||||
OCV_OPTION(WITH_IPP "Include Intel IPP support" ON IF (X86_64 OR X86) )
|
||||
OCV_OPTION(WITH_JASPER "Include JPEG2K support" ON IF (NOT IOS) )
|
||||
OCV_OPTION(WITH_JPEG "Include JPEG support" ON)
|
||||
OCV_OPTION(WITH_WEBP "Include WebP support" ON IF (NOT IOS) )
|
||||
@@ -153,7 +153,7 @@ OCV_OPTION(WITH_V4L "Include Video 4 Linux support" ON
|
||||
OCV_OPTION(WITH_LIBV4L "Use libv4l for Video 4 Linux support" ON IF (UNIX AND NOT ANDROID) )
|
||||
OCV_OPTION(WITH_DSHOW "Build VideoIO with DirectShow support" ON IF (WIN32 AND NOT ARM) )
|
||||
OCV_OPTION(WITH_MSMF "Build VideoIO with Media Foundation support" OFF IF WIN32 )
|
||||
OCV_OPTION(WITH_XIMEA "Include XIMEA cameras support" OFF IF (NOT ANDROID AND NOT APPLE) )
|
||||
OCV_OPTION(WITH_XIMEA "Include XIMEA cameras support" OFF IF (NOT ANDROID) )
|
||||
OCV_OPTION(WITH_XINE "Include Xine support (GPL)" OFF IF (UNIX AND NOT APPLE AND NOT ANDROID) )
|
||||
OCV_OPTION(WITH_CLP "Include Clp support (EPL)" OFF)
|
||||
OCV_OPTION(WITH_OPENCL "Include OpenCL Runtime support" ON IF (NOT IOS) )
|
||||
@@ -215,13 +215,18 @@ OCV_OPTION(ENABLE_SSSE3 "Enable SSSE3 instructions"
|
||||
OCV_OPTION(ENABLE_SSE41 "Enable SSE4.1 instructions" OFF IF ((CV_ICC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) )
|
||||
OCV_OPTION(ENABLE_SSE42 "Enable SSE4.2 instructions" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) )
|
||||
OCV_OPTION(ENABLE_AVX "Enable AVX instructions" OFF IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) )
|
||||
OCV_OPTION(ENABLE_NEON "Enable NEON instructions" OFF IF CMAKE_COMPILER_IS_GNUCXX AND ARM )
|
||||
OCV_OPTION(ENABLE_VFPV3 "Enable VFPv3-D32 instructions" OFF IF CMAKE_COMPILER_IS_GNUCXX AND ARM )
|
||||
OCV_OPTION(ENABLE_NEON "Enable NEON instructions" OFF IF CMAKE_COMPILER_IS_GNUCXX AND (ARM OR IOS) )
|
||||
OCV_OPTION(ENABLE_VFPV3 "Enable VFPv3-D32 instructions" OFF IF CMAKE_COMPILER_IS_GNUCXX AND (ARM OR IOS) )
|
||||
OCV_OPTION(ENABLE_NOISY_WARNINGS "Show all warnings even if they are too noisy" OFF )
|
||||
OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors" OFF )
|
||||
OCV_OPTION(ENABLE_WINRT_MODE "Build with Windows Runtime support" OFF IF WIN32 )
|
||||
OCV_OPTION(ENABLE_WINRT_MODE_NATIVE "Build with Windows Runtime native C++ support" OFF IF WIN32 )
|
||||
OCV_OPTION(ANDROID_EXAMPLES_WITH_LIBS "Build binaries of Android examples with native libraries" OFF IF ANDROID )
|
||||
OCV_OPTION(ENABLE_IMPL_COLLECTION "Collect implementation data on function call" OFF )
|
||||
|
||||
if(ENABLE_IMPL_COLLECTION)
|
||||
add_definitions(-DCV_COLLECT_IMPL_DATA)
|
||||
endif()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -254,7 +259,7 @@ else()
|
||||
set(OPENCV_DOC_INSTALL_PATH share/OpenCV/doc)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
if(DEFINED OpenCV_RUNTIME AND DEFINED OpenCV_ARCH)
|
||||
set(OpenCV_INSTALL_BINARIES_PREFIX "${OpenCV_ARCH}/${OpenCV_RUNTIME}/")
|
||||
else()
|
||||
@@ -294,7 +299,7 @@ if(ANDROID)
|
||||
else()
|
||||
set(LIBRARY_OUTPUT_PATH "${OpenCV_BINARY_DIR}/lib")
|
||||
set(3P_LIBRARY_OUTPUT_PATH "${OpenCV_BINARY_DIR}/3rdparty/lib${LIB_SUFFIX}")
|
||||
if(WIN32)
|
||||
if(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
if(OpenCV_STATIC)
|
||||
set(OPENCV_LIB_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}")
|
||||
else()
|
||||
@@ -359,7 +364,7 @@ set(OPENCV_EXTRA_MODULES_PATH "" CACHE PATH "Where to look for additional OpenCV
|
||||
find_host_package(Git QUIET)
|
||||
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "2.[0-9].[0-9]*"
|
||||
execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*"
|
||||
WORKING_DIRECTORY "${OpenCV_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE OPENCV_VCSVERSION
|
||||
RESULT_VARIABLE GIT_RESULT
|
||||
@@ -453,8 +458,13 @@ include(cmake/OpenCVFindLibsPerf.cmake)
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# --- LATEX for pdf documentation ---
|
||||
unset(HAVE_DOXYGEN CACHE)
|
||||
if(BUILD_DOCS)
|
||||
include(cmake/OpenCVFindLATEX.cmake)
|
||||
find_host_program(DOXYGEN_BUILD doxygen)
|
||||
if (DOXYGEN_BUILD)
|
||||
set(HAVE_DOXYGEN 1)
|
||||
endif (DOXYGEN_BUILD)
|
||||
endif(BUILD_DOCS)
|
||||
|
||||
# --- Python Support ---
|
||||
@@ -1043,7 +1053,8 @@ status(" ant:" ANT_EXECUTABLE THEN "${ANT_EXECUTABLE} (ver ${A
|
||||
if(NOT ANDROID)
|
||||
status(" JNI:" JNI_INCLUDE_DIRS THEN "${JNI_INCLUDE_DIRS}" ELSE NO)
|
||||
endif()
|
||||
status(" Java tests:" BUILD_TESTS AND (CAN_BUILD_ANDROID_PROJECTS OR HAVE_opencv_java) THEN YES ELSE NO)
|
||||
status(" Java wrappers:" HAVE_opencv_java THEN YES ELSE NO)
|
||||
status(" Java tests:" BUILD_TESTS AND opencv_test_java_BINARY_DIR THEN YES ELSE NO)
|
||||
|
||||
# ========================= matlab =========================
|
||||
status("")
|
||||
@@ -1065,6 +1076,7 @@ if(BUILD_DOCS)
|
||||
status(" Sphinx:" HAVE_SPHINX THEN "${SPHINX_BUILD} (ver ${SPHINX_VERSION})" ELSE NO)
|
||||
status(" PdfLaTeX compiler:" PDFLATEX_COMPILER THEN "${PDFLATEX_COMPILER}" ELSE NO)
|
||||
status(" PlantUML:" PLANTUML THEN "${PLANTUML}" ELSE NO)
|
||||
status(" Doxygen:" HAVE_DOXYGEN THEN "YES (${DOXYGEN_BUILD})" ELSE NO)
|
||||
endif()
|
||||
|
||||
# ========================== samples and tests ==========================
|
||||
|
||||
@@ -106,6 +106,10 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
add_extra_compiler_option(-march=i686)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_extra_compiler_option(-Wno-semicolon-before-method-body)
|
||||
endif()
|
||||
|
||||
# Other optimizations
|
||||
if(ENABLE_OMIT_FRAME_POINTER)
|
||||
add_extra_compiler_option(-fomit-frame-pointer)
|
||||
|
||||
@@ -83,7 +83,12 @@ function(find_python preferred_version min_version library_env include_dir_env
|
||||
endif()
|
||||
|
||||
# not using _version_string here, because it might not conform to the CMake version format
|
||||
find_host_package(PythonLibs "${_version_major_minor}.${_version_patch}" EXACT)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
# builder version can differ from target, matching base version (e.g. 2.7)
|
||||
find_host_package(PythonLibs "${_version_major_minor}")
|
||||
else()
|
||||
find_host_package(PythonLibs "${_version_major_minor}.${_version_patch}" EXACT)
|
||||
endif()
|
||||
|
||||
if(PYTHONLIBS_FOUND)
|
||||
# Copy outputs
|
||||
@@ -228,7 +233,7 @@ find_python(3.4 "${MIN_VER_PYTHON3}" PYTHON3_LIBRARY PYTHON3_INCLUDE_DIR
|
||||
PYTHON3_NUMPY_INCLUDE_DIRS PYTHON3_NUMPY_VERSION)
|
||||
|
||||
# Use Python 2 as default Python interpreter
|
||||
if(PYTHON2LIBS_FOUND)
|
||||
if(PYTHON2INTERP_FOUND)
|
||||
set(PYTHON_DEFAULT_AVAILABLE "TRUE")
|
||||
set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
@@ -254,6 +254,7 @@ if(WITH_DSHOW)
|
||||
endif(WITH_DSHOW)
|
||||
|
||||
# --- VideoInput/Microsoft Media Foundation ---
|
||||
ocv_clear_vars(HAVE_MSMF)
|
||||
if(WITH_MSMF)
|
||||
check_include_file(Mfapi.h HAVE_MSMF)
|
||||
endif(WITH_MSMF)
|
||||
|
||||
@@ -31,6 +31,12 @@ if(WIN32)
|
||||
else()
|
||||
set(XIMEA_FOUND 0)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
if(EXISTS /Library/Frameworks/m3api.framework)
|
||||
set(XIMEA_FOUND 1)
|
||||
else()
|
||||
set(XIMEA_FOUND 0)
|
||||
endif()
|
||||
else()
|
||||
if(EXISTS /opt/XIMEA)
|
||||
set(XIMEA_FOUND 1)
|
||||
|
||||
@@ -154,13 +154,19 @@ if(WIN32)
|
||||
endif()
|
||||
configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" @ONLY)
|
||||
configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" @ONLY)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" COMPONENT dev)
|
||||
install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
|
||||
else()
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" COMPONENT dev)
|
||||
install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
|
||||
endif()
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT dev)
|
||||
install(FILES "${OpenCV_SOURCE_DIR}/cmake/OpenCVConfig.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/" COMPONENT dev)
|
||||
if (CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" COMPONENT dev)
|
||||
install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
|
||||
else()
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" COMPONENT dev)
|
||||
install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
|
||||
endif()
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT dev)
|
||||
install(FILES "${OpenCV_SOURCE_DIR}/cmake/OpenCVConfig.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/" COMPONENT dev)
|
||||
else ()
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib/cmake/opencv-${OPENCV_VERSION}" COMPONENT dev)
|
||||
install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib/cmake/opencv-${OPENCV_VERSION}" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
|
||||
install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/opencv-${OPENCV_VERSION}" COMPONENT dev)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
@@ -945,9 +945,19 @@ function(ocv_add_samples)
|
||||
endif()
|
||||
|
||||
if(INSTALL_C_EXAMPLES AND NOT WIN32 AND EXISTS "${samples_path}")
|
||||
file(GLOB sample_files "${samples_path}/*")
|
||||
file(GLOB DEPLOY_FILES_AND_DIRS "${samples_path}/*")
|
||||
foreach(ITEM ${DEPLOY_FILES_AND_DIRS})
|
||||
IF( IS_DIRECTORY "${ITEM}" )
|
||||
LIST( APPEND sample_dirs "${ITEM}" )
|
||||
ELSE()
|
||||
LIST( APPEND sample_files "${ITEM}" )
|
||||
ENDIF()
|
||||
endforeach()
|
||||
install(FILES ${sample_files}
|
||||
DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/${module_id}
|
||||
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples)
|
||||
install(DIRECTORY ${sample_dirs}
|
||||
DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/${module_id}
|
||||
USE_SOURCE_PERMISSIONS COMPONENT samples)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -242,6 +242,24 @@ macro(ocv_warnings_disable)
|
||||
endif(NOT ENABLE_NOISY_WARNINGS)
|
||||
endmacro()
|
||||
|
||||
macro(add_apple_compiler_options the_module)
|
||||
ocv_check_flag_support(OBJCXX "-fobjc-exceptions" HAVE_OBJC_EXCEPTIONS)
|
||||
if(HAVE_OBJC_EXCEPTIONS)
|
||||
foreach(source ${OPENCV_MODULE_${the_module}_SOURCES})
|
||||
if("${source}" MATCHES "\\.mm$")
|
||||
get_source_file_property(flags "${source}" COMPILE_FLAGS)
|
||||
if(flags)
|
||||
set(flags "${_flags} -fobjc-exceptions")
|
||||
else()
|
||||
set(flags "-fobjc-exceptions")
|
||||
endif()
|
||||
|
||||
set_source_files_properties("${source}" PROPERTIES COMPILE_FLAGS "${flags}")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Provides an option that the user can optionally select.
|
||||
# Can accept condition to control when option is available for user.
|
||||
# Usage:
|
||||
|
||||
@@ -49,7 +49,7 @@ if(NOT DEFINED OpenCV_MODULES_SUFFIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(@USE_IPPICV@) # value is defined by package builder
|
||||
if("@USE_IPPICV@" STREQUAL "TRUE") # value is defined by package builder (use STREQUAL to comply new CMake policy CMP0012)
|
||||
if(NOT TARGET ippicv)
|
||||
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_PATH_RELATIVE_IPPICV@")
|
||||
add_library(ippicv STATIC IMPORTED)
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
#
|
||||
#-----------------------
|
||||
# CMake file for OpenCV docs
|
||||
#
|
||||
#-----------------------
|
||||
|
||||
if(BUILD_DOCS AND HAVE_SPHINX)
|
||||
set(HAVE_DOC_GENERATOR BUILD_DOCS AND (HAVE_SPHINX OR HAVE_DOXYGEN))
|
||||
|
||||
if(HAVE_DOC_GENERATOR)
|
||||
project(opencv_docs)
|
||||
|
||||
set(DOC_LIST
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo2.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo-white.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv.ico"
|
||||
"${OpenCV_SOURCE_DIR}/doc/pattern.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/acircles_pattern.png")
|
||||
if(NOT INSTALL_CREATE_DISTRIB)
|
||||
list(APPEND DOC_LIST "${OpenCV_SOURCE_DIR}/doc/haartraining.htm")
|
||||
endif()
|
||||
|
||||
set(OPTIONAL_DOC_LIST "")
|
||||
|
||||
|
||||
# build lists of modules to be documented
|
||||
set(BASE_MODULES "")
|
||||
set(EXTRA_MODULES "")
|
||||
@@ -32,18 +18,29 @@ if(BUILD_DOCS AND HAVE_SPHINX)
|
||||
list(APPEND EXTRA_MODULES ${mod})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(FIXED_ORDER_MODULES core imgproc imgcodecs videoio highgui video calib3d features2d objdetect ml flann photo stitching)
|
||||
|
||||
list(REMOVE_ITEM BASE_MODULES ${FIXED_ORDER_MODULES})
|
||||
|
||||
ocv_list_sort(BASE_MODULES)
|
||||
ocv_list_sort(EXTRA_MODULES)
|
||||
|
||||
set(FIXED_ORDER_MODULES core imgproc imgcodecs videoio highgui video calib3d features2d objdetect ml flann photo stitching)
|
||||
list(REMOVE_ITEM BASE_MODULES ${FIXED_ORDER_MODULES})
|
||||
set(BASE_MODULES ${FIXED_ORDER_MODULES} ${BASE_MODULES})
|
||||
|
||||
# build lists of documentation files and generate table of contents for reference manual
|
||||
set(DOC_LIST
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo2.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv-logo-white.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/opencv.ico"
|
||||
"${OpenCV_SOURCE_DIR}/doc/pattern.png"
|
||||
"${OpenCV_SOURCE_DIR}/doc/acircles_pattern.png")
|
||||
set(OPTIONAL_DOC_LIST "")
|
||||
endif(HAVE_DOC_GENERATOR)
|
||||
|
||||
# ========= Sphinx docs =========
|
||||
if(BUILD_DOCS AND HAVE_SPHINX)
|
||||
if(NOT INSTALL_CREATE_DISTRIB)
|
||||
list(APPEND DOC_LIST "${OpenCV_SOURCE_DIR}/doc/haartraining.htm")
|
||||
endif()
|
||||
|
||||
# build lists of documentation files and generate table of contents for reference manual
|
||||
set(DOC_FAKE_ROOT "${CMAKE_CURRENT_BINARY_DIR}/fake-root")
|
||||
set(DOC_FAKE_ROOT_FILES "")
|
||||
|
||||
@@ -103,7 +100,6 @@ if(BUILD_DOCS AND HAVE_SPHINX)
|
||||
if(PDFLATEX_COMPILER)
|
||||
add_custom_target(docs
|
||||
COMMAND ${SPHINX_BUILD} ${BUILD_PLANTUML} -b latex -c "${CMAKE_CURRENT_SOURCE_DIR}" "${DOC_FAKE_ROOT}" .
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/pics ${CMAKE_CURRENT_BINARY_DIR}/doc/opencv1/pics
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/patch_refman_latex.py" opencv2refman.tex
|
||||
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/patch_refman_latex.py" opencv2manager.tex
|
||||
@@ -147,12 +143,48 @@ if(BUILD_DOCS AND HAVE_SPHINX)
|
||||
set_target_properties(html_docs PROPERTIES FOLDER "documentation")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
# ========= Doxygen docs =========
|
||||
if(BUILD_DOCS AND HAVE_DOXYGEN)
|
||||
set(candidates)
|
||||
set(all_headers)
|
||||
set(all_images)
|
||||
list(APPEND candidates ${BASE_MODULES} ${EXTRA_MODULES})
|
||||
# blacklisted modules
|
||||
ocv_list_filterout(candidates "^ts$")
|
||||
# gathering headers
|
||||
foreach(m ${candidates})
|
||||
set(all_headers ${all_headers} "${OPENCV_MODULE_opencv_${m}_HEADERS}")
|
||||
set(docs_dir "${OPENCV_MODULE_opencv_${m}_LOCATION}/doc")
|
||||
if(EXISTS ${docs_dir})
|
||||
set(all_images ${all_images} ${docs_dir})
|
||||
set(all_headers ${all_headers} ${docs_dir})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# additional config
|
||||
string(REGEX REPLACE ";" " \\\\\\n" CMAKE_DOXYGEN_INPUT_LIST "${all_headers}")
|
||||
string(REGEX REPLACE ";" " \\\\\\n" CMAKE_DOXYGEN_IMAGE_PATH "${all_images}")
|
||||
set(CMAKE_DOXYGEN_INDEX_MD "${CMAKE_SOURCE_DIR}/README.md")
|
||||
set(CMAKE_DOXYGEN_LAYOUT "${CMAKE_CURRENT_SOURCE_DIR}/DoxygenLayout.xml")
|
||||
set(CMAKE_DOXYGEN_OUTPUT_PATH "doxygen")
|
||||
|
||||
# writing file
|
||||
set(doxyfile "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
|
||||
configure_file(Doxyfile.in ${doxyfile} @ONLY)
|
||||
|
||||
add_custom_target(doxygen
|
||||
COMMAND ${DOXYGEN_BUILD} ${doxyfile}
|
||||
DEPENDS ${doxyfile} ${all_headers} ${all_images})
|
||||
endif()
|
||||
|
||||
if(HAVE_DOC_GENERATOR)
|
||||
# installation
|
||||
foreach(f ${DOC_LIST})
|
||||
install(FILES "${f}" DESTINATION "${OPENCV_DOC_INSTALL_PATH}" COMPONENT docs)
|
||||
endforeach()
|
||||
|
||||
foreach(f ${OPTIONAL_DOC_LIST})
|
||||
install(FILES "${f}" DESTINATION "${OPENCV_DOC_INSTALL_PATH}" OPTIONAL COMPONENT docs)
|
||||
endforeach()
|
||||
|
||||
endif()
|
||||
endif(HAVE_DOC_GENERATOR)
|
||||
|
||||
@@ -1,124 +1,271 @@
|
||||
# Doxyfile 1.3.9.1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = opencv
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = OpenCV
|
||||
PROJECT_NUMBER = @OPENCV_VERSION@
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
PROJECT_BRIEF = "Open Source Computer Vision"
|
||||
PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/opencv-logo-small.png
|
||||
OUTPUT_DIRECTORY = @CMAKE_DOXYGEN_OUTPUT_PATH@
|
||||
CREATE_SUBDIRS = YES
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
SORT_BRIEF_DOCS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
TCL_SUBST =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
MARKDOWN_SUPPORT = YES
|
||||
AUTOLINK_SUPPORT = NO
|
||||
BUILTIN_STL_SUPPORT = YES
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
INLINE_SIMPLE_STRUCTS = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_PACKAGE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
SHOW_GROUPED_MEMB_INC = NO
|
||||
FORCE_LOCAL_INCLUDES = NO
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
STRICT_PROTO_MATCHING = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE = @CMAKE_DOXYGEN_LAYOUT@
|
||||
CITE_BIB_FILES =
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = @CMAKE_DOXYGEN_INPUT_LIST@
|
||||
FILE_PATTERNS = *.cpp *.h*
|
||||
RECURSIVE = NO
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS =
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS = CV_WRAP \
|
||||
CV_EXPORTS \
|
||||
CV_EXPORTS_W \
|
||||
CV_WRAP_AS
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH = @CMAKE_DOXYGEN_IMAGE_PATH@
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
FILTER_SOURCE_PATTERNS =
|
||||
USE_MDFILE_AS_MAINPAGE = @CMAKE_DOXYGEN_INDEX_MD@
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
SOURCE_TOOLTIPS = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = NO
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
|
||||
DOCSET_PUBLISHER_NAME = Publisher
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE = org.doxygen.Project
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
GENERATE_ECLIPSEHELP = NO
|
||||
ECLIPSE_DOC_ID = org.doxygen.Project
|
||||
DISABLE_INDEX = YES
|
||||
GENERATE_TREEVIEW = YES
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
TREEVIEW_WIDTH = 250
|
||||
EXT_LINKS_IN_WINDOW = YES
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_FORMAT = HTML-CSS
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_EXTENSIONS =
|
||||
MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
SERVER_BASED_SEARCH = NO
|
||||
EXTERNAL_SEARCH = NO
|
||||
SEARCHENGINE_URL =
|
||||
SEARCHDATA_FILE = searchdata.xml
|
||||
EXTERNAL_SEARCH_ID =
|
||||
EXTRA_SEARCH_MAPPINGS =
|
||||
GENERATE_LATEX = YES
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
LATEX_FOOTER =
|
||||
LATEX_EXTRA_FILES =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
GENERATE_RTF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
GENERATE_MAN = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
GENERATE_XML = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
XML_OUTPUT = xml
|
||||
XML_PROGRAMLISTING = YES
|
||||
GENERATE_DOCBOOK = NO
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
PREDEFINED = CV_EXPORTS= CVAPI(x)=x __cplusplus=1
|
||||
SEARCH_INCLUDES = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = CV_WRAP= \
|
||||
__cplusplus=1 \
|
||||
CVAPI(x)=x \
|
||||
CV_PROP_RW= \
|
||||
CV_EXPORTS= \
|
||||
CV_EXPORTS_W=
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
MSCGEN_PATH =
|
||||
DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = NO
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
UML_LOOK = NO
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = YES
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALL_GRAPH = YES
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = svg
|
||||
INTERACTIVE_SVG = YES
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = YES
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
<doxygenlayout version="1.0">
|
||||
<!-- Generated by doxygen 1.8.6 -->
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="yes" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="" intro=""/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="filelist" visible="yes" title="Files index" intro=""/>
|
||||
<tab type="globals" visible="yes" title="Global objects" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<memberdecl>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<services title=""/>
|
||||
<interfaces title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<allmemberslink visible="yes"/>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="yes"/>
|
||||
<memberdecl>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="yes"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<memberdecl>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<constantgroups visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="yes"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<memberdecl>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
<membergroups visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
<detaileddescription title=""/>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
@@ -0,0 +1,274 @@
|
||||
{#
|
||||
basic/layout.html
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Master layout template for Sphinx themes.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- block doctype -%}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
{%- endblock %}
|
||||
{% set script_files = script_files + [pathto("_static/insertIframe.js", 1)] %}
|
||||
{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
|
||||
{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
|
||||
{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and
|
||||
(sidebars != []) %}
|
||||
{%- set url_root = pathto('', 1) %}
|
||||
{# XXX necessary? #}
|
||||
{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
|
||||
{%- if not embedded and docstitle %}
|
||||
{%- set titlesuffix = " — "|safe + docstitle|e %}
|
||||
{%- else %}
|
||||
{%- set titlesuffix = "" %}
|
||||
{%- endif %}
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-33108845-1']);
|
||||
_gaq.push(['_setDomainName', 'opencv.org']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
{%- macro relbar() %}
|
||||
<div class="related">
|
||||
<h3>{{ _('Navigation') }}</h3>
|
||||
<ul>
|
||||
{%- for rellink in rellinks %}
|
||||
<li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
|
||||
<a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
|
||||
{{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
|
||||
{%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
|
||||
{%- endfor %}
|
||||
{%- block rootrellink %}
|
||||
<li><a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}</li>
|
||||
{%- endblock %}
|
||||
{%- for parent in parents %}
|
||||
<li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
|
||||
{%- endfor %}
|
||||
{%- block relbaritems %} {% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro sidebar() %}
|
||||
{%- if render_sidebar %}
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
{%- block sidebarlogo %}
|
||||
{%- if logo %}
|
||||
<p class="logo"><a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- if sidebars == None %}
|
||||
{%- block sidebarsearch %}
|
||||
{%- include "searchbox.html" %}
|
||||
{%- endblock %}
|
||||
{%- endif %}
|
||||
{%- if sidebars != None %}
|
||||
{#- new style sidebar: explicitly include/exclude templates #}
|
||||
{%- for sidebartemplate in sidebars %}
|
||||
{%- include sidebartemplate %}
|
||||
{%- endfor %}
|
||||
{%- else %}
|
||||
{#- old style sidebars: using blocks -- should be deprecated #}
|
||||
{%- block sidebartoc %}
|
||||
{%- include "localtoc.html" %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarrel %}
|
||||
{%- include "relations.html" %}
|
||||
{%- endblock %}
|
||||
{%- if customsidebar %}
|
||||
{%- include customsidebar %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro script() %}
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: '{{ url_root }}',
|
||||
VERSION: '{{ release|e }}',
|
||||
COLLAPSE_INDEX: false,
|
||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||
HAS_SOURCE: {{ has_source|lower }}
|
||||
};
|
||||
</script>
|
||||
{%- for scriptfile in script_files %}
|
||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro css() %}
|
||||
<link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
|
||||
{%- for cssfile in css_files %}
|
||||
<link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
|
||||
{%- endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset={{ encoding }}" />
|
||||
{{ metatags }}
|
||||
{%- block htmltitle %}
|
||||
<title>{{ title|striptags|e }}{{ titlesuffix }}</title>
|
||||
{%- endblock %}
|
||||
{{ css() }}
|
||||
{%- if not embedded %}
|
||||
{{ script() }}
|
||||
{%- if use_opensearch %}
|
||||
<link rel="search" type="application/opensearchdescription+xml"
|
||||
title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
|
||||
href="{{ pathto('_static/opensearch.xml', 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- if favicon %}
|
||||
<link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- block linktags %}
|
||||
{%- if hasdoc('about') %}
|
||||
<link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('genindex') %}
|
||||
<link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('search') %}
|
||||
<link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
|
||||
{%- endif %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
<link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
|
||||
{%- endif %}
|
||||
<link rel="top" title="{{ docstitle|e }}" href="{{ pathto('index') }}" />
|
||||
{%- if parents %}
|
||||
<link rel="up" title="{{ parents[-1].title|striptags|e }}" href="{{ parents[-1].link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- if prev %}
|
||||
<link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block extrahead %}
|
||||
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300,400,700'
|
||||
rel='stylesheet' type='text/css' />
|
||||
{%- if not embedded %}
|
||||
<style type="text/css">
|
||||
table.right { float: right; margin-left: 20px; }
|
||||
table.right td { border: 1px solid #ccc; }
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
// intelligent scrolling of the sidebar content
|
||||
$(window).scroll(function() {
|
||||
var sb = $('.sphinxsidebarwrapper');
|
||||
var win = $(window);
|
||||
var sbh = sb.height();
|
||||
var offset = $('.sphinxsidebar').position()['top'];
|
||||
var wintop = win.scrollTop();
|
||||
var winbot = wintop + win.innerHeight();
|
||||
var curtop = sb.position()['top'];
|
||||
var curbot = curtop + sbh;
|
||||
// does sidebar fit in window?
|
||||
if (sbh < win.innerHeight()) {
|
||||
// yes: easy case -- always keep at the top
|
||||
sb.css('top', $u.min([$u.max([0, wintop - offset - 10]),
|
||||
$(document).height() - sbh - 200]));
|
||||
} else {
|
||||
// no: only scroll if top/bottom edge of sidebar is at
|
||||
// top/bottom edge of window
|
||||
if (curtop > wintop && curbot > winbot) {
|
||||
sb.css('top', $u.max([wintop - offset - 10, 0]));
|
||||
} else if (curtop < wintop && curbot < winbot) {
|
||||
sb.css('top', $u.min([winbot - sbh - offset - 20,
|
||||
$(document).height() - sbh - 200]));
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{%- endif %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
{%- block header %}{% endblock %}
|
||||
|
||||
{%- block relbar1 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block sidebar1 %} {# possible location for sidebar #} {% endblock %}
|
||||
{%- block sidebar2 %}{{ sidebar() }}{% endblock %}
|
||||
<body>
|
||||
|
||||
{%- block content %}
|
||||
|
||||
<div class="document">
|
||||
{%- block document %}
|
||||
<div class="documentwrapper">
|
||||
{%- if render_sidebar %}
|
||||
<div class="bodywrapper">
|
||||
{%- endif %}
|
||||
<div class="body">
|
||||
{% block body %} {% endblock %}
|
||||
</div>
|
||||
<div class="feedback">
|
||||
<h2>Help and Feedback</h2>
|
||||
You did not find what you were looking for?
|
||||
<ul>
|
||||
{% if theme_lang == 'c' %}
|
||||
{% endif %}
|
||||
{% if theme_lang == 'cpp' %}
|
||||
<li>Try the <a href="http://docs.opencv.org/opencv_cheatsheet.pdf">Cheatsheet</a>.</li>
|
||||
{% endif %}
|
||||
{% if theme_lang == 'py' %}
|
||||
<li>Try the <a href="cookbook.html">Cookbook</a>.</li>
|
||||
{% endif %}
|
||||
<li>Ask a question on the <a href="http://answers.opencv.org">Q&A forum</a>.</li>
|
||||
<li>If you think something is missing or wrong in the documentation,
|
||||
please file a <a href="http://code.opencv.org">bug report</a>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
{%- if render_sidebar %}
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
<div class="clearer"></div>
|
||||
</div>
|
||||
{%- endblock %}
|
||||
|
||||
{%- block relbar2 %}{{ relbar() }}{% endblock %}
|
||||
|
||||
{%- block footer %}
|
||||
<div class="footer">
|
||||
{%- if show_copyright %}
|
||||
{%- if hasdoc('copyright') %}
|
||||
{% trans path=pathto('copyright'), copyright=copyright|e %}© <a href="{{ path }}">Copyright</a> {{ copyright }}.{% endtrans %}
|
||||
{%- else %}
|
||||
{% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- endif %}
|
||||
{%- if last_updated %}
|
||||
{% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- if show_sphinx %}
|
||||
{% trans sphinx_version=sphinx_version|e %}Created using <a href="http://sphinx-doc.org/">Sphinx</a> {{ sphinx_version }}.{% endtrans %}
|
||||
{%- endif %}
|
||||
{%- if show_source and has_source and sourcename %}
|
||||
<a href="{{ pathto('_sources/' + sourcename, true)|e }}" rel="nofollow">{{ _('Show this page source.') }}</a>
|
||||
{%- endif %}
|
||||
</div>
|
||||
{%- endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
{#
|
||||
basic/searchbox.html
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sphinx sidebar template: quick search box.
|
||||
|
||||
:copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
#}
|
||||
{%- if pagename != "search" and builder != "singlehtml" %}
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>{{ _('Quick search') }}</h3>
|
||||
<form class="search" action="{{ pathto('search') }}" method="get">
|
||||
<input type="text" name="q" />
|
||||
<input type="submit" value="{{ _('Go') }}" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
{%- endif %}
|
||||
|
After Width: | Height: | Size: 513 B |
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* sphinxdoc.css_t
|
||||
* ~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- sphinxdoc theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
background-image: url(bodybg.png);
|
||||
color: black;
|
||||
padding: 0;
|
||||
border-right: 1px solid #0a507a;
|
||||
border-left: 1px solid #0a507a;
|
||||
|
||||
margin: 0 auto;
|
||||
min-width: 780px;
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: white;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 240px 0 0;
|
||||
border-right: 1px solid #0a507a;
|
||||
}
|
||||
|
||||
div.body {
|
||||
margin: 0;
|
||||
padding: 0.5em 20px 20px 20px;
|
||||
}
|
||||
|
||||
div.related {
|
||||
font-size: 1em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
background-image: url(relbg.png);
|
||||
text-align: left;
|
||||
border-top: 1px solid #002e50;
|
||||
border-bottom: 1px solid #002e50;
|
||||
}
|
||||
|
||||
div.related li + li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related ul li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
div.related ul li a {
|
||||
margin: 0;
|
||||
padding: 0 5px 0 5px;
|
||||
line-height: 1.75em;
|
||||
color: #f9f9f0;
|
||||
text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
div.related ul li a:hover {
|
||||
color: white;
|
||||
text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
div.footer {
|
||||
background-image: url(footerbg.png);
|
||||
color: #ccc;
|
||||
text-shadow: 0 0 .2px rgba(255, 255, 255, 0.8);
|
||||
padding: 3px 8px 3px 0;
|
||||
clear: both;
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
word-wrap: break-word;
|
||||
margin: 0;
|
||||
padding: 0 15px 15px 0;
|
||||
width: 210px;
|
||||
float: right;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.sphinxsidebar .logo {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.sphinxsidebar .logo img {
|
||||
width: 150px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #aaa;
|
||||
font-family: 'Open Sans', 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||
'Verdana', sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="text"] {
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar #searchbox input[type="submit"] {
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 {
|
||||
font-size: 1.5em;
|
||||
border-top: 1px solid #0a507a;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4 {
|
||||
font-size: 1.2em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
||||
margin-right: -15px;
|
||||
margin-left: -15px;
|
||||
padding-right: 14px;
|
||||
padding-left: 14px;
|
||||
color: #333;
|
||||
font-weight: 300;
|
||||
/*text-shadow: 0px 0px 0.5px rgba(0, 0, 0, 0.4);*/
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper > h3:first-child {
|
||||
margin-top: 0.5em;
|
||||
border: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
color: #444;
|
||||
margin-top: 7px;
|
||||
padding: 0;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-left: 20px;
|
||||
list-style-image: url(listitem.png);
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
p {
|
||||
margin: 0.8em 0 0.5em 0;
|
||||
}
|
||||
|
||||
a, a tt {
|
||||
color: #2878a2;
|
||||
}
|
||||
|
||||
a:hover, a tt:hover {
|
||||
color: #68b8c2;
|
||||
}
|
||||
|
||||
a tt {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #0a507a;
|
||||
background-color: #e5f5ff;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 1.em 0 0.2em 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1em 0 -0.3em 0;
|
||||
}
|
||||
|
||||
h1 { font-size: 200%; }
|
||||
h2 { font-size: 160%; }
|
||||
h3 { font-size: 140%; }
|
||||
h4 { font-size: 120%; }
|
||||
h5 { font-size: 110%; }
|
||||
h6 { font-size: 100%; }
|
||||
|
||||
div a, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.body h1 a tt, div.body h2 a tt, div.body h3 a tt,
|
||||
div.body h4 a tt, div.body h5 a tt, div.body h6 a tt {
|
||||
color: #0a507a !important;
|
||||
font-size: inherit !important;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
color: #0a507a !important;
|
||||
font-size: 12px;
|
||||
margin-left: 6px;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none !important;
|
||||
float: right;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #ccc;
|
||||
color: white!important;
|
||||
}
|
||||
|
||||
cite, code, tt {
|
||||
font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono',
|
||||
monospace;
|
||||
font-size: 14px;
|
||||
min-width: 780px;
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
tt {
|
||||
color: #003048;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
tt.descname, tt.descclassname, tt.xref {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #abc;
|
||||
margin: 2em;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'Consolas', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono',
|
||||
monospace;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.015em;
|
||||
line-height: 120%;
|
||||
padding: 0.5em;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 2px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
pre a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
td.code pre {
|
||||
max-width: 740px;
|
||||
overflow: auto;
|
||||
overflow-y: hidden; /* fixes display issues on Chrome browsers */
|
||||
}
|
||||
|
||||
div.quotebar {
|
||||
background-color: #f8f8f8;
|
||||
max-width: 250px;
|
||||
float: right;
|
||||
padding: 0px 7px;
|
||||
border: 1px solid #ccc;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 -0.5em 0 -0.5em;
|
||||
}
|
||||
|
||||
table td, table th {
|
||||
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
div.admonition ul li, div.warning ul li,
|
||||
div.admonition ol li, div.warning ol li {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
/* ------------------ our styles ----------------*/
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
text-align: justify;
|
||||
line-height: 130%;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div.toctree-wrapper li, ul.simple li {
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/*a.toc-backref {
|
||||
}*/
|
||||
|
||||
div.feedback {
|
||||
/*background-color: #;*/
|
||||
/*color: #;*/
|
||||
padding: 20px 20px 30px 20px;
|
||||
border-top: 1px solid #002e50;
|
||||
}
|
||||
|
||||
div.feedback h2 {
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
div.feedback a {
|
||||
/*color: #;*/
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.math p {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dl.function > dt:first-child {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
dl.cfunction > dt:first-child {
|
||||
margin-bottom: 7px;
|
||||
color: #8080B0;
|
||||
}
|
||||
|
||||
dl.cfunction > dt:first-child tt.descname {
|
||||
color: #8080B0;
|
||||
}
|
||||
|
||||
dl.pyfunction > dt:first-child {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
dl.jfunction > dt:first-child {
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
table.field-list {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
em.menuselection, em.guilabel {
|
||||
font-family: 'Lucida Sans', 'Lucida Sans Unicode', 'Lucida Grande', Verdana,
|
||||
Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.enumeratevisibleitemswithsquare ul {
|
||||
list-style: square;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.enumeratevisibleitemswithsquare li {
|
||||
margin-bottom: 0.2em;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
.enumeratevisibleitemswithsquare p {
|
||||
margin-bottom: 0pt;
|
||||
margin-top: 1pt;
|
||||
}
|
||||
|
||||
.enumeratevisibleitemswithsquare dl {
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.toctableopencv {
|
||||
width: 100% ;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.toctableopencv colgroup col:first-child {
|
||||
width: 100pt !important;
|
||||
max-width: 100pt !important;
|
||||
min-width: 100pt !important;
|
||||
}
|
||||
|
||||
.toctableopencv colgroup col:nth-child(2) {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
div.body ul.search li {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.linenodiv {
|
||||
min-width: 1em;
|
||||
text-align: right;
|
||||
}
|
||||
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 230 B |
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 223 B |
@@ -0,0 +1,4 @@
|
||||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = default.css
|
||||
pygments_style = sphinx
|
||||
@@ -114,7 +114,7 @@ todo_include_todos=True
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'blue'
|
||||
html_theme = 'sphinxdoc'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
@@ -133,7 +133,7 @@ html_theme_path = ['_themes']
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = 'opencv-logo-white.png'
|
||||
html_logo = 'opencv-logo2.png'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
@@ -325,6 +325,7 @@ extlinks = {
|
||||
'imgproc_geometric' : ('http://docs.opencv.org/modules/imgproc/doc/geometric_transformations.html#%s', None ),
|
||||
'miscellaneous_transformations' : ('http://docs.opencv.org/modules/imgproc/doc/miscellaneous_transformations.html#%s', None),
|
||||
'user_interface' : ('http://docs.opencv.org/modules/highgui/doc/user_interface.html#%s', None),
|
||||
'video' : ('http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html#%s', None),
|
||||
|
||||
# 'opencv_group' : ('http://answers.opencv.org/%s', None),
|
||||
'opencv_qa' : ('http://answers.opencv.org/%s', None),
|
||||
@@ -402,6 +403,7 @@ extlinks = {
|
||||
'contour_area' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=contourarea#contourarea%s', None),
|
||||
'arc_length' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=arclength#arclength%s', None),
|
||||
'point_polygon_test' : ('http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest%s', None),
|
||||
'feature_detection_and_description' : ('http://docs.opencv.org/modules/features2d/doc/feature_detection_and_description.html#%s', None),
|
||||
'feature_detector' : ( 'http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=featuredetector#FeatureDetector%s', None),
|
||||
'feature_detector_detect' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=detect#featuredetector-detect%s', None ),
|
||||
'surf_feature_detector' : ('http://docs.opencv.org/modules/features2d/doc/common_interfaces_of_feature_detectors.html?highlight=surffeaturedetector#surffeaturedetector%s', None ),
|
||||
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,112 @@
|
||||
.. _Bindings_Basics:
|
||||
|
||||
How OpenCV-Python Bindings Works?
|
||||
************************************
|
||||
|
||||
Goal
|
||||
=====
|
||||
|
||||
Learn:
|
||||
|
||||
* How OpenCV-Python bindings are generated?
|
||||
* How to extend new OpenCV modules to Python?
|
||||
|
||||
How OpenCV-Python bindings are generated?
|
||||
=========================================
|
||||
|
||||
In OpenCV, all algorithms are implemented in C++. But these algorithms can be used from different languages like Python, Java etc. This is made possible by the bindings generators. These generators create a bridge between C++ and Python which enables users to call C++ functions from Python. To get a complete picture of what is happening in background, a good knowledge of Python/C API is required. A simple example on extending C++ functions to Python can be found in official Python documentation[1]. So extending all functions in OpenCV to Python by writing their wrapper functions manually is a time-consuming task. So OpenCV does it in a more intelligent way. OpenCV generates these wrapper functions automatically from the C++ headers using some Python scripts which are located in ``modules/python/src2``. We will look into what they do.
|
||||
|
||||
First, ``modules/python/CMakeFiles.txt`` is a CMake script which checks the modules to be extended to Python. It will automatically check all the modules to be extended and grab their header files. These header files contain list of all classes, functions, constants etc. for that particular modules.
|
||||
|
||||
Second, these header files are passed to a Python script, ``modules/python/src2/gen2.py``. This is the Python bindings generator script. It calls another Python script ``modules/python/src2/hdr_parser.py``. This is the header parser script. This header parser splits the complete header file into small Python lists. So these lists contain all details about a particular function, class etc. For example, a function will be parsed to get a list containing function name, return type, input arguments, argument types etc. Final list contains details of all the functions, structs, classes etc. in that header file.
|
||||
|
||||
But header parser doesn't parse all the functions/classes in the header file. The developer has to specify which functions should be exported to Python. For that, there are certain macros added to the beginning of these declarations which enables the header parser to identify functions to be parsed. These macros are added by the developer who programs the particular function. In short, the developer decides which functions should be extended to Python and which are not. Details of those macros will be given in next session.
|
||||
|
||||
So header parser returns a final big list of parsed functions. Our generator script (gen2.py) will create wrapper functions for all the functions/classes/enums/structs parsed by header parser (You can find these header files during compilation in the ``build/modules/python/`` folder as ``pyopencv_generated_*.h`` files). But there may be some basic OpenCV datatypes like Mat, Vec4i, Size. They need to be extended manually. For example, a Mat type should be extended to Numpy array, Size should be extended to a tuple of two integers etc. Similarly, there may be some complex structs/classes/functions etc. which need to be extended manually. All such manual wrapper functions are placed in ``modules/python/src2/pycv2.hpp``.
|
||||
|
||||
So now only thing left is the compilation of these wrapper files which gives us **cv2** module. So when you call a function, say ``res = equalizeHist(img1,img2)`` in Python, you pass two numpy arrays and you expect another numpy array as the output. So these numpy arrays are converted to ``cv::Mat`` and then calls the ``equalizeHist()`` function in C++. Final result, ``res`` will be converted back into a Numpy array. So in short, almost all operations are done in C++ which gives us almost same speed as that of C++.
|
||||
|
||||
So this is the basic version of how OpenCV-Python bindings are generated.
|
||||
|
||||
|
||||
How to extend new modules to Python?
|
||||
=====================================
|
||||
|
||||
Header parser parse the header files based on some wrapper macros added to function declaration. Enumeration constants don't need any wrapper macros. They are automatically wrapped. But remaining functions, classes etc. need wrapper macros.
|
||||
|
||||
Functions are extended using ``CV_EXPORTS_W`` macro. An example is shown below.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
|
||||
|
||||
Header parser can understand the input and output arguments from keywords like ``InputArray, OutputArray`` etc. But sometimes, we may need to hardcode inputs and outputs. For that, macros like ``CV_OUT, CV_IN_OUT`` etc. are used.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
CV_EXPORTS_W void minEnclosingCircle( InputArray points,
|
||||
CV_OUT Point2f& center, CV_OUT float& radius );
|
||||
|
||||
For large classes also, ``CV_EXPORTS_W`` is used. To extend class methods, ``CV_WRAP`` is used. Similarly, ``CV_PROP`` is used for class fields.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
class CV_EXPORTS_W CLAHE : public Algorithm
|
||||
{
|
||||
public:
|
||||
CV_WRAP virtual void apply(InputArray src, OutputArray dst) = 0;
|
||||
|
||||
CV_WRAP virtual void setClipLimit(double clipLimit) = 0;
|
||||
CV_WRAP virtual double getClipLimit() const = 0;
|
||||
}
|
||||
|
||||
Overloaded functions can be extended using ``CV_EXPORTS_AS``. But we need to pass a new name so that each function will be called by that name in Python. Take the case of integral function below. Three functions are available, so each one is named with a suffix in Python. Similarly ``CV_WRAP_AS`` can be used to wrap overloaded methods.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
//! computes the integral image
|
||||
CV_EXPORTS_W void integral( InputArray src, OutputArray sum, int sdepth = -1 );
|
||||
|
||||
//! computes the integral image and integral for the squared image
|
||||
CV_EXPORTS_AS(integral2) void integral( InputArray src, OutputArray sum,
|
||||
OutputArray sqsum, int sdepth = -1, int sqdepth = -1 );
|
||||
|
||||
//! computes the integral image, integral for the squared image and the tilted integral image
|
||||
CV_EXPORTS_AS(integral3) void integral( InputArray src, OutputArray sum,
|
||||
OutputArray sqsum, OutputArray tilted,
|
||||
int sdepth = -1, int sqdepth = -1 );
|
||||
|
||||
Small classes/structs are extended using ``CV_EXPORTS_W_SIMPLE``. These structs are passed by value to C++ functions. Examples are KeyPoint, Match etc. Their methods are extended by ``CV_WRAP`` and fields are extended by ``CV_PROP_RW``.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
class CV_EXPORTS_W_SIMPLE DMatch
|
||||
{
|
||||
public:
|
||||
CV_WRAP DMatch();
|
||||
CV_WRAP DMatch(int _queryIdx, int _trainIdx, float _distance);
|
||||
CV_WRAP DMatch(int _queryIdx, int _trainIdx, int _imgIdx, float _distance);
|
||||
|
||||
CV_PROP_RW int queryIdx; // query descriptor index
|
||||
CV_PROP_RW int trainIdx; // train descriptor index
|
||||
CV_PROP_RW int imgIdx; // train image index
|
||||
|
||||
CV_PROP_RW float distance;
|
||||
};
|
||||
|
||||
Some other small classes/structs can be exported using ``CV_EXPORTS_W_MAP`` where it is exported to a Python native dictionary. Moments() is an example of it.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
class CV_EXPORTS_W_MAP Moments
|
||||
{
|
||||
public:
|
||||
//! spatial moments
|
||||
CV_PROP_RW double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03;
|
||||
//! central moments
|
||||
CV_PROP_RW double mu20, mu11, mu02, mu30, mu21, mu12, mu03;
|
||||
//! central normalized moments
|
||||
CV_PROP_RW double nu20, nu11, nu02, nu30, nu21, nu12, nu03;
|
||||
};
|
||||
|
||||
So these are the major extension macros available in OpenCV. Typically, a developer has to put proper macros in their appropriate positions. Rest is done by generator scripts. Sometimes, there may be an exceptional cases where generator scripts cannot create the wrappers. Such functions need to be handled manually. But most of the time, a code written according to OpenCV coding guidelines will be automatically wrapped by generator scripts.
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,36 @@
|
||||
.. _PY_Table-Of-Content-Bindings:
|
||||
|
||||
|
||||
OpenCV-Python Bindings
|
||||
--------------------------------
|
||||
|
||||
Here, you will learn how OpenCV-Python bindings are generated.
|
||||
|
||||
|
||||
* :ref:`Bindings_Basics`
|
||||
|
||||
.. tabularcolumns:: m{100pt} m{300pt}
|
||||
.. cssclass:: toctableopencv
|
||||
|
||||
=========== ======================================================
|
||||
|bind1| Learn how OpenCV-Python bindings are generated.
|
||||
|
||||
=========== ======================================================
|
||||
|
||||
.. |bind1| image:: images/nlm_icon.jpg
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\pagebreak
|
||||
|
||||
.. We use a custom table of content format and as the table of content only informs Sphinx about the hierarchy of the files, no need to show it.
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
../py_bindings_basics/py_bindings_basics
|
||||
@@ -48,7 +48,7 @@ Below code snippet shows a simple procedure to create disparity map.
|
||||
plt.imshow(disparity,'gray')
|
||||
plt.show()
|
||||
|
||||
Below image contains the original image (left) and its disparity map (right). As you can see, result is contaminated with high degree of noise. By adjusting the values of numDisparities and blockSize, you can get more better result.
|
||||
Below image contains the original image (left) and its disparity map (right). As you can see, result is contaminated with high degree of noise. By adjusting the values of numDisparities and blockSize, you can get a better result.
|
||||
|
||||
.. image:: images/disparity_map.jpg
|
||||
:alt: Disparity Map
|
||||
|
||||
@@ -49,7 +49,7 @@ You can modify the pixel values the same way.
|
||||
|
||||
.. warning:: Numpy is a optimized library for fast array calculations. So simply accessing each and every pixel values and modifying it will be very slow and it is discouraged.
|
||||
|
||||
.. note:: Above mentioned method is normally used for selecting a region of array, say first 5 rows and last 3 columns like that. For individual pixel access, Numpy array methods, ``array.item()`` and ``array.itemset()`` is considered to be more better. But it always returns a scalar. So if you want to access all B,G,R values, you need to call ``array.item()`` separately for all.
|
||||
.. note:: Above mentioned method is normally used for selecting a region of array, say first 5 rows and last 3 columns like that. For individual pixel access, Numpy array methods, ``array.item()`` and ``array.itemset()`` is considered to be better. But it always returns a scalar. So if you want to access all B,G,R values, you need to call ``array.item()`` separately for all.
|
||||
|
||||
Better pixel accessing and editing method :
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ Measuring Performance in IPython
|
||||
|
||||
Sometimes you may need to compare the performance of two similar operations. IPython gives you a magic command ``%timeit`` to perform this. It runs the code several times to get more accurate results. Once again, they are suitable to measure single line codes.
|
||||
|
||||
For example, do you know which of the following addition operation is more better, ``x = 5; y = x**2``, ``x = 5; y = x*x``, ``x = np.uint8([5]); y = x*x`` or ``y = np.square(x)`` ? We will find it with %timeit in IPython shell.
|
||||
For example, do you know which of the following addition operation is better, ``x = 5; y = x**2``, ``x = 5; y = x*x``, ``x = np.uint8([5]); y = x*x`` or ``y = np.square(x)`` ? We will find it with %timeit in IPython shell.
|
||||
::
|
||||
|
||||
In [10]: x = 5
|
||||
|
||||
@@ -29,7 +29,7 @@ Image is very simple. At the top of image, six small image patches are given. Qu
|
||||
|
||||
A and B are flat surfaces, and they are spread in a lot of area. It is difficult to find the exact location of these patches.
|
||||
|
||||
C and D are much more simpler. They are edges of the building. You can find an approximate location, but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal to the edge, it is different. So edge is much more better feature compared to flat area, but not good enough (It is good in jigsaw puzzle for comparing continuity of edges).
|
||||
C and D are much more simpler. They are edges of the building. You can find an approximate location, but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal to the edge, it is different. So edge is a much better feature compared to flat area, but not good enough (It is good in jigsaw puzzle for comparing continuity of edges).
|
||||
|
||||
Finally, E and F are some corners of the building. And they can be easily found out. Because at corners, wherever you move this patch, it will look different. So they can be considered as a good feature. So now we move into more simpler (and widely used image) for better understanding.
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ Now I want to apply U-SURF, so that it won't find the orientation.
|
||||
|
||||
>>> plt.imshow(img2),plt.show()
|
||||
|
||||
See the results below. All the orientations are shown in same direction. It is more faster than previous. If you are working on cases where orientation is not a problem (like panorama stitching) etc, this is more better.
|
||||
See the results below. All the orientations are shown in same direction. It is more faster than previous. If you are working on cases where orientation is not a problem (like panorama stitching) etc, this is better.
|
||||
|
||||
.. image:: images/surf_kp2.jpg
|
||||
:alt: Upright-SURF
|
||||
|
||||
@@ -69,7 +69,7 @@ To draw a polygon, first you need coordinates of vertices. Make those points int
|
||||
|
||||
.. Note:: If third argument is ``False``, you will get a polylines joining all the points, not a closed shape.
|
||||
|
||||
.. Note:: ``cv2.polylines()`` can be used to draw multiple lines. Just create a list of all the lines you want to draw and pass it to the function. All lines will be drawn individually. It is more better and faster way to draw a group of lines than calling ``cv2.line()`` for each line.
|
||||
.. Note:: ``cv2.polylines()`` can be used to draw multiple lines. Just create a list of all the lines you want to draw and pass it to the function. All lines will be drawn individually. It is a much better and faster way to draw a group of lines than calling ``cv2.line()`` for each line.
|
||||
|
||||
Adding Text to Images:
|
||||
------------------------
|
||||
|
||||
@@ -48,7 +48,7 @@ Creating mouse callback function has a specific format which is same everywhere.
|
||||
More Advanced Demo
|
||||
===================
|
||||
|
||||
Now we go for much more better application. In this, we draw either rectangles or circles (depending on the mode we select) by dragging the mouse like we do in Paint application. So our mouse callback function has two parts, one to draw rectangle and other to draw the circles. This specific example will be really helpful in creating and understanding some interactive applications like object tracking, image segmentation etc.
|
||||
Now we go for a much better application. In this, we draw either rectangles or circles (depending on the mode we select) by dragging the mouse like we do in Paint application. So our mouse callback function has two parts, one to draw rectangle and other to draw the circles. This specific example will be really helpful in creating and understanding some interactive applications like object tracking, image segmentation etc.
|
||||
::
|
||||
|
||||
import cv2
|
||||
|
||||
@@ -64,7 +64,7 @@ The result we get is a two dimensional array of size 180x256. So we can show the
|
||||
|
||||
Method - 2 : Using Matplotlib
|
||||
------------------------------
|
||||
We can use **matplotlib.pyplot.imshow()** function to plot 2D histogram with different color maps. It gives us much more better idea about the different pixel density. But this also, doesn't gives us idea what color is there on a first look, unless you know the Hue values of different colors. Still I prefer this method. It is simple and better.
|
||||
We can use **matplotlib.pyplot.imshow()** function to plot 2D histogram with different color maps. It gives us a much better idea about the different pixel density. But this also, doesn't gives us idea what color is there on a first look, unless you know the Hue values of different colors. Still I prefer this method. It is simple and better.
|
||||
|
||||
.. note:: While using this function, remember, interpolation flag should be ``nearest`` for better results.
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ It was proposed by **Michael J. Swain , Dana H. Ballard** in their paper **Index
|
||||
|
||||
**What is it actually in simple words?** It is used for image segmentation or finding objects of interest in an image. In simple words, it creates an image of the same size (but single channel) as that of our input image, where each pixel corresponds to the probability of that pixel belonging to our object. In more simpler worlds, the output image will have our object of interest in more white compared to remaining part. Well, that is an intuitive explanation. (I can't make it more simpler). Histogram Backprojection is used with camshift algorithm etc.
|
||||
|
||||
**How do we do it ?** We create a histogram of an image containing our object of interest (in our case, the ground, leaving player and other things). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is more better way to define the object than its grayscale intensity. We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to the ground and show it. The resulting output on proper thresholding gives us the ground alone.
|
||||
**How do we do it ?** We create a histogram of an image containing our object of interest (in our case, the ground, leaving player and other things). The object should fill the image as far as possible for better results. And a color histogram is preferred over grayscale histogram, because color of the object is a better way to define the object than its grayscale intensity. We then "back-project" this histogram over our test image where we need to find the object, ie in other words, we calculate the probability of every pixel belonging to the ground and show it. The resulting output on proper thresholding gives us the ground alone.
|
||||
|
||||
Algorithm in Numpy
|
||||
====================
|
||||
|
||||
@@ -45,7 +45,7 @@ So now we use **cv2.calcHist()** function to find the histogram. Let's familiari
|
||||
.. centered:: *cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])*
|
||||
|
||||
#. images : it is the source image of type uint8 or float32. it should be given in square brackets, ie, "[img]".
|
||||
#. channels : it is also given in square brackets. It the index of channel for which we calculate histogram. For example, if input is grayscale image, its value is [0]. For color image, you can pass [0],[1] or [2] to calculate histogram of blue,green or red channel respectively.
|
||||
#. channels : it is also given in square brackets. It is the index of channel for which we calculate histogram. For example, if input is grayscale image, its value is [0]. For color image, you can pass [0], [1] or [2] to calculate histogram of blue, green or red channel respectively.
|
||||
#. mask : mask image. To find histogram of full image, it is given as "None". But if you want to find histogram of particular region of image, you have to create a mask image for that and give it as mask. (I will show an example later.)
|
||||
#. histSize : this represents our BIN count. Need to be given in square brackets. For full scale, we pass [256].
|
||||
#. ranges : this is our RANGE. Normally, it is [0,256].
|
||||
|
||||
@@ -37,7 +37,7 @@ Now let's see it in OpenCV.
|
||||
kNN in OpenCV
|
||||
===============
|
||||
|
||||
We will do a simple example here, with two families (classes), just like above. Then in the next chapter, we will do much more better example.
|
||||
We will do a simple example here, with two families (classes), just like above. Then in the next chapter, we will do an even better example.
|
||||
|
||||
So here, we label the Red family as **Class-0** (so denoted by 0) and Blue family as **Class-1** (denoted by 1). We create 25 families or 25 training data, and label them either Class-0 or Class-1. We do all these with the help of Random Number Generator in Numpy.
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -30,7 +30,7 @@ Installing OpenCV from prebuilt binaries
|
||||
|
||||
7. Goto **opencv/build/python/2.7** folder.
|
||||
|
||||
8. Copy **cv2.pyd** to **C:/Python27/lib/site-packeges**.
|
||||
8. Copy **cv2.pyd** to **C:/Python27/lib/site-packages**.
|
||||
|
||||
9. Open Python IDLE and type following codes in Python terminal.
|
||||
|
||||
|
||||
@@ -159,6 +159,20 @@ OpenCV-Python Tutorials
|
||||
:alt: OD Icon
|
||||
|
||||
|
||||
* :ref:`PY_Table-Of-Content-Bindings`
|
||||
|
||||
.. tabularcolumns:: m{100pt} m{300pt}
|
||||
.. cssclass:: toctableopencv
|
||||
|
||||
=========== =====================================================================
|
||||
|PyBin| In this section, we will see how OpenCV-Python bindings are generated
|
||||
|
||||
=========== =====================================================================
|
||||
|
||||
.. |PyBin| image:: images/obj_icon.jpg
|
||||
:height: 80pt
|
||||
:width: 80pt
|
||||
:alt: OD Icon
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
@@ -178,3 +192,4 @@ OpenCV-Python Tutorials
|
||||
py_ml/py_table_of_contents_ml/py_table_of_contents_ml
|
||||
py_photo/py_table_of_contents_photo/py_table_of_contents_photo
|
||||
py_objdetect/py_table_of_contents_objdetect/py_table_of_contents_objdetect
|
||||
py_bindings/py_table_of_contents_bindings/py_table_of_contents_bindings
|
||||
|
||||
@@ -9,7 +9,7 @@ Video Analysis
|
||||
.. cssclass:: toctableopencv
|
||||
|
||||
=========== ======================================================
|
||||
|vdo_1| We have already seen an example of color-based tracking. It is simpler. This time, we see much more better algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them.
|
||||
|vdo_1| We have already seen an example of color-based tracking. It is simpler. This time, we see significantly better algorithms like "Meanshift", and its upgraded version, "Camshift" to find and track them.
|
||||
|
||||
=========== ======================================================
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ Explanation
|
||||
{
|
||||
case Settings::CHESSBOARD:
|
||||
found = findChessboardCorners( view, s.boardSize, pointBuf,
|
||||
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);
|
||||
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);
|
||||
break;
|
||||
case Settings::CIRCLES_GRID:
|
||||
found = findCirclesGrid( view, s.boardSize, pointBuf );
|
||||
@@ -158,9 +158,9 @@ Explanation
|
||||
if( s.calibrationPattern == Settings::CHESSBOARD)
|
||||
{
|
||||
Mat viewGray;
|
||||
cvtColor(view, viewGray, CV_BGR2GRAY);
|
||||
cvtColor(view, viewGray, COLOR_BGR2GRAY);
|
||||
cornerSubPix( viewGray, pointBuf, Size(11,11),
|
||||
Size(-1,-1), TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
|
||||
Size(-1,-1), TermCriteria( TermCriteria::EPS+TermCriteria::MAX_ITER, 30, 0.1 ));
|
||||
}
|
||||
|
||||
if( mode == CAPTURING && // For camera only take new samples after delay time
|
||||
@@ -327,7 +327,7 @@ We do the calibration with the help of the :calib3d:`calibrateCamera <calibratec
|
||||
.. code-block:: cpp
|
||||
|
||||
cameraMatrix = Mat::eye(3, 3, CV_64F);
|
||||
if( s.flag & CV_CALIB_FIX_ASPECT_RATIO )
|
||||
if( s.flag & CALIB_FIX_ASPECT_RATIO )
|
||||
cameraMatrix.at<double>(0,0) = 1.0;
|
||||
|
||||
+ The distortion coefficient matrix. Initialize with zero.
|
||||
@@ -364,7 +364,7 @@ We do the calibration with the help of the :calib3d:`calibrateCamera <calibratec
|
||||
{
|
||||
projectPoints( Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, // project
|
||||
distCoeffs, imagePoints2);
|
||||
err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L2); // difference
|
||||
err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2); // difference
|
||||
|
||||
int n = (int)objectPoints[i].size();
|
||||
perViewErrors[i] = (float) std::sqrt(err*err/n); // save for this view
|
||||
|
||||
@@ -28,12 +28,12 @@ Now, let us write a code that detects a chessboard in a new image and finds its
|
||||
#.
|
||||
Create an empty console project. Load a test image: ::
|
||||
|
||||
Mat img = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
|
||||
Mat img = imread(argv[1], IMREAD_GRAYSCALE);
|
||||
|
||||
#.
|
||||
Detect a chessboard in this image using findChessboard function. ::
|
||||
|
||||
bool found = findChessboardCorners( img, boardSize, ptvec, CV_CALIB_CB_ADAPTIVE_THRESH );
|
||||
bool found = findChessboardCorners( img, boardSize, ptvec, CALIB_CB_ADAPTIVE_THRESH );
|
||||
|
||||
#.
|
||||
Now, write a function that generates a ``vector<Point3f>`` array of 3d coordinates of a chessboard in any coordinate system. For simplicity, let us choose a system such that one of the chessboard corners is in the origin and the board is in the plane *z = 0*.
|
||||
|
||||
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 106 KiB |
@@ -0,0 +1,750 @@
|
||||
.. _realTimePoseEstimation:
|
||||
|
||||
Real Time pose estimation of a textured object
|
||||
**********************************************
|
||||
|
||||
Nowadays, augmented reality is one of the top research topic in computer vision and robotics fields. The most elemental problem in augmented reality is the estimation of the camera pose respect of an object in the case of computer vision area to do later some 3D rendering or in the case of robotics obtain an object pose in order to grasp it and do some manipulation. However, this is not a trivial problem to solve due to the fact that the most common issue in image processing is the computational cost of applying a lot of algorithms or mathematical operations for solving a problem which is basic and immediateley for humans.
|
||||
|
||||
|
||||
Goal
|
||||
====
|
||||
|
||||
In this tutorial is explained how to build a real time application to estimate the camera pose in order to track a textured object with six degrees of freedom given a 2D image and its 3D textured model.
|
||||
|
||||
The application will have the followings parts:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ Read 3D textured object model and object mesh.
|
||||
+ Take input from Camera or Video.
|
||||
+ Extract ORB features and descriptors from the scene.
|
||||
+ Match scene descriptors with model descriptors using Flann matcher.
|
||||
+ Pose estimation using PnP + Ransac.
|
||||
+ Linear Kalman Filter for bad poses rejection.
|
||||
|
||||
|
||||
Theory
|
||||
======
|
||||
|
||||
In computer vision estimate the camera pose from *n* 3D-to-2D point correspondences is a fundamental and well understood problem. The most general version of the problem requires estimating the six degrees of freedom of the pose and five calibration parameters: focal length, principal point, aspect ratio and skew. It could be established with a minimum of 6 correspondences, using the well known Direct Linear Transform (DLT) algorithm. There are, though, several simplifications to the problem which turn into an extensive list of different algorithms that improve the accuracy of the DLT.
|
||||
|
||||
The most common simplification is to assume known calibration parameters which is the so-called Perspective-*n*-Point problem:
|
||||
|
||||
.. image:: images/pnp.jpg
|
||||
:alt: Perspective-n-Point problem scheme
|
||||
:align: center
|
||||
|
||||
**Problem Formulation:** Given a set of correspondences between 3D points :math:`p_i` expressed in a world reference frame, and their 2D projections :math:`u_i` onto the image, we seek to retrieve the pose (:math:`R` and :math:`t`) of the camera w.r.t. the world and the focal length :math:`f`.
|
||||
|
||||
OpenCV provides four different approaches to solve the Perspective-*n*-Point problem which return :math:`R` and :math:`t`. Then, using the following formula it's possible to project 3D points into the image plane:
|
||||
|
||||
.. math::
|
||||
|
||||
s\ \left [ \begin{matrix} u \\ v \\ 1 \end{matrix} \right ] = \left [ \begin{matrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix} \right ] \left [ \begin{matrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \end{matrix} \right ] \left [ \begin{matrix} X \\ Y \\ Z\\ 1 \end{matrix} \right ]
|
||||
|
||||
The complete documentation of how to manage with this equations is in :calib3d:`Camera Calibration and 3D Reconstruction <>`.
|
||||
|
||||
Source code
|
||||
===========
|
||||
|
||||
You can find the source code of this tutorial in the :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/` folder of the OpenCV source library.
|
||||
|
||||
The tutorial consists of two main programs:
|
||||
|
||||
1. **Model registration**
|
||||
|
||||
This applicaton is exclusive to whom don't have a 3D textured model of the object to be detected. You can use this program to create your own textured 3D model. This program only works for planar objects, then if you want to model an object with complex shape you should use a sophisticated software to create it.
|
||||
|
||||
The application needs an input image of the object to be registered and its 3D mesh. We have also to provide the intrinsic parameters of the camera with which the input image was taken. All the files need to be specified using the absolute path or the relative one from your application’s working directory. If none files are specified the program will try to open the provided default parameters.
|
||||
|
||||
The application starts up extracting the ORB features and descriptors from the input image and then uses the mesh along with the `Möller–Trumbore intersection algorithm <http://http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm/>`_ to compute the 3D coordinates of the found features. Finally, the 3D points and the descriptors are stored in different lists in a file with YAML format which each row is a different point. The technical background on how to store the files can be found in the :ref:`fileInputOutputXMLYAML` tutorial.
|
||||
|
||||
.. image:: images/registration.png
|
||||
:alt: Model registration
|
||||
:align: center
|
||||
|
||||
|
||||
2. **Model detection**
|
||||
|
||||
The aim of this application is estimate in real time the object pose given its 3D textured model.
|
||||
|
||||
The application starts up loading the 3D textured model in YAML file format with the same structure explained in the model registration program. From the scene, the ORB features and descriptors are detected and extracted. Then, is used :flann_based_matcher:`FlannBasedMatcher<>` with :flann:`LshIndexParams <flann-index-t-index>` to do the matching between the scene descriptors and the model descriptors. Using the found matches along with :calib3d:`solvePnPRansac <solvepnpransac>` function the :math:`R` and :math:`t` of the camera are computed. Finally, a :video:`KalmanFilter<kalmanfilter>` is applied in order to reject bad poses.
|
||||
|
||||
In the case that you compiled OpenCV with the samples, you can find it in :file:`opencv/build/bin/cpp-tutorial-pnp_detection`. Then you can run the application and change some parameters:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
This program shows how to detect an object given its 3D textured model. You can choose to use a recorded video or the webcam.
|
||||
Usage:
|
||||
./cpp-tutorial-pnp_detection -help
|
||||
Keys:
|
||||
'esc' - to quit.
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Usage: cpp-tutorial-pnp_detection [params]
|
||||
|
||||
-c, --confidence (value:0.95)
|
||||
RANSAC confidence
|
||||
-e, --error (value:2.0)
|
||||
RANSAC reprojection errror
|
||||
-f, --fast (value:true)
|
||||
use of robust fast match
|
||||
-h, --help (value:true)
|
||||
print this message
|
||||
--in, --inliers (value:30)
|
||||
minimum inliers for Kalman update
|
||||
--it, --iterations (value:500)
|
||||
RANSAC maximum iterations count
|
||||
-k, --keypoints (value:2000)
|
||||
number of keypoints to detect
|
||||
--mesh
|
||||
path to ply mesh
|
||||
--method, --pnp (value:0)
|
||||
PnP method: (0) ITERATIVE - (1) EPNP - (2) P3P - (3) DLS
|
||||
--model
|
||||
path to yml model
|
||||
-r, --ratio (value:0.7)
|
||||
threshold for ratio test
|
||||
-v, --video
|
||||
path to recorded video
|
||||
|
||||
For example, you can run the application changing the pnp method:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --method=2
|
||||
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Here is explained in detail the code for the real time application:
|
||||
|
||||
1. **Read 3D textured object model and object mesh.**
|
||||
|
||||
In order to load the textured model I implemented the *class* **Model** which has the function *load()* that opens a YAML file and take the stored 3D points with its corresponding descriptors. You can find an example of a 3D textured model in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/cookies_ORB.yml`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
/** Load a YAML file using OpenCV **/
|
||||
void Model::load(const std::string path)
|
||||
{
|
||||
cv::Mat points3d_mat;
|
||||
|
||||
cv::FileStorage storage(path, cv::FileStorage::READ);
|
||||
storage["points_3d"] >> points3d_mat;
|
||||
storage["descriptors"] >> descriptors_;
|
||||
|
||||
points3d_mat.copyTo(list_points3d_in_);
|
||||
|
||||
storage.release();
|
||||
|
||||
}
|
||||
|
||||
In the main program the model is loaded as follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
Model model; // instantiate Model object
|
||||
model.load(yml_read_path); // load a 3D textured object model
|
||||
|
||||
In order to read the model mesh I implemented a *class* **Mesh** which has a function *load()* that opens a :math:`*`.ply file and store the 3D points of the object and also the composed triangles. You can find an example of a model mesh in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/box.ply`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
/** Load a CSV with *.ply format **/
|
||||
void Mesh::load(const std::string path)
|
||||
{
|
||||
|
||||
// Create the reader
|
||||
CsvReader csvReader(path);
|
||||
|
||||
// Clear previous data
|
||||
list_vertex_.clear();
|
||||
list_triangles_.clear();
|
||||
|
||||
// Read from .ply file
|
||||
csvReader.readPLY(list_vertex_, list_triangles_);
|
||||
|
||||
// Update mesh attributes
|
||||
num_vertexs_ = list_vertex_.size();
|
||||
num_triangles_ = list_triangles_.size();
|
||||
|
||||
}
|
||||
|
||||
In the main program the mesh is loaded as follows:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
Mesh mesh; // instantiate Mesh object
|
||||
mesh.load(ply_read_path); // load an object mesh
|
||||
|
||||
You can also load different model and mesh:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --mesh=/absolute_path_to_your_mesh.ply --model=/absolute_path_to_your_model.yml
|
||||
|
||||
|
||||
2. **Take input from Camera or Video**
|
||||
|
||||
To detect is necessary capture video. It's done loading a recorded video by passing the absolute path where it is located in your machine. In order to test the application you can find a recorded video in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/Data/box.mp4`.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cv::VideoCapture cap; // instantiate VideoCapture
|
||||
cap.open(video_read_path); // open a recorded video
|
||||
|
||||
if(!cap.isOpened()) // check if we succeeded
|
||||
{
|
||||
std::cout << "Could not open the camera device" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Then the algorithm is computed frame per frame:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cv::Mat frame, frame_vis;
|
||||
|
||||
while(cap.read(frame) && cv::waitKey(30) != 27) // capture frame until ESC is pressed
|
||||
{
|
||||
|
||||
frame_vis = frame.clone(); // refresh visualisation frame
|
||||
|
||||
// MAIN ALGORITHM
|
||||
|
||||
}
|
||||
|
||||
You can also load different recorded video:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --video=/absolute_path_to_your_video.mp4
|
||||
|
||||
|
||||
3. **Extract ORB features and descriptors from the scene**
|
||||
|
||||
The next step is to detect the scene features and extract it descriptors. For this task I implemented a *class* **RobustMatcher** which has a function for keypoints detection and features extraction. You can find it in :file:`samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/RobusMatcher.cpp`. In your *RobusMatch* object you can use any of the 2D features detectors of OpenCV. In this case I used :feature_detection_and_description:`ORB<orb>` features because is based on :feature_detection_and_description:`FAST<fast>` to detect the keypoints and :descriptor_extractor:`BRIEF<briefdescriptorextractor>` to extract the descriptors which means that is fast and robust to rotations. You can find more detailed information about *ORB* in the documentation.
|
||||
|
||||
The following code is how to instantiate and set the features detector and the descriptors extractor:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
RobustMatcher rmatcher; // instantiate RobustMatcher
|
||||
|
||||
cv::FeatureDetector * detector = new cv::OrbFeatureDetector(numKeyPoints); // instatiate ORB feature detector
|
||||
cv::DescriptorExtractor * extractor = new cv::OrbDescriptorExtractor(); // instatiate ORB descriptor extractor
|
||||
|
||||
rmatcher.setFeatureDetector(detector); // set feature detector
|
||||
rmatcher.setDescriptorExtractor(extractor); // set descriptor extractor
|
||||
|
||||
The features and descriptors will be computed by the *RobustMatcher* inside the matching function.
|
||||
|
||||
|
||||
4. **Match scene descriptors with model descriptors using Flann matcher**
|
||||
|
||||
It is the first step in our detection algorithm. The main idea is to match the scene descriptors with our model descriptors in order to know the 3D coordinates of the found features into the current scene.
|
||||
|
||||
Firstly, we have to set which matcher we want to use. In this case is used :flann_based_matcher:`FlannBasedMatcher<>` matcher which in terms of computational cost is faster than the :brute_force_matcher:`BruteForceMatcher<bfmatcher>` matcher as we increase the trained collectction of features. Then, for FlannBased matcher the index created is *Multi-Probe LSH: Efficient Indexing for High-Dimensional Similarity Search* due to *ORB* descriptors are binary.
|
||||
|
||||
You can tune the *LSH* and search parameters to improve the matching efficiency:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cv::Ptr<cv::flann::IndexParams> indexParams = cv::makePtr<cv::flann::LshIndexParams>(6, 12, 1); // instantiate LSH index parameters
|
||||
cv::Ptr<cv::flann::SearchParams> searchParams = cv::makePtr<cv::flann::SearchParams>(50); // instantiate flann search parameters
|
||||
|
||||
cv::DescriptorMatcher * matcher = new cv::FlannBasedMatcher(indexParams, searchParams); // instantiate FlannBased matcher
|
||||
rmatcher.setDescriptorMatcher(matcher); // set matcher
|
||||
|
||||
|
||||
Secondly, we have to call the matcher by using *robustMatch()* or *fastRobustMatch()* function. The difference of using this two functions is its computational cost. The first method is slower but more robust at filtering good matches because uses two ratio test and a symmetry test. In contrast, the second method is faster but less robust because only applies a single ratio test to the matches.
|
||||
|
||||
The following code is to get the model 3D points and its descriptors and then call the matcher in the main program:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Get the MODEL INFO
|
||||
|
||||
std::vector<cv::Point3f> list_points3d_model = model.get_points3d(); // list with model 3D coordinates
|
||||
cv::Mat descriptors_model = model.get_descriptors(); // list with descriptors of each 3D coordinate
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// -- Step 1: Robust matching between model descriptors and scene descriptors
|
||||
|
||||
std::vector<cv::DMatch> good_matches; // to obtain the model 3D points in the scene
|
||||
std::vector<cv::KeyPoint> keypoints_scene; // to obtain the 2D points of the scene
|
||||
|
||||
if(fast_match)
|
||||
{
|
||||
rmatcher.fastRobustMatch(frame, good_matches, keypoints_scene, descriptors_model);
|
||||
}
|
||||
else
|
||||
{
|
||||
rmatcher.robustMatch(frame, good_matches, keypoints_scene, descriptors_model);
|
||||
}
|
||||
|
||||
The following code corresponds to the *robustMatch()* function which belongs to the *RobustMatcher* class. This function uses the given image to detect the keypoints and extract the descriptors, match using *two Nearest Neighbour* the extracted descriptors with the given model descriptors and vice versa. Then, a ratio test is applied to the two direction matches in order to remove these matches which its distance ratio between the first and second best match is larger than a given threshold. Finally, a symmetry test is applied in order the remove non symmetrical matches.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void RobustMatcher::robustMatch( const cv::Mat& frame, std::vector<cv::DMatch>& good_matches,
|
||||
std::vector<cv::KeyPoint>& keypoints_frame,
|
||||
const std::vector<cv::KeyPoint>& keypoints_model, const cv::Mat& descriptors_model )
|
||||
{
|
||||
|
||||
// 1a. Detection of the ORB features
|
||||
this->computeKeyPoints(frame, keypoints_frame);
|
||||
|
||||
// 1b. Extraction of the ORB descriptors
|
||||
cv::Mat descriptors_frame;
|
||||
this->computeDescriptors(frame, keypoints_frame, descriptors_frame);
|
||||
|
||||
// 2. Match the two image descriptors
|
||||
std::vector<std::vector<cv::DMatch> > matches12, matches21;
|
||||
|
||||
// 2a. From image 1 to image 2
|
||||
matcher_->knnMatch(descriptors_frame, descriptors_model, matches12, 2); // return 2 nearest neighbours
|
||||
|
||||
// 2b. From image 2 to image 1
|
||||
matcher_->knnMatch(descriptors_model, descriptors_frame, matches21, 2); // return 2 nearest neighbours
|
||||
|
||||
// 3. Remove matches for which NN ratio is > than threshold
|
||||
// clean image 1 -> image 2 matches
|
||||
int removed1 = ratioTest(matches12);
|
||||
// clean image 2 -> image 1 matches
|
||||
int removed2 = ratioTest(matches21);
|
||||
|
||||
// 4. Remove non-symmetrical matches
|
||||
symmetryTest(matches12, matches21, good_matches);
|
||||
|
||||
}
|
||||
|
||||
After the matches filtering we have to subtract the 2D and 3D correspondences from the found scene keypoints and our 3D model using the obtained *DMatches* vector. For more information about :basicstructures:`DMatch <dmatch>` check the documentation.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// -- Step 2: Find out the 2D/3D correspondences
|
||||
|
||||
std::vector<cv::Point3f> list_points3d_model_match; // container for the model 3D coordinates found in the scene
|
||||
std::vector<cv::Point2f> list_points2d_scene_match; // container for the model 2D coordinates found in the scene
|
||||
|
||||
for(unsigned int match_index = 0; match_index < good_matches.size(); ++match_index)
|
||||
{
|
||||
cv::Point3f point3d_model = list_points3d_model[ good_matches[match_index].trainIdx ]; // 3D point from model
|
||||
cv::Point2f point2d_scene = keypoints_scene[ good_matches[match_index].queryIdx ].pt; // 2D point from the scene
|
||||
list_points3d_model_match.push_back(point3d_model); // add 3D point
|
||||
list_points2d_scene_match.push_back(point2d_scene); // add 2D point
|
||||
}
|
||||
|
||||
You can also change the ratio test threshold, the number of keypoints to detect as well as use or not the robust matcher:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --ratio=0.8 --keypoints=1000 --fast=false
|
||||
|
||||
|
||||
5. **Pose estimation using PnP + Ransac**
|
||||
|
||||
Once with the 2D and 3D correspondences we have to apply a PnP algorithm in order to estimate the camera pose. The reason why we have to use :calib3d:`solvePnPRansac <solvepnpransac>` instead of :calib3d:`solvePnP <solvepnp>` is due to the fact that after the matching not all the found correspondences are correct and, as like as not, there are false correspondences or also called *outliers*. The `Random Sample Consensus <http://en.wikipedia.org/wiki/RANSAC>`_ or *Ransac* is a non-deterministic iterative method which estimate parameters of a mathematical model from observed data producing an aproximate result as the number of iterations increase. After appyling *Ransac* all the *outliers* will be eliminated to then estimate the camera pose with a certain probability to obtain a good solution.
|
||||
|
||||
For the camera pose estimation I have implemented a *class* **PnPProblem**. This *class* has 4 atributes: a given calibration matrix, the rotation matrix, the translation matrix and the rotation-translation matrix. The intrinsic calibration parameters of the camera which you are using to estimate the pose are necessary. In order to obtain the parameters you can check :ref:`CameraCalibrationSquareChessBoardTutorial` and :ref:`cameraCalibrationOpenCV` tutorials.
|
||||
|
||||
The following code is how to declare the *PnPProblem class* in the main program:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Intrinsic camera parameters: UVC WEBCAM
|
||||
|
||||
double f = 55; // focal length in mm
|
||||
double sx = 22.3, sy = 14.9; // sensor size
|
||||
double width = 640, height = 480; // image size
|
||||
|
||||
double params_WEBCAM[] = { width*f/sx, // fx
|
||||
height*f/sy, // fy
|
||||
width/2, // cx
|
||||
height/2}; // cy
|
||||
|
||||
PnPProblem pnp_detection(params_WEBCAM); // instantiate PnPProblem class
|
||||
|
||||
The following code is how the *PnPProblem class* initialises its atributes:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Custom constructor given the intrinsic camera parameters
|
||||
|
||||
PnPProblem::PnPProblem(const double params[])
|
||||
{
|
||||
_A_matrix = cv::Mat::zeros(3, 3, CV_64FC1); // intrinsic camera parameters
|
||||
_A_matrix.at<double>(0, 0) = params[0]; // [ fx 0 cx ]
|
||||
_A_matrix.at<double>(1, 1) = params[1]; // [ 0 fy cy ]
|
||||
_A_matrix.at<double>(0, 2) = params[2]; // [ 0 0 1 ]
|
||||
_A_matrix.at<double>(1, 2) = params[3];
|
||||
_A_matrix.at<double>(2, 2) = 1;
|
||||
_R_matrix = cv::Mat::zeros(3, 3, CV_64FC1); // rotation matrix
|
||||
_t_matrix = cv::Mat::zeros(3, 1, CV_64FC1); // translation matrix
|
||||
_P_matrix = cv::Mat::zeros(3, 4, CV_64FC1); // rotation-translation matrix
|
||||
|
||||
}
|
||||
|
||||
OpenCV provides four PnP methods: ITERATIVE, EPNP, P3P and DLS. Depending on the application type, the estimation method will be different. In the case that we want to make a real time application, the more suitable methods are EPNP and P3P due to that are faster than ITERATIVE and DLS at finding an optimal solution. However, EPNP and P3P are not especially robust in front of planar surfaces and sometimes the pose estimation seems to have a mirror effect. Therefore, in this this tutorial is used ITERATIVE method due to the object to be detected has planar surfaces.
|
||||
|
||||
The OpenCV Ransac implementation wants you to provide three parameters: the maximum number of iterations until stop the algorithm, the maximum allowed distance between the observed and computed point projections to consider it an inlier and the confidence to obtain a good result. You can tune these paramaters in order to improve your algorithm performance. Increasing the number of iterations you will have a more accurate solution, but will take more time to find a solution. Increasing the reprojection error will reduce the computation time, but your solution will be unaccurate. Decreasing the confidence your arlgorithm will be faster, but the obtained solution will be unaccurate.
|
||||
|
||||
The following parameters work for this application:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// RANSAC parameters
|
||||
|
||||
int iterationsCount = 500; // number of Ransac iterations.
|
||||
float reprojectionError = 2.0; // maximum allowed distance to consider it an inlier.
|
||||
float confidence = 0.95; // ransac successful confidence.
|
||||
|
||||
|
||||
The following code corresponds to the *estimatePoseRANSAC()* function which belongs to the *PnPProblem class*. This function estimates the rotation and translation matrix given a set of 2D/3D correspondences, the desired PnP method to use, the output inliers container and the Ransac parameters:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Estimate the pose given a list of 2D/3D correspondences with RANSAC and the method to use
|
||||
|
||||
void PnPProblem::estimatePoseRANSAC( const std::vector<cv::Point3f> &list_points3d, // list with model 3D coordinates
|
||||
const std::vector<cv::Point2f> &list_points2d, // list with scene 2D coordinates
|
||||
int flags, cv::Mat &inliers, int iterationsCount, // PnP method; inliers container
|
||||
float reprojectionError, float confidence ) // Ransac parameters
|
||||
{
|
||||
cv::Mat distCoeffs = cv::Mat::zeros(4, 1, CV_64FC1); // vector of distortion coefficients
|
||||
cv::Mat rvec = cv::Mat::zeros(3, 1, CV_64FC1); // output rotation vector
|
||||
cv::Mat tvec = cv::Mat::zeros(3, 1, CV_64FC1); // output translation vector
|
||||
|
||||
bool useExtrinsicGuess = false; // if true the function uses the provided rvec and tvec values as
|
||||
// initial approximations of the rotation and translation vectors
|
||||
|
||||
cv::solvePnPRansac( list_points3d, list_points2d, _A_matrix, distCoeffs, rvec, tvec,
|
||||
useExtrinsicGuess, iterationsCount, reprojectionError, confidence,
|
||||
inliers, flags );
|
||||
|
||||
Rodrigues(rvec,_R_matrix); // converts Rotation Vector to Matrix
|
||||
_t_matrix = tvec; // set translation matrix
|
||||
|
||||
this->set_P_matrix(_R_matrix, _t_matrix); // set rotation-translation matrix
|
||||
|
||||
}
|
||||
|
||||
In the following code are the 3th and 4th steps of the main algorithm. The first, calling the above function and the second taking the output inliers vector from Ransac to get the 2D scene points for drawing purpose. As seen in the code we must be sure to apply Ransac if we have matches, in the other case, the function :calib3d:`solvePnPRansac <solvepnpransac>` crashes due to any OpenCV *bug*.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
if(good_matches.size() > 0) // None matches, then RANSAC crashes
|
||||
{
|
||||
|
||||
// -- Step 3: Estimate the pose using RANSAC approach
|
||||
pnp_detection.estimatePoseRANSAC( list_points3d_model_match, list_points2d_scene_match,
|
||||
pnpMethod, inliers_idx, iterationsCount, reprojectionError, confidence );
|
||||
|
||||
|
||||
// -- Step 4: Catch the inliers keypoints to draw
|
||||
for(int inliers_index = 0; inliers_index < inliers_idx.rows; ++inliers_index)
|
||||
{
|
||||
int n = inliers_idx.at<int>(inliers_index); // i-inlier
|
||||
cv::Point2f point2d = list_points2d_scene_match[n]; // i-inlier point 2D
|
||||
list_points2d_inliers.push_back(point2d); // add i-inlier to list
|
||||
}
|
||||
|
||||
|
||||
Finally, once the camera pose has been estimated we can use the :math:`R` and :math:`t` in order to compute the 2D projection onto the image of a given 3D point expressed in a world reference frame using the showed formula on *Theory*.
|
||||
|
||||
The following code corresponds to the *backproject3DPoint()* function which belongs to the *PnPProblem class*. The function backproject a given 3D point expressed in a world reference frame onto a 2D image:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Backproject a 3D point to 2D using the estimated pose parameters
|
||||
|
||||
cv::Point2f PnPProblem::backproject3DPoint(const cv::Point3f &point3d)
|
||||
{
|
||||
// 3D point vector [x y z 1]'
|
||||
cv::Mat point3d_vec = cv::Mat(4, 1, CV_64FC1);
|
||||
point3d_vec.at<double>(0) = point3d.x;
|
||||
point3d_vec.at<double>(1) = point3d.y;
|
||||
point3d_vec.at<double>(2) = point3d.z;
|
||||
point3d_vec.at<double>(3) = 1;
|
||||
|
||||
// 2D point vector [u v 1]'
|
||||
cv::Mat point2d_vec = cv::Mat(4, 1, CV_64FC1);
|
||||
point2d_vec = _A_matrix * _P_matrix * point3d_vec;
|
||||
|
||||
// Normalization of [u v]'
|
||||
cv::Point2f point2d;
|
||||
point2d.x = point2d_vec.at<double>(0) / point2d_vec.at<double>(2);
|
||||
point2d.y = point2d_vec.at<double>(1) / point2d_vec.at<double>(2);
|
||||
|
||||
return point2d;
|
||||
}
|
||||
|
||||
The above function is used to compute all the 3D points of the object *Mesh* to show the pose of the object.
|
||||
|
||||
You can also change RANSAC parameters and PnP method:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --error=0.25 --confidence=0.90 --iterations=250 --method=3
|
||||
|
||||
|
||||
6. **Linear Kalman Filter for bad poses rejection**
|
||||
|
||||
Is it common in computer vision or robotics fields that after applying detection or tracking techniques, bad results are obtained due to some sensor errors. In order to avoid these bad detections in this tutorial is explained how to implement a Linear Kalman Filter. The Kalman Filter will be applied after detected a given number of inliers.
|
||||
|
||||
You can find more information about what `Kalman Filter <http://en.wikipedia.org/wiki/Kalman_filter>`_ is. In this tutorial it's used the OpenCV implementation of the :video:`Kalman Filter <kalmanfilter>` based on `Linear Kalman Filter for position and orientation tracking <http://campar.in.tum.de/Chair/KalmanFilter>`_ to set the dynamics and measurement models.
|
||||
|
||||
Firstly, we have to define our state vector which will have 18 states: the positional data (x,y,z) with its first and second derivatives (velocity and acceleration), then rotation is added in form of three euler angles (roll, pitch, jaw) together with their first and second derivatives (angular velocity and acceleration)
|
||||
|
||||
.. math::
|
||||
|
||||
X = (x,y,z,\dot x,\dot y,\dot z,\ddot x,\ddot y,\ddot z,\psi,\theta,\phi,\dot \psi,\dot \theta,\dot \phi,\ddot \psi,\ddot \theta,\ddot \phi)^T
|
||||
|
||||
Secondly, we have to define the number of measuremnts which will be 6: from :math:`R` and :math:`t` we can extract :math:`(x,y,z)` and :math:`(\psi,\theta,\phi)`. In addition, we have to define the number of control actions to apply to the system which in this case will be *zero*. Finally, we have to define the differential time between measurements which in this case is :math:`1/T`, where *T* is the frame rate of the video.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cv::KalmanFilter KF; // instantiate Kalman Filter
|
||||
|
||||
int nStates = 18; // the number of states
|
||||
int nMeasurements = 6; // the number of measured states
|
||||
int nInputs = 0; // the number of action control
|
||||
|
||||
double dt = 0.125; // time between measurements (1/FPS)
|
||||
|
||||
initKalmanFilter(KF, nStates, nMeasurements, nInputs, dt); // init function
|
||||
|
||||
|
||||
The following code corresponds to the *Kalman Filter* initialisation. Firstly, is set the process noise, the measurement noise and the error covariance matrix. Secondly, are set the transition matrix which is the dynamic model and finally the measurement matrix, which is the measurement model.
|
||||
|
||||
You can tune the process and measurement noise to improve the *Kalman Filter* performance. As the measurement noise is reduced the faster will converge doing the algorithm sensitive in front of bad measurements.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void initKalmanFilter(cv::KalmanFilter &KF, int nStates, int nMeasurements, int nInputs, double dt)
|
||||
{
|
||||
|
||||
KF.init(nStates, nMeasurements, nInputs, CV_64F); // init Kalman Filter
|
||||
|
||||
cv::setIdentity(KF.processNoiseCov, cv::Scalar::all(1e-5)); // set process noise
|
||||
cv::setIdentity(KF.measurementNoiseCov, cv::Scalar::all(1e-4)); // set measurement noise
|
||||
cv::setIdentity(KF.errorCovPost, cv::Scalar::all(1)); // error covariance
|
||||
|
||||
|
||||
/** DYNAMIC MODEL **/
|
||||
|
||||
// [1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 1 0 0 dt 0 0 dt2 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 1 0 0 dt 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0 dt2]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 dt]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
|
||||
|
||||
// position
|
||||
KF.transitionMatrix.at<double>(0,3) = dt;
|
||||
KF.transitionMatrix.at<double>(1,4) = dt;
|
||||
KF.transitionMatrix.at<double>(2,5) = dt;
|
||||
KF.transitionMatrix.at<double>(3,6) = dt;
|
||||
KF.transitionMatrix.at<double>(4,7) = dt;
|
||||
KF.transitionMatrix.at<double>(5,8) = dt;
|
||||
KF.transitionMatrix.at<double>(0,6) = 0.5*pow(dt,2);
|
||||
KF.transitionMatrix.at<double>(1,7) = 0.5*pow(dt,2);
|
||||
KF.transitionMatrix.at<double>(2,8) = 0.5*pow(dt,2);
|
||||
|
||||
// orientation
|
||||
KF.transitionMatrix.at<double>(9,12) = dt;
|
||||
KF.transitionMatrix.at<double>(10,13) = dt;
|
||||
KF.transitionMatrix.at<double>(11,14) = dt;
|
||||
KF.transitionMatrix.at<double>(12,15) = dt;
|
||||
KF.transitionMatrix.at<double>(13,16) = dt;
|
||||
KF.transitionMatrix.at<double>(14,17) = dt;
|
||||
KF.transitionMatrix.at<double>(9,15) = 0.5*pow(dt,2);
|
||||
KF.transitionMatrix.at<double>(10,16) = 0.5*pow(dt,2);
|
||||
KF.transitionMatrix.at<double>(11,17) = 0.5*pow(dt,2);
|
||||
|
||||
|
||||
/** MEASUREMENT MODEL **/
|
||||
|
||||
// [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
|
||||
// [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
|
||||
|
||||
KF.measurementMatrix.at<double>(0,0) = 1; // x
|
||||
KF.measurementMatrix.at<double>(1,1) = 1; // y
|
||||
KF.measurementMatrix.at<double>(2,2) = 1; // z
|
||||
KF.measurementMatrix.at<double>(3,9) = 1; // roll
|
||||
KF.measurementMatrix.at<double>(4,10) = 1; // pitch
|
||||
KF.measurementMatrix.at<double>(5,11) = 1; // yaw
|
||||
|
||||
}
|
||||
|
||||
In the following code is the 5th step of the main algorithm. When the obtained number of inliers after *Ransac* is over the threshold, the measurements matrix is filled and then the *Kalman Filter* is updated:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// -- Step 5: Kalman Filter
|
||||
|
||||
// GOOD MEASUREMENT
|
||||
if( inliers_idx.rows >= minInliersKalman )
|
||||
{
|
||||
|
||||
// Get the measured translation
|
||||
cv::Mat translation_measured(3, 1, CV_64F);
|
||||
translation_measured = pnp_detection.get_t_matrix();
|
||||
|
||||
// Get the measured rotation
|
||||
cv::Mat rotation_measured(3, 3, CV_64F);
|
||||
rotation_measured = pnp_detection.get_R_matrix();
|
||||
|
||||
// fill the measurements vector
|
||||
fillMeasurements(measurements, translation_measured, rotation_measured);
|
||||
|
||||
}
|
||||
|
||||
// Instantiate estimated translation and rotation
|
||||
cv::Mat translation_estimated(3, 1, CV_64F);
|
||||
cv::Mat rotation_estimated(3, 3, CV_64F);
|
||||
|
||||
// update the Kalman filter with good measurements
|
||||
updateKalmanFilter( KF, measurements,
|
||||
translation_estimated, rotation_estimated);
|
||||
|
||||
The following code corresponds to the *fillMeasurements()* function which converts the measured `Rotation Matrix to Eulers angles <http://euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm>`_ and fill the measurements matrix along with the measured translation vector:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void fillMeasurements( cv::Mat &measurements,
|
||||
const cv::Mat &translation_measured, const cv::Mat &rotation_measured)
|
||||
{
|
||||
// Convert rotation matrix to euler angles
|
||||
cv::Mat measured_eulers(3, 1, CV_64F);
|
||||
measured_eulers = rot2euler(rotation_measured);
|
||||
|
||||
// Set measurement to predict
|
||||
measurements.at<double>(0) = translation_measured.at<double>(0); // x
|
||||
measurements.at<double>(1) = translation_measured.at<double>(1); // y
|
||||
measurements.at<double>(2) = translation_measured.at<double>(2); // z
|
||||
measurements.at<double>(3) = measured_eulers.at<double>(0); // roll
|
||||
measurements.at<double>(4) = measured_eulers.at<double>(1); // pitch
|
||||
measurements.at<double>(5) = measured_eulers.at<double>(2); // yaw
|
||||
}
|
||||
|
||||
|
||||
The following code corresponds to the *updateKalmanFilter()* function which update the Kalman Filter and set the estimated Rotation Matrix and translation vector. The estimated Rotation Matrix comes from the estimated `Euler angles to Rotation Matrix <http://euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/index.htm>`_.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void updateKalmanFilter( cv::KalmanFilter &KF, cv::Mat &measurement,
|
||||
cv::Mat &translation_estimated, cv::Mat &rotation_estimated )
|
||||
{
|
||||
|
||||
// First predict, to update the internal statePre variable
|
||||
cv::Mat prediction = KF.predict();
|
||||
|
||||
// The "correct" phase that is going to use the predicted value and our measurement
|
||||
cv::Mat estimated = KF.correct(measurement);
|
||||
|
||||
// Estimated translation
|
||||
translation_estimated.at<double>(0) = estimated.at<double>(0);
|
||||
translation_estimated.at<double>(1) = estimated.at<double>(1);
|
||||
translation_estimated.at<double>(2) = estimated.at<double>(2);
|
||||
|
||||
// Estimated euler angles
|
||||
cv::Mat eulers_estimated(3, 1, CV_64F);
|
||||
eulers_estimated.at<double>(0) = estimated.at<double>(9);
|
||||
eulers_estimated.at<double>(1) = estimated.at<double>(10);
|
||||
eulers_estimated.at<double>(2) = estimated.at<double>(11);
|
||||
|
||||
// Convert estimated quaternion to rotation matrix
|
||||
rotation_estimated = euler2rot(eulers_estimated);
|
||||
|
||||
}
|
||||
|
||||
The 6th step is set the estimated rotation-translation matrix:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// -- Step 6: Set estimated projection matrix
|
||||
pnp_detection_est.set_P_matrix(rotation_estimated, translation_estimated);
|
||||
|
||||
|
||||
The last and optional step is draw the found pose. To do it I implemented a function to draw all the mesh 3D points and an extra reference axis:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// -- Step X: Draw pose
|
||||
|
||||
drawObjectMesh(frame_vis, &mesh, &pnp_detection, green); // draw current pose
|
||||
drawObjectMesh(frame_vis, &mesh, &pnp_detection_est, yellow); // draw estimated pose
|
||||
|
||||
double l = 5;
|
||||
std::vector<cv::Point2f> pose_points2d;
|
||||
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,0,0))); // axis center
|
||||
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(l,0,0))); // axis x
|
||||
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,l,0))); // axis y
|
||||
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(cv::Point3f(0,0,l))); // axis z
|
||||
draw3DCoordinateAxes(frame_vis, pose_points2d); // draw axes
|
||||
|
||||
You can also modify the minimum inliers to update Kalman Filter:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
./cpp-tutorial-pnp_detection --inliers=20
|
||||
|
||||
|
||||
Results
|
||||
=======
|
||||
|
||||
The following videos are the results of pose estimation in real time using the explained detection algorithm using the following parameters:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// Robust Matcher parameters
|
||||
|
||||
int numKeyPoints = 2000; // number of detected keypoints
|
||||
float ratio = 0.70f; // ratio test
|
||||
bool fast_match = true; // fastRobustMatch() or robustMatch()
|
||||
|
||||
|
||||
// RANSAC parameters
|
||||
|
||||
int iterationsCount = 500; // number of Ransac iterations.
|
||||
int reprojectionError = 2.0; // maximum allowed distance to consider it an inlier.
|
||||
float confidence = 0.95; // ransac successful confidence.
|
||||
|
||||
|
||||
// Kalman Filter parameters
|
||||
|
||||
int minInliersKalman = 30; // Kalman threshold updating
|
||||
|
||||
|
||||
You can watch the real time pose estimation on the `YouTube here <http://www.youtube.com/user/opencvdev/videos>`_.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div align="center">
|
||||
<iframe title="Pose estimation of textured object using OpenCV" width="560" height="349" src="http://www.youtube.com/embed/XNATklaJlSQ?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
|
||||
</div>
|
||||
</br></br>
|
||||
<div align="center">
|
||||
<iframe title="Pose estimation of textured object using OpenCV in cluttered background" width="560" height="349" src="http://www.youtube.com/embed/YLS9bWek78k?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
|
||||
</div>
|
||||
|
After Width: | Height: | Size: 83 KiB |
@@ -45,6 +45,25 @@ Although we got most of our images in a 2D format they do come from a 3D world.
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
+
|
||||
.. tabularcolumns:: m{100pt} m{300pt}
|
||||
.. cssclass:: toctableopencv
|
||||
|
||||
===================== ==============================================
|
||||
|PoseEstimation| **Title:** :ref:`realTimePoseEstimation`
|
||||
|
||||
*Compatibility:* > OpenCV 2.0
|
||||
|
||||
*Author:* Edgar Riba
|
||||
|
||||
Real time pose estimation of a textured object using ORB features, FlannBased matcher, PnP approach plus Ransac and Linear Kalman Filter to reject possible bad poses.
|
||||
|
||||
===================== ==============================================
|
||||
|
||||
.. |PoseEstimation| image:: images/real_time_pose_estimation.jpg
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\pagebreak
|
||||
@@ -54,3 +73,4 @@ Although we got most of our images in a 2D format they do come from a 3D world.
|
||||
|
||||
../camera_calibration_square_chess/camera_calibration_square_chess
|
||||
../camera_calibration/camera_calibration
|
||||
../real_time_pose/real_time_pose
|
||||
|
||||
@@ -120,13 +120,13 @@ In this sample I'll show how to calculate and show the *magnitude* image of a Fo
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
normalize(magI, magI, 0, 1, CV_MINMAX); // Transform the matrix with float values into a
|
||||
// viewable image form (float between values 0 and 1).
|
||||
normalize(magI, magI, 0, 1, NORM_MINMAX); // Transform the matrix with float values into a
|
||||
// viewable image form (float between values 0 and 1).
|
||||
|
||||
Result
|
||||
======
|
||||
|
||||
An application idea would be to determine the geometrical orientation present in the image. For example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform. Let us use :download:`this horizontal <../../../../samples/cpp/tutorial_code/images/imageTextN.png>` and :download:`this rotated<../../../../samples/cpp/tutorial_code/images/imageTextR.png>` image about a text.
|
||||
An application idea would be to determine the geometrical orientation present in the image. For example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two main components of a text snippet may be also seen in case of the Fourier transform. Let us use :download:`this horizontal <../../../../samples/data/imageTextN.png>` and :download:`this rotated<../../../../samples/data/imageTextR.png>` image about a text.
|
||||
|
||||
In case of the horizontal text:
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ To tackle this issue OpenCV uses a reference counting system. The idea is that e
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
Mat A, C; // creates just the header parts
|
||||
A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // here we'll know the method used (allocate matrix)
|
||||
Mat A, C; // creates just the header parts
|
||||
A = imread(argv[1], IMREAD_COLOR); // here we'll know the method used (allocate matrix)
|
||||
|
||||
Mat B(A); // Use the copy constructor
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ Explanation
|
||||
|
||||
int Displaying_Big_End( Mat image, char* window_name, RNG rng )
|
||||
{
|
||||
Size textsize = getTextSize("OpenCV forever!", CV_FONT_HERSHEY_COMPLEX, 3, 5, 0);
|
||||
Size textsize = getTextSize("OpenCV forever!", FONT_HERSHEY_COMPLEX, 3, 5, 0);
|
||||
Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2);
|
||||
int lineType = 8;
|
||||
|
||||
@@ -203,7 +203,7 @@ Explanation
|
||||
for( int i = 0; i < 255; i += 2 )
|
||||
{
|
||||
image2 = image - Scalar::all(i);
|
||||
putText( image2, "OpenCV forever!", org, CV_FONT_HERSHEY_COMPLEX, 3,
|
||||
putText( image2, "OpenCV forever!", org, FONT_HERSHEY_COMPLEX, 3,
|
||||
Scalar(i, i, 255), 5, lineType );
|
||||
|
||||
imshow( window_name, image2 );
|
||||
|
||||
@@ -14,3 +14,4 @@
|
||||
.. |Author_MimmoC| unicode:: Mimmo U+0020 Cosenza
|
||||
.. |Author_BarisD| unicode:: Bar U+0131 U+015F U+0020 Evrim U+0020 Demir U+00F6 z
|
||||
.. |Author_DomenicoB| unicode:: Domenico U+0020 Daniele U+0020 Bloisi
|
||||
.. |Author_MarvinS| unicode:: Marvin U+0020 Smith
|
||||
|
||||
@@ -46,7 +46,7 @@ Source Code
|
||||
Explanation
|
||||
===========
|
||||
|
||||
1. **Load images and homography**
|
||||
#. **Load images and homography**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -59,7 +59,7 @@ Explanation
|
||||
|
||||
We are loading grayscale images here. Homography is stored in the xml created with FileStorage.
|
||||
|
||||
2. **Detect keypoints and compute descriptors using AKAZE**
|
||||
#. **Detect keypoints and compute descriptors using AKAZE**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -72,7 +72,7 @@ Explanation
|
||||
|
||||
We create AKAZE object and use it's *operator()* functionality. Since we don't need the *mask* parameter, *noArray()* is used.
|
||||
|
||||
3. **Use brute-force matcher to find 2-nn matches**
|
||||
#. **Use brute-force matcher to find 2-nn matches**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -82,7 +82,7 @@ Explanation
|
||||
|
||||
We use Hamming distance, because AKAZE uses binary descriptor by default.
|
||||
|
||||
4. **Use 2-nn matches to find correct keypoint matches**
|
||||
#. **Use 2-nn matches to find correct keypoint matches**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -99,7 +99,7 @@ Explanation
|
||||
|
||||
If the closest match is *ratio* closer than the second closest one, then the match is correct.
|
||||
|
||||
5. **Check if our matches fit in the homography model**
|
||||
#. **Check if our matches fit in the homography model**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -125,7 +125,7 @@ Explanation
|
||||
|
||||
We create a new set of matches for the inliers, because it is required by the drawing function.
|
||||
|
||||
6. **Output results**
|
||||
#. **Output results**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
@@ -150,12 +150,10 @@ Found matches
|
||||
|
||||
A-KAZE Matching Results
|
||||
--------------------------
|
||||
Keypoints 1: 2943
|
||||
|
||||
Keypoints 2: 3511
|
||||
|
||||
Matches: 447
|
||||
|
||||
Inliers: 308
|
||||
|
||||
Inliers Ratio: 0.689038
|
||||
::code-block:: none
|
||||
Keypoints 1: 2943
|
||||
Keypoints 2: 3511
|
||||
Matches: 447
|
||||
Inliers: 308
|
||||
Inlier Ratio: 0.689038
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
.. _akazeTracking:
|
||||
|
||||
|
||||
AKAZE and ORB planar tracking
|
||||
******************************
|
||||
|
||||
Introduction
|
||||
------------------
|
||||
|
||||
In this tutorial we will compare *AKAZE* and *ORB* local features
|
||||
using them to find matches between video frames and track object movements.
|
||||
|
||||
The algorithm is as follows:
|
||||
|
||||
* Detect and describe keypoints on the first frame, manually set object boundaries
|
||||
* For every next frame:
|
||||
|
||||
#. Detect and describe keypoints
|
||||
#. Match them using bruteforce matcher
|
||||
#. Estimate homography transformation using RANSAC
|
||||
#. Filter inliers from all the matches
|
||||
#. Apply homography transformation to the bounding box to find the object
|
||||
#. Draw bounding box and inliers, compute inlier ratio as evaluation metric
|
||||
|
||||
.. image:: images/frame.png
|
||||
:height: 480pt
|
||||
:width: 640pt
|
||||
:alt: Result frame example
|
||||
:align: center
|
||||
|
||||
Data
|
||||
===========
|
||||
To do the tracking we need a video and object position on the first frame.
|
||||
|
||||
You can download our example video and data from `here <https://docs.google.com/file/d/0B72G7D4snftJandBb0taLVJHMFk>`_.
|
||||
|
||||
To run the code you have to specify input and output video path and object bounding box.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
./planar_tracking blais.mp4 result.avi blais_bb.xml.gz
|
||||
|
||||
Source Code
|
||||
===========
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp
|
||||
:language: cpp
|
||||
:linenos:
|
||||
:tab-width: 4
|
||||
|
||||
Explanation
|
||||
===========
|
||||
|
||||
Tracker class
|
||||
--------------
|
||||
|
||||
This class implements algorithm described abobve
|
||||
using given feature detector and descriptor matcher.
|
||||
|
||||
* **Setting up the first frame**
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
void Tracker::setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats)
|
||||
{
|
||||
first_frame = frame.clone();
|
||||
(*detector)(first_frame, noArray(), first_kp, first_desc);
|
||||
stats.keypoints = (int)first_kp.size();
|
||||
drawBoundingBox(first_frame, bb);
|
||||
putText(first_frame, title, Point(0, 60), FONT_HERSHEY_PLAIN, 5, Scalar::all(0), 4);
|
||||
object_bb = bb;
|
||||
}
|
||||
|
||||
We compute and store keypoints and descriptors from the first frame and prepare it for the output.
|
||||
|
||||
We need to save number of detected keypoints to make sure both detectors locate roughly the same number of those.
|
||||
|
||||
* **Processing frames**
|
||||
|
||||
#. Locate keypoints and compute descriptors
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
(*detector)(frame, noArray(), kp, desc);
|
||||
|
||||
To find matches between frames we have to locate the keypoints first.
|
||||
|
||||
In this tutorial detectors are set up to find about 1000 keypoints on each frame.
|
||||
|
||||
#. Use 2-nn matcher to find correspondences
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
matcher->knnMatch(first_desc, desc, matches, 2);
|
||||
for(unsigned i = 0; i < matches.size(); i++) {
|
||||
if(matches[i][0].distance < nn_match_ratio * matches[i][1].distance) {
|
||||
matched1.push_back(first_kp[matches[i][0].queryIdx]);
|
||||
matched2.push_back( kp[matches[i][0].trainIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
If the closest match is *nn_match_ratio* closer than the second closest one, then it's a match.
|
||||
|
||||
2. Use *RANSAC* to estimate homography transformation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
homography = findHomography(Points(matched1), Points(matched2),
|
||||
RANSAC, ransac_thresh, inlier_mask);
|
||||
|
||||
If there are at least 4 matches we can use random sample consensus to estimate image transformation.
|
||||
|
||||
3. Save the inliers
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
for(unsigned i = 0; i < matched1.size(); i++) {
|
||||
if(inlier_mask.at<uchar>(i)) {
|
||||
int new_i = static_cast<int>(inliers1.size());
|
||||
inliers1.push_back(matched1[i]);
|
||||
inliers2.push_back(matched2[i]);
|
||||
inlier_matches.push_back(DMatch(new_i, new_i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Since *findHomography* computes the inliers we only have to save the chosen points and matches.
|
||||
|
||||
4. Project object bounding box
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
perspectiveTransform(object_bb, new_bb, homography);
|
||||
|
||||
If there is a reasonable number of inliers we can use estimated transformation to locate the object.
|
||||
|
||||
Results
|
||||
=======
|
||||
You can watch the resulting `video on youtube <http://www.youtube.com/watch?v=LWY-w8AGGhE>`_.
|
||||
|
||||
*AKAZE* statistics:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Matches 626
|
||||
Inliers 410
|
||||
Inlier ratio 0.58
|
||||
Keypoints 1117
|
||||
|
||||
*ORB* statistics:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Matches 504
|
||||
Inliers 319
|
||||
Inlier ratio 0.56
|
||||
Keypoints 1112
|
||||
|
After Width: | Height: | Size: 318 KiB |
@@ -12,29 +12,20 @@ The goal of this tutorial is to learn how to use *features2d* and *calib3d* modu
|
||||
#.
|
||||
Create a new console project. Read two input images. ::
|
||||
|
||||
Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
|
||||
Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);
|
||||
Mat img1 = imread(argv[1], IMREAD_GRAYSCALE);
|
||||
Mat img2 = imread(argv[2], IMREAD_GRAYSCALE);
|
||||
|
||||
#.
|
||||
Detect keypoints in both images. ::
|
||||
Detect keypoints in both images and compute descriptors for each of the keypoints. ::
|
||||
|
||||
// detecting keypoints
|
||||
FastFeatureDetector detector(15);
|
||||
Ptr<Feature2D> surf = SURF::create();
|
||||
vector<KeyPoint> keypoints1;
|
||||
detector.detect(img1, keypoints1);
|
||||
Mat descriptors1;
|
||||
surf->detectAndCompute(img1, Mat(), keypoints1, descriptors1);
|
||||
|
||||
... // do the same for the second image
|
||||
|
||||
#.
|
||||
Compute descriptors for each of the keypoints. ::
|
||||
|
||||
// computing descriptors
|
||||
SurfDescriptorExtractor extractor;
|
||||
Mat descriptors1;
|
||||
extractor.compute(img1, keypoints1, descriptors1);
|
||||
|
||||
... // process keypoints from the second image as well
|
||||
|
||||
#.
|
||||
Now, find the closest matches between descriptors from the first image to the second: ::
|
||||
|
||||
@@ -59,7 +50,7 @@ The goal of this tutorial is to learn how to use *features2d* and *calib3d* modu
|
||||
vector<Point2f> points1, points2;
|
||||
// fill the arrays with the points
|
||||
....
|
||||
Mat H = findHomography(Mat(points1), Mat(points2), CV_RANSAC, ransacReprojThreshold);
|
||||
Mat H = findHomography(Mat(points1), Mat(points2), RANSAC, ransacReprojThreshold);
|
||||
|
||||
|
||||
#.
|
||||
|
||||
@@ -45,8 +45,8 @@ This tutorial code's is shown lines below.
|
||||
if( argc != 3 )
|
||||
{ return -1; }
|
||||
|
||||
Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
|
||||
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
|
||||
|
||||
if( !img_1.data || !img_2.data )
|
||||
{ return -1; }
|
||||
|
||||
@@ -44,8 +44,8 @@ This tutorial code's is shown lines below.
|
||||
if( argc != 3 )
|
||||
{ readme(); return -1; }
|
||||
|
||||
Mat img_1 = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_1 = imread( argv[1], IMREAD_GRAYSCALE );
|
||||
Mat img_2 = imread( argv[2], IMREAD_GRAYSCALE );
|
||||
|
||||
if( !img_1.data || !img_2.data )
|
||||
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
|
||||
|
||||
@@ -43,8 +43,8 @@ This tutorial code's is shown lines below.
|
||||
if( argc != 3 )
|
||||
{ readme(); return -1; }
|
||||
|
||||
Mat img_object = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_scene = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
|
||||
Mat img_object = imread( argv[1], IMREAD_GRAYSCALE );
|
||||
Mat img_scene = imread( argv[2], IMREAD_GRAYSCALE );
|
||||
|
||||
if( !img_object.data || !img_scene.data )
|
||||
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
|
||||
@@ -108,7 +108,7 @@ This tutorial code's is shown lines below.
|
||||
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
|
||||
}
|
||||
|
||||
Mat H = findHomography( obj, scene, CV_RANSAC );
|
||||
Mat H = findHomography( obj, scene, RANSAC );
|
||||
|
||||
//-- Get the corners from the image_1 ( the object to be "detected" )
|
||||
std::vector<Point2f> obj_corners(4);
|
||||
|
||||
|
After Width: | Height: | Size: 31 KiB |
@@ -194,7 +194,7 @@ Learn about how to use the feature points detectors, descriptors and matching f
|
||||
|
||||
*Author:* Fedor Morozov
|
||||
|
||||
Use *AKAZE* local features to find correspondence between two images.
|
||||
Using *AKAZE* local features to find correspondence between two images.
|
||||
|
||||
===================== ==============================================
|
||||
|
||||
@@ -202,6 +202,21 @@ Learn about how to use the feature points detectors, descriptors and matching f
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
===================== ==============================================
|
||||
|AkazeTracking| **Title:** :ref:`akazeTracking`
|
||||
|
||||
*Compatibility:* > OpenCV 3.0
|
||||
|
||||
*Author:* Fedor Morozov
|
||||
|
||||
Using *AKAZE* and *ORB* for planar object tracking.
|
||||
|
||||
===================== ==============================================
|
||||
|
||||
.. |AkazeTracking| image:: images/AKAZE_Tracking_Tutorial_Cover.png
|
||||
:height: 90pt
|
||||
:width: 90pt
|
||||
|
||||
.. raw:: latex
|
||||
|
||||
\pagebreak
|
||||
@@ -221,3 +236,4 @@ Learn about how to use the feature points detectors, descriptors and matching f
|
||||
../feature_homography/feature_homography
|
||||
../detection_of_planar_objects/detection_of_planar_objects
|
||||
../akaze_matching/akaze_matching
|
||||
../akaze_tracking/akaze_tracking
|
||||
|
||||
@@ -49,10 +49,10 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
{
|
||||
/// Load source image and convert it to gray
|
||||
src = imread( argv[1], 1 );
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
/// Create Window
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create Trackbar to set the number of corners
|
||||
createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo);
|
||||
@@ -105,13 +105,13 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
rng.uniform(0,255)), -1, 8, 0 ); }
|
||||
|
||||
/// Show what you got
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, copy );
|
||||
|
||||
/// Set the neeed parameters to find the refined corners
|
||||
Size winSize = Size( 5, 5 );
|
||||
Size zeroZone = Size( -1, -1 );
|
||||
TermCriteria criteria = TermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 40, 0.001 );
|
||||
TermCriteria criteria = TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001 );
|
||||
|
||||
/// Calculate the refined corner locations
|
||||
cornerSubPix( src_gray, corners, winSize, zeroZone, criteria );
|
||||
|
||||
@@ -50,10 +50,10 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
{
|
||||
/// Load source image and convert it to gray
|
||||
src = imread( argv[1], 1 );
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
/// Create Window
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create Trackbar to set the number of corners
|
||||
createTrackbar( "Max corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo );
|
||||
@@ -106,7 +106,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
rng.uniform(0,255)), -1, 8, 0 ); }
|
||||
|
||||
/// Show what you got
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, copy );
|
||||
}
|
||||
|
||||
|
||||
@@ -180,10 +180,10 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
{
|
||||
/// Load source image and convert it to gray
|
||||
src = imread( argv[1], 1 );
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
/// Create a window and a trackbar
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );
|
||||
imshow( source_window, src );
|
||||
|
||||
@@ -223,7 +223,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
}
|
||||
/// Showing the result
|
||||
namedWindow( corners_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( corners_window, WINDOW_AUTOSIZE );
|
||||
imshow( corners_window, dst_norm_scaled );
|
||||
}
|
||||
|
||||
|
||||
@@ -79,18 +79,18 @@ Videos have many-many information attached to them besides the content of the fr
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
Size refS = Size((int) captRefrnc.get(CV_CAP_PROP_FRAME_WIDTH),
|
||||
(int) captRefrnc.get(CV_CAP_PROP_FRAME_HEIGHT)),
|
||||
Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
|
||||
(int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
|
||||
|
||||
cout << "Reference frame resolution: Width=" << refS.width << " Height=" << refS.height
|
||||
<< " of nr#: " << captRefrnc.get(CV_CAP_PROP_FRAME_COUNT) << endl;
|
||||
<< " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
|
||||
|
||||
When you are working with videos you may often want to control these values yourself. To do this there is a :hgvideo:`set <videocapture-set>` function. Its first argument remains the name of the property you want to change and there is a second of double type containing the value to be set. It will return true if it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time or frame:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
captRefrnc.set(CV_CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video
|
||||
captRefrnc.set(CV_CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
|
||||
captRefrnc.set(CAP_PROP_POS_MSEC, 1.2); // go to the 1.2 second in the video
|
||||
captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
|
||||
// now a read operation would read the frame at the set position
|
||||
|
||||
For properties you can read and change look into the documentation of the :hgvideo:`get <videocapture-get>` and :hgvideo:`set <videocapture-set>` functions.
|
||||
@@ -122,7 +122,7 @@ Here the :math:`MAX_I^2` is the maximum valid value for a pixel. In case of the
|
||||
s1.convertTo(s1, CV_32F); // cannot make a square on 8 bits
|
||||
s1 = s1.mul(s1); // |I1 - I2|^2
|
||||
|
||||
Scalar s = sum(s1); // sum elements per channel
|
||||
Scalar s = sum(s1); // sum elements per channel
|
||||
|
||||
double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ To create a video file you just need to create an instance of the :hgvideo:`Vide
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
VideoCapture inputVideo(source); // Open input
|
||||
int ex = static_cast<int>(inputVideo.get(CV_CAP_PROP_FOURCC)); // Get Codec Type- Int form
|
||||
VideoCapture inputVideo(source); // Open input
|
||||
int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC)); // Get Codec Type- Int form
|
||||
|
||||
OpenCV internally works with this integer type and expect this as its second parameter. Now to convert from the integer form to string we may use two methods: a bitwise operator and a union method. The first one extracting from an int the characters looks like (an "and" operation, some shifting and adding a 0 at the end to close the string):
|
||||
|
||||
@@ -100,9 +100,9 @@ Here it is, how I use it in the sample:
|
||||
.. code-block:: cpp
|
||||
|
||||
VideoWriter outputVideo;
|
||||
Size S = Size((int) inputVideo.get(CV_CAP_PROP_FRAME_WIDTH), //Acquire input size
|
||||
(int) inputVideo.get(CV_CAP_PROP_FRAME_HEIGHT));
|
||||
outputVideo.open(NAME , ex, inputVideo.get(CV_CAP_PROP_FPS),S, true);
|
||||
Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH), //Acquire input size
|
||||
(int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
|
||||
outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);
|
||||
|
||||
Afterwards, you use the :hgvideo:`isOpened() <videowriter-isopened>` function to find out if the open operation succeeded or not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open the object with success you can send the frames of the video in a sequential order by using the :hgvideo:`write<videowriter-write>` function of the class. Alternatively, you can use its overloaded operator << :
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.1 KiB |
@@ -106,8 +106,8 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
{ return -1; }
|
||||
|
||||
/// Create windows
|
||||
namedWindow( "Erosion Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Dilation Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
|
||||
namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
|
||||
cvMoveWindow( "Dilation Demo", src.cols, 0 );
|
||||
|
||||
/// Create Erosion Trackbar
|
||||
|
||||
@@ -145,7 +145,7 @@ Code
|
||||
*/
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Load the source image
|
||||
src = imread( "../images/lena.jpg", 1 );
|
||||
@@ -195,7 +195,7 @@ Code
|
||||
dst = Mat::zeros( src.size(), src.type() );
|
||||
putText( dst, caption,
|
||||
Point( src.cols/4, src.rows/2),
|
||||
CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
|
||||
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
|
||||
|
||||
imshow( window_name, dst );
|
||||
int c = waitKey( DELAY_CAPTION );
|
||||
|
||||
@@ -128,7 +128,7 @@ Code
|
||||
/// Read the image
|
||||
src = imread( argv[1], 1 );
|
||||
/// Transform it to HSV
|
||||
cvtColor( src, hsv, CV_BGR2HSV );
|
||||
cvtColor( src, hsv, COLOR_BGR2HSV );
|
||||
|
||||
/// Use only the Hue value
|
||||
hue.create( hsv.size(), hsv.depth() );
|
||||
@@ -137,7 +137,7 @@ Code
|
||||
|
||||
/// Create Trackbar to enter the number of bins
|
||||
char* window_image = "Source image";
|
||||
namedWindow( window_image, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_image, WINDOW_AUTOSIZE );
|
||||
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
|
||||
Hist_and_Backproj(0, 0);
|
||||
|
||||
@@ -198,7 +198,7 @@ Explanation
|
||||
.. code-block:: cpp
|
||||
|
||||
src = imread( argv[1], 1 );
|
||||
cvtColor( src, hsv, CV_BGR2HSV );
|
||||
cvtColor( src, hsv, COLOR_BGR2HSV );
|
||||
|
||||
#. For this tutorial, we will use only the Hue value for our 1-D histogram (check out the fancier code in the links above if you want to use the more standard H-S histogram, which yields better results):
|
||||
|
||||
@@ -224,7 +224,7 @@ Explanation
|
||||
.. code-block:: cpp
|
||||
|
||||
char* window_image = "Source image";
|
||||
namedWindow( window_image, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_image, WINDOW_AUTOSIZE );
|
||||
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
|
||||
Hist_and_Backproj(0, 0);
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ Code
|
||||
}
|
||||
|
||||
/// Display
|
||||
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
|
||||
imshow("calcHist Demo", histImage );
|
||||
|
||||
waitKey(0);
|
||||
@@ -309,7 +309,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow("calcHist Demo", WINDOW_AUTOSIZE );
|
||||
imshow("calcHist Demo", histImage );
|
||||
|
||||
waitKey(0);
|
||||
|
||||
@@ -119,9 +119,9 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src_base, hsv_base, CV_BGR2HSV );
|
||||
cvtColor( src_test1, hsv_test1, CV_BGR2HSV );
|
||||
cvtColor( src_test2, hsv_test2, CV_BGR2HSV );
|
||||
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
|
||||
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
|
||||
cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );
|
||||
|
||||
#. Also, create an image of half the base image (in HSV format):
|
||||
|
||||
|
||||
@@ -113,14 +113,14 @@ Code
|
||||
return -1;}
|
||||
|
||||
/// Convert to grayscale
|
||||
cvtColor( src, src, CV_BGR2GRAY );
|
||||
cvtColor( src, src, COLOR_BGR2GRAY );
|
||||
|
||||
/// Apply Histogram Equalization
|
||||
equalizeHist( src, dst );
|
||||
|
||||
/// Display results
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( equalized_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( equalized_window, WINDOW_AUTOSIZE );
|
||||
|
||||
imshow( source_window, src );
|
||||
imshow( equalized_window, dst );
|
||||
@@ -157,7 +157,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src, src, CV_BGR2GRAY );
|
||||
cvtColor( src, src, COLOR_BGR2GRAY );
|
||||
|
||||
#. Apply histogram equalization with the function :equalize_hist:`equalizeHist <>` :
|
||||
|
||||
@@ -171,8 +171,8 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( equalized_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( equalized_window, WINDOW_AUTOSIZE );
|
||||
|
||||
imshow( source_window, src );
|
||||
imshow( equalized_window, dst );
|
||||
|
||||
@@ -158,8 +158,8 @@ Code
|
||||
templ = imread( argv[2], 1 );
|
||||
|
||||
/// Create windows
|
||||
namedWindow( image_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( image_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create Trackbar
|
||||
char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
|
||||
@@ -239,8 +239,8 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( image_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( image_window, WINDOW_AUTOSIZE );
|
||||
namedWindow( result_window, WINDOW_AUTOSIZE );
|
||||
|
||||
#. Create the Trackbar to enter the kind of matching method to be used. When a change is detected the callback function **MatchingMethod** is called.
|
||||
|
||||
@@ -306,11 +306,11 @@ Explanation
|
||||
+ **Mat():** Optional mask
|
||||
|
||||
|
||||
#. For the first two methods ( CV\_SQDIFF and CV\_SQDIFF\_NORMED ) the best match are the lowest values. For all the others, higher values represent better matches. So, we save the corresponding value in the **matchLoc** variable:
|
||||
#. For the first two methods ( TM\_SQDIFF and MT\_SQDIFF\_NORMED ) the best match are the lowest values. For all the others, higher values represent better matches. So, we save the corresponding value in the **matchLoc** variable:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
|
||||
if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED )
|
||||
{ matchLoc = minLoc; }
|
||||
else
|
||||
{ matchLoc = maxLoc; }
|
||||
|
||||
@@ -142,10 +142,10 @@ Code
|
||||
dst.create( src.size(), src.type() );
|
||||
|
||||
/// Convert the image to grayscale
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
/// Create a window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create a Trackbar for user to enter threshold
|
||||
createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
|
||||
@@ -203,13 +203,13 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
#. Create a window to display the results
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
#. Create a Trackbar for the user to enter the lower threshold for our Canny detector:
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ Code
|
||||
printf( " ** Press 'ESC' to exit the program \n");
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Initialize arguments for the filter
|
||||
top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows);
|
||||
@@ -150,7 +150,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
#. Now we initialize the argument that defines the size of the borders (*top*, *bottom*, *left* and *right*). We give them a value of 5% the size of *src*.
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ Code
|
||||
{ return -1; }
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Initialize arguments for the filter
|
||||
anchor = Point( -1, -1 );
|
||||
@@ -151,7 +151,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
#. Initialize the arguments for the linear filter
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ Code
|
||||
{ return -1; }
|
||||
|
||||
/// Convert it to gray
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
/// Reduce the noise so we avoid false circle detection
|
||||
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
|
||||
@@ -75,7 +75,7 @@ Code
|
||||
vector<Vec3f> circles;
|
||||
|
||||
/// Apply the Hough Transform to find the circles
|
||||
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
|
||||
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
|
||||
|
||||
/// Draw the circles detected
|
||||
for( size_t i = 0; i < circles.size(); i++ )
|
||||
@@ -89,7 +89,7 @@ Code
|
||||
}
|
||||
|
||||
/// Show your results
|
||||
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE );
|
||||
imshow( "Hough Circle Transform Demo", src );
|
||||
|
||||
waitKey(0);
|
||||
@@ -114,7 +114,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
|
||||
#. Apply a Gaussian blur to reduce noise and avoid false circle detection:
|
||||
|
||||
@@ -128,13 +128,13 @@ Explanation
|
||||
|
||||
vector<Vec3f> circles;
|
||||
|
||||
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
|
||||
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
|
||||
|
||||
with the arguments:
|
||||
|
||||
* *src_gray*: Input image (grayscale).
|
||||
* *circles*: A vector that stores sets of 3 values: :math:`x_{c}, y_{c}, r` for each detected circle.
|
||||
* *CV_HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV.
|
||||
* *HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in OpenCV.
|
||||
* *dp = 1*: The inverse ratio of resolution.
|
||||
* *min_dist = src_gray.rows/8*: Minimum distance between detected centers.
|
||||
* *param_1 = 200*: Upper threshold for the internal Canny edge detector.
|
||||
@@ -162,7 +162,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE );
|
||||
imshow( "Hough Circle Transform Demo", src );
|
||||
|
||||
#. Wait for the user to exit the program
|
||||
|
||||
@@ -133,7 +133,7 @@ Code
|
||||
|
||||
Mat dst, cdst;
|
||||
Canny(src, dst, 50, 200, 3);
|
||||
cvtColor(dst, cdst, CV_GRAY2BGR);
|
||||
cvtColor(dst, cdst, COLOR_GRAY2BGR);
|
||||
|
||||
#if 0
|
||||
vector<Vec2f> lines;
|
||||
@@ -149,7 +149,7 @@ Code
|
||||
pt1.y = cvRound(y0 + 1000*(a));
|
||||
pt2.x = cvRound(x0 - 1000*(-b));
|
||||
pt2.y = cvRound(y0 - 1000*(a));
|
||||
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
|
||||
line( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);
|
||||
}
|
||||
#else
|
||||
vector<Vec4i> lines;
|
||||
@@ -223,7 +223,7 @@ Explanation
|
||||
pt1.y = cvRound(y0 + 1000*(a));
|
||||
pt2.x = cvRound(x0 - 1000*(-b));
|
||||
pt2.y = cvRound(y0 - 1000*(a));
|
||||
line( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
|
||||
line( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);
|
||||
}
|
||||
|
||||
#. **Probabilistic Hough Line Transform**
|
||||
@@ -252,7 +252,7 @@ Explanation
|
||||
for( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
Vec4i l = lines[i];
|
||||
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA);
|
||||
line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -88,10 +88,10 @@ Code
|
||||
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
|
||||
|
||||
/// Convert the image to grayscale
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Apply Laplace function
|
||||
Mat abs_dst;
|
||||
@@ -141,7 +141,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
#. Apply the Laplacian operator to the grayscale image:
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ Code
|
||||
map_y.create( src.size(), CV_32FC1 );
|
||||
|
||||
/// Create window
|
||||
namedWindow( remap_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( remap_window, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Loop
|
||||
while( true )
|
||||
@@ -106,7 +106,7 @@ Code
|
||||
|
||||
/// Update map_x & map_y. Then apply remap
|
||||
update_map();
|
||||
remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
|
||||
remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
|
||||
|
||||
/// Display results
|
||||
imshow( remap_window, dst );
|
||||
@@ -186,7 +186,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( remap_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( remap_window, WINDOW_AUTOSIZE );
|
||||
|
||||
#. Establish a loop. Each 1000 ms we update our mapping matrices (*mat_x* and *mat_y*) and apply them to our source image:
|
||||
|
||||
@@ -202,7 +202,7 @@ Explanation
|
||||
|
||||
/// Update map_x & map_y. Then apply remap
|
||||
update_map();
|
||||
remap( src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
|
||||
remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0,0, 0) );
|
||||
|
||||
/// Display results
|
||||
imshow( remap_window, dst );
|
||||
@@ -214,7 +214,7 @@ Explanation
|
||||
* **dst**: Destination image of same size as *src*
|
||||
* **map_x**: The mapping function in the x direction. It is equivalent to the first component of :math:`h(i,j)`
|
||||
* **map_y**: Same as above, but in y direction. Note that *map_y* and *map_x* are both of the same size as *src*
|
||||
* **CV_INTER_LINEAR**: The type of interpolation to use for non-integer pixels. This is by default.
|
||||
* **INTER_LINEAR**: The type of interpolation to use for non-integer pixels. This is by default.
|
||||
* **BORDER_CONSTANT**: Default
|
||||
|
||||
How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading:
|
||||
|
||||
@@ -154,10 +154,10 @@ Code
|
||||
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
|
||||
|
||||
/// Convert it to gray
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Generate grad_x and grad_y
|
||||
Mat grad_x, grad_y;
|
||||
@@ -217,7 +217,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
#. Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the function :sobel:`Sobel <>` as shown below:
|
||||
|
||||
|
||||
@@ -155,13 +155,13 @@ Code
|
||||
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
|
||||
|
||||
/// Show what you got
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( warp_window, WINDOW_AUTOSIZE );
|
||||
imshow( warp_window, warp_dst );
|
||||
|
||||
namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( warp_rotate_window, WINDOW_AUTOSIZE );
|
||||
imshow( warp_rotate_window, warp_rotate_dst );
|
||||
|
||||
/// Wait until user exits the program
|
||||
@@ -265,13 +265,13 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
namedWindow( warp_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( warp_window, WINDOW_AUTOSIZE );
|
||||
imshow( warp_window, warp_dst );
|
||||
|
||||
namedWindow( warp_rotate_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( warp_rotate_window, WINDOW_AUTOSIZE );
|
||||
imshow( warp_rotate_window, warp_rotate_dst );
|
||||
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
{ return -1; }
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create Trackbar to select Morphology operation
|
||||
createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
|
||||
|
||||
@@ -119,7 +119,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
dst = tmp;
|
||||
|
||||
/// Create window
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
imshow( window_name, dst );
|
||||
|
||||
/// Loop
|
||||
@@ -175,7 +175,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
imshow( window_name, dst );
|
||||
|
||||
* Perform an infinite loop waiting for user input.
|
||||
|
||||
@@ -49,12 +49,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
blur( src_gray, src_gray, Size(3,3) );
|
||||
|
||||
/// Create Window
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
@@ -74,7 +74,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
/// Detect edges using Threshold
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Approximate contours to polygons + get bounding rects and circles
|
||||
vector<vector<Point> > contours_poly( contours.size() );
|
||||
@@ -100,7 +100,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
}
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
blur( src_gray, src_gray, Size(3,3) );
|
||||
|
||||
/// Create Window
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
@@ -74,7 +74,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
/// Detect edges using Threshold
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Find the rotated rectangles and ellipses for each contour
|
||||
vector<RotatedRect> minRect( contours.size() );
|
||||
@@ -102,7 +102,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
blur( src_gray, src_gray, Size(3,3) );
|
||||
|
||||
/// Create Window
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
@@ -72,7 +72,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
/// Detect edges using canny
|
||||
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
|
||||
/// Find contours
|
||||
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Draw contours
|
||||
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
|
||||
@@ -83,7 +83,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
}
|
||||
|
||||
|
||||
@@ -47,12 +47,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
blur( src_gray, src_gray, Size(3,3) );
|
||||
|
||||
/// Create Window
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
@@ -74,7 +74,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
|
||||
|
||||
/// Find contours
|
||||
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Find the convex hull object for each contour
|
||||
vector<vector<Point> >hull( contours.size() );
|
||||
@@ -91,7 +91,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Hull demo", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Hull demo", WINDOW_AUTOSIZE );
|
||||
imshow( "Hull demo", drawing );
|
||||
}
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert image to gray and blur it
|
||||
cvtColor( src, src_gray, CV_BGR2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_BGR2GRAY );
|
||||
blur( src_gray, src_gray, Size(3,3) );
|
||||
|
||||
/// Create Window
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
|
||||
createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
|
||||
@@ -74,7 +74,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
/// Detect edges using canny
|
||||
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
|
||||
/// Find contours
|
||||
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
findContours( canny_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
|
||||
|
||||
/// Get the moments
|
||||
vector<Moments> mu(contours.size() );
|
||||
@@ -96,7 +96,7 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
}
|
||||
|
||||
/// Show in a window
|
||||
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Contours", WINDOW_AUTOSIZE );
|
||||
imshow( "Contours", drawing );
|
||||
|
||||
/// Calculate the area with the moments 00 and compare with the result of the OpenCV function
|
||||
|
||||
@@ -88,9 +88,9 @@ This tutorial code's is shown lines below. You can also download it from `here <
|
||||
|
||||
/// Create Window and show your results
|
||||
char* source_window = "Source";
|
||||
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( source_window, WINDOW_AUTOSIZE );
|
||||
imshow( source_window, src );
|
||||
namedWindow( "Distance", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Distance", WINDOW_AUTOSIZE );
|
||||
imshow( "Distance", drawing );
|
||||
|
||||
waitKey(0);
|
||||
|
||||
@@ -167,10 +167,10 @@ The tutorial code's is shown lines below. You can also download it from `here <h
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert the image to Gray
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
/// Create a window to display results
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
/// Create Trackbar to choose type of Threshold
|
||||
createTrackbar( trackbar_type,
|
||||
@@ -228,14 +228,14 @@ Explanation
|
||||
src = imread( argv[1], 1 );
|
||||
|
||||
/// Convert the image to Gray
|
||||
cvtColor( src, src_gray, CV_RGB2GRAY );
|
||||
cvtColor( src, src_gray, COLOR_RGB2GRAY );
|
||||
|
||||
|
||||
* Create a window to display the result
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( window_name, WINDOW_AUTOSIZE );
|
||||
|
||||
* Create :math:`2` trackbars for the user to enter user input:
|
||||
|
||||
|
||||
@@ -39,41 +39,41 @@ You'll almost always end up using the:
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:tab-width: 4
|
||||
:lines: 1-4
|
||||
:lines: 1-6
|
||||
|
||||
We also include the *iostream* to facilitate console line output and input. To avoid data structure and function name conflicts with other libraries, OpenCV has its own namespace: *cv*. To avoid the need appending prior each of these the *cv::* keyword you can import the namespace in the whole file by using the lines:
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:tab-width: 4
|
||||
:lines: 6-7
|
||||
:lines: 8-9
|
||||
|
||||
This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function. We start up assuring that we acquire a valid image name argument from the command line.
|
||||
This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function. We start up assuring that we acquire a valid image name argument from the command line. Otherwise take a picture by default: "HappyFish.jpg".
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:tab-width: 4
|
||||
:lines: 11-15
|
||||
:lines: 13-17
|
||||
|
||||
Then create a *Mat* object that will store the data of the loaded image.
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:tab-width: 4
|
||||
:lines: 17
|
||||
:lines: 19
|
||||
|
||||
Now we call the :imread:`imread <>` function which loads the image name specified by the first argument (*argv[1]*). The second argument specifies the format in what we want the image. This may be:
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ CV_LOAD_IMAGE_UNCHANGED (<0) loads the image as is (including the alpha channel if present)
|
||||
+ CV_LOAD_IMAGE_GRAYSCALE ( 0) loads the image as an intensity one
|
||||
+ CV_LOAD_IMAGE_COLOR (>0) loads the image in the RGB format
|
||||
+ IMREAD_UNCHANGED (<0) loads the image as is (including the alpha channel if present)
|
||||
+ IMREAD_GRAYSCALE ( 0) loads the image as an intensity one
|
||||
+ IMREAD_COLOR (>0) loads the image in the RGB format
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:tab-width: 4
|
||||
:lines: 18
|
||||
:lines: 20
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -83,26 +83,26 @@ After checking that the image data was loaded correctly, we want to display our
|
||||
|
||||
.. container:: enumeratevisibleitemswithsquare
|
||||
|
||||
+ *CV_WINDOW_AUTOSIZE* is the only supported one if you do not use the Qt backend. In this case the window size will take up the size of the image it shows. No resize permitted!
|
||||
+ *CV_WINDOW_NORMAL* on Qt you may use this to allow window resize. The image will resize itself according to the current window size. By using the | operator you also need to specify if you would like the image to keep its aspect ratio (*CV_WINDOW_KEEPRATIO*) or not (*CV_WINDOW_FREERATIO*).
|
||||
+ *WINDOW_AUTOSIZE* is the only supported one if you do not use the Qt backend. In this case the window size will take up the size of the image it shows. No resize permitted!
|
||||
+ *WINDOW_NORMAL* on Qt you may use this to allow window resize. The image will resize itself according to the current window size. By using the | operator you also need to specify if you would like the image to keep its aspect ratio (*WINDOW_KEEPRATIO*) or not (*WINDOW_FREERATIO*).
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:lines: 26
|
||||
:lines: 28
|
||||
:tab-width: 4
|
||||
|
||||
Finally, to update the content of the OpenCV window with a new image use the :imshow:`imshow <>` function. Specify the OpenCV window name to update and the image to use during this operation:
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:lines: 27
|
||||
:lines: 29
|
||||
:tab-width: 4
|
||||
|
||||
Because we want our window to be displayed until the user presses a key (otherwise the program would end far too quickly), we use the :wait_key:`waitKey <>` function whose only parameter is just how long should it wait for a user input (measured in milliseconds). Zero means to wait forever.
|
||||
|
||||
.. literalinclude:: ../../../../samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
|
||||
:language: cpp
|
||||
:lines: 29
|
||||
:lines: 31
|
||||
:tab-width: 4
|
||||
|
||||
Result
|
||||
|
||||
@@ -68,7 +68,7 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
cvtColor( image, gray_image, CV_BGR2GRAY );
|
||||
cvtColor( image, gray_image, COLOR_BGR2GRAY );
|
||||
|
||||
As you can see, :miscellaneous_transformations:`cvtColor <cvtcolor>` takes as arguments:
|
||||
|
||||
@@ -76,7 +76,7 @@ Explanation
|
||||
|
||||
* a source image (*image*)
|
||||
* a destination image (*gray_image*), in which we will save the converted image.
|
||||
* an additional parameter that indicates what kind of transformation will be performed. In this case we use **CV_BGR2GRAY** (because of :readwriteimage:`imread <imread>` has BGR default channel order in case of color images).
|
||||
* an additional parameter that indicates what kind of transformation will be performed. In this case we use **COLOR_BGR2GRAY** (because of :readwriteimage:`imread <imread>` has BGR default channel order in case of color images).
|
||||
|
||||
#. So now we have our new *gray_image* and want to save it on disk (otherwise it will get lost after the program ends). To save it, we will use a function analagous to :readwriteimage:`imread <imread>`: :readwriteimage:`imwrite <imwrite>`
|
||||
|
||||
@@ -90,8 +90,8 @@ Explanation
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
namedWindow( imageName, CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( "Gray image", CV_WINDOW_AUTOSIZE );
|
||||
namedWindow( imageName, WINDOW_AUTOSIZE );
|
||||
namedWindow( "Gray image", WINDOW_AUTOSIZE );
|
||||
|
||||
imshow( imageName, image );
|
||||
imshow( "Gray image", gray_image );
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.1 KiB |
@@ -4,7 +4,7 @@ Introduction to OpenCV
|
||||
-----------------------------------------------------------
|
||||
|
||||
Here you can read tutorials about how to set up your computer to work with the OpenCV library.
|
||||
Additionally you can find a few very basic sample source code that will let introduce you to the
|
||||
Additionally you can find very basic sample source code to introduce you to the
|
||||
world of the OpenCV.
|
||||
|
||||
.. include:: ../../definitions/tocDefinitions.rst
|
||||
|
||||
@@ -90,25 +90,24 @@ A full list, for the latest version would contain:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
opencv_calib3d249d.lib
|
||||
opencv_contrib249d.lib
|
||||
opencv_core249d.lib
|
||||
opencv_features2d249d.lib
|
||||
opencv_flann249d.lib
|
||||
opencv_gpu249d.lib
|
||||
opencv_highgui249d.lib
|
||||
opencv_imgproc249d.lib
|
||||
opencv_legacy249d.lib
|
||||
opencv_ml249d.lib
|
||||
opencv_nonfree249d.lib
|
||||
opencv_objdetect249d.lib
|
||||
opencv_ocl249d.lib
|
||||
opencv_photo249d.lib
|
||||
opencv_stitching249d.lib
|
||||
opencv_superres249d.lib
|
||||
opencv_ts249d.lib
|
||||
opencv_video249d.lib
|
||||
opencv_videostab249d.lib
|
||||
opencv_calib3d300d.lib
|
||||
opencv_core300d.lib
|
||||
opencv_features2d300d.lib
|
||||
opencv_flann300d.lib
|
||||
opencv_highgui300d.lib
|
||||
opencv_imgcodecs300d.lib
|
||||
opencv_imgproc300d.lib
|
||||
opencv_ml300d.lib
|
||||
opencv_objdetect300d.lib
|
||||
opencv_photo300d.lib
|
||||
opencv_shape300d.lib
|
||||
opencv_stitching300d.lib
|
||||
opencv_superres300d.lib
|
||||
opencv_ts300d.lib
|
||||
opencv_video300d.lib
|
||||
opencv_videoio300d.lib
|
||||
opencv_videostab300d.lib
|
||||
|
||||
|
||||
The letter *d* at the end just indicates that these are the libraries required for the debug. Now click ok to save and do the same with a new property inside the Release rule section. Make sure to omit the *d* letters from the library names and to save the property sheets with the save icon above them.
|
||||
|
||||
@@ -161,7 +160,7 @@ You can start a Visual Studio build from two places. Either inside from the *IDE
|
||||
|
||||
.. |voila| unicode:: voil U+00E1
|
||||
|
||||
This is important to remember when you code inside the code open and save commands. You're resources will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless you give a full, explicit path as parameter for the I/O functions. In the code above we open :download:`this OpenCV logo<../../../../samples/cpp/tutorial_code/images/opencv-logo.png>`. Before starting up the application make sure you place the image file in your current working directory. Modify the image file name inside the code to try it out on other images too. Run it and |voila|:
|
||||
This is important to remember when you code inside the code open and save commands. You're resources will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless you give a full, explicit path as parameter for the I/O functions. In the code above we open :download:`this OpenCV logo<../../../../samples/data/opencv-logo.png>`. Before starting up the application make sure you place the image file in your current working directory. Modify the image file name inside the code to try it out on other images too. Run it and |voila|:
|
||||
|
||||
.. image:: images/SuccessVisualStudioWindows.jpg
|
||||
:alt: You should have this.
|
||||
|
||||
@@ -65,7 +65,7 @@ Image Watch works with any existing project that uses OpenCV image objects (for
|
||||
|
||||
cout << "Loading input image: " << argv[1] << endl;
|
||||
Mat input;
|
||||
input = imread(argv[1], CV_LOAD_IMAGE_COLOR);
|
||||
input = imread(argv[1], IMREAD_COLOR);
|
||||
|
||||
cout << "Detecting edges in input image" << endl;
|
||||
Mat edges;
|
||||
|
||||