├── .gitignore ├── AUTHORS.txt ├── COPYING ├── README.rst ├── munkres.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── munkres.xccheckout │ └── xcuserdata │ │ └── sym.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── sym.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── munkres.xcscheme │ └── xcschememanagement.plist └── src ├── main.cpp ├── munkres ├── munkres.cpp └── munkres.h /.gitignore: -------------------------------------------------------------------------------- 1 | src/munkrestest 2 | *.so 3 | *.o 4 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | 2 | The following is a list of much appreciated contributors: 3 | 4 | 5 | John Weaver 6 | Gluttton 7 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | munkres-opencv 3 | =========== 4 | 5 | An implementation of the Kuhn–Munkres algorithm forked from John Weaver 6 | Simplified the source code structure and ported to support OPENCV only. 7 | cv::Mat_ has been used instead of John's matrix class. It is cleaner and better support for empty matrix cases in OPENCV multiple object tracking. 8 | 9 | 10 | Usage 11 | ----- 12 | 13 | You have to have OPENCV 2.4 or above installed to use this. 14 | For MacOS user, Xcode project file is included. 15 | Basic usage can be referred from main.cpp 16 | 17 | License 18 | ------- 19 | 20 | Port to OPENCV by Shen Yiming 2014 21 | 22 | Copyright (c) 2007-2013 John Weaver and contributors. 23 | 24 | Licensed under the GPLv2. See the file COPYING for details. 25 | 26 | 27 | -------------------------------------------------------------------------------- /munkres.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2104F0EE190A085200729A3A /* libopencv_core.2.4.8.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2104F0ED190A085200729A3A /* libopencv_core.2.4.8.dylib */; }; 11 | 21FB463E18FF713C0057CAAD /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FB463A18FF713C0057CAAD /* main.cpp */; }; 12 | 21FB463F18FF713C0057CAAD /* munkres.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21FB463C18FF713C0057CAAD /* munkres.cpp */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXCopyFilesBuildPhase section */ 16 | 21935E1118FF64F6001D2E31 /* CopyFiles */ = { 17 | isa = PBXCopyFilesBuildPhase; 18 | buildActionMask = 2147483647; 19 | dstPath = /usr/share/man/man1/; 20 | dstSubfolderSpec = 0; 21 | files = ( 22 | ); 23 | runOnlyForDeploymentPostprocessing = 1; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 2104F0ED190A085200729A3A /* libopencv_core.2.4.8.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libopencv_core.2.4.8.dylib; path = ../../../../usr/local/Cellar/opencv/2.4.8.2/lib/libopencv_core.2.4.8.dylib; sourceTree = ""; }; 29 | 21935E1318FF64F6001D2E31 /* munkres */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = munkres; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 21FB463A18FF713C0057CAAD /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; }; 31 | 21FB463B18FF713C0057CAAD /* munkres.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = munkres.1; path = src/munkres.1; sourceTree = SOURCE_ROOT; }; 32 | 21FB463C18FF713C0057CAAD /* munkres.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = munkres.cpp; path = src/munkres.cpp; sourceTree = SOURCE_ROOT; }; 33 | 21FB463D18FF713C0057CAAD /* munkres.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = munkres.h; path = src/munkres.h; sourceTree = SOURCE_ROOT; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | 21935E1018FF64F6001D2E31 /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | 2104F0EE190A085200729A3A /* libopencv_core.2.4.8.dylib in Frameworks */, 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 21935E0A18FF64F6001D2E31 = { 49 | isa = PBXGroup; 50 | children = ( 51 | 2104F0ED190A085200729A3A /* libopencv_core.2.4.8.dylib */, 52 | 21935E1518FF64F6001D2E31 /* src */, 53 | 21935E1418FF64F6001D2E31 /* Products */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | 21935E1418FF64F6001D2E31 /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 21935E1318FF64F6001D2E31 /* munkres */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | 21935E1518FF64F6001D2E31 /* src */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 21FB463A18FF713C0057CAAD /* main.cpp */, 69 | 21FB463B18FF713C0057CAAD /* munkres.1 */, 70 | 21FB463C18FF713C0057CAAD /* munkres.cpp */, 71 | 21FB463D18FF713C0057CAAD /* munkres.h */, 72 | ); 73 | name = src; 74 | path = munkres; 75 | sourceTree = ""; 76 | }; 77 | /* End PBXGroup section */ 78 | 79 | /* Begin PBXNativeTarget section */ 80 | 21935E1218FF64F6001D2E31 /* munkres */ = { 81 | isa = PBXNativeTarget; 82 | buildConfigurationList = 21935E1C18FF64F6001D2E31 /* Build configuration list for PBXNativeTarget "munkres" */; 83 | buildPhases = ( 84 | 21935E0F18FF64F6001D2E31 /* Sources */, 85 | 21935E1018FF64F6001D2E31 /* Frameworks */, 86 | 21935E1118FF64F6001D2E31 /* CopyFiles */, 87 | ); 88 | buildRules = ( 89 | ); 90 | dependencies = ( 91 | ); 92 | name = munkres; 93 | productName = munkres; 94 | productReference = 21935E1318FF64F6001D2E31 /* munkres */; 95 | productType = "com.apple.product-type.tool"; 96 | }; 97 | /* End PBXNativeTarget section */ 98 | 99 | /* Begin PBXProject section */ 100 | 21935E0B18FF64F6001D2E31 /* Project object */ = { 101 | isa = PBXProject; 102 | attributes = { 103 | LastUpgradeCheck = 0510; 104 | ORGANIZATIONNAME = SYM; 105 | }; 106 | buildConfigurationList = 21935E0E18FF64F6001D2E31 /* Build configuration list for PBXProject "munkres" */; 107 | compatibilityVersion = "Xcode 3.2"; 108 | developmentRegion = English; 109 | hasScannedForEncodings = 0; 110 | knownRegions = ( 111 | en, 112 | ); 113 | mainGroup = 21935E0A18FF64F6001D2E31; 114 | productRefGroup = 21935E1418FF64F6001D2E31 /* Products */; 115 | projectDirPath = ""; 116 | projectRoot = ""; 117 | targets = ( 118 | 21935E1218FF64F6001D2E31 /* munkres */, 119 | ); 120 | }; 121 | /* End PBXProject section */ 122 | 123 | /* Begin PBXSourcesBuildPhase section */ 124 | 21935E0F18FF64F6001D2E31 /* Sources */ = { 125 | isa = PBXSourcesBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | 21FB463F18FF713C0057CAAD /* munkres.cpp in Sources */, 129 | 21FB463E18FF713C0057CAAD /* main.cpp in Sources */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXSourcesBuildPhase section */ 134 | 135 | /* Begin XCBuildConfiguration section */ 136 | 21935E1A18FF64F6001D2E31 /* Debug */ = { 137 | isa = XCBuildConfiguration; 138 | buildSettings = { 139 | ALWAYS_SEARCH_USER_PATHS = NO; 140 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 141 | CLANG_CXX_LIBRARY = "libc++"; 142 | CLANG_ENABLE_MODULES = YES; 143 | CLANG_ENABLE_OBJC_ARC = YES; 144 | CLANG_WARN_BOOL_CONVERSION = YES; 145 | CLANG_WARN_CONSTANT_CONVERSION = YES; 146 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 147 | CLANG_WARN_EMPTY_BODY = YES; 148 | CLANG_WARN_ENUM_CONVERSION = YES; 149 | CLANG_WARN_INT_CONVERSION = YES; 150 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 151 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 152 | COPY_PHASE_STRIP = NO; 153 | GCC_C_LANGUAGE_STANDARD = gnu99; 154 | GCC_DYNAMIC_NO_PIC = NO; 155 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 156 | GCC_OPTIMIZATION_LEVEL = 0; 157 | GCC_PREPROCESSOR_DEFINITIONS = ( 158 | "DEBUG=1", 159 | "$(inherited)", 160 | ); 161 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 162 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 163 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 164 | GCC_WARN_UNDECLARED_SELECTOR = YES; 165 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 166 | GCC_WARN_UNUSED_FUNCTION = YES; 167 | GCC_WARN_UNUSED_VARIABLE = YES; 168 | MACOSX_DEPLOYMENT_TARGET = 10.9; 169 | ONLY_ACTIVE_ARCH = YES; 170 | SDKROOT = macosx; 171 | }; 172 | name = Debug; 173 | }; 174 | 21935E1B18FF64F6001D2E31 /* Release */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 179 | CLANG_CXX_LIBRARY = "libc++"; 180 | CLANG_ENABLE_MODULES = YES; 181 | CLANG_ENABLE_OBJC_ARC = YES; 182 | CLANG_WARN_BOOL_CONVERSION = YES; 183 | CLANG_WARN_CONSTANT_CONVERSION = YES; 184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN_ENUM_CONVERSION = YES; 187 | CLANG_WARN_INT_CONVERSION = YES; 188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 189 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 190 | COPY_PHASE_STRIP = YES; 191 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 192 | ENABLE_NS_ASSERTIONS = NO; 193 | GCC_C_LANGUAGE_STANDARD = gnu99; 194 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 195 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 196 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 197 | GCC_WARN_UNDECLARED_SELECTOR = YES; 198 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 199 | GCC_WARN_UNUSED_FUNCTION = YES; 200 | GCC_WARN_UNUSED_VARIABLE = YES; 201 | MACOSX_DEPLOYMENT_TARGET = 10.9; 202 | SDKROOT = macosx; 203 | }; 204 | name = Release; 205 | }; 206 | 21935E1D18FF64F6001D2E31 /* Debug */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | HEADER_SEARCH_PATHS = ( 210 | "$(inherited)", 211 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 212 | /usr/local/include, 213 | ); 214 | LIBRARY_SEARCH_PATHS = ( 215 | /usr/local/lib, 216 | /usr/local/Cellar/opencv/2.4.8.2/lib, 217 | ); 218 | PRODUCT_NAME = "$(TARGET_NAME)"; 219 | }; 220 | name = Debug; 221 | }; 222 | 21935E1E18FF64F6001D2E31 /* Release */ = { 223 | isa = XCBuildConfiguration; 224 | buildSettings = { 225 | HEADER_SEARCH_PATHS = ( 226 | "$(inherited)", 227 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 228 | /usr/local/include, 229 | ); 230 | LIBRARY_SEARCH_PATHS = ( 231 | /usr/local/lib, 232 | /usr/local/Cellar/opencv/2.4.8.2/lib, 233 | ); 234 | PRODUCT_NAME = "$(TARGET_NAME)"; 235 | }; 236 | name = Release; 237 | }; 238 | /* End XCBuildConfiguration section */ 239 | 240 | /* Begin XCConfigurationList section */ 241 | 21935E0E18FF64F6001D2E31 /* Build configuration list for PBXProject "munkres" */ = { 242 | isa = XCConfigurationList; 243 | buildConfigurations = ( 244 | 21935E1A18FF64F6001D2E31 /* Debug */, 245 | 21935E1B18FF64F6001D2E31 /* Release */, 246 | ); 247 | defaultConfigurationIsVisible = 0; 248 | defaultConfigurationName = Release; 249 | }; 250 | 21935E1C18FF64F6001D2E31 /* Build configuration list for PBXNativeTarget "munkres" */ = { 251 | isa = XCConfigurationList; 252 | buildConfigurations = ( 253 | 21935E1D18FF64F6001D2E31 /* Debug */, 254 | 21935E1E18FF64F6001D2E31 /* Release */, 255 | ); 256 | defaultConfigurationIsVisible = 0; 257 | defaultConfigurationName = Release; 258 | }; 259 | /* End XCConfigurationList section */ 260 | }; 261 | rootObject = 21935E0B18FF64F6001D2E31 /* Project object */; 262 | } 263 | -------------------------------------------------------------------------------- /munkres.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /munkres.xcodeproj/project.xcworkspace/xcshareddata/munkres.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 446C9FB6-AFA7-4DC8-98FF-2FF0112F989E 9 | IDESourceControlProjectName 10 | munkres 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 91BF8E03-6992-477B-AC52-92A0BCB4BCF8 14 | https://github.com/soimy/munkres-opencv.git 15 | 16 | IDESourceControlProjectPath 17 | munkres.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 91BF8E03-6992-477B-AC52-92A0BCB4BCF8 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/soimy/munkres-opencv.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 91BF8E03-6992-477B-AC52-92A0BCB4BCF8 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 91BF8E03-6992-477B-AC52-92A0BCB4BCF8 36 | IDESourceControlWCCName 37 | munkres-opencv 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /munkres.xcodeproj/project.xcworkspace/xcuserdata/sym.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soimy/munkres-opencv/e1fc4c2efb1278e01c0fa816f3a353541791e186/munkres.xcodeproj/project.xcworkspace/xcuserdata/sym.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /munkres.xcodeproj/xcuserdata/sym.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /munkres.xcodeproj/xcuserdata/sym.xcuserdatad/xcschemes/munkres.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 52 | 58 | 59 | 60 | 61 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /munkres.xcodeproj/xcuserdata/sym.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | munkres.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 21935E1218FF64F6001D2E31 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 John Weaver 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | /* 20 | * Some example code. 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "munkres.h" 30 | 31 | int 32 | main(int argc, char *argv[]) { 33 | int nrows = 4; 34 | int ncols = 3; 35 | 36 | if ( argc == 3 ) { 37 | nrows = atoi(argv[1]); 38 | ncols = atoi(argv[2]); 39 | } 40 | 41 | cv::Mat_ matrix(nrows, ncols); 42 | 43 | // srandom(time(NULL)); // Seed random number generator. 44 | std::mt19937 eng((std::random_device())()); 45 | std::uniform_int_distribution<> dist(1,50); 46 | 47 | // Initialize matrix with random values. 48 | for ( int row = 0 ; row < nrows ; row++ ) { 49 | for ( int col = 0 ; col < ncols ; col++ ) { 50 | matrix(row,col) = (int)dist(eng); 51 | } 52 | } 53 | 54 | // Display begin matrix state. 55 | for ( int row = 0 ; row < nrows ; row++ ) { 56 | for ( int col = 0 ; col < ncols ; col++ ) { 57 | std::cout.width(2); 58 | std::cout << (int)matrix(row,col) << ","; 59 | } 60 | std::cout << std::endl; 61 | } 62 | std::cout << std::endl; 63 | 64 | // Apply Munkres algorithm to matrix. 65 | Munkres m; 66 | m.diag(false); 67 | m.solve(matrix); 68 | 69 | // Display solved matrix. 70 | for ( int row = 0 ; row < nrows ; row++ ) { 71 | for ( int col = 0 ; col < ncols ; col++ ) { 72 | std::cout.width(2); 73 | std::cout << matrix(row,col) << ","; 74 | } 75 | std::cout << std::endl; 76 | } 77 | 78 | std::cout << std::endl; 79 | 80 | 81 | for ( int row = 0 ; row < nrows ; row++ ) { 82 | int rowcount = 0; 83 | for ( int col = 0 ; col < ncols ; col++ ) { 84 | if ( matrix(row,col) == 0 ) 85 | rowcount++; 86 | } 87 | if ( rowcount != 1 ) 88 | std::cerr << "Row " << row << " has " << rowcount << " columns that have been matched." << std::endl; 89 | } 90 | 91 | for ( int col = 0 ; col < ncols ; col++ ) { 92 | int colcount = 0; 93 | for ( int row = 0 ; row < nrows ; row++ ) { 94 | if ( matrix(row,col) == 0 ) 95 | colcount++; 96 | } 97 | if ( colcount != 1 ) 98 | std::cerr << "Column " << col << " has " << colcount << " rows that have been matched." << std::endl; 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/munkres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soimy/munkres-opencv/e1fc4c2efb1278e01c0fa816f3a353541791e186/src/munkres -------------------------------------------------------------------------------- /src/munkres.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 John Weaver 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | #include "munkres.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | unsigned int 28 | minsize(cv::Mat_ &m) { 29 | return (m.rows < m.cols) ? m.rows : m.cols; 30 | } 31 | 32 | int 33 | maxValue(cv::Mat_ &m) { 34 | int max = 0;//std::numeric_limits::min(); 35 | for (int i = 0; i < m.rows; i++) { 36 | for (int j = 0; j < m.cols; j++) { 37 | max = std::max(max, m(i,j)); 38 | } 39 | } 40 | return max; 41 | } 42 | 43 | void 44 | extendMat(cv::Mat_ &m, unsigned int rows, unsigned int cols, int value = 0) { 45 | cv::Size2i interSize; 46 | interSize.height = std::min(rows, m.rows); 47 | interSize.width = std::min(cols, m.cols); 48 | cv::Mat tm(rows, cols, m.type()); 49 | tm.setTo(cv::Scalar(value)); 50 | if(interSize.width!=0 && interSize.height!=0) 51 | m(cv::Rect(cv::Point(0,0), interSize)).copyTo(tm(cv::Rect(cv::Point(0,0), interSize))); 52 | m = tm; 53 | } 54 | 55 | void 56 | replace_infinites(cv::Mat_ &matrix) { 57 | const unsigned int rows = matrix.rows, 58 | columns = matrix.cols; 59 | // assert( rows > 0 && columns > 0 ); 60 | if(rows==0 || columns==0) 61 | return; 62 | double max = matrix(0, 0); 63 | const auto infinity = std::numeric_limits::infinity(); 64 | 65 | // Find the greatest value in the matrix that isn't infinity. 66 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 67 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 68 | if ( matrix(row, col) != infinity ) { 69 | if ( max == infinity ) { 70 | max = matrix(row, col); 71 | } else { 72 | max = std::max(max, matrix(row, col)); 73 | } 74 | } 75 | } 76 | } 77 | 78 | // a value higher than the maximum value present in the matrix. 79 | if ( max == infinity ) { 80 | // This case only occurs when all values are infinite. 81 | max = 0; 82 | } else { 83 | max++; 84 | } 85 | 86 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 87 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 88 | if ( matrix(row, col) == infinity ) { 89 | matrix(row, col) = max; 90 | } 91 | } 92 | } 93 | 94 | } 95 | 96 | void 97 | minimize_along_direction(cv::Mat_ &matrix, bool over_columns) { 98 | const unsigned int outer_size = over_columns ? matrix.cols : matrix.rows, 99 | inner_size = over_columns ? matrix.rows : matrix.cols; 100 | 101 | // Look for a minimum value to subtract from all values along 102 | // the "outer" direction. 103 | for ( unsigned int i = 0 ; i < outer_size ; i++ ) { 104 | double min = over_columns ? matrix(0, i) : matrix(i, 0); 105 | 106 | // As long as the current minimum is greater than zero, 107 | // keep looking for the minimum. 108 | // Start at one because we already have the 0th value in min. 109 | for ( unsigned int j = 1 ; j < inner_size && min > 0 ; j++ ) { 110 | min = std::min( 111 | min, 112 | over_columns ? matrix(j, i) : matrix(i, j)); 113 | } 114 | 115 | if ( min > 0 ) { 116 | for ( unsigned int j = 0 ; j < inner_size ; j++ ) { 117 | if ( over_columns ) { 118 | matrix(j, i) -= min; 119 | } else { 120 | matrix(i, j) -= min; 121 | } 122 | } 123 | } 124 | } 125 | } 126 | 127 | 128 | bool 129 | Munkres::find_uncovered_in_matrix(double item, unsigned int &row, unsigned int &col) const { 130 | unsigned int rows = matrix.rows, 131 | columns = matrix.cols; 132 | 133 | for ( row = 0 ; row < rows ; row++ ) { 134 | if ( !row_mask[row] ) { 135 | for ( col = 0 ; col < columns ; col++ ) { 136 | if ( !col_mask[col] ) { 137 | if ( matrix(row,col) == item ) { 138 | return true; 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | return false; 146 | } 147 | 148 | bool 149 | Munkres::pair_in_list(const std::pair &needle, const std::list > &haystack) { 150 | for ( std::list >::const_iterator i = haystack.begin() ; i != haystack.end() ; i++ ) { 151 | if ( needle == *i ) { 152 | return true; 153 | } 154 | } 155 | 156 | return false; 157 | } 158 | 159 | int 160 | Munkres::step1(void) { 161 | const unsigned int rows = matrix.rows, 162 | columns = matrix.cols; 163 | 164 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 165 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 166 | if ( 0 == matrix(row, col) ) { 167 | bool isstarred = false; 168 | for ( unsigned int nrow = 0 ; nrow < rows ; nrow++ ) 169 | if ( STAR == mask_matrix(nrow,col) ) { 170 | isstarred = true; 171 | break; 172 | } 173 | 174 | if ( !isstarred ) { 175 | for ( unsigned int ncol = 0 ; ncol < columns ; ncol++ ) 176 | if ( STAR == mask_matrix(row, ncol) ) { 177 | isstarred = true; 178 | break; 179 | } 180 | } 181 | 182 | if ( !isstarred ) { 183 | mask_matrix(row,col) = STAR; 184 | } 185 | } 186 | } 187 | } 188 | 189 | return 2; 190 | } 191 | 192 | int 193 | Munkres::step2(void) { 194 | const unsigned int rows = matrix.rows, 195 | columns = matrix.cols; 196 | unsigned int covercount = 0; 197 | 198 | for ( unsigned int row = 0 ; row < rows ; row++ ) 199 | for ( unsigned int col = 0 ; col < columns ; col++ ) 200 | if ( STAR == mask_matrix(row, col) ) { 201 | col_mask[col] = true; 202 | covercount++; 203 | } 204 | 205 | if ( covercount >= minsize(matrix) ) { 206 | if(isDiag) { 207 | std::cout << "Final cover count: " << covercount << std::endl; 208 | } 209 | return 0; 210 | } 211 | 212 | if(isDiag) { 213 | std::cout << "Munkres matrix has " << covercount << " of " << minsize(matrix) << " Columns covered:" << std::endl; 214 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 215 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 216 | std::cout.width(4); 217 | std::cout << matrix(row, col) << ","; 218 | } 219 | std::cout << std::endl; 220 | } 221 | std::cout << std::endl; 222 | } 223 | 224 | 225 | return 3; 226 | } 227 | 228 | int 229 | Munkres::step3(void) { 230 | /* 231 | Main Zero Search 232 | 233 | 1. Find an uncovered Z in the distance matrix and prime it. If no such zero exists, go to Step 5 234 | 2. If No Z* exists in the row of the Z', go to Step 4. 235 | 3. If a Z* exists, cover this row and uncover the column of the Z*. Return to Step 3.1 to find a new Z 236 | */ 237 | if ( find_uncovered_in_matrix(0, saverow, savecol) ) { 238 | mask_matrix(saverow,savecol) = PRIME; // prime it. 239 | } else { 240 | return 5; 241 | } 242 | 243 | for ( unsigned int ncol = 0 ; ncol < matrix.cols ; ncol++ ) { 244 | if ( mask_matrix(saverow,ncol) == STAR ) { 245 | row_mask[saverow] = true; //cover this row and 246 | col_mask[ncol] = false; // uncover the column containing the starred zero 247 | return 3; // repeat 248 | } 249 | } 250 | 251 | return 4; // no starred zero in the row containing this primed zero 252 | } 253 | 254 | int 255 | Munkres::step4(void) { 256 | const unsigned int rows = matrix.rows, 257 | columns = matrix.cols; 258 | 259 | // seq contains pairs of row/column values where we have found 260 | // either a star or a prime that is part of the ``alternating sequence``. 261 | std::list > seq; 262 | // use saverow, savecol from step 3. 263 | std::pair z0(saverow, savecol); 264 | seq.insert(seq.end(), z0); 265 | 266 | // We have to find these two pairs: 267 | std::pair z1(-1, -1); 268 | std::pair z2n(-1, -1); 269 | 270 | unsigned int row, col = savecol; 271 | /* 272 | Increment Set of Starred Zeros 273 | 274 | 1. Construct the ``alternating sequence'' of primed and starred zeros: 275 | 276 | Z0 : Unpaired Z' from Step 4.2 277 | Z1 : The Z* in the column of Z0 278 | Z[2N] : The Z' in the row of Z[2N-1], if such a zero exists 279 | Z[2N+1] : The Z* in the column of Z[2N] 280 | 281 | The sequence eventually terminates with an unpaired Z' = Z[2N] for some N. 282 | */ 283 | bool madepair; 284 | do { 285 | madepair = false; 286 | for ( row = 0 ; row < rows ; row++ ) { 287 | if ( mask_matrix(row,col) == STAR ) { 288 | z1.first = row; 289 | z1.second = col; 290 | if ( pair_in_list(z1, seq) ) { 291 | continue; 292 | } 293 | 294 | madepair = true; 295 | seq.insert(seq.end(), z1); 296 | break; 297 | } 298 | } 299 | 300 | if ( !madepair ) 301 | break; 302 | 303 | madepair = false; 304 | 305 | for ( col = 0 ; col < columns ; col++ ) { 306 | if ( mask_matrix(row, col) == PRIME ) { 307 | z2n.first = row; 308 | z2n.second = col; 309 | if ( pair_in_list(z2n, seq) ) { 310 | continue; 311 | } 312 | madepair = true; 313 | seq.insert(seq.end(), z2n); 314 | break; 315 | } 316 | } 317 | } while ( madepair ); 318 | 319 | for ( std::list >::iterator i = seq.begin() ; 320 | i != seq.end() ; 321 | i++ ) { 322 | // 2. Unstar each starred zero of the sequence. 323 | if ( mask_matrix(i->first,i->second) == STAR ) 324 | mask_matrix(i->first,i->second) = NORMAL; 325 | 326 | // 3. Star each primed zero of the sequence, 327 | // thus increasing the number of starred zeros by one. 328 | if ( mask_matrix(i->first,i->second) == PRIME ) 329 | mask_matrix(i->first,i->second) = STAR; 330 | } 331 | 332 | // 4. Erase all primes, uncover all columns and rows, 333 | for ( unsigned int row = 0 ; row < mask_matrix.rows ; row++ ) { 334 | for ( unsigned int col = 0 ; col < mask_matrix.cols ; col++ ) { 335 | if ( mask_matrix(row,col) == PRIME ) { 336 | mask_matrix(row,col) = NORMAL; 337 | } 338 | } 339 | } 340 | 341 | for ( unsigned int i = 0 ; i < rows ; i++ ) { 342 | row_mask[i] = false; 343 | } 344 | 345 | for ( unsigned int i = 0 ; i < columns ; i++ ) { 346 | col_mask[i] = false; 347 | } 348 | 349 | // and return to Step 2. 350 | return 2; 351 | } 352 | 353 | int 354 | Munkres::step5(void) { 355 | const unsigned int rows = matrix.rows, 356 | columns = matrix.cols; 357 | /* 358 | New Zero Manufactures 359 | 360 | 1. Let h be the smallest uncovered entry in the (modified) distance matrix. 361 | 2. Add h to all covered rows. 362 | 3. Subtract h from all uncovered columns 363 | 4. Return to Step 3, without altering stars, primes, or covers. 364 | */ 365 | double h = 0; 366 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 367 | if ( !row_mask[row] ) { 368 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 369 | if ( !col_mask[col] ) { 370 | if ( (h > matrix(row, col) && matrix(row, col) != 0) || h == 0 ) { 371 | h = matrix(row, col); 372 | } 373 | } 374 | } 375 | } 376 | } 377 | 378 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 379 | if ( row_mask[row] ) { 380 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 381 | matrix(row, col) += h; 382 | } 383 | } 384 | } 385 | 386 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 387 | if ( !col_mask[col] ) { 388 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 389 | matrix(row, col) -= h; 390 | } 391 | } 392 | } 393 | 394 | return 3; 395 | } 396 | 397 | /* 398 | * 399 | * Linear assignment problem solution 400 | * [modifies matrix in-place.] 401 | * matrix(row,col): row major format assumed. 402 | * 403 | * Assignments are remaining 0 values 404 | * (extra 0 values are replaced with -1) 405 | * 406 | */ 407 | void 408 | Munkres::solve(cv::Mat_ &m) { 409 | const unsigned int rows = m.rows, 410 | columns = m.cols, 411 | size = std::max(rows, columns); 412 | 413 | if(isDiag) { 414 | std::cout << "Munkres input matrix:" << std::endl; 415 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 416 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 417 | std::cout.width(4); 418 | std::cout << m(row, col) << ","; 419 | } 420 | std::cout << std::endl; 421 | } 422 | std::cout << std::endl; 423 | } 424 | 425 | bool notdone = true; 426 | int step = 1; 427 | 428 | // Copy input matrix 429 | this->matrix = m; 430 | 431 | if ( rows != columns ) { 432 | // If the input matrix isn't square, make it square 433 | // and fill the empty values with the largest value present 434 | // in the matrix. 435 | extendMat(matrix, size, size, maxValue(matrix)); 436 | } 437 | 438 | 439 | // STAR == 1 == starred, PRIME == 2 == primed 440 | // mask_matrix.resize(size, size); 441 | extendMat(mask_matrix, size, size); 442 | 443 | row_mask = new bool[size]; 444 | col_mask = new bool[size]; 445 | for ( unsigned int i = 0 ; i < size ; i++ ) { 446 | row_mask[i] = false; 447 | } 448 | 449 | for ( unsigned int i = 0 ; i < size ; i++ ) { 450 | col_mask[i] = false; 451 | } 452 | 453 | // Prepare the matrix values... 454 | 455 | // If there were any infinities, replace them with a value greater 456 | // than the maximum value in the matrix. 457 | replace_infinites(matrix); 458 | 459 | minimize_along_direction(matrix, false); 460 | minimize_along_direction(matrix, true); 461 | 462 | // Follow the steps 463 | while ( notdone ) { 464 | switch ( step ) { 465 | case 0: 466 | notdone = false; 467 | // end the step flow 468 | break; 469 | case 1: 470 | step = step1(); 471 | // step is always 2 472 | break; 473 | case 2: 474 | step = step2(); 475 | // step is always either 0 or 3 476 | break; 477 | case 3: 478 | step = step3(); 479 | // step in [3, 4, 5] 480 | break; 481 | case 4: 482 | step = step4(); 483 | // step is always 2 484 | break; 485 | case 5: 486 | step = step5(); 487 | // step is always 3 488 | break; 489 | } 490 | } 491 | 492 | // Store results 493 | for ( unsigned int row = 0 ; row < size ; row++ ) { 494 | for ( unsigned int col = 0 ; col < size ; col++ ) { 495 | if ( mask_matrix(row, col) == STAR ) { 496 | matrix(row, col) = 0; 497 | } else { 498 | matrix(row, col) = -1; 499 | } 500 | } 501 | } 502 | 503 | if(isDiag) { 504 | std::cout << "Munkres output matrix:" << std::endl; 505 | for ( unsigned int row = 0 ; row < rows ; row++ ) { 506 | for ( unsigned int col = 0 ; col < columns ; col++ ) { 507 | std::cout.width(2); 508 | std::cout << matrix(row, col) << ","; 509 | } 510 | std::cout << std::endl; 511 | } 512 | std::cout << std::endl; 513 | } 514 | 515 | 516 | // Remove the excess rows or columns that we added to fit the 517 | // input to a square matrix. 518 | // matrix.resize(rows, columns); 519 | extendMat(matrix, rows, columns); 520 | 521 | m = matrix; 522 | 523 | delete [] row_mask; 524 | delete [] col_mask; 525 | } 526 | 527 | Munkres::Munkres(){ 528 | isDiag = false; 529 | } 530 | 531 | void Munkres::diag(bool status){ 532 | isDiag = status; 533 | } -------------------------------------------------------------------------------- /src/munkres.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2007 John Weaver 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | 19 | #if !defined(_MUNKRES_H_) 20 | #define _MUNKRES_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | class Munkres { 27 | public: 28 | Munkres(); 29 | ~Munkres(){}; 30 | void solve(cv::Mat_ &m); 31 | void diag(bool); 32 | private: 33 | static const int NORMAL = 0; 34 | static const int STAR = 1; 35 | static const int PRIME = 2; 36 | inline bool find_uncovered_in_matrix(double, unsigned int&, unsigned int&) const; 37 | inline bool pair_in_list(const std::pair &, const std::list > &); 38 | int step1(void); 39 | int step2(void); 40 | int step3(void); 41 | int step4(void); 42 | int step5(void); 43 | int step6(void); 44 | 45 | cv::Mat_ mask_matrix; 46 | cv::Mat_ matrix; 47 | bool *row_mask; 48 | bool *col_mask; 49 | unsigned int saverow, savecol; 50 | bool isDiag; 51 | }; 52 | 53 | #endif /* !defined(_MUNKRES_H_) */ 54 | --------------------------------------------------------------------------------