├── CMakeLists.txt ├── INSTALL.md ├── LICENSE ├── README.md ├── clean.sh ├── include └── gdal-segment.hpp ├── releases └── GDAL-Tools_31_10_2015.exe ├── samples ├── 1-segment.sh ├── 25cm_orto0.jpg ├── kermit000.jpg └── logo │ ├── 25cm_orth0-LSC.png │ ├── 25cm_orth0-SEEDS.png │ ├── 25cm_orth0-SLIC.png │ ├── 25cm_orth0-SLICO.png │ └── small_logo.gif └── src ├── CMakeLists.txt ├── gdal-segment.cpp └── io ├── raster.cpp └── vector.cpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #/* 2 | # * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | # */ 15 | 16 | #/* CMakeLists.txt */ 17 | #/* Project builder */ 18 | 19 | PROJECT(gdal-segment) 20 | 21 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 22 | 23 | IF(COMMAND CMAKE_POLICY) 24 | CMAKE_POLICY(SET CMP0016 NEW) 25 | CMAKE_POLICY(SET CMP0054 NEW) 26 | ENDIF(COMMAND CMAKE_POLICY) 27 | 28 | SET(CMAKE_SKIP_BUILD_RPATH TRUE) 29 | SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 30 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) 31 | 32 | SET(CMAKE_MODULE_PATH "cmake/;${CMAKE_MODULE_PATH}") 33 | 34 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) 35 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) 36 | 37 | # Set a default build type if none was specified 38 | IF(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 39 | MESSAGE(STATUS "Setting build type to 'Release' as none was specified.") 40 | SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) 41 | # Set the possible values of build type for cmake-gui 42 | SET_PROPERTY(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" 43 | "MinSizeRel" "RelWithDebInfo") 44 | ENDIF() 45 | 46 | # Default build is in Release mode 47 | IF(NOT CMAKE_BUILD_TYPE AND NOT MSVC) 48 | SET(CMAKE_BUILD_TYPE "Release") 49 | ENDIF(NOT CMAKE_BUILD_TYPE AND NOT MSVC) 50 | 51 | IF (NOT WIN32) 52 | SET(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -O3") 53 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -O3 -std=c++11") 54 | ENDIF() 55 | 56 | ##### 57 | # find OpenMP library 58 | FIND_PACKAGE(OpenMP) 59 | IF(OPENMP_FOUND) 60 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 61 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 62 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}") 63 | MESSAGE(STATUS "OpenMP found.") 64 | ENDIF() 65 | 66 | ##### 67 | # find OpenCV 68 | FIND_PACKAGE(OpenCV REQUIRED core ximgproc hdf) 69 | IF(OpenCV_FOUND) 70 | INCLUDE_DIRECTORIES(${OpenCV_INCLUDE_DIRS}) 71 | MESSAGE(STATUS "OpenCV version: " ${OpenCV_VERSION}) 72 | MESSAGE(STATUS "OpenCV include: " ${OpenCV_INCLUDE_DIRS}) 73 | STRING(COMPARE LESS "${OpenCV_VERSION}" 3.3.0 VersionIncompatible) 74 | IF(VersionIncompatible) 75 | MESSAGE(FATAL_ERROR "OpenCV minimum 3.3.0 required.") 76 | ENDIF() 77 | ENDIF() 78 | 79 | 80 | ##### 81 | # find GDAL library 82 | FIND_PACKAGE(GDAL COMPONENTS REQUIRED) 83 | IF(GDAL_FOUND) 84 | INCLUDE_DIRECTORIES(${GDAL_INCLUDE_DIRS}) 85 | MESSAGE(STATUS "GDAL found.") 86 | # Extract GDAL version from gdal_version.h 87 | SET(GDAL_VERSION_FILE ${GDAL_INCLUDE_DIRS}/gdal_version.h) 88 | IF (NOT EXISTS ${GDAL_VERSION_FILE}) 89 | GDAL_REPORT_NOT_FOUND( 90 | "Could not find file: ${GDAL_VERSION_FILE} " 91 | "containing version information in GDAL install located at: " 92 | "${GDAL_INCLUDE_DIRS}.") 93 | ELSE (NOT EXISTS ${GDAL_VERSION_FILE}) 94 | FILE(READ ${GDAL_VERSION_FILE} GDAL_VERSION_FILE_CONTENTS) 95 | STRING(REGEX MATCH "define GDAL_VERSION_MAJOR +[0-9]+" 96 | GDAL_VERSION_MAJOR "${GDAL_VERSION_FILE_CONTENTS}") 97 | STRING(REGEX REPLACE "define GDAL_VERSION_MAJOR +([0-9]+)" "\\1" 98 | GDAL_VERSION_MAJOR "${GDAL_VERSION_MAJOR}") 99 | STRING(REGEX MATCH "define GDAL_VERSION_MINOR +[0-9]+" 100 | GDAL_VERSION_MINOR "${GDAL_VERSION_FILE_CONTENTS}") 101 | STRING(REGEX REPLACE "define GDAL_VERSION_MINOR +([0-9]+)" "\\1" 102 | GDAL_VERSION_MINOR "${GDAL_VERSION_MINOR}") 103 | STRING(REGEX MATCH "define GDAL_VERSION_REV +[0-9]+" 104 | GDAL_VERSION_REV "${GDAL_VERSION_FILE_CONTENTS}") 105 | STRING(REGEX REPLACE "define GDAL_VERSION_REV +([0-9]+)" "\\1" 106 | GDAL_VERSION_REV "${GDAL_VERSION_REV}") 107 | SET(GDAL_VERSION "${GDAL_VERSION_MAJOR}.${GDAL_VERSION_MINOR}.${GDAL_VERSION_REV}") 108 | ENDIF(NOT EXISTS ${GDAL_VERSION_FILE}) 109 | MESSAGE(STATUS "GDAL version: ${GDAL_VERSION}") 110 | ADD_DEFINITIONS( -DGDALVER=${GDAL_VERSION_MAJOR} ) 111 | ENDIF() 112 | 113 | # local directory 114 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include/) 115 | 116 | ADD_SUBDIRECTORY(src/) 117 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | To compile and install GDAL-Segment GDAL, OpenCV and OpenCV_Contrib libraries are required. 4 | 5 | * GDAL [1] 1.x or 2.x is required, your distro probably already has it. 6 | * OpenCV [2] minimum 3.1.0 (or trunk) including OpenCV_Contrib [3] part is required. 7 | 8 | ``` 9 | [1] http://www.gdal.org/ 10 | [2] https://github.com/Itseez/opencv 11 | [3] https://github.com/Itseez/opencv_contrib 12 | ``` 13 | 14 | (1) Prepareing: 15 | 16 | * You need OpenCV >= 3.1.0 or trunk. 17 | * If you don't have these versions installed then make sure distro has no *opencv* preinstalled: 18 | ``` 19 | mkdir somewhere 20 | cd somewhere 21 | git clone https://github.com/Itseez/opencv.git 22 | cd opencv 23 | git clone https://github.com/Itseez/opencv_contrib.git 24 | cd opencv_contrib 25 | mkdir build 26 | cd build 27 | cmake CMAKE_VERBOSE=1 -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules -DCMAKE_SKIP_RPATH=ON ../ 28 | make 29 | make install 30 | ``` 31 | (2) GDAL-Segment: 32 | 33 | * To compile GDAL-Segment itself: 34 | ``` 35 | mkdir somewhat 36 | git clone https://github.com/cbalint13/gdal-segment.git 37 | cd gdal-segment 38 | mkdir build 39 | cd build 40 | cmake ../ 41 | make 42 | ``` 43 | 44 | ---<<<--- 45 | 46 | Please cite following papers: 47 | 48 | * [1] "SLIC Superpixels Compared to State-of-the-art Superpixel Methods" 49 | Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, 50 | and Sabine Susstrunk, IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, 51 | November 2012. 52 | 53 | * [2] "SLIC Superpixels" Radhakrishna Achanta, Appu Shaji, Kevin Smith, 54 | Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical 55 | Report no. 149300, June 2010. 56 | 57 | * [3] "SEEDS: Superpixels extracted via energy-driven sampling" 58 | Van den Bergh, Michael and Boix, Xavier and Roig, Gemma and de Capitani, 59 | Benjamin and Van Gool, Luc, ECCV 2012 60 | 61 | * [4] "Superpixel Segmentation using Linear Spectral Clustering" 62 | Zhengqin Li, Jiansheng Chen, IEEE Conference on Computer Vision and Pattern 63 | Recognition (CVPR), Jun. 2015 64 | 65 | 66 | --->>>--- 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, 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 Lesser 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 | {description} 294 | Copyright (C) {year} {fullname} 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 along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gdal-segment 2 | 3 | ![Logo](https://github.com/cbalint13/gdal-segment/blob/master/samples/logo/small_logo.gif) 4 | 5 | * **GDAL Segment** implements various segmentation algorithms over raster images. It can 6 | be used to segment large aerial, satellite imagery of various formats supported by GDAL and 7 | various layouts like multispectral or hyperspectral. It uses OpenCV for it's core algorithms, 8 | and GDAL for undelying I/O. Implementation here follows several multithread and memory 9 | friendly optimizations, thus very large scenes are supported well. 10 | 11 | * At this moment it implements LSC, SLIC, SLICO, MSLIC and SEEDS. 12 | 13 | ``` 14 | Usage: gdal-segment [-help] src_raster1 src_raster2 .. src_rasterN -out dst_vector 15 | [-of 'ESRI Shapefile' is default] 16 | [-b R B (N-th band from R-th raster)] [-algo ] 17 | [-niter <1..500>] [-region ] 18 | [-blur (apply 3x3 gaussian blur)] 19 | 20 | Default niter: 10 iterations 21 | ``` 22 | 23 | **Requirements:** 24 | - **[gdal](http://www.gdal.org)** 1.x or 2.x 25 | - **[opencv](https://github.com/Itseez/opencv)** & **[opencv_contrib](https://github.com/Itseez/opencv_contrib)** >= 3.1 26 | - Please follow [INSTALL.md](https://github.com/cbalint13/gdal-segment/blob/master/INSTALL.md) for detailed requirements and install steps. 27 | 28 | **Related citations:** 29 | 30 | * [1] "SLIC Superpixels Compared to State-of-the-art Superpixel Methods" 31 | Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, 32 | and Sabine Susstrunk, IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, 33 | November 2012. 34 | 35 | * [2] "SLIC Superpixels" Radhakrishna Achanta, Appu Shaji, Kevin Smith, 36 | Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical 37 | Report no. 149300, June 2010. 38 | 39 | * [3] "SEEDS: Superpixels extracted via energy-driven sampling" 40 | Van den Bergh, Michael and Boix, Xavier and Roig, Gemma and de Capitani, 41 | Benjamin and Van Gool, Luc, ECCV 2012 42 | 43 | * [4] "Superpixel Segmentation using Linear Spectral Clustering" 44 | Zhengqin Li, Jiansheng Chen, IEEE Conference on Computer Vision and Pattern 45 | Recognition (CVPR), Jun. 2015 46 | 47 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf bin/* 4 | 5 | rm -rf samples/output*.??? 6 | 7 | find . -name cmake_install.cmake -exec rm -rf {} \; 8 | find . -name CMakeCache.txt -exec rm -rf {} \; 9 | find . -name CMakeFiles -exec rm -rf {} \; 10 | find . -name Makefile -exec rm -rf {} \; -------------------------------------------------------------------------------- /include/gdal-segment.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | */ 15 | 16 | /* gdal-segment.hpp */ 17 | /* main include */ 18 | 19 | #ifndef SLICSEG_H 20 | #define SLICSEG_H 21 | 22 | #include 23 | 24 | 25 | #ifdef _WIN 26 | typedef __int32 u_int32_t; 27 | #endif 28 | 29 | typedef struct LINE { 30 | unsigned int sX; 31 | unsigned int sY; 32 | unsigned int eX; 33 | unsigned int eY; 34 | } LINE; 35 | 36 | // raster operation 37 | void LoadRaster( const std::vector< std::string > InFilenames, 38 | std::vector< cv::Mat >& raster ); 39 | 40 | // raster statistics 41 | void ComputeStats( const cv::Mat klabels, 42 | const std::vector< cv::Mat > raster, 43 | cv::Mat& labelpixels, cv::Mat& avgCH, cv::Mat& stdCH ); 44 | 45 | // vector contours 46 | void LabelContours( const cv::Mat klabels, std::vector< std::vector< LINE > >& linelists); 47 | 48 | // vactor dump 49 | void SavePolygons( const std::vector< std::string > InFilenames, 50 | const char *OutFilename, const char *OutFormat, 51 | const cv::Mat klabels, 52 | const std::vector< cv::Mat > raster, 53 | const cv::Mat labelpixels, 54 | const cv::Mat avgCH, const cv::Mat stdCH, 55 | std::vector< std::vector< LINE > >& linelists ); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /releases/GDAL-Tools_31_10_2015.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/releases/GDAL-Tools_31_10_2015.exe -------------------------------------------------------------------------------- /samples/1-segment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf output-slic.??? 4 | ../bin/gdal-segment -algo SLIC -region 10 -niter 10 25cm_orto0.jpg -lab -out output-slic.shp 5 | 6 | rm -rf output-slico.??? 7 | ../bin/gdal-segment -algo SLICO -region 10 -niter 10 25cm_orto0.jpg -lab -out output-slico.shp 8 | 9 | rm -rf output-mslic.??? 10 | ../bin/gdal-segment -blur -algo MSLIC -region 15 -niter 10 25cm_orto0.jpg -lab -out output-mslic.shp 11 | 12 | rm -rf output-seeds.??? 13 | ../bin/gdal-segment -algo SEEDS -region 10 -niter 25 25cm_orto0.jpg -lab -out output-seeds.shp 14 | 15 | rm -rf output-lsc.??? 16 | ../bin/gdal-segment -algo LSC -region 10 -niter 20 25cm_orto0.jpg -lab -out output-lsc.shp 17 | -------------------------------------------------------------------------------- /samples/25cm_orto0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/25cm_orto0.jpg -------------------------------------------------------------------------------- /samples/kermit000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/kermit000.jpg -------------------------------------------------------------------------------- /samples/logo/25cm_orth0-LSC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/logo/25cm_orth0-LSC.png -------------------------------------------------------------------------------- /samples/logo/25cm_orth0-SEEDS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/logo/25cm_orth0-SEEDS.png -------------------------------------------------------------------------------- /samples/logo/25cm_orth0-SLIC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/logo/25cm_orth0-SLIC.png -------------------------------------------------------------------------------- /samples/logo/25cm_orth0-SLICO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/logo/25cm_orth0-SLICO.png -------------------------------------------------------------------------------- /samples/logo/small_logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cbalint13/gdal-segment/1a66cdfce98d9dd221497082a8d99c34b9e2840f/samples/logo/small_logo.gif -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #/* 2 | # * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | # */ 15 | 16 | #/* CMakeLists.txt */ 17 | #/* GDAL Segment */ 18 | 19 | ADD_EXECUTABLE(gdal-segment 20 | io/raster.cpp 21 | io/vector.cpp 22 | gdal-segment.cpp) 23 | 24 | TARGET_LINK_LIBRARIES(gdal-segment ${GDAL_LIBRARY} ${OpenCV_LIBS}) 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/gdal-segment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | */ 15 | 16 | /* 17 | "SLIC Superpixels Compared to State-of-the-art Superpixel Methods" 18 | Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi, Pascal Fua, 19 | and Sabine Susstrunk, IEEE TPAMI, Volume 34, Issue 11, Pages 2274-2282, 20 | November 2012. 21 | 22 | "SLIC Superpixels" Radhakrishna Achanta, Appu Shaji, Kevin Smith, 23 | Aurelien Lucchi, Pascal Fua, and Sabine Süsstrunk, EPFL Technical 24 | Report no. 149300, June 2010. 25 | 26 | "SEEDS: Superpixels Extracted via Energy-Driven Sampling", 27 | Van den Bergh M., Boix X., Roig G., de Capitani B. and Van Gool L., 28 | In European Conference on Computer Vision (Vol. 7, pp. 13-26)., 2012 29 | 30 | "Superpixel Segmentation using Linear Spectral Clustering" 31 | Zhengqin Li, Jiansheng Chen, 32 | IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 33 | Jun. 2015 34 | 35 | */ 36 | 37 | /* slic-segment.cpp */ 38 | /* SLIC superpixels segment */ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "gdal.h" 46 | #include "gdal_priv.h" 47 | #include "ogrsf_frmts.h" 48 | #include "cpl_string.h" 49 | #include "cpl_csv.h" 50 | 51 | #include "gdal-segment.hpp" 52 | 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | using namespace std; 60 | using namespace cv; 61 | using namespace cv::ximgproc; 62 | 63 | 64 | 65 | int main(int argc, char ** argv) 66 | { 67 | const char *algo = ""; 68 | vector< string > InFilenames; 69 | const char *OutFilename = NULL; 70 | const char *OutStatH5name = NULL; 71 | const char *OutFormat = "ESRI Shapefile"; 72 | 73 | // general defaults 74 | int niter = 0; 75 | bool blur = false; 76 | bool labcol = false; 77 | bool enforce = true; 78 | int regionsize = 0; 79 | 80 | // some counters 81 | int64 startTime, endTime; 82 | int64 startSecond, endSecond; 83 | double frequency = cv::getTickFrequency(); 84 | 85 | // register 86 | GDALAllRegister(); 87 | OGRRegisterAll(); 88 | 89 | argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 ); 90 | 91 | if( argc < 1 ) 92 | exit( -argc ); 93 | 94 | // default help 95 | bool help = false; 96 | bool askhelp = false; 97 | 98 | /* 99 | * load arguments 100 | */ 101 | 102 | for( int i = 1; i < argc; i++ ) 103 | { 104 | if( argv[i][0] == '-' ) 105 | { 106 | if( EQUAL( argv[i],"-help" ) ) { 107 | askhelp = true; 108 | break; 109 | } 110 | if( EQUAL( argv[i],"-algo" ) ) { 111 | algo = argv[i+1]; 112 | i++; continue; 113 | } 114 | if( EQUAL( argv[i],"-region" ) ) { 115 | regionsize = atoi(argv[i+1]); 116 | i++; continue; 117 | } 118 | if( EQUAL( argv[i],"-niter" ) ) { 119 | niter = atoi(argv[i+1]); 120 | i++; continue; 121 | } 122 | if( EQUAL( argv[i],"-out" ) ) { 123 | OutFilename = argv[i+1]; 124 | i++; continue; 125 | } 126 | if( EQUAL( argv[i],"-h5stat" ) ) { 127 | OutStatH5name = argv[i+1]; 128 | i++; continue; 129 | } 130 | if( EQUAL( argv[i],"-of" ) ) { 131 | OutFormat = argv[i+1]; 132 | i++; continue; 133 | } 134 | if( EQUAL( argv[i],"-blur" ) ) { 135 | blur = true; 136 | continue; 137 | } 138 | if( EQUAL( argv[i],"-lab" ) ) { 139 | labcol = true; 140 | continue; 141 | } 142 | if( EQUAL( argv[i],"-merge" ) ) { 143 | if( EQUAL( argv[i+1],"true" ) ) 144 | enforce = true; 145 | else if( EQUAL( argv[i+1],"false" ) ) 146 | enforce = false; 147 | else 148 | help = true; 149 | i++; continue; 150 | } 151 | printf( "Invalid %s option.\n\n", argv[i] ); 152 | help = true; 153 | } 154 | else if( argv[i][0] != '-' ) 155 | { 156 | InFilenames.push_back( argv[i] ); 157 | continue; 158 | } 159 | } 160 | 161 | if ( !askhelp ) 162 | { 163 | // check parameters 164 | if ( EQUAL( algo, "SLIC" ) 165 | || EQUAL( algo, "SLICO" ) 166 | || EQUAL( algo, "MSLIC" ) ) 167 | { 168 | if (!niter) niter = 10; 169 | if (!regionsize) regionsize = 10; 170 | } 171 | else if ( EQUAL( algo, "SEEDS" ) ) 172 | { 173 | if (!niter) niter = 20; 174 | if (!regionsize) regionsize = 10; 175 | } 176 | else if ( EQUAL( algo, "LSC" ) ) 177 | { 178 | if (!niter) niter = 20; 179 | if (!regionsize) regionsize = 10; 180 | } 181 | else 182 | { 183 | if ( EQUAL(algo, "" ) ) 184 | printf( "\nERROR: No algorithm specified.\n" ); 185 | else 186 | printf( "\nERROR: Invalid algorithm: %s\n", algo ); 187 | help = true; 188 | } 189 | if ( InFilenames.size() == 0 ) 190 | { 191 | printf( "\nERROR: No input file specified.\n" ); 192 | help = true; 193 | } 194 | if (! OutFilename ) 195 | { 196 | printf( "\nERROR: No output file specified.\n" ); 197 | help = true; 198 | } 199 | } 200 | 201 | if ( help || askhelp ) { 202 | printf( "\nUsage: gdal-segment [-help] src_raster1 src_raster2 .. src_rasterN -out dst_vector\n" 203 | " [-of 'ESRI Shapefile' is default]\n" 204 | " [-h5stat ]\n" 205 | " [-b R B (B-th band from R-th raster)] [-algo ]\n" 206 | " [-blur (apply 3x3 gaussian blur)] [-lab (convert rgb ro lab colorspace)]\n" 207 | " [-merge ]\n" 208 | " [-niter <1..500>] [-region ]\n" 209 | "Default niter: 10 iterations\n\n" ); 210 | 211 | GDALDestroyDriverManager(); 212 | exit( 1 ); 213 | } 214 | 215 | #if GDALVER >= 2 216 | GDALDriverManager *poR = GetGDALDriverManager(); 217 | GDALDriver *poDriver = poR->GetDriverByName( OutFormat ); 218 | #else 219 | OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar(); 220 | OGRSFDriver *poDriver = poR->GetDriverByName( OutFormat ); 221 | #endif 222 | 223 | // check drivers 224 | if( poDriver == NULL ) 225 | { 226 | printf( "Unable to find driver `%s'.\n", OutFormat ); 227 | printf( "The following drivers are available:\n" ); 228 | for( int i = 0; i < poR->GetDriverCount(); i++ ) 229 | { 230 | #if GDALVER >= 2 231 | const char *prop = poR->GetDriver(i)->GetMetadataItem( GDAL_DCAP_RASTER ); 232 | if ( prop == NULL ) 233 | { 234 | const char *name = poR->GetDriver(i)->GetDescription(); 235 | const char *desc = poR->GetDriver(i)->GetMetadataItem( GDAL_DMD_LONGNAME ); 236 | printf( " -> '%s' (%s)\n", name, desc ); 237 | } 238 | #else 239 | printf( " -> '%s'\n", poR->GetDriver(i)->GetName()); 240 | #endif 241 | } 242 | exit( 1 ); 243 | } 244 | 245 | printf( "Segments raster using: %s\n", algo ); 246 | printf( "Process use parameter: region=%i niter=%i\n", regionsize, niter ); 247 | 248 | /* 249 | * load raster image 250 | */ 251 | 252 | startTime = cv::getTickCount(); 253 | std::vector< cv::Mat > raster; 254 | LoadRaster( InFilenames, raster ); 255 | endTime = cv::getTickCount(); 256 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 257 | 258 | std::vector original; 259 | 260 | if ( labcol ) 261 | { 262 | Mat temp; 263 | // safe copy original 264 | merge(raster, temp); 265 | split(temp, original); 266 | temp.release(); 267 | } 268 | 269 | if ( blur ) 270 | { 271 | printf( "Apply Gaussian Blur (3x3 kernel)\n" ); 272 | startTime = cv::getTickCount(); 273 | for( size_t b = 0; b < raster.size(); b++ ) 274 | { 275 | GaussianBlur( raster[b], raster[b], Size( 3, 3 ), 0.0f, 0.0f, BORDER_DEFAULT ); 276 | GDALTermProgress( (float)b / (float)raster.size(), NULL, NULL ); 277 | } 278 | GDALTermProgress( 1.0f, NULL, NULL ); 279 | endTime = cv::getTickCount(); 280 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 281 | } 282 | 283 | 284 | Mat rgb; 285 | if ( labcol ) 286 | { 287 | Mat lab; 288 | raster.resize(3); 289 | printf( "Convert to LAB colorspace.\n" ); 290 | merge( raster, rgb ); 291 | cvtColor( rgb, lab, CV_RGB2Lab ); 292 | split(lab, raster); 293 | } 294 | 295 | /* 296 | * init segments 297 | */ 298 | 299 | printf( "Init Superpixels\n" ); 300 | Ptr slic; 301 | Ptr seed; 302 | Ptr lsc; 303 | 304 | startTime = cv::getTickCount(); 305 | if ( EQUAL ( algo, "SLIC" ) ) 306 | slic = createSuperpixelSLIC( raster, SLIC, regionsize, 10.0f ); 307 | else if ( EQUAL( algo, "SLICO" ) ) 308 | slic = createSuperpixelSLIC( raster, SLICO, regionsize, 10.0f ); 309 | else if ( EQUAL( algo, "MSLIC" ) ) 310 | slic = createSuperpixelSLIC( raster, MSLIC, regionsize, 10.0f ); 311 | else if ( EQUAL( algo, "LSC" ) ) 312 | lsc = createSuperpixelLSC( raster, regionsize, 0.075f ); 313 | else if ( EQUAL( algo, "SEEDS" ) ) 314 | { 315 | // only few datatype is supported 316 | if ( ( raster[0].depth() != CV_8U ) 317 | &&( raster.size() != 3 ) ) 318 | { 319 | printf( "\nERROR: Input datatype is not supported by SEED. Use RGB or Gray with Byte types.\n" ); 320 | exit( 0 ); 321 | } 322 | 323 | int clusters = int(((float)raster[0].cols / (float)regionsize) 324 | * ((float)raster[0].rows / (float)regionsize)); 325 | seed = createSuperpixelSEEDS( raster[0].cols, raster[0].rows, raster.size(), clusters, 1, 2, 5, true ); 326 | } 327 | else 328 | { 329 | printf( "\nERROR: No such algorithm: [%s].\n", algo ); 330 | exit( 1 ); 331 | } 332 | endTime = cv::getTickCount(); 333 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 334 | 335 | size_t m_labels = 0; 336 | if ( EQUAL( algo, "SLIC" ) 337 | || EQUAL( algo, "SLICO" ) 338 | || EQUAL( algo, "MSLIC" ) ) 339 | m_labels = slic->getNumberOfSuperpixels(); 340 | else if ( EQUAL( algo, "SEEDS" ) ) 341 | m_labels = seed->getNumberOfSuperpixels(); 342 | else if ( EQUAL( algo, "LSC" ) ) 343 | m_labels = lsc->getNumberOfSuperpixels(); 344 | 345 | startTime = cv::getTickCount(); 346 | printf( "Grow Superpixels: #%i iterations\n", niter ); 347 | printf( " inits: %lu superpixels\n", m_labels ); 348 | 349 | /* 350 | * start compute segments 351 | */ 352 | 353 | startSecond = cv::getTickCount(); 354 | if ( EQUAL( algo, "SLIC" ) 355 | || EQUAL( algo, "SLICO" ) 356 | || EQUAL( algo, "MSLIC" ) ) 357 | slic->iterate( niter ); 358 | else if ( EQUAL( algo, "LSC" ) ) 359 | lsc->iterate( niter ); 360 | else if ( EQUAL( algo, "SEEDS" ) ) 361 | { 362 | cv::Mat whole; 363 | cv::merge(raster,whole); 364 | seed->iterate( whole, niter ); 365 | } 366 | endSecond = cv::getTickCount(); 367 | 368 | 369 | if( EQUAL( algo, "SLIC" ) 370 | || EQUAL( algo, "SLICO" ) 371 | || EQUAL( algo, "MSLIC" ) ) 372 | m_labels = slic->getNumberOfSuperpixels(); 373 | else if ( EQUAL( algo, "SEEDS" ) ) 374 | m_labels = seed->getNumberOfSuperpixels(); 375 | else if ( EQUAL( algo, "LSC" ) ) 376 | m_labels = lsc->getNumberOfSuperpixels(); 377 | 378 | printf( " count: %lu superpixels (growed in %.6f sec)\n", 379 | m_labels, ( endSecond - startSecond ) / frequency ); 380 | 381 | // get smooth labels 382 | startSecond = cv::getTickCount(); 383 | if ( EQUAL( algo, "SLIC" ) 384 | || EQUAL( algo, "SLICO" ) 385 | || EQUAL( algo, "MSLIC" ) ) 386 | { 387 | if ( enforce == true ) 388 | slic->enforceLabelConnectivity(); 389 | } 390 | else if ( EQUAL( algo, "LSC" ) ) 391 | { 392 | if ( enforce == true) 393 | lsc->enforceLabelConnectivity(); 394 | } 395 | endSecond = cv::getTickCount(); 396 | 397 | if ( EQUAL( algo, "SLIC" ) 398 | || EQUAL( algo, "MSLIC" ) 399 | || EQUAL( algo, "SLICO" ) ) 400 | m_labels = slic->getNumberOfSuperpixels(); 401 | else if ( EQUAL( algo, "SEEDS" ) ) 402 | m_labels = seed->getNumberOfSuperpixels(); 403 | else if ( EQUAL( algo, "LSC" ) ) 404 | m_labels = lsc->getNumberOfSuperpixels(); 405 | 406 | if ( ! EQUAL( algo, "SEEDS" ) ) 407 | { 408 | printf( " final: %lu superpixels (merged in %.6f sec)\n", 409 | m_labels, ( endSecond - startSecond ) / frequency ); 410 | endTime = cv::getTickCount(); 411 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 412 | } 413 | 414 | 415 | // storage 416 | cv::Mat klabels; 417 | if( EQUAL( algo, "SLIC" ) 418 | || EQUAL( algo, "MSLIC" ) 419 | || EQUAL( algo, "SLICO" ) ) 420 | slic->getLabels( klabels ); 421 | else if( EQUAL( algo, "SEEDS" ) ) 422 | seed->getLabels( klabels ); 423 | else if( EQUAL( algo, "LSC" ) ) 424 | lsc->getLabels( klabels ); 425 | 426 | // release mem 427 | slic.release(); 428 | seed.release(); 429 | lsc.release(); 430 | 431 | /* 432 | * get segments contour 433 | */ 434 | 435 | std::vector< std::vector< LINE > > linelists( m_labels ); 436 | 437 | startTime = cv::getTickCount(); 438 | LabelContours( klabels, linelists ); 439 | endTime = cv::getTickCount(); 440 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 441 | 442 | 443 | /* 444 | * statistics 445 | */ 446 | 447 | startTime = cv::getTickCount(); 448 | 449 | if ( labcol ) 450 | { 451 | raster = original; 452 | } 453 | 454 | // superpixels property 455 | size_t m_bands = raster.size(); 456 | 457 | Mat labelpixels(m_labels, 1, CV_32S); 458 | Mat avgCH(m_bands, m_labels, CV_64F); 459 | Mat stdCH(m_bands, m_labels, CV_64F); 460 | 461 | ComputeStats( klabels, raster, labelpixels, avgCH, stdCH ); 462 | endTime = cv::getTickCount(); 463 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 464 | 465 | 466 | /* 467 | * dump vector 468 | */ 469 | 470 | startTime = cv::getTickCount(); 471 | SavePolygons( InFilenames, OutFilename, OutFormat, klabels, 472 | raster, labelpixels, avgCH, stdCH, linelists ); 473 | endTime = cv::getTickCount(); 474 | printf( "Time: %.6f sec\n\n", ( endTime - startTime ) / frequency ); 475 | 476 | 477 | /* 478 | * dump stats 479 | */ 480 | 481 | if ( OutStatH5name ) 482 | { 483 | cv::Ptr h5io = cv::hdf::open( OutStatH5name ); 484 | h5io->dswrite( avgCH, "average" ); 485 | h5io->dswrite( stdCH, "stddevs" ); 486 | h5io->dswrite( labelpixels, "pixarea" ); 487 | h5io->close(); 488 | } 489 | 490 | /* 491 | * END 492 | */ 493 | 494 | printf( "Finish.\n" ); 495 | 496 | return 0; 497 | 498 | } 499 | -------------------------------------------------------------------------------- /src/io/raster.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | */ 15 | 16 | /* raster.cpp */ 17 | /* Raster I/O */ 18 | 19 | #include 20 | 21 | #include "gdal.h" 22 | #include "gdal_priv.h" 23 | #include "cpl_string.h" 24 | #include "cpl_csv.h" 25 | 26 | #include 27 | 28 | #include "gdal-segment.hpp" 29 | 30 | using namespace cv; 31 | 32 | 33 | 34 | void LoadRaster( const std::vector< std::string > InFilenames, 35 | std::vector< cv::Mat >& raster ) 36 | { 37 | int rasters = 0; 38 | int channel = 0; 39 | 40 | std::string prev_dType = ""; 41 | int prev_XSize = 0, prev_YSize = 0; 42 | 43 | for ( size_t i = 0; i < InFilenames.size(); i++ ) 44 | { 45 | 46 | GDALDataset* piDataset; 47 | 48 | // open the dataset 49 | piDataset = (GDALDataset*) GDALOpen(InFilenames[i].c_str(), GA_ReadOnly); 50 | 51 | if( piDataset == NULL ) 52 | { 53 | printf("\nERROR: Couldn't open dataset %s\n", InFilenames[i].c_str()); 54 | exit( 1 ); 55 | } 56 | 57 | if( piDataset->GetGCPCount() > 0 ) 58 | { 59 | printf("\nERROR: Cannot handle raster with GCP points.\n"); 60 | exit( 1 ); 61 | } 62 | 63 | rasters++; 64 | printf ("\nLoad Raster #%i (#%lu): %s\n", rasters, 65 | InFilenames.size(), InFilenames[i].c_str()); 66 | 67 | // count raster bands 68 | int nBands = piDataset->GetRasterCount(); 69 | printf (" Scene have [%i] bands\n", nBands); 70 | 71 | 72 | // gather all bands 73 | for ( int iB = 0; iB < nBands; iB++ ) 74 | { 75 | 76 | int iX, iY; 77 | int iXBlock, iYBlock; 78 | int nXBlockSize, nYBlockSize; 79 | 80 | cv::Mat Channel; 81 | cv::Mat pabyData; 82 | GDALDataType rType; 83 | 84 | // get parameters from input dataset 85 | const int nXSize = piDataset->GetRasterBand(iB+1)->GetXSize(); 86 | const int nYSize = piDataset->GetRasterBand(iB+1)->GetYSize(); 87 | piDataset->GetRasterBand(iB+1)->GetBlockSize( &nXBlockSize, &nYBlockSize ); 88 | 89 | rType = piDataset->GetRasterBand(iB+1)->GetRasterDataType(); 90 | 91 | int nXBlocks = (nXSize + nXBlockSize - 1) / nXBlockSize; 92 | int nYBlocks = (nYSize + nYBlockSize - 1) / nYBlockSize; 93 | 94 | std::string dType; 95 | 96 | switch( rType ) 97 | { 98 | case GDT_Byte: 99 | dType = "Byte"; 100 | Channel = cv::Mat( nYSize, nXSize, CV_8U); 101 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_8U); 102 | break; 103 | 104 | case GDT_UInt16: 105 | dType = "UInt16"; 106 | Channel = cv::Mat( nYSize, nXSize, CV_16U); 107 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_16U); 108 | break; 109 | 110 | case GDT_Int16: 111 | dType = "Int16"; 112 | Channel = cv::Mat( nYSize, nXSize, CV_16S); 113 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_16S); 114 | break; 115 | 116 | case GDT_Int32: 117 | dType = "Int32"; 118 | Channel = cv::Mat( nYSize, nXSize, CV_32S); 119 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_32S); 120 | break; 121 | 122 | case GDT_Float32: 123 | dType = "Float32"; 124 | Channel = cv::Mat( nYSize, nXSize, CV_32F); 125 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_32F); 126 | break; 127 | 128 | case GDT_Float64: 129 | dType = "Float64"; 130 | Channel = cv::Mat( nYSize, nXSize, CV_64F); 131 | pabyData = cv::Mat( nYBlockSize, nXBlockSize, CV_64F); 132 | break; 133 | 134 | default: 135 | printf ("\nERROR: Unsupported raster data type.\n"); 136 | exit ( 1 ); 137 | } 138 | 139 | channel++; 140 | 141 | // consistency 142 | if ( channel > 1 ) 143 | { 144 | if ( ( prev_XSize != nXSize ) 145 | ||( prev_YSize != nYSize ) ) 146 | { 147 | printf ("\nERROR: CH #%i has different size: (%iP x %iL) than previous (%iP x %iL).\n", 148 | channel, nXSize, nYSize, prev_XSize, prev_YSize); 149 | exit ( 1 ); 150 | } 151 | if ( prev_dType != dType ) 152 | { 153 | printf ("\nERROR: CH #%i has different data type [%s] then previous [%s]\n", 154 | channel, dType.c_str(), prev_dType.c_str()); 155 | exit ( 1 ); 156 | } 157 | } 158 | 159 | // store previous 160 | prev_dType = dType; 161 | prev_XSize = nXSize; 162 | prev_YSize = nYSize; 163 | 164 | printf (" CH: #%03i chann: (#%i Band | [%s])\n", channel, iB+1, dType.c_str()); 165 | printf (" areas: (%i Pixels x %i Lines) pixels\n", nXSize, nYSize); 166 | printf (" tiles: (%i Columns x %i Rows) blocks\n", nXBlocks, nYBlocks); 167 | printf (" block: (%i Pixels x %i Lines) pixels / tile\n", nXBlockSize, nYBlockSize); 168 | printf (" "); 169 | 170 | CPLErr error; 171 | 172 | for( iYBlock = 0; iYBlock < nYBlocks; iYBlock++ ) 173 | { 174 | for( iXBlock = 0; iXBlock < nXBlocks; iXBlock++ ) 175 | { 176 | int nXValid, nYValid; 177 | 178 | // compute the portion of the block that is valid 179 | // for partial edge blocks. 180 | if( (iXBlock+1) * nXBlockSize > nXSize ) 181 | nXValid = nXSize - iXBlock * nXBlockSize; 182 | else 183 | nXValid = nXBlockSize; 184 | 185 | if( (iYBlock+1) * nYBlockSize > nYSize ) 186 | nYValid = nYSize - iYBlock * nYBlockSize; 187 | else 188 | nYValid = nYBlockSize; 189 | 190 | error = piDataset->GetRasterBand(iB+1)->ReadBlock( iXBlock, iYBlock, pabyData.data ); 191 | 192 | if ( error != CE_None ) 193 | printf("ERROR: GetRasterBand()\n"); 194 | 195 | // cache some computations 196 | const int iXAllBlocks = iXBlock * nXBlockSize; 197 | const int iYAllBlocks = iYBlock * nYBlockSize; 198 | 199 | for (iY = 0; iY < nYValid; iY++) 200 | { 201 | // cache some computations 202 | const int iYOffset = iY * nXBlockSize; 203 | const int iYShifts = iY + iYAllBlocks; 204 | 205 | for (iX = 0; iX < nXValid; iX++) 206 | { 207 | switch( rType ) 208 | { 209 | case GDT_Byte: 210 | Channel.at( iYShifts, iX + iXAllBlocks ) 211 | = pabyData.at( iYOffset + iX ); 212 | break; 213 | 214 | case GDT_UInt16: 215 | Channel.at( iYShifts, iX + iXAllBlocks ) 216 | = pabyData.at( iYOffset + iX ); 217 | break; 218 | 219 | case GDT_Int16: 220 | Channel.at( iYShifts, iX + iXAllBlocks ) 221 | = pabyData.at( iYOffset + iX ); 222 | break; 223 | 224 | case GDT_Int32: 225 | Channel.at( iYShifts, iX + iXAllBlocks ) 226 | = pabyData.at( iYOffset + iX ); 227 | break; 228 | 229 | case GDT_Float32: 230 | Channel.at( iYShifts, iX + iXAllBlocks ) 231 | = pabyData.at( iYOffset + iX ); 232 | break; 233 | 234 | case GDT_Float64: 235 | Channel.at( iYShifts, iX + iXAllBlocks ) 236 | = pabyData.at( iYOffset + iX ); 237 | break; 238 | 239 | default: 240 | printf ("\nERROR: Unsupported raster data type.\n"); 241 | exit ( 1 ); 242 | } 243 | } 244 | } 245 | } 246 | GDALTermProgress( (float)((iYBlock+1) / (float)nYBlocks), NULL, NULL); 247 | } 248 | pabyData.empty(); 249 | raster.push_back(Channel); 250 | GDALTermProgress( 1.0f, NULL, NULL ); 251 | } 252 | GDALTermProgress( 1.0f, NULL, NULL ); 253 | GDALClose( (GDALDatasetH) piDataset ); 254 | } 255 | } 256 | 257 | void ComputeStats( const cv::Mat klabels, 258 | const std::vector< cv::Mat > raster, 259 | cv::Mat& labelpixels, cv::Mat& avgCH, cv::Mat& stdCH ) 260 | { 261 | 262 | avgCH = Scalar::all(0); 263 | stdCH = Scalar::all(0); 264 | labelpixels = Scalar::all(0); 265 | 266 | const int m_bands = (int) raster.size(); 267 | Mat sumCH = Mat::zeros(m_bands, klabels.cols*klabels.rows, CV_64F); 268 | 269 | printf ("Compute Statistics\n"); 270 | 271 | printf (" Computing CLASS polygons intensity\n"); 272 | printf (" "); 273 | for (int y = 0; y < klabels.rows; y++) 274 | { 275 | const int yklabels = y * klabels.cols; 276 | for (int x = 0; x < klabels.cols; x++) 277 | { 278 | const int i = yklabels + x; 279 | const int k = klabels.at(i); 280 | // gather how many pixels per class we have 281 | labelpixels.at( klabels.at(i) )++; 282 | // summ all pixel intensities 283 | #pragma omp parallel for schedule(dynamic) 284 | for (int b = 0; b < m_bands; b++) 285 | { 286 | switch ( raster[b].depth() ) 287 | { 288 | case CV_8U: 289 | sumCH.at(b,k) += (double) raster[b].at(i); 290 | break; 291 | case CV_8S: 292 | sumCH.at(b,k) += (double) raster[b].at(i); 293 | break; 294 | case CV_16U: 295 | sumCH.at(b,k) += (double) raster[b].at(i); 296 | break; 297 | case CV_16S: 298 | sumCH.at(b,k) += (double) raster[b].at(i); 299 | break; 300 | case CV_32S: 301 | sumCH.at(b,k) += (double) raster[b].at(i); 302 | break; 303 | case CV_32F: 304 | sumCH.at(b,k) += (double) raster[b].at(i); 305 | break; 306 | case CV_64F: 307 | sumCH.at(b,k) += (double) raster[b].at(i); 308 | break; 309 | default: 310 | CV_Error( Error::StsInternal, "\nERROR: Invalid raster depth" ); 311 | break; 312 | } 313 | } 314 | } 315 | GDALTermProgress( (float)(y+1) / (float)(klabels.rows), NULL, NULL ); 316 | } 317 | GDALTermProgress( 1.0f, NULL, NULL ); 318 | 319 | printf (" Computing CLASS averaged intensity\n"); 320 | printf (" "); 321 | for (int k = 0; k < labelpixels.rows; k++) 322 | { 323 | #pragma omp parallel for schedule(dynamic) 324 | for (int b = 0; b < m_bands; b++) 325 | { 326 | avgCH.at(b,k) = sumCH.at(b,k) / (double) labelpixels.at(k); 327 | } 328 | GDALTermProgress( (float)(k+1) / (float)(labelpixels.rows), NULL, NULL ); 329 | } 330 | GDALTermProgress( 1.0f, NULL, NULL ); 331 | 332 | printf (" Computing CLASS standard deviation\n"); 333 | printf (" "); 334 | for (int y = 0; y < klabels.rows; y++) 335 | { 336 | const int yklabels = y * klabels.cols; 337 | for (int x = 0; x < klabels.cols; x++) 338 | { 339 | const int i = yklabels + x; 340 | const int k = klabels.at(i); 341 | #pragma omp parallel for schedule(dynamic) 342 | for (int b = 0; b < m_bands; b++) 343 | { 344 | switch ( raster[b].depth() ) 345 | { 346 | case CV_8U: 347 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 348 | - avgCH.at(b,klabels.at(i)), 2 ); 349 | break; 350 | case CV_8S: 351 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 352 | - avgCH.at(b,klabels.at(i)), 2 ); 353 | break; 354 | case CV_16U: 355 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 356 | - avgCH.at(b,klabels.at(i)), 2 ); 357 | break; 358 | case CV_16S: 359 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 360 | - avgCH.at(b,klabels.at(i)), 2 ); 361 | break; 362 | case CV_32S: 363 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 364 | - avgCH.at(b,klabels.at(i)), 2 ); 365 | break; 366 | case CV_32F: 367 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 368 | - avgCH.at(b,klabels.at(i)), 2 ); 369 | break; 370 | case CV_64F: 371 | stdCH.at(b,k) += pow( (double) raster[b].at(i) 372 | - avgCH.at(b,klabels.at(i)), 2 ); 373 | break; 374 | default: 375 | CV_Error( Error::StsInternal, "\nERROR: Invalid raster depth" ); 376 | break; 377 | } 378 | } 379 | } 380 | GDALTermProgress( (float)(y+1) / (float)(klabels.rows), NULL, NULL ); 381 | } 382 | GDALTermProgress( 1.0f, NULL, NULL ); 383 | 384 | printf (" Normalize CLASS standard deviation\n"); 385 | printf (" "); 386 | 387 | for (int k = 0; k < labelpixels.rows; k++) 388 | { 389 | #pragma omp parallel for schedule(dynamic) 390 | for (int b = 0; b < m_bands; b++) 391 | { 392 | stdCH.at(b,k) = sqrt(stdCH.at(b,k) / labelpixels.at(k)); 393 | } 394 | GDALTermProgress( (float)(k+1) / (float)(labelpixels.rows), NULL, NULL ); 395 | } 396 | GDALTermProgress( 1.0f, NULL, NULL ); 397 | 398 | } 399 | -------------------------------------------------------------------------------- /src/io/vector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Balint Cristian (cristian.balint@gmail.com) 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 | */ 15 | 16 | /* vector.cpp */ 17 | /* Vector I/O */ 18 | 19 | #include 20 | 21 | #include "gdal.h" 22 | #include "gdal_priv.h" 23 | #include "ogrsf_frmts.h" 24 | #include "cpl_string.h" 25 | #include "cpl_csv.h" 26 | 27 | #include 28 | 29 | #include "gdal-segment.hpp" 30 | 31 | using namespace std; 32 | using namespace cv; 33 | 34 | 35 | void LabelContours( const cv::Mat klabels, std::vector< std::vector< LINE > >& linelists ) 36 | { 37 | // iterate through pixels and check edges 38 | printf ("Parse edges in segmented image\n"); 39 | for (int y = 0; y < klabels.rows; y++) 40 | { 41 | const int yklabels = y*klabels.cols; 42 | for (int x = 0; x < klabels.cols; x++) 43 | { 44 | const int i = yklabels + x; 45 | 46 | LINE line; 47 | // check right pixel 48 | if ( x == klabels.cols - 1 ) 49 | { 50 | line.sX = x + 1; line.sY = y; 51 | line.eX = x + 1; line.eY = y + 1; 52 | { 53 | linelists[klabels.at(i)].push_back(line); 54 | } 55 | 56 | } else if ( klabels.at(i) 57 | != klabels.at(i + 1) ) 58 | { 59 | line.sX = x + 1; line.sY = y; 60 | line.eX = x + 1; line.eY = y + 1; 61 | { 62 | linelists[klabels.at(i)].push_back(line); 63 | } 64 | } 65 | // check left pixel 66 | if ( x == 0 ) 67 | { 68 | line.sX = x; line.sY = y; 69 | line.eX = x, line.eY = y + 1; 70 | { 71 | linelists[klabels.at(i)].push_back(line); 72 | } 73 | } else if ( klabels.at(i) 74 | != klabels.at(i - 1) ) 75 | { 76 | line.sX = x; line.sY = y; 77 | line.eX = x, line.eY = y + 1; 78 | { 79 | linelists[klabels.at(i)].push_back(line); 80 | } 81 | } 82 | // check top pixel 83 | if ( y == 0 ) 84 | { 85 | line.sX = x; line.sY = y; 86 | line.eX = x + 1; line.eY = y; 87 | { 88 | linelists[klabels.at(i)].push_back(line); 89 | } 90 | } else if ( klabels.at(i) 91 | != klabels.at((y-1)*klabels.cols + x) ) 92 | { 93 | line.sX = x; line.sY = y; 94 | line.eX = x + 1; line.eY = y; 95 | { 96 | linelists[klabels.at(i)].push_back(line); 97 | } 98 | } 99 | // check bottom pixel 100 | if ( y == klabels.rows - 1 ) 101 | { 102 | line.sX = x; line.sY = y + 1; 103 | line.eX = x + 1; line.eY = y + 1; 104 | { 105 | linelists[klabels.at(i)].push_back(line); 106 | } 107 | 108 | } else if ( klabels.at(i) 109 | != klabels.at((y+1)*klabels.cols + x) ) 110 | { 111 | line.sX = x; line.sY = y + 1; 112 | line.eX = x + 1; line.eY = y + 1; 113 | { 114 | linelists[klabels.at(i)].push_back(line); 115 | } 116 | } 117 | } 118 | GDALTermProgress( (float)(y) / (float)(klabels.rows), NULL, NULL ); 119 | } 120 | GDALTermProgress( 1.0f, NULL, NULL ); 121 | } 122 | 123 | 124 | void SavePolygons( const std::vector< std::string > InFilenames, 125 | const char *OutFilename, const char *OutFormat, 126 | const cv::Mat klabels, 127 | const std::vector< cv::Mat > raster, 128 | const Mat labelpixels, 129 | const Mat avgCH, const Mat stdCH, 130 | std::vector< std::vector< LINE > >& linelists ) 131 | { 132 | 133 | CPLLocaleC oLocaleCForcer(); 134 | CPLErrorReset(); 135 | 136 | #if GDALVER >= 2 137 | GDALDriver *liDriver; 138 | liDriver = GetGDALDriverManager()->GetDriverByName( OutFormat ); 139 | #else 140 | OGRSFDriver *liDriver; 141 | liDriver = OGRSFDriverRegistrar::GetRegistrar() 142 | ->GetDriverByName( OutFormat ); 143 | #endif 144 | 145 | // speed up SQLite 146 | CPLSetThreadLocalConfigOption("OGR_SQLITE_SYNCHRONOUS", "OFF"); 147 | 148 | if( liDriver == NULL ) 149 | { 150 | printf( "\nERROR: %s driver not available.\n", OutFormat ); 151 | exit( 1 ); 152 | } 153 | 154 | const size_t m_bands = raster.size(); 155 | const size_t m_labels = labelpixels.rows; 156 | 157 | #if GDALVER >= 2 158 | GDALDataset *liDS; 159 | liDS = liDriver->Create( OutFilename, 0, 0, 0, GDT_Unknown, NULL ); 160 | #else 161 | OGRDataSource *liDS; 162 | liDS = liDriver->CreateDataSource( OutFilename, NULL ); 163 | #endif 164 | 165 | if( liDS == NULL ) 166 | { 167 | printf( "\nERROR: Creation of output file failed.\n" ); 168 | exit( 1 ); 169 | } 170 | 171 | // dataset 172 | GDALDataset* piDataset; 173 | piDataset = (GDALDataset*) GDALOpen(InFilenames[0].c_str(), GA_ReadOnly); 174 | 175 | // spatialref 176 | OGRSpatialReference oSRS; 177 | oSRS.SetProjCS( piDataset->GetProjectionRef() ); 178 | 179 | OGRLayer *liLayer; 180 | liLayer = liDS->CreateLayer( "segments", &oSRS, wkbPolygon, NULL ); 181 | 182 | if( liLayer == NULL ) 183 | { 184 | printf( "\nERROR: Layer creation failed.\n" ); 185 | exit( 1 ); 186 | } 187 | // spatial transform 188 | double adfGeoTransform[6]; 189 | double oX = 0.0f; double oY = 0.0f; 190 | double mX = 1.0f; double mY = -1.0f; 191 | if( piDataset->GetGeoTransform( adfGeoTransform ) == CE_None ) { 192 | oX = adfGeoTransform[0]; oY = adfGeoTransform[3]; 193 | mX = adfGeoTransform[1]; mY = adfGeoTransform[5]; 194 | } 195 | GDALClose( (GDALDatasetH) piDataset ); 196 | 197 | OGRFieldDefn *clsIdField = new OGRFieldDefn( "CLASS", OFTInteger ); 198 | liLayer->CreateField( clsIdField ); 199 | 200 | OGRFieldDefn *pixArField = new OGRFieldDefn( "AREA", OFTInteger ); 201 | liLayer->CreateField( pixArField ); 202 | 203 | for ( size_t b = 0; b < m_bands; b++ ) 204 | { 205 | stringstream value; value << b+1; 206 | std::string FieldName = value.str() + "_AVERAGE"; 207 | OGRFieldDefn *lavrgField = new OGRFieldDefn( FieldName.c_str(), OFTReal ); 208 | liLayer->CreateField( lavrgField ); 209 | } 210 | 211 | for ( size_t b = 0; b < m_bands; b++ ) 212 | { 213 | stringstream value; value << b+1; 214 | std::string FieldName = value.str() + "_STDDEV"; 215 | OGRFieldDefn *lavrgField = new OGRFieldDefn( FieldName.c_str(), OFTReal ); 216 | liLayer->CreateField( lavrgField ); 217 | } 218 | 219 | int multiring = 0; 220 | printf ("Write File: %s (polygon)\n", OutFilename); 221 | for (size_t k = 0; k < m_labels; k++) 222 | { 223 | 224 | if ( multiring == 1 ) 225 | { 226 | k = k - 1; 227 | multiring = 0; 228 | } 229 | 230 | if ( linelists[k].size() == 0 ) 231 | continue; 232 | 233 | // insert field data 234 | OGRFeature *liFeature; 235 | liFeature = OGRFeature::CreateFeature( liLayer->GetLayerDefn() ); 236 | liFeature->SetField( "CLASS", (int) k ); 237 | liFeature->SetField( "AREA", (int) labelpixels.at(k) ); 238 | 239 | for ( size_t b = 0; b < m_bands; b++ ) 240 | { 241 | stringstream value; value << b+1; 242 | std::string FieldName = value.str() + "_AVERAGE"; 243 | liFeature->SetField( FieldName.c_str(), (double) avgCH.at(b,k) ); 244 | } 245 | for ( size_t b = 0; b < m_bands; b++ ) 246 | { 247 | stringstream value; value << b+1; 248 | std::string FieldName = value.str() + "_STDDEV"; 249 | liFeature->SetField( FieldName.c_str(), (double) stdCH.at(b,k) ); 250 | } 251 | // initiate polygon start 252 | OGRLinearRing linestring; 253 | linestring.setCoordinateDimension(2); 254 | linestring.addPoint( oX + (double) linelists[k][0].sX * mX, oY + mY * (double) linelists[k][0].sY ); 255 | linestring.addPoint( oX + (double) linelists[k][0].eX * mX, oY + mY * (double) linelists[k][0].eY ); 256 | linelists[k].erase( linelists[k].begin() ); 257 | 258 | // construct polygon from lines 259 | while ( linelists[k].size() > 0 ) 260 | { 261 | if ( multiring == 1 ) break; 262 | 263 | vector::iterator it = linelists[k].begin(); 264 | for (; it != linelists[k].end(); ++it) 265 | { 266 | double ltX = linestring.getX(linestring.getNumPoints()-1); 267 | double ltY = linestring.getY(linestring.getNumPoints()-1); 268 | double csX = oX + (double) it->sX * mX; 269 | double csY = oY + mY * (double) it->sY; 270 | double ceX = oX + (double) it->eX * mX; 271 | double ceY = oY + mY * (double) it->eY; 272 | 273 | if ( ( csX == ltX ) && ( csY == ltY ) ) { 274 | linestring.addPoint(ceX, ceY); 275 | linelists[k].erase(it); 276 | break; 277 | } 278 | if ( ( ceX == ltX ) && ( ceY == ltY ) ) { 279 | linestring.addPoint(csX, csY); 280 | linelists[k].erase(it); 281 | break; 282 | } 283 | if (it == linelists[k].end()-1) { 284 | multiring = 1; 285 | break; 286 | } 287 | } 288 | } 289 | 290 | OGRPolygon polygon; 291 | linestring.closeRings(); 292 | 293 | // simplify poligons 294 | // remove colinear vertices 295 | OGRLinearRing linesimple; 296 | float pointPrevX = 0, pointPrevY = 0; 297 | for (int i = 0; i < linestring.getNumPoints(); i++) 298 | { 299 | OGRPoint point; 300 | linestring.getPoint(i, &point); 301 | 302 | // start 303 | if ( i == 0) 304 | { 305 | linesimple.addPoint( &point ); 306 | pointPrevX = point.getX(); 307 | pointPrevY = point.getY(); 308 | continue; 309 | } 310 | // end vertex 311 | if ( i == linestring.getNumPoints() - 1 ) 312 | { 313 | linesimple.addPoint( &point ); 314 | continue; 315 | } 316 | 317 | OGRPoint pointNext; 318 | linestring.getPoint(i+1, &pointNext); 319 | // | x1 y1 1 | 320 | // det | x2 y2 1 | = 0 => p1,p2,p3 are colinear 321 | // | x3 y3 1 | 322 | // x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2) == 0 323 | // only if not colinear with previous and next 324 | if ( pointPrevX*(point.getY()-pointNext.getY()) + 325 | point.getX()*(pointNext.getY()-pointPrevY) + 326 | pointNext.getX()*(pointPrevY-point.getY()) != 0 ) 327 | { 328 | linesimple.addPoint( &point ); 329 | pointPrevX = point.getX(); 330 | pointPrevY = point.getY(); 331 | } 332 | } 333 | 334 | // as polygon geometry 335 | polygon.addRing( &linesimple ); 336 | liFeature->SetGeometry( &polygon ); 337 | 338 | if( liLayer->CreateFeature( liFeature ) != OGRERR_NONE ) 339 | { 340 | printf( "\nERROR: Failed to create feature in vector layer.\n" ); 341 | exit( 1 ); 342 | } 343 | OGRFeature::DestroyFeature( liFeature ); 344 | GDALTermProgress( (float)(k+1) / (float)(m_labels), NULL, NULL ); 345 | } 346 | GDALTermProgress( 1.0f, NULL, NULL ); 347 | 348 | #if GDALVER >= 2 349 | GDALClose( liDS ); 350 | #else 351 | OGRDataSource::DestroyDataSource( liDS ); 352 | #endif 353 | 354 | 355 | } 356 | --------------------------------------------------------------------------------