├── .gitignore ├── CMakeLists.txt ├── COPYING.md ├── INSTALL.md ├── LICENSE-MPL2.md ├── README.md ├── appveyor.yml └── src ├── depthMapEntity ├── CMakeLists.txt ├── DepthMapEntity.cpp ├── DepthMapEntity.hpp ├── mv_matrix3x3.hpp ├── mv_point2d.hpp ├── mv_point3d.hpp ├── plugin.hpp └── qmldir ├── imageIOHandler ├── CMakeLists.txt ├── QtOIIOHandler.cpp ├── QtOIIOHandler.hpp ├── QtOIIOPlugin.cpp ├── QtOIIOPlugin.hpp └── QtOIIOPlugin.json └── jetColorMap.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Compiled Static libraries 17 | *.lai 18 | *.la 19 | *.a 20 | *.lib 21 | 22 | # Executables 23 | *.exe 24 | *.out 25 | *.app 26 | 27 | # Build directories 28 | build* 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message("CMake version: ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}") 2 | cmake_minimum_required(VERSION 3.4) 3 | project(QtOIIO LANGUAGES CXX C) 4 | 5 | find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) 6 | 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | # C++11 for Qt5 9 | if(${QT_VERSION_MAJOR} EQUAL 5) 10 | set(CMAKE_CXX_STANDARD 11) 11 | endif() 12 | 13 | # C++17 for Qt6 14 | if(${QT_VERSION_MAJOR} EQUAL 6) 15 | set(CMAKE_CXX_STANDARD 17) 16 | endif() 17 | 18 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) 19 | 20 | 21 | # OpenImageIO 22 | find_package(OpenImageIO REQUIRED) 23 | if(TARGET OpenImageIO::OpenImageIO) 24 | message(STATUS "OpenImageIO found.") 25 | else() 26 | message(SEND_ERROR "Failed to find OpenImageIO.") 27 | endif() 28 | 29 | 30 | # Qt 31 | set(CMAKE_AUTOMOC ON) 32 | set(CMAKE_INCLUDE_CURRENT_DIR ON) # needed for automoc 33 | 34 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core REQUIRED) 35 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) 36 | 37 | 38 | if(Qt${QT_VERSION_MAJOR}Core_FOUND) 39 | message(STATUS "Qt ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR} found.") 40 | endif() 41 | 42 | add_definitions(-DQT_PLUGIN) 43 | add_definitions(-DQT_SHARED) 44 | add_definitions(-DQT_NO_DEBUG) 45 | 46 | # comment to get qDebug outputs 47 | add_definitions(-DQT_NO_DEBUG_OUTPUT) 48 | 49 | # comment to handle all possible file formats 50 | # by default: jpeg, png and ico are handled by Qt (for performance reasons) 51 | add_definitions(-DQTOIIO_USE_FORMATS_BLACKLIST) 52 | 53 | add_subdirectory(src/imageIOHandler) 54 | 55 | # TODO: Make it works for Qt6 56 | # Add to Qt5 only for the moment since 3dcore 57 | # is not part of the distribution anymore. 58 | # Source: https://www.kdab.com/qt-3d-changes-in-qt-6/ 59 | if(Qt5_FOUND) 60 | add_subdirectory(src/depthMapEntity) 61 | endif() 62 | # add_subdirectory(src/depthMapEntity) 63 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | ## QtOIIO License 2 | 3 | QtOIIO is licensed under the [MPL2 license](LICENSE-MPL2.md). 4 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Development 2 | This guide will help you build and install QtOIIO plugin. 3 | 4 | ## Requirements 5 | QtOIIO requires: 6 | * [Qt5](https://www.qt.io/) (>= 5.13, make sure to use the **same version** as the target application) 7 | * [OpenImageIO](https://github.com/https://github.com/OpenImageIO/oiio) (>= 1.8.7) - with OpenEXR support for depthmaps visualization 8 | * [CMake](https://cmake.org/) (>= 3.4) 9 | * On Windows platform: Microsoft Visual Studio (>= 2015.3) 10 | 11 | > **Note for Windows**: 12 | We recommend using [VCPKG](https://github.com/Microsoft/vcpkg) to get OpenImageIO. Qt version there is too old at the moment though, using official installer is necessary. 13 | 14 | ## Build instructions 15 | 16 | In the following steps, replace with the installation path of your choice. 17 | 18 | 19 | #### Windows 20 | > We will use "NMake Makefiles" generators here to have one-line build/installation, 21 | but Visual Studio solutions can be generated if need be. 22 | 23 | From a developer command-line, using Qt 5.13 (built with VS2015) and VCPKG for OIIO: 24 | ``` 25 | set QT_DIR=/path/to/qt/5.13.0/msvc2017_64 26 | cmake .. -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake -DCMAKE_PREFIX_PATH=%QT_DIR% -DVCPKG_TARGET_TRIPLET=x64-windows -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release 27 | nmake install 28 | ``` 29 | 30 | #### Linux 31 | 32 | ```bash 33 | export QT_DIR=/path/to/qt/5.13.0/gcc_64 34 | export OPENIMAGEIO_DIR=/path/to/oiio/install 35 | export 36 | cmake .. -DCMAKE_PREFIX_PATH=$QT_DIR 37 | -DOPENIMAGEIO_LIBRARY_DIR_HINTS:PATH=$OPENIMAGEIO_DIR/lib/ -DOPENIMAGEIO_INCLUDE_DIR:PATH=$OPENIMAGEIO_DIR/include/ -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release 38 | make install 39 | ``` 40 | 41 | ## Usage 42 | Once built, setup those environment variables before launching your application: 43 | 44 | ```bash 45 | # Windows: 46 | set QML2_IMPORT_PATH=/qml;%QML2_IMPORT_PATH% 47 | set QT_PLUGIN_PATH=;%QT_PLUGIN_PATH% 48 | 49 | # Linux: 50 | export QML2_IMPORT_PATH=/qml:$QML2_IMPORT_PATH 51 | export QT_PLUGIN_PATH=:$QT_PLUGIN_PATH 52 | ``` 53 | -------------------------------------------------------------------------------- /LICENSE-MPL2.md: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QtOIIO - OIIO plugin for Qt 2 | 3 | QtOIIO is a C++ plugin providing an [OpenImageIO](http://github.com/OpenImageIO/oiio) backend for image IO in Qt. 4 | It has been developed to visualize RAW images from DSLRs in [Meshroom](https://github.com/alicevision/meshroom), as well as some intermediate files of the [AliceVision](https://github.com/alicevision/AliceVision) framework stored in EXR format (i.e: depthmaps). 5 | 6 | Continuous integration: 7 | * Windows: [![Build status](https://ci.appveyor.com/api/projects/status/te46xg9oan317bdy/branch/develop?svg=true)](https://ci.appveyor.com/project/AliceVision/qtoiio/branch/develop) 8 | 9 | ## License 10 | 11 | The project is released under MPLv2, see [**COPYING.md**](COPYING.md). 12 | 13 | 14 | ## Get the project 15 | 16 | Get the source code: 17 | ```bash 18 | git clone --recursive git://github.com/alicevision/QtOIIO 19 | cd QtOIIO 20 | ``` 21 | See [**INSTALL.md**](INSTALL.md) to build and install the project. 22 | 23 | ## Usage 24 | When added to the `QT_PLUGIN_PATH`, all supported image files will be loaded through this plugin. 25 | 26 | This plugin also provides a QML Qt3D Entity to load depthmaps files stored in EXR format: 27 | 28 | ```js 29 | import DepthMapEntity 1.0 30 | 31 | Scene3D { 32 | DepthMapEntity { 33 | source: "depthmap.exr" 34 | } 35 | } 36 | 37 | ``` 38 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '1.0.{build}' 2 | 3 | image: Visual Studio 2017 4 | 5 | configuration: 6 | - Release 7 | 8 | platform: 9 | - x64 10 | 11 | environment: 12 | QT5: C:\Qt\5.13\msvc2017_64 13 | # APPVEYOR_SAVE_CACHE_ON_ERROR: true 14 | 15 | install: 16 | - vcpkg list 17 | - vcpkg install 18 | openimageio 19 | --triplet %PLATFORM%-windows 20 | - vcpkg list 21 | 22 | before_build: 23 | - md build 24 | - cd build 25 | - cmake .. -G "Visual Studio 14 2015 Win64" 26 | -DCMAKE_BUILD_TYPE=%CONFIGURATION% 27 | -DCMAKE_PREFIX_PATH=%QT5% 28 | -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake 29 | 30 | build: 31 | project: $(APPVEYOR_BUILD_FOLDER)\build\INSTALL.vcxproj 32 | verbosity: minimal 33 | 34 | # comment the above and uncomment the following to just build the dependencies 35 | # build_script: 36 | # - echo "Dependencies installed." 37 | 38 | cache: 39 | c:\tools\vcpkg\installed\ 40 | 41 | -------------------------------------------------------------------------------- /src/depthMapEntity/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Target srcs 2 | file(GLOB_RECURSE TARGET_SRCS *.cpp *.cxx *.cc *.C *.c *.h *.hpp) 3 | 4 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Gui REQUIRED) 5 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Qml REQUIRED) 6 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Quick REQUIRED) 7 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS 3DCore REQUIRED) 8 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS 3DRender REQUIRED) 9 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS 3DExtras REQUIRED) 10 | 11 | # Target properties 12 | add_library(depthMapEntityQmlPlugin SHARED ${TARGET_SRCS}) 13 | target_link_libraries(depthMapEntityQmlPlugin 14 | PUBLIC 15 | OpenImageIO::OpenImageIO 16 | Qt${QT_VERSION_MAJOR}::Core 17 | Qt${QT_VERSION_MAJOR}::Gui 18 | Qt${QT_VERSION_MAJOR}::Qml 19 | Qt${QT_VERSION_MAJOR}::Quick 20 | Qt${QT_VERSION_MAJOR}::3DCore 21 | Qt${QT_VERSION_MAJOR}::3DRender 22 | Qt${QT_VERSION_MAJOR}::3DExtras 23 | ) 24 | 25 | # QT5_USE_MODULES(depthMapEntityQmlPlugin Core Qml Quick 3DCore 3DRender 3DExtras ${OPENIMAGEIO_LIBRARIES}) 26 | 27 | 28 | # Install settings 29 | install(FILES "qmldir" 30 | DESTINATION ${CMAKE_INSTALL_PREFIX}/qml/DepthMapEntity) 31 | install(TARGETS depthMapEntityQmlPlugin 32 | DESTINATION "${CMAKE_INSTALL_PREFIX}/qml/DepthMapEntity") 33 | -------------------------------------------------------------------------------- /src/depthMapEntity/DepthMapEntity.cpp: -------------------------------------------------------------------------------- 1 | #include "DepthMapEntity.hpp" 2 | #include "mv_point3d.hpp" 3 | #include "mv_point2d.hpp" 4 | #include "mv_matrix3x3.hpp" 5 | 6 | #include "../jetColorMap.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | namespace oiio = OIIO; 27 | 28 | 29 | namespace depthMapEntity { 30 | 31 | 32 | struct Vec3f 33 | { 34 | Vec3f() {} 35 | Vec3f(float x_, float y_, float z_) 36 | : x(x_) 37 | , y(y_) 38 | , z(z_) 39 | {} 40 | union { 41 | struct 42 | { 43 | float x, y, z; 44 | }; 45 | float m[3]; 46 | }; 47 | 48 | inline Vec3f operator-(const Vec3f& p) const 49 | { 50 | return Vec3f(x - p.x, y - p.y, z - p.z); 51 | } 52 | 53 | inline double size() const 54 | { 55 | double d = x * x + y * y + z * z; 56 | if(d == 0.0) 57 | { 58 | return 0.0; 59 | } 60 | 61 | return sqrt(d); 62 | } 63 | }; 64 | 65 | inline Vec3f cross(const Vec3f& a, const Vec3f& b) 66 | { 67 | Vec3f vc; 68 | vc.x = a.y * b.z - a.z * b.y; 69 | vc.y = a.z * b.x - a.x * b.z; 70 | vc.z = a.x * b.y - a.y * b.x; 71 | 72 | return vc; 73 | } 74 | 75 | DepthMapEntity::DepthMapEntity(Qt3DCore::QNode* parent) 76 | : Qt3DCore::QEntity(parent) 77 | , _displayMode(DisplayMode::Unknown) 78 | , _pointSizeParameter(new Qt3DRender::QParameter) 79 | { 80 | qDebug() << "[DepthMapEntity] DepthMapEntity"; 81 | createMaterials(); 82 | } 83 | 84 | void DepthMapEntity::setSource(const QUrl& value) 85 | { 86 | if(_source == value) 87 | return; 88 | _source = value; 89 | loadDepthMap(); 90 | Q_EMIT sourceChanged(); 91 | } 92 | 93 | void DepthMapEntity::setDisplayMode(const DepthMapEntity::DisplayMode& value) 94 | { 95 | if(_displayMode == value) 96 | return; 97 | _displayMode = value; 98 | updateMaterial(); 99 | 100 | Q_EMIT displayModeChanged(); 101 | } 102 | 103 | void DepthMapEntity::setDisplayColor(bool value) 104 | { 105 | if(_displayColor == value) 106 | return; 107 | _displayColor = value; 108 | updateMaterial(); 109 | 110 | Q_EMIT displayColorChanged(); 111 | } 112 | 113 | void DepthMapEntity::updateMaterial() 114 | { 115 | if(_status != DepthMapEntity::Ready) 116 | return; 117 | 118 | Qt3DRender::QMaterial* newMaterial = nullptr; 119 | 120 | switch(_displayMode) 121 | { 122 | case DisplayMode::Points: 123 | newMaterial = _cloudMaterial; 124 | _meshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Points); 125 | break; 126 | case DisplayMode::Triangles: 127 | _meshRenderer->setPrimitiveType(Qt3DRender::QGeometryRenderer::Triangles); 128 | if(_displayColor) 129 | newMaterial = _colorMaterial; 130 | else 131 | newMaterial = _diffuseMaterial; 132 | break; 133 | default: 134 | newMaterial = _diffuseMaterial; 135 | } 136 | 137 | if(newMaterial == _currentMaterial) 138 | return; 139 | 140 | if(_currentMaterial) 141 | removeComponent(_currentMaterial); 142 | 143 | _currentMaterial = newMaterial; 144 | addComponent(_currentMaterial); 145 | } 146 | 147 | void DepthMapEntity::setPointSize(const float& value) 148 | { 149 | if(_pointSize == value) 150 | return; 151 | _pointSize = value; 152 | _pointSizeParameter->setValue(value); 153 | _cloudMaterial->setEnabled(_pointSize > 0.0f); 154 | Q_EMIT pointSizeChanged(); 155 | } 156 | 157 | // private 158 | void DepthMapEntity::createMaterials() 159 | { 160 | using namespace Qt3DRender; 161 | using namespace Qt3DExtras; 162 | 163 | { 164 | _cloudMaterial = new QMaterial(this); 165 | 166 | // configure cloud material 167 | QEffect* effect = new QEffect; 168 | QTechnique* technique = new QTechnique; 169 | QRenderPass* renderPass = new QRenderPass; 170 | QShaderProgram* shaderProgram = new QShaderProgram; 171 | 172 | // set vertex shader 173 | shaderProgram->setVertexShaderCode(R"(#version 130 174 | in vec3 vertexPosition; 175 | in vec3 vertexColor; 176 | out vec3 color; 177 | uniform mat4 mvp; 178 | uniform mat4 projectionMatrix; 179 | uniform mat4 viewportMatrix; 180 | uniform float pointSize; 181 | void main() 182 | { 183 | color = vertexColor; 184 | gl_Position = mvp * vec4(vertexPosition, 1.0); 185 | gl_PointSize = max(viewportMatrix[1][1] * projectionMatrix[1][1] * pointSize / gl_Position.w, 1.0); 186 | } 187 | )"); 188 | 189 | // set fragment shader 190 | shaderProgram->setFragmentShaderCode(R"(#version 130 191 | in vec3 color; 192 | out vec4 fragColor; 193 | void main(void) 194 | { 195 | fragColor = vec4(color, 1.0); 196 | } 197 | )"); 198 | 199 | // add a pointSize uniform 200 | _pointSizeParameter->setName("pointSize"); 201 | _pointSizeParameter->setValue(_pointSize); 202 | _cloudMaterial->addParameter(_pointSizeParameter); 203 | 204 | // build the material 205 | renderPass->setShaderProgram(shaderProgram); 206 | technique->addRenderPass(renderPass); 207 | effect->addTechnique(technique); 208 | _cloudMaterial->setEffect(effect); 209 | } 210 | { 211 | _colorMaterial = new QPerVertexColorMaterial(this); 212 | } 213 | { 214 | _diffuseMaterial = new QDiffuseSpecularMaterial(this); 215 | _diffuseMaterial->setAmbient(QColor(0, 0, 0)); 216 | _diffuseMaterial->setDiffuse(QColor(255, 255, 255)); 217 | _diffuseMaterial->setSpecular(QColor(0, 0, 0)); 218 | _diffuseMaterial->setShininess(0.0); 219 | } 220 | } 221 | 222 | bool validTriangleRatio(const Vec3f& a, const Vec3f& b, const Vec3f& c) 223 | { 224 | std::vector distances = { 225 | (a - b).size(), 226 | (b - c).size(), 227 | (c - a).size() 228 | }; 229 | double mi = std::min({distances[0], distances[1], distances[2]}); 230 | double ma = std::max({distances[0], distances[1], distances[2]}); 231 | if(ma == 0.0) 232 | return false; 233 | return (mi / ma) > 1.0 / 5.0; 234 | } 235 | 236 | 237 | // private 238 | void DepthMapEntity::loadDepthMap() 239 | { 240 | _status = DepthMapEntity::Loading; 241 | 242 | if(_meshRenderer) 243 | { 244 | removeComponent(_meshRenderer); 245 | _meshRenderer->deleteLater(); 246 | _meshRenderer = nullptr; 247 | } 248 | 249 | qDebug() << "[DepthMapEntity] loadDepthMap"; 250 | if(!_source.isValid()) 251 | { 252 | _status = DepthMapEntity::Error; 253 | return; 254 | } 255 | 256 | qDebug() << "[DepthMapEntity] Load Depth Map: " << _source.toLocalFile(); 257 | 258 | // verify that the file is a valid depthMap based on its metadata 259 | { 260 | const std::string imagePath = _source.toLocalFile().toStdString(); 261 | std::unique_ptr in(oiio::ImageInput::open(imagePath)); 262 | const oiio::ImageSpec& inSpec = in->spec(); 263 | // check for a specific metadata entry 264 | const oiio::ParamValue* param = inSpec.find_attribute("AliceVision:CArr"); 265 | if(!param) 266 | { 267 | _status = DepthMapEntity::Error; 268 | return; 269 | } 270 | } 271 | 272 | using namespace Qt3DRender; 273 | 274 | oiio::ImageSpec configSpec; 275 | // libRAW configuration 276 | configSpec.attribute("raw:auto_bright", 0); // don't want exposure correction 277 | configSpec.attribute("raw:use_camera_wb", 1); // want white balance correction 278 | configSpec.attribute("raw:ColorSpace", "sRGB"); // want colorspace sRGB 279 | configSpec.attribute("raw:use_camera_matrix", 3); // want to use embeded color profile 280 | 281 | oiio::ImageBuf inBuf(_source.toLocalFile().toStdString(), 0, 0, NULL, &configSpec); 282 | const oiio::ImageSpec& inSpec = inBuf.spec(); 283 | 284 | qDebug() << "[DepthMapEntity] Image Size: " << inSpec.width << "x" << inSpec.height; 285 | 286 | point3d CArr; 287 | const oiio::ParamValue * cParam = inSpec.find_attribute("AliceVision:CArr"); // , oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::VEC3)); 288 | if(cParam) 289 | { 290 | qDebug() << "[DepthMapEntity] CArr: " << cParam->nvalues(); 291 | std::copy_n((const double*)cParam->data(), 3, CArr.m); 292 | } 293 | else 294 | { 295 | qDebug() << "[DepthMapEntity] missing metadata CArr."; 296 | } 297 | 298 | matrix3x3 iCamArr; 299 | const oiio::ParamValue * icParam = inSpec.find_attribute("AliceVision:iCamArr", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33)); 300 | if(icParam) 301 | { 302 | qDebug() << "[DepthMapEntity] iCamArr: " << icParam->nvalues(); 303 | std::copy_n((const double*)icParam->data(), 9, iCamArr.m); 304 | } 305 | else 306 | { 307 | qDebug() << "[DepthMapEntity] missing metadata iCamArr."; 308 | } 309 | 310 | const QUrl simPath = QUrl::fromLocalFile(_source.path().replace("depthMap", "simMap")); 311 | oiio::ImageBuf simBuf; 312 | 313 | if(simPath.isValid()) 314 | { 315 | qDebug() << "[DepthMapEntity] Load Sim Map: " << simPath; 316 | simBuf.reset(simPath.toLocalFile().toStdString(), 0, 0, NULL, &configSpec); 317 | } 318 | 319 | const oiio::ImageSpec& simSpec = simBuf.spec(); 320 | const bool validSimMap = (simSpec.width == inSpec.width) && (simSpec.height == inSpec.height); 321 | 322 | oiio::ImageBufAlgo::PixelStats stats; 323 | oiio::ImageBufAlgo::computePixelStats(stats, inBuf); 324 | 325 | std::vector indexPerPixel(inSpec.width * inSpec.height, -1); 326 | std::vector positions; 327 | std::vector colors; 328 | 329 | for(int y = 0; y < inSpec.height; ++y) 330 | { 331 | for(int x = 0; x < inSpec.width; ++x) 332 | { 333 | float depthValue = 0.0f; 334 | inBuf.getpixel(x, y, &depthValue, 1); 335 | if(!isfinite(depthValue) || depthValue <= 0.f) 336 | continue; 337 | 338 | point3d p = CArr + (iCamArr * point2d((double)x, (double)y)).normalize() * depthValue; 339 | Vec3f position(p.x, -p.y, -p.z); 340 | 341 | indexPerPixel[y * inSpec.width + x] = positions.size(); 342 | positions.push_back(position); 343 | 344 | if(validSimMap) 345 | { 346 | float simValue = 0.0f; 347 | simBuf.getpixel(x, y, &simValue, 1); 348 | Color32f color = getColor32fFromJetColorMapClamp(simValue); 349 | colors.push_back(color); 350 | } 351 | else 352 | { 353 | const float range = stats.max[0] - stats.min[0]; 354 | float normalizedDepthValue = range != 0.0f ? (depthValue - stats.min[0]) / range : 1.0f; 355 | Color32f color = getColor32fFromJetColorMapClamp(normalizedDepthValue); 356 | colors.push_back(color); 357 | } 358 | } 359 | } 360 | 361 | qDebug() << "[DepthMapEntity] Valid Depth Values: " << positions.size(); 362 | 363 | // create geometry 364 | QGeometry* customGeometry = new QGeometry; 365 | 366 | // vertices buffer 367 | std::vector trianglesIndexes; 368 | trianglesIndexes.reserve(2*3*positions.size()); 369 | for(int y = 0; y < inSpec.height-1; ++y) 370 | { 371 | for(int x = 0; x < inSpec.width-1; ++x) 372 | { 373 | int pixelIndexA = indexPerPixel[y * inSpec.width + x]; 374 | int pixelIndexB = indexPerPixel[(y + 1) * inSpec.width + x]; 375 | int pixelIndexC = indexPerPixel[(y + 1) * inSpec.width + x + 1]; 376 | int pixelIndexD = indexPerPixel[y * inSpec.width + x + 1]; 377 | if(pixelIndexA != -1 && 378 | pixelIndexB != -1 && 379 | pixelIndexC != -1 && 380 | validTriangleRatio(positions[pixelIndexA], positions[pixelIndexB], positions[pixelIndexC])) 381 | { 382 | trianglesIndexes.push_back(pixelIndexA); 383 | trianglesIndexes.push_back(pixelIndexB); 384 | trianglesIndexes.push_back(pixelIndexC); 385 | } 386 | if(pixelIndexC != -1 && 387 | pixelIndexD != -1 && 388 | pixelIndexA != -1 && 389 | validTriangleRatio(positions[pixelIndexC], positions[pixelIndexD], positions[pixelIndexA])) 390 | { 391 | trianglesIndexes.push_back(pixelIndexC); 392 | trianglesIndexes.push_back(pixelIndexD); 393 | trianglesIndexes.push_back(pixelIndexA); 394 | } 395 | } 396 | } 397 | qDebug() << "[DepthMapEntity] Nb triangles: " << trianglesIndexes.size(); 398 | 399 | std::vector triangles; 400 | triangles.resize(trianglesIndexes.size()); 401 | for(int i = 0; i < trianglesIndexes.size(); ++i) 402 | { 403 | triangles[i] = positions[trianglesIndexes[i]]; 404 | } 405 | std::vector normals; 406 | normals.resize(triangles.size()); 407 | for(int i = 0; i < trianglesIndexes.size(); i+=3) 408 | { 409 | Vec3f normal = cross(triangles[i+1]-triangles[i], triangles[i+2]-triangles[i]); 410 | for(int t = 0; t < 3; ++t) 411 | normals[i+t] = normal; 412 | } 413 | 414 | QBuffer* vertexBuffer = new QBuffer(QBuffer::VertexBuffer); 415 | QByteArray trianglesData((const char*)&triangles[0], triangles.size() * sizeof(Vec3f)); 416 | vertexBuffer->setData(trianglesData); 417 | 418 | QBuffer* normalBuffer = new QBuffer(QBuffer::VertexBuffer); 419 | QByteArray normalsData((const char*)&normals[0], normals.size() * sizeof(Vec3f)); 420 | normalBuffer->setData(normalsData); 421 | 422 | QAttribute* positionAttribute = new QAttribute(this); 423 | positionAttribute->setName(QAttribute::defaultPositionAttributeName()); 424 | positionAttribute->setAttributeType(QAttribute::VertexAttribute); 425 | positionAttribute->setBuffer(vertexBuffer); 426 | positionAttribute->setDataType(QAttribute::Float); 427 | positionAttribute->setDataSize(3); 428 | positionAttribute->setByteOffset(0); 429 | positionAttribute->setByteStride(sizeof(Vec3f)); 430 | positionAttribute->setCount(triangles.size()); 431 | 432 | QAttribute* normalAttribute = new QAttribute(this); 433 | normalAttribute->setName(QAttribute::defaultNormalAttributeName()); 434 | normalAttribute->setAttributeType(Qt3DRender::QAttribute::VertexAttribute); 435 | normalAttribute->setBuffer(normalBuffer); 436 | normalAttribute->setDataType(QAttribute::Float); 437 | normalAttribute->setDataSize(3); 438 | normalAttribute->setByteOffset(0); 439 | normalAttribute->setByteStride(sizeof(Vec3f)); 440 | normalAttribute->setCount(normals.size()); 441 | 442 | customGeometry->addAttribute(positionAttribute); 443 | customGeometry->addAttribute(normalAttribute); 444 | // customGeometry->setBoundingVolumePositionAttribute(positionAttribute); 445 | 446 | // Duplicate colors as we cannot use indexes! 447 | std::vector colorsFlat; 448 | colorsFlat.reserve(trianglesIndexes.size()); 449 | for(int i = 0; i < trianglesIndexes.size(); ++i) 450 | { 451 | colorsFlat.push_back(colors[trianglesIndexes[i]]); 452 | } 453 | 454 | // read color data 455 | QBuffer* colorDataBuffer = new QBuffer(QBuffer::VertexBuffer); 456 | QByteArray colorData((const char*)colorsFlat[0].m, colorsFlat.size() * 3 * sizeof(float)); 457 | colorDataBuffer->setData(colorData); 458 | 459 | QAttribute* colorAttribute = new QAttribute; 460 | qDebug() << "Qt3DRender::QAttribute::defaultColorAttributeName(): " << Qt3DRender::QAttribute::defaultColorAttributeName(); 461 | colorAttribute->setName(Qt3DRender::QAttribute::defaultColorAttributeName()); 462 | colorAttribute->setAttributeType(QAttribute::VertexAttribute); 463 | colorAttribute->setBuffer(colorDataBuffer); 464 | colorAttribute->setDataType(QAttribute::Float); 465 | colorAttribute->setDataSize(3); 466 | colorAttribute->setByteOffset(0); 467 | colorAttribute->setByteStride(3 * sizeof(float)); 468 | colorAttribute->setCount(colorsFlat.size()); 469 | customGeometry->addAttribute(colorAttribute); 470 | 471 | // create the geometry renderer 472 | _meshRenderer = new QGeometryRenderer; 473 | _meshRenderer->setGeometry(customGeometry); 474 | 475 | _status = DepthMapEntity::Ready; 476 | 477 | // add components 478 | addComponent(_meshRenderer); 479 | updateMaterial(); 480 | qDebug() << "DepthMapEntity: Mesh Renderer added."; 481 | } 482 | 483 | } // namespace 484 | -------------------------------------------------------------------------------- /src/depthMapEntity/DepthMapEntity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace depthMapEntity { 15 | 16 | class DepthMapEntity : public Qt3DCore::QEntity 17 | { 18 | Q_OBJECT 19 | Q_ENUMS(DisplayMode) 20 | 21 | Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged); 22 | Q_PROPERTY(Status status READ status NOTIFY statusChanged) 23 | Q_PROPERTY(DisplayMode displayMode READ displayMode WRITE setDisplayMode NOTIFY displayModeChanged); 24 | Q_PROPERTY(bool displayColor READ displayColor WRITE setDisplayColor NOTIFY displayColorChanged); 25 | Q_PROPERTY(float pointSize READ pointSize WRITE setPointSize NOTIFY pointSizeChanged); 26 | 27 | public: 28 | 29 | // Identical to SceneLoader.Status 30 | enum Status { 31 | None = 0, 32 | Loading, 33 | Ready, 34 | Error 35 | }; 36 | Q_ENUM(Status) 37 | 38 | DepthMapEntity(Qt3DCore::QNode* = nullptr); 39 | ~DepthMapEntity() = default; 40 | 41 | enum class DisplayMode { 42 | Points, 43 | Triangles, 44 | Unknown 45 | }; 46 | 47 | public: 48 | Q_SLOT const QUrl& source() const { return _source; } 49 | Q_SLOT void setSource(const QUrl&); 50 | 51 | Status status() const { return _status; } 52 | 53 | void setStatus(Status status) { 54 | if(status == _status) 55 | return; 56 | _status = status; 57 | Q_EMIT statusChanged(_status); 58 | } 59 | 60 | Q_SLOT DisplayMode displayMode() const { return _displayMode; } 61 | Q_SLOT void setDisplayMode(const DisplayMode&); 62 | 63 | Q_SLOT bool displayColor() const { return _displayColor; } 64 | Q_SLOT void setDisplayColor(bool); 65 | 66 | Q_SLOT float pointSize() const { return _pointSize; } 67 | Q_SLOT void setPointSize(const float& value); 68 | 69 | private: 70 | void loadDepthMap(); 71 | void createMaterials(); 72 | void updateMaterial(); 73 | 74 | public: 75 | Q_SIGNAL void sourceChanged(); 76 | Q_SIGNAL void statusChanged(Status status); 77 | Q_SIGNAL void displayModeChanged(); 78 | Q_SIGNAL void displayColorChanged(); 79 | Q_SIGNAL void pointSizeChanged(); 80 | 81 | private: 82 | Status _status = DepthMapEntity::None; 83 | QUrl _source; 84 | DisplayMode _displayMode = DisplayMode::Triangles; 85 | bool _displayColor = true; 86 | float _pointSize = 0.5f; 87 | Qt3DRender::QParameter* _pointSizeParameter; 88 | Qt3DRender::QMaterial* _cloudMaterial; 89 | Qt3DExtras::QDiffuseSpecularMaterial* _diffuseMaterial; 90 | Qt3DExtras::QPerVertexColorMaterial* _colorMaterial; 91 | Qt3DRender::QMaterial* _currentMaterial = nullptr; 92 | Qt3DRender::QGeometryRenderer* _meshRenderer = nullptr; 93 | }; 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/depthMapEntity/mv_matrix3x3.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of the AliceVision project. 2 | // This Source Code Form is subject to the terms of the Mozilla Public License, 3 | // v. 2.0. If a copy of the MPL was not distributed with this file, 4 | // You can obtain one at https://mozilla.org/MPL/2.0/. 5 | 6 | #pragma once 7 | 8 | #include "mv_point2d.hpp" 9 | #include "mv_point3d.hpp" 10 | 11 | #include 12 | 13 | 14 | class matrix3x3 15 | { 16 | public: 17 | union { 18 | struct 19 | { 20 | double m11, m12, m13, m21, m22, m23, m31, m32, m33; 21 | }; 22 | double m[9]; 23 | }; 24 | 25 | inline matrix3x3() 26 | { 27 | m11 = 0.0; 28 | m12 = 0.0; 29 | m13 = 0.0; 30 | m21 = 0.0; 31 | m22 = 0.0; 32 | m23 = 0.0; 33 | m31 = 0.0; 34 | m32 = 0.0; 35 | m33 = 0.0; 36 | } 37 | 38 | inline matrix3x3& operator=(const matrix3x3& m) = default; 39 | 40 | inline matrix3x3 operator-(double d) const 41 | { 42 | matrix3x3 m; 43 | m.m11 = m11 - d; 44 | m.m12 = m12 - d; 45 | m.m13 = m13 - d; 46 | m.m21 = m21 - d; 47 | m.m22 = m22 - d; 48 | m.m23 = m23 - d; 49 | m.m31 = m31 - d; 50 | m.m32 = m32 - d; 51 | m.m33 = m33 - d; 52 | 53 | return m; 54 | } 55 | 56 | inline matrix3x3 operator/(double d) const 57 | { 58 | matrix3x3 m; 59 | m.m11 = m11 / d; 60 | m.m12 = m12 / d; 61 | m.m13 = m13 / d; 62 | m.m21 = m21 / d; 63 | m.m22 = m22 / d; 64 | m.m23 = m23 / d; 65 | m.m31 = m31 / d; 66 | m.m32 = m32 / d; 67 | m.m33 = m33 / d; 68 | 69 | return m; 70 | } 71 | 72 | inline matrix3x3 operator-() const 73 | { 74 | matrix3x3 m; 75 | m.m11 = -m11; 76 | m.m12 = -m12; 77 | m.m13 = -m13; 78 | m.m21 = -m21; 79 | m.m22 = -m22; 80 | m.m23 = -m23; 81 | m.m31 = -m31; 82 | m.m32 = -m32; 83 | m.m33 = -m33; 84 | 85 | return m; 86 | } 87 | 88 | inline matrix3x3 operator-(const matrix3x3& M) const 89 | { 90 | matrix3x3 m; 91 | m.m11 = m11 - M.m11; 92 | m.m12 = m12 - M.m12; 93 | m.m13 = m13 - M.m13; 94 | m.m21 = m21 - M.m21; 95 | m.m22 = m22 - M.m22; 96 | m.m23 = m23 - M.m23; 97 | m.m31 = m31 - M.m31; 98 | m.m32 = m32 - M.m32; 99 | m.m33 = m33 - M.m33; 100 | 101 | return m; 102 | } 103 | 104 | inline matrix3x3 operator*(const matrix3x3& _m) const 105 | { 106 | matrix3x3 m; 107 | m.m11 = m11 * _m.m11 + m12 * _m.m21 + m13 * _m.m31; 108 | m.m12 = m11 * _m.m12 + m12 * _m.m22 + m13 * _m.m32; 109 | m.m13 = m11 * _m.m13 + m12 * _m.m23 + m13 * _m.m33; 110 | 111 | m.m21 = m21 * _m.m11 + m22 * _m.m21 + m23 * _m.m31; 112 | m.m22 = m21 * _m.m12 + m22 * _m.m22 + m23 * _m.m32; 113 | m.m23 = m21 * _m.m13 + m22 * _m.m23 + m23 * _m.m33; 114 | 115 | m.m31 = m31 * _m.m11 + m32 * _m.m21 + m33 * _m.m31; 116 | m.m32 = m31 * _m.m12 + m32 * _m.m22 + m33 * _m.m32; 117 | m.m33 = m31 * _m.m13 + m32 * _m.m23 + m33 * _m.m33; 118 | 119 | return m; 120 | } 121 | 122 | inline matrix3x3 transpose() const 123 | { 124 | matrix3x3 m; 125 | m.m11 = m11; 126 | m.m12 = m21; 127 | m.m13 = m31; 128 | m.m21 = m12; 129 | m.m22 = m22; 130 | m.m23 = m32; 131 | m.m31 = m13; 132 | m.m32 = m23; 133 | m.m33 = m33; 134 | 135 | return m; 136 | } 137 | 138 | inline double deteminant() const 139 | { 140 | return m11 * m22 * m33 - m11 * m23 * m32 - m12 * m21 * m33 + m12 * m23 * m31 + m13 * m21 * m32 - m13 * m22 * m31; 141 | } 142 | 143 | inline bool isSingular() const 144 | { 145 | return (deteminant() == 0.0f); 146 | } 147 | 148 | inline double det() const 149 | { 150 | return m11 * (m33 * m22 - m32 * m23) - m21 * (m33 * m12 - m32 * m13) + m31 * (m23 * m12 - m22 * m13); 151 | } 152 | 153 | inline matrix3x3 inverse() const 154 | { 155 | matrix3x3 m; 156 | inverse(m); 157 | return m; 158 | } 159 | 160 | inline void QR(matrix3x3& Q, matrix3x3& R) 161 | { 162 | /* 163 | point3d a1 = point3d(m13,m23,m33); 164 | point3d a2 = point3d(m12,m22,m32); 165 | point3d a3 = point3d(m11,m21,m31); 166 | */ 167 | 168 | /* 169 | point3d a1 = point3d(m11,m21,m31); 170 | point3d a2 = point3d(m12,m22,m32); 171 | point3d a3 = point3d(m13,m23,m33); 172 | */ 173 | 174 | /* 175 | point3d a1 = point3d(m31,m32,m33); 176 | point3d a2 = point3d(m21,m22,m23); 177 | point3d a3 = point3d(m11,m12,m13); 178 | */ 179 | 180 | point3d a1 = point3d(m11, m12, m13); 181 | point3d a2 = point3d(m21, m22, m23); 182 | point3d a3 = point3d(m31, m32, m33); 183 | 184 | point3d u1 = a1; 185 | point3d e1 = u1.normalize(); 186 | point3d u2 = a2 - proj(e1, a2); 187 | point3d e2 = u2.normalize(); 188 | point3d u3 = a3 - proj(e1, a3) - proj(e2, a3); 189 | point3d e3 = u3.normalize(); 190 | 191 | Q.m11 = e1.x; 192 | Q.m12 = e1.y; 193 | Q.m13 = e1.z; 194 | Q.m21 = e2.x; 195 | Q.m22 = e2.y; 196 | Q.m23 = e2.z; 197 | Q.m31 = e3.x; 198 | Q.m32 = e3.y; 199 | Q.m33 = e3.z; 200 | 201 | R.m11 = dot(e1, a1); 202 | R.m12 = dot(e1, a2); 203 | R.m13 = dot(e1, a3); 204 | R.m21 = 0.0f; 205 | R.m22 = dot(e2, a2); 206 | R.m23 = dot(e2, a3); 207 | R.m31 = 0.0f; 208 | R.m32 = 0.0f; 209 | R.m33 = dot(e3, a3); 210 | } 211 | 212 | inline matrix3x3 transpodeAndEnd1End1() 213 | { 214 | matrix3x3 S = transpose(); 215 | matrix3x3 SS; 216 | SS.m11 = S.m33; 217 | SS.m12 = S.m32; 218 | SS.m13 = S.m31; 219 | SS.m21 = S.m23; 220 | SS.m22 = S.m22; 221 | SS.m23 = S.m21; 222 | SS.m31 = S.m13; 223 | SS.m32 = S.m12; 224 | SS.m33 = S.m11; 225 | return SS; 226 | } 227 | 228 | inline void RQ(matrix3x3& R, matrix3x3& Q) 229 | { 230 | /* 231 | matrix3x3 S = transpodeAndEnd1End1(); 232 | 233 | 234 | printf("S\n"); 235 | S.doprintf(); 236 | 237 | S.QR(Q, R); 238 | 239 | printf("R\n"); 240 | R.doprintf(); 241 | printf("Q\n"); 242 | Q.doprintf(); 243 | 244 | 245 | Q = Q.transpodeAndEnd1End1(); 246 | R = R.transpodeAndEnd1End1(); 247 | 248 | if (Q.deteminant()<0.0f) 249 | { 250 | R.m11 = -R.m11; 251 | R.m21 = -R.m21; 252 | R.m31 = -R.m31; 253 | 254 | Q.m11 = -Q.m11; 255 | Q.m12 = -Q.m12; 256 | Q.m13 = -Q.m13; 257 | }; 258 | */ 259 | 260 | point3d a1 = point3d(m31, m32, m33); 261 | point3d a2 = point3d(m21, m22, m23); 262 | point3d a3 = point3d(m11, m12, m13); 263 | 264 | point3d u1 = a1; 265 | point3d e1 = u1.normalize(); 266 | point3d u2 = a2 - proj(e1, a2); 267 | point3d e2 = u2.normalize(); 268 | point3d u3 = a3 - proj(e1, a3) - proj(e2, a3); 269 | point3d e3 = u3.normalize(); 270 | 271 | Q.m11 = e3.x; 272 | Q.m12 = e3.y; 273 | Q.m13 = e3.z; 274 | Q.m21 = e2.x; 275 | Q.m22 = e2.y; 276 | Q.m23 = e2.z; 277 | Q.m31 = e1.x; 278 | Q.m32 = e1.y; 279 | Q.m33 = e1.z; 280 | 281 | R.m11 = dot(e1, a1); 282 | R.m12 = dot(e1, a2); 283 | R.m13 = dot(e1, a3); 284 | R.m21 = 0.0f; 285 | R.m22 = dot(e2, a2); 286 | R.m23 = dot(e2, a3); 287 | R.m31 = 0.0f; 288 | R.m32 = 0.0f; 289 | R.m33 = dot(e3, a3); 290 | 291 | matrix3x3 RR = R; 292 | R.m11 = RR.m33; 293 | R.m12 = RR.m23; 294 | R.m13 = RR.m13; 295 | R.m21 = RR.m32; 296 | R.m22 = RR.m22; 297 | R.m23 = RR.m12; 298 | R.m31 = RR.m31; 299 | R.m32 = RR.m21; 300 | R.m33 = RR.m11; 301 | } 302 | 303 | inline bool inverse(matrix3x3& m) const 304 | { 305 | double dt = det(); 306 | 307 | if((fabs(dt) < 0.00000001f) || std::isnan(dt)) 308 | { 309 | return false; 310 | } 311 | 312 | m.m11 = (m33 * m22 - m32 * m23) / dt; 313 | m.m12 = -(m33 * m12 - m32 * m13) / dt; 314 | m.m13 = (m23 * m12 - m22 * m13) / dt; 315 | m.m21 = -(m33 * m21 - m31 * m23) / dt; 316 | m.m22 = (m33 * m11 - m31 * m13) / dt; 317 | m.m23 = -(m23 * m11 - m21 * m13) / dt; 318 | m.m31 = (m32 * m21 - m31 * m22) / dt; 319 | m.m32 = -(m32 * m11 - m31 * m12) / dt; 320 | m.m33 = (m22 * m11 - m21 * m12) / dt; 321 | 322 | return true; 323 | 324 | /* 325 | | m11 m12 m13 |-1 | m33m22-m32m23 -(m33m12-m32m13) m23m12-m22m13 | 326 | | m21 m22 m23 | = 1/DET * | -(m33m21-m31m23) m33m11-m31m13 -(m23m11-m21m13) | 327 | | m31 m32 m33 | | m32m21-m31m22 -(m32m11-m31m12) m22m11-m21m12 | 328 | 329 | with DET = m11(m33m22-m32m23)-m21(m33m12-m32m13)+m31(m23m12-m22m13) 330 | */ 331 | 332 | /* 333 | double mem[9]; 334 | mem[0] = (double)m11; mem[1] = (double)m12; mem[2] = (double)m13; 335 | mem[3] = (double)m21; mem[4] = (double)m22; mem[5] = (double)m23; 336 | mem[6] = (double)m31; mem[7] = (double)m32; mem[8] = (double)m33; 337 | 338 | Matrix K(mem, 3, 3); 339 | Matrix KK = K; 340 | Matrix iK = KK.Inversed(); 341 | 342 | 343 | matrix3x3 m; 344 | m.m11 = (double)iK.M(1,1); 345 | m.m12 = (double)iK.M(1,2); 346 | m.m13 = (double)iK.M(1,3); 347 | m.m21 = (double)iK.M(2,1); 348 | m.m22 = (double)iK.M(2,2); 349 | m.m23 = (double)iK.M(2,3); 350 | m.m31 = (double)iK.M(3,1); 351 | m.m32 = (double)iK.M(3,2); 352 | m.m33 = (double)iK.M(3,3); 353 | 354 | K.Detach(); 355 | 356 | return m; 357 | */ 358 | } 359 | 360 | void doprintf() const 361 | { 362 | printf("%f %f %f\n", m11, m12, m13); 363 | printf("%f %f %f\n", m21, m22, m23); 364 | printf("%f %f %f\n", m31, m32, m33); 365 | } 366 | }; 367 | 368 | inline matrix3x3 I3x3() 369 | { 370 | matrix3x3 m; 371 | m.m11 = 1.0; 372 | m.m12 = 0.0; 373 | m.m13 = 0.0; 374 | 375 | m.m21 = 0.0; 376 | m.m22 = 1.0; 377 | m.m23 = 0.0; 378 | 379 | m.m31 = 0.0; 380 | m.m32 = 0.0; 381 | m.m33 = 1.0; 382 | 383 | return m; 384 | } 385 | 386 | inline matrix3x3 diag3x3(double d1, double d2, double d3) 387 | { 388 | matrix3x3 m; 389 | m.m11 = d1; 390 | m.m12 = 0.0; 391 | m.m13 = 0.0; 392 | 393 | m.m21 = 0.0; 394 | m.m22 = d2; 395 | m.m23 = 0.0; 396 | 397 | m.m31 = 0.0; 398 | m.m32 = 0.0; 399 | m.m33 = d3; 400 | 401 | return m; 402 | } 403 | 404 | inline matrix3x3 angRad2rot(float radx, float rady, float radz) 405 | { 406 | float angx = radx; 407 | float angy = rady; 408 | float angz = radz; 409 | 410 | float sa = sin(angy); 411 | float ca = cos(angy); 412 | float sb = sin(angx); 413 | float cb = cos(angx); 414 | float sc = sin(angz); 415 | float cc = cos(angz); 416 | 417 | matrix3x3 ra; 418 | ra.m11 = ca; 419 | ra.m12 = sa; 420 | ra.m13 = 0.0f; 421 | ra.m21 = -sa; 422 | ra.m22 = ca; 423 | ra.m23 = 0.0f; 424 | ra.m31 = 0.0f; 425 | ra.m32 = 0.0f; 426 | ra.m33 = 1.0f; 427 | 428 | matrix3x3 rb; 429 | rb.m11 = cb; 430 | rb.m12 = 0.0f; 431 | rb.m13 = sb; 432 | rb.m21 = 0.0f; 433 | rb.m22 = 1.0f; 434 | rb.m23 = 0.0f; 435 | rb.m31 = -sb; 436 | rb.m32 = 0.0f; 437 | rb.m33 = cb; 438 | 439 | matrix3x3 rc; 440 | rc.m11 = 1.0f; 441 | rc.m12 = 0.0f; 442 | rc.m13 = 0.0f; 443 | rc.m21 = 0.0f; 444 | rc.m22 = cc; 445 | rc.m23 = sc; 446 | rc.m31 = 0.0f; 447 | rc.m32 = -sc; 448 | rc.m33 = cc; 449 | 450 | return rc * rb * ra; 451 | } 452 | 453 | inline point3d operator*(const matrix3x3& M, const point2d& _p) 454 | { 455 | point3d p; 456 | p.x = M.m11 * _p.x + M.m12 * _p.y + M.m13; 457 | p.y = M.m21 * _p.x + M.m22 * _p.y + M.m23; 458 | p.z = M.m31 * _p.x + M.m32 * _p.y + M.m33; 459 | return p; 460 | } 461 | 462 | -------------------------------------------------------------------------------- /src/depthMapEntity/mv_point2d.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of the AliceVision project. 2 | // This Source Code Form is subject to the terms of the Mozilla Public License, 3 | // v. 2.0. If a copy of the MPL was not distributed with this file, 4 | // You can obtain one at https://mozilla.org/MPL/2.0/. 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 11 | class point2d 12 | { 13 | public: 14 | union { 15 | struct 16 | { 17 | double x, y; 18 | }; 19 | double m[2]; 20 | }; 21 | 22 | inline point2d() 23 | { 24 | x = 0.0; 25 | y = 0.0; 26 | } 27 | 28 | inline point2d(const double _x, const double _y) 29 | { 30 | x = _x; 31 | y = _y; 32 | } 33 | 34 | inline point2d(const int _x, const int _y) 35 | { 36 | x = (double)_x; 37 | y = (double)_y; 38 | } 39 | 40 | inline point2d& operator=(const point2d& param) 41 | { 42 | x = param.x; 43 | y = param.y; 44 | return *this; 45 | } 46 | 47 | inline point2d operator-(const point2d& _p) const 48 | { 49 | return point2d(x - _p.x, y - _p.y); 50 | } 51 | 52 | inline point2d operator+(const point2d& _p) const 53 | { 54 | return point2d(x + _p.x, y + _p.y); 55 | } 56 | 57 | inline point2d operator*(const double d) const 58 | { 59 | return point2d(x * d, y * d); 60 | } 61 | 62 | inline point2d operator+(const double d) const 63 | { 64 | return point2d(x + d, y + d); 65 | } 66 | 67 | inline point2d operator/(const double d) const 68 | { 69 | return point2d(x / d, y / d); 70 | } 71 | 72 | inline point2d normalize() const 73 | { 74 | double d = std::sqrt(x * x + y * y); 75 | return point2d(x / d, y / d); 76 | } 77 | 78 | inline double size() const 79 | { 80 | return std::sqrt(x * x + y * y); 81 | } 82 | 83 | friend double dot(const point2d& p1, const point2d& p2); 84 | }; 85 | 86 | inline double dot(const point2d& p1, const point2d& p2) 87 | { 88 | return p1.x * p2.x + p1.y * p2.y; 89 | } 90 | -------------------------------------------------------------------------------- /src/depthMapEntity/mv_point3d.hpp: -------------------------------------------------------------------------------- 1 | // This file is part of the AliceVision project. 2 | // This Source Code Form is subject to the terms of the Mozilla Public License, 3 | // v. 2.0. If a copy of the MPL was not distributed with this file, 4 | // You can obtain one at https://mozilla.org/MPL/2.0/. 5 | 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 12 | class point3d 13 | { 14 | public: 15 | union { 16 | struct 17 | { 18 | double x, y, z; 19 | }; 20 | double m[3]; 21 | }; 22 | 23 | inline point3d() 24 | { 25 | x = 0.0; 26 | y = 0.0; 27 | z = 0.0; 28 | } 29 | 30 | inline point3d(double _x, double _y, double _z) 31 | { 32 | x = _x; 33 | y = _y; 34 | z = _z; 35 | } 36 | 37 | inline point3d& operator=(const point3d& param) 38 | { 39 | x = param.x; 40 | y = param.y; 41 | z = param.z; 42 | return *this; 43 | } 44 | 45 | inline bool operator==(const point3d& param) 46 | { 47 | return (x == param.x) && (y == param.y) && (z == param.z); 48 | } 49 | 50 | inline point3d operator-(const point3d& _p) const 51 | { 52 | return point3d(x - _p.x, y - _p.y, z - _p.z); 53 | } 54 | 55 | inline point3d operator-() const 56 | { 57 | return point3d(-x, -y, -z); 58 | } 59 | 60 | inline point3d operator+(const point3d& _p) const 61 | { 62 | return point3d(x + _p.x, y + _p.y, z + _p.z); 63 | } 64 | 65 | inline point3d operator*(const double d) const 66 | { 67 | return point3d(x * d, y * d, z * d); 68 | } 69 | 70 | inline point3d operator/(const double d) const 71 | { 72 | return point3d(x / d, y / d, z / d); 73 | } 74 | 75 | inline point3d normalize() const 76 | { 77 | double d = std::sqrt(x * x + y * y + z * z); 78 | return point3d(x / d, y / d, z / d); 79 | } 80 | 81 | inline double size() const 82 | { 83 | double d = x * x + y * y + z * z; 84 | if(d == 0.0) 85 | { 86 | return 0.0; 87 | } 88 | 89 | return sqrt(d); 90 | } 91 | 92 | inline double size2() const 93 | { 94 | return x * x + y * y + z * z; 95 | } 96 | 97 | void doprintf() const 98 | { 99 | printf("%f %f %f\n", x, y, z); 100 | } 101 | 102 | friend double dot(const point3d& p1, const point3d& p2); 103 | friend point3d cross(const point3d& a, const point3d& b); 104 | friend point3d proj(point3d& e, point3d& a); 105 | }; 106 | 107 | inline double dot(const point3d& p1, const point3d& p2) 108 | { 109 | return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z; 110 | } 111 | 112 | inline point3d cross(const point3d& a, const point3d& b) 113 | { 114 | point3d vc; 115 | vc.x = a.y * b.z - a.z * b.y; 116 | vc.y = a.z * b.x - a.x * b.z; 117 | vc.z = a.x * b.y - a.y * b.x; 118 | 119 | return vc; 120 | } 121 | 122 | inline point3d proj(point3d& e, point3d& a) 123 | { 124 | return e * (dot(e, a) / dot(e, e)); 125 | } 126 | 127 | inline double pointLineDistance3D(const point3d& point, const point3d& linePoint, const point3d& lineVectNormalized) 128 | { 129 | return cross(lineVectNormalized, linePoint - point).size(); 130 | } 131 | -------------------------------------------------------------------------------- /src/depthMapEntity/plugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DepthMapEntity.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace depthMapEntity { 9 | 10 | class DepthMapEntityQmlPlugin : public QQmlExtensionPlugin 11 | { 12 | Q_OBJECT 13 | Q_PLUGIN_METADATA(IID "depthMapEntity.qmlPlugin") 14 | 15 | public: 16 | void initializeEngine(QQmlEngine* engine, const char* uri) override {} 17 | void registerTypes(const char* uri) override 18 | { 19 | Q_ASSERT(uri == QLatin1String("DepthMapEntity")); 20 | qmlRegisterType(uri, 2, 1, "DepthMapEntity"); 21 | } 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/depthMapEntity/qmldir: -------------------------------------------------------------------------------- 1 | module DepthMapEntity 2 | 3 | plugin depthMapEntityQmlPlugin 4 | -------------------------------------------------------------------------------- /src/imageIOHandler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES_files_QtOIIO 2 | QtOIIOHandler.cpp 3 | QtOIIOHandler.hpp 4 | QtOIIOPlugin.cpp 5 | QtOIIOPlugin.hpp 6 | ) 7 | source_group("QtOIIO" FILES ${SOURCES_files_QtOIIO}) 8 | 9 | add_library(QtOIIOPlugin 10 | SHARED 11 | ${SOURCES_files_QtOIIO} 12 | ) 13 | 14 | target_link_libraries(QtOIIOPlugin 15 | PUBLIC 16 | OpenImageIO::OpenImageIO 17 | Qt${QT_VERSION_MAJOR}::Core 18 | Qt${QT_VERSION_MAJOR}::Gui 19 | ) 20 | 21 | install(TARGETS QtOIIOPlugin DESTINATION imageformats) 22 | -------------------------------------------------------------------------------- /src/imageIOHandler/QtOIIOHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "QtOIIOHandler.hpp" 2 | 3 | #include "../jetColorMap.hpp" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | namespace oiio = OIIO; 20 | 21 | inline const float& clamp( const float& v, const float& lo, const float& hi ) 22 | { 23 | assert( !(hi < lo) ); 24 | return (v < lo) ? lo : (hi < v) ? hi : v; 25 | } 26 | 27 | inline unsigned short floatToUShort(float v) 28 | { 29 | return clamp(v, 0.0f, 1.0f) * 65535; 30 | } 31 | 32 | QtOIIOHandler::QtOIIOHandler() 33 | { 34 | qDebug() << "[QtOIIO] QtOIIOHandler"; 35 | } 36 | 37 | QtOIIOHandler::~QtOIIOHandler() 38 | { 39 | } 40 | 41 | bool QtOIIOHandler::canRead() const 42 | { 43 | if(canRead(device())) 44 | { 45 | setFormat("OpenImageIO"); 46 | return true; 47 | } 48 | return false; 49 | } 50 | 51 | bool QtOIIOHandler::canRead(QIODevice *device) 52 | { 53 | QFileDevice* d = dynamic_cast(device); 54 | if(d) 55 | { 56 | // qDebug() << "[QtOIIO] Can read file: " << d->fileName().toStdString(); 57 | return true; 58 | } 59 | // qDebug() << "[QtOIIO] Cannot read."; 60 | return false; 61 | } 62 | 63 | bool QtOIIOHandler::read(QImage *image) 64 | { 65 | bool convertGrayscaleToJetColorMap = true; // how to expose it as an option? 66 | 67 | // qDebug() << "[QtOIIO] Read Image"; 68 | QFileDevice* d = dynamic_cast(device()); 69 | if(!d) 70 | { 71 | qWarning() << "[QtOIIO] Read image failed (not a FileDevice)."; 72 | return false; 73 | } 74 | const std::string path = d->fileName().toStdString(); 75 | 76 | qInfo() << "[QtOIIO] Read image: " << path.c_str(); 77 | // check requested channels number 78 | // assert(nchannels == 1 || nchannels >= 3); 79 | 80 | oiio::ImageSpec configSpec; 81 | // libRAW configuration 82 | //configSpec.attribute("raw:user_flip", 0); 83 | configSpec.attribute("raw:auto_bright", 0); // don't want exposure correction 84 | configSpec.attribute("raw:use_camera_wb", 1); // want white balance correction 85 | #if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8 86 | // In these previous versions of oiio, there was no Linear option 87 | configSpec.attribute("raw:ColorSpace", "sRGB"); // want colorspace sRGB 88 | #else 89 | configSpec.attribute("raw:ColorSpace", "Linear"); // want linear colorspace with sRGB primaries 90 | #endif 91 | configSpec.attribute("raw:use_camera_matrix", 3); // want to use embeded color profile 92 | 93 | oiio::ImageBuf inBuf(path, 0, 0, NULL, &configSpec); 94 | 95 | if(!inBuf.initialized()) 96 | throw std::runtime_error("Can't find/open image file '" + path + "'."); 97 | 98 | #if OIIO_VERSION <= (10000 * 2 + 100 * 0 + 8) // OIIO_VERSION <= 2.0.8 99 | // Workaround for bug in RAW colorspace management in previous versions of OIIO: 100 | // When asking sRGB we got sRGB primaries with linear gamma, 101 | // but oiio::ColorSpace was wrongly set to sRGB. 102 | oiio::ImageSpec inSpec = inBuf.spec(); 103 | if(inSpec.get_string_attribute("oiio:ColorSpace", "") == "sRGB") 104 | { 105 | const auto in = oiio::ImageInput::open(path, nullptr); 106 | const std::string formatStr = in->format_name(); 107 | if(formatStr == "raw") 108 | { 109 | // For the RAW plugin: override colorspace as linear (as the content is linear with sRGB primaries but declared as sRGB) 110 | inSpec.attribute("oiio:ColorSpace", "Linear"); 111 | qDebug() << "OIIO workaround: RAW input image " << QString::fromStdString(path) << " is in Linear."; 112 | } 113 | } 114 | #else 115 | const oiio::ImageSpec& inSpec = inBuf.spec(); 116 | #endif 117 | float pixelAspectRatio = inSpec.get_float_attribute("PixelAspectRatio", 1.0f); 118 | 119 | qInfo() << "[QtOIIO] width:" << inSpec.width << ", height:" << inSpec.height << ", nchannels:" << inSpec.nchannels << ", format:" << inSpec.format.c_str(); 120 | 121 | if(inSpec.nchannels >= 3) 122 | { 123 | // Color conversion to sRGB 124 | const std::string& colorSpace = inSpec.get_string_attribute("oiio:ColorSpace", "sRGB"); // default image color space is sRGB 125 | 126 | if(colorSpace != "sRGB") // color conversion to sRGB 127 | { 128 | oiio::ImageBufAlgo::colorconvert(inBuf, inBuf, colorSpace, "sRGB"); 129 | qDebug() << "Convert image " << QString::fromStdString(path) << " from " << QString::fromStdString(colorSpace) << " to sRGB colorspace"; 130 | } 131 | } 132 | 133 | int nchannels = 0; 134 | const bool moreThan8Bits = inSpec.format != oiio::TypeDesc::UINT8 && inSpec.format != oiio::TypeDesc::INT8; 135 | QImage::Format format = QImage::NImageFormats; 136 | if(inSpec.nchannels == 4) 137 | { 138 | if(moreThan8Bits) 139 | format = QImage::Format_RGBA64; // Qt documentation: The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12) 140 | else 141 | format = QImage::Format_ARGB32; // Qt documentation: The image is stored using a 32-bit ARGB format (0xAARRGGBB). 142 | nchannels = 4; 143 | } 144 | else if(inSpec.nchannels == 3) 145 | { 146 | if(moreThan8Bits) 147 | format = QImage::Format_RGBX64; // Qt documentation: The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16). This is the same as the Format_RGBA64 except alpha must always be 65535. (added in Qt 5.12) 148 | else 149 | format = QImage::Format_RGB32; // Qt documentation: The image is stored using a 32-bit RGB format (0xffRRGGBB). 150 | nchannels = 4; 151 | } 152 | else if(inSpec.nchannels == 1) 153 | { 154 | if(convertGrayscaleToJetColorMap) 155 | { 156 | format = QImage::Format_RGB32; // Qt documentation: The image is stored using a 32-bit RGB format (0xffRRGGBB). 157 | nchannels = 4; 158 | } 159 | else 160 | { 161 | if(moreThan8Bits) 162 | format = QImage::Format_Grayscale16; // Qt documentation: The image is stored using an 16-bit grayscale format. (added in Qt 5.13) 163 | else 164 | format = QImage::Format_Grayscale8; // Qt documentation: The image is stored using an 8-bit grayscale format. 165 | nchannels = 1; 166 | } 167 | } 168 | else 169 | { 170 | qWarning() << "[QtOIIO] failed to load \"" << path.c_str() << "\", nchannels=" << inSpec.nchannels; 171 | return false; 172 | } 173 | 174 | { 175 | std::string formatStr; 176 | switch(format) 177 | { 178 | case QImage::Format_RGBA64: formatStr = "Format_RGBA64"; break; 179 | case QImage::Format_ARGB32: formatStr = "Format_ARGB32"; break; 180 | case QImage::Format_RGBX64: formatStr = "Format_RGBX64"; break; 181 | case QImage::Format_RGB32: formatStr = "Format_RGB32"; break; 182 | case QImage::Format_Grayscale16: formatStr = "Format_Grayscale16"; break; 183 | case QImage::Format_Grayscale8: formatStr = "Format_Grayscale8"; break; 184 | default: 185 | formatStr = std::string("Unknown QImage Format:") + std::to_string(int(format)); 186 | } 187 | qDebug() << "[QtOIIO] QImage Format: " << formatStr.c_str(); 188 | } 189 | 190 | qDebug() << "[QtOIIO] nchannels:" << nchannels; 191 | 192 | // check picture channels number 193 | if(inSpec.nchannels < 3 && inSpec.nchannels != 1) 194 | { 195 | qWarning() << "[QtOIIO] Cannot load channels of image file '" << path.c_str() << "' (nchannels=" << inSpec.nchannels << ")."; 196 | return false; 197 | } 198 | 199 | // // convert to grayscale if needed 200 | // if(nchannels == 1 && inSpec.nchannels >= 3) 201 | // { 202 | // // convertion region of interest (for inSpec.nchannels > 3) 203 | // oiio::ROI convertionROI = inBuf.roi(); 204 | // convertionROI.chbegin = 0; 205 | // convertionROI.chend = 3; 206 | 207 | // // compute luminance via a weighted sum of R,G,B 208 | // // (assuming Rec709 primaries and a linear scale) 209 | // const float weights[3] = {.2126, .7152, .0722}; 210 | // oiio::ImageBuf grayscaleBuf; 211 | // oiio::ImageBufAlgo::channel_sum(grayscaleBuf, inBuf, weights, convertionROI); 212 | // inBuf.copy(grayscaleBuf); 213 | // } 214 | 215 | // // add missing channels 216 | // if(inSpec.nchannels < 3 && nchannels > inSpec.nchannels) 217 | // { 218 | // oiio::ImageSpec requestedSpec(inSpec.width, inSpec.height, nchannels, typeDesc); 219 | // oiio::ImageBuf requestedBuf(requestedSpec); 220 | 221 | // // duplicate first channel for RGB 222 | // if(requestedSpec.nchannels >= 3 && inSpec.nchannels < 3) 223 | // { 224 | // oiio::ImageBufAlgo::paste(requestedBuf, 0, 0, 0, 0, inBuf); 225 | // oiio::ImageBufAlgo::paste(requestedBuf, 0, 0, 0, 1, inBuf); 226 | // oiio::ImageBufAlgo::paste(requestedBuf, 0, 0, 0, 2, inBuf); 227 | // } 228 | // inBuf.swap(requestedBuf); 229 | // } 230 | 231 | // qDebug() << "[QtOIIO] create output QImage"; 232 | QImage result(inSpec.width, inSpec.height, format); 233 | 234 | // if the input is grayscale, we have the option to convert it with a color map 235 | if(convertGrayscaleToJetColorMap && inSpec.nchannels == 1) 236 | { 237 | const oiio::TypeDesc typeDesc = oiio::TypeDesc::UINT8; 238 | oiio::ImageSpec requestedSpec(inSpec.width, inSpec.height, nchannels, typeDesc); 239 | oiio::ImageBuf tmpBuf(requestedSpec); 240 | // perceptually uniform: "inferno", "viridis", "magma", "plasma" -- others: "blue-red", "spectrum", "heat" 241 | const char* colorMapEnv = std::getenv("QTOIIO_COLORMAP"); 242 | const std::string colorMapType = colorMapEnv ? colorMapEnv : "plasma"; 243 | 244 | // detect AliceVision special files that require a jetColorMap based conversion 245 | const bool isDepthMap = d->fileName().contains("depthMap"); 246 | const bool isNmodMap = d->fileName().contains("nmodMap"); 247 | 248 | if(colorMapEnv) 249 | { 250 | qDebug() << "[QtOIIO] compute colormap \"" << colorMapType.c_str() << "\""; 251 | oiio::ImageBufAlgo::color_map(tmpBuf, inBuf, 0, colorMapType); 252 | } 253 | else if(isDepthMap || isNmodMap) 254 | { 255 | oiio::ImageBufAlgo::PixelStats stats; 256 | oiio::ImageBufAlgo::computePixelStats(stats, inBuf); 257 | 258 | #pragma omp parallel for 259 | for(int y = 0; y < inSpec.height; ++y) 260 | { 261 | for(int x = 0; x < inSpec.width; ++x) 262 | { 263 | float depthValue = 0.0f; 264 | inBuf.getpixel(x, y, &depthValue, 1); 265 | const float range = stats.max[0] - stats.min[0]; 266 | const float normalizedDepthValue = range != 0.0f ? (depthValue - stats.min[0]) / range : 1.0f; 267 | Color32f color; 268 | if(isDepthMap) 269 | color = getColor32fFromJetColorMap(normalizedDepthValue); 270 | else if(isNmodMap) 271 | color = getColor32fFromJetColorMapClamp(normalizedDepthValue); 272 | tmpBuf.setpixel(x, y, color.m, 3); // set only 3 channels (RGB) 273 | } 274 | } 275 | } 276 | else 277 | { 278 | #pragma omp parallel for 279 | for(int y = 0; y < inSpec.height; ++y) 280 | { 281 | for(int x = 0; x < inSpec.width; ++x) 282 | { 283 | float depthValue = 0.0f; 284 | inBuf.getpixel(x, y, &depthValue, 1); 285 | Color32f color = getColor32fFromJetColorMap(depthValue); 286 | tmpBuf.setpixel(x, y, color.m, 3); // set only 3 channels (RGB) 287 | } 288 | } 289 | } 290 | // qDebug() << "[QtOIIO] compute colormap done"; 291 | inBuf.swap(tmpBuf); 292 | 293 | { 294 | oiio::ROI exportROI = inBuf.roi(); 295 | exportROI.chbegin = 0; 296 | exportROI.chend = nchannels; 297 | 298 | // qDebug() << "[QtOIIO] fill output QImage"; 299 | inBuf.get_pixels(exportROI, typeDesc, result.bits()); 300 | } 301 | } 302 | 303 | // Shuffle channels to convert from OIIO to Qt 304 | else if(nchannels == 4) 305 | { 306 | const oiio::TypeDesc typeDesc = moreThan8Bits ? oiio::TypeDesc::UINT16 : oiio::TypeDesc::UINT8; 307 | 308 | if(moreThan8Bits) // same than: format == QImage::Format_RGBA64 || format == QImage::Format_RGBX64 309 | { 310 | qDebug() << "[QtOIIO] Convert '" << inSpec.format.c_str() << "'' OIIO image to 'uint16' Qt image."; 311 | #pragma omp parallel for 312 | for(int y = 0; y < inSpec.height; ++y) 313 | { 314 | for(int x = 0; x < inSpec.width; ++x) 315 | { 316 | float rgba[4] = {0.0, 0.0, 0.0, 1.0}; 317 | inBuf.getpixel(x, y, rgba, 4); 318 | 319 | quint64* p = (quint64*)(result.scanLine(y)) + x; 320 | QRgba64 color = QRgba64::fromRgba64(floatToUShort(rgba[0]), floatToUShort(rgba[1]), floatToUShort(rgba[2]), floatToUShort(rgba[3])); 321 | *p = (quint64)color; 322 | } 323 | } 324 | } 325 | else 326 | { 327 | oiio::ImageSpec requestedSpec(inSpec.width, inSpec.height, nchannels, typeDesc); 328 | oiio::ImageBuf tmpBuf(requestedSpec); 329 | // qDebug() << "[QtOIIO] shuffle channels"; 330 | 331 | std::vector channelOrder = {0, 1, 2, 3}; 332 | float channelValues[] = {1.f, 1.f, 1.f, 1.f}; 333 | if(format == QImage::Format_ARGB32) 334 | { 335 | // (0xAARRGGBB) => 3, 0, 1, 2 in reverse order 336 | channelOrder = {2, 1, 0, 3}; 337 | } 338 | else if(format == QImage::Format_RGB32) 339 | { 340 | channelOrder = {2, 1, 0, -1}; // not sure 341 | } 342 | else 343 | { 344 | qWarning() << "Unsupported format conversion."; 345 | } 346 | // qWarning() << "channelOrder: " << channelOrder[0] << ", " << channelOrder[1] << ", " << channelOrder[2] << ", " << channelOrder[3]; 347 | oiio::ImageBufAlgo::channels(tmpBuf, inBuf, 4, &channelOrder.front(), channelValues, {}, false); 348 | inBuf.swap(tmpBuf); 349 | // qDebug() << "[QtOIIO] shuffle channels done"; 350 | 351 | { 352 | oiio::ROI exportROI = inBuf.roi(); 353 | exportROI.chbegin = 0; 354 | exportROI.chend = nchannels; 355 | 356 | // qDebug() << "[QtOIIO] fill output QImage"; 357 | inBuf.get_pixels(exportROI, typeDesc, result.bits()); 358 | } 359 | } 360 | } 361 | 362 | 363 | if (pixelAspectRatio != 1.0f) 364 | { 365 | QSize newSize(inSpec.width * pixelAspectRatio, inSpec.height); 366 | result = result.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 367 | } 368 | 369 | // qDebug() << "[QtOIIO] Image loaded: \"" << path << "\""; 370 | if (_scaledSize.isValid()) 371 | { 372 | qDebug() << "[QTOIIO] _scaledSize: " << _scaledSize.width() << "x" << _scaledSize.height(); 373 | *image = result.scaled(_scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); 374 | } 375 | else 376 | { 377 | *image = result; 378 | } 379 | return true; 380 | } 381 | 382 | bool QtOIIOHandler::write(const QImage &image) 383 | { 384 | // TODO 385 | return false; 386 | } 387 | 388 | bool QtOIIOHandler::supportsOption(ImageOption option) const 389 | { 390 | if(option == Size) 391 | return true; 392 | if(option == ImageTransformation) 393 | return true; 394 | if(option == ScaledSize) 395 | return true; 396 | 397 | return false; 398 | } 399 | 400 | QVariant QtOIIOHandler::option(ImageOption option) const 401 | { 402 | const auto getImageInput = [](QIODevice* device) -> std::unique_ptr { 403 | QFileDevice* d = dynamic_cast(device); 404 | if(!d) 405 | { 406 | qDebug() << "[QtOIIO] Read image failed (not a FileDevice)."; 407 | return std::unique_ptr(nullptr); 408 | } 409 | std::string path = d->fileName().toStdString(); 410 | return std::unique_ptr(oiio::ImageInput::open(path)); 411 | }; 412 | 413 | if (option == Size) 414 | { 415 | std::unique_ptr imageInput = getImageInput(device()); 416 | if(imageInput.get() == nullptr) 417 | return QVariant(); 418 | 419 | return QSize(imageInput->spec().width, imageInput->spec().height); 420 | } 421 | else if(option == ImageTransformation) 422 | { 423 | std::unique_ptr imageInput = getImageInput(device()); 424 | if(imageInput.get() == nullptr) 425 | { 426 | return QImageIOHandler::TransformationNone; 427 | } 428 | // Translate OIIO transformations to QImageIOHandler::ImageTransformation 429 | switch(oiio::ImageBuf(imageInput->spec()).orientation()) 430 | { 431 | case 1: return QImageIOHandler::TransformationNone; break; 432 | case 2: return QImageIOHandler::TransformationMirror; break; 433 | case 3: return QImageIOHandler::TransformationRotate180; break; 434 | case 4: return QImageIOHandler::TransformationFlip; break; 435 | case 5: return QImageIOHandler::TransformationMirrorAndRotate90; break; 436 | case 6: return QImageIOHandler::TransformationRotate90; break; 437 | case 7: return QImageIOHandler::TransformationFlipAndRotate90; break; 438 | case 8: return QImageIOHandler::TransformationRotate270; break; 439 | } 440 | } 441 | return QImageIOHandler::option(option); 442 | } 443 | 444 | void QtOIIOHandler::setOption(ImageOption option, const QVariant &value) 445 | { 446 | Q_UNUSED(option); 447 | Q_UNUSED(value); 448 | if (option == ScaledSize && value.isValid()) 449 | { 450 | _scaledSize = value.value(); 451 | qDebug() << "[QTOIIO] setOption scaledSize: " << _scaledSize.width() << "x" << _scaledSize.height(); 452 | } 453 | } 454 | 455 | QByteArray QtOIIOHandler::name() const 456 | { 457 | return "OpenImageIO"; 458 | } 459 | -------------------------------------------------------------------------------- /src/imageIOHandler/QtOIIOHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class QtOIIOHandler : public QImageIOHandler 6 | { 7 | public: 8 | QtOIIOHandler(); 9 | ~QtOIIOHandler(); 10 | 11 | bool canRead() const; 12 | bool read(QImage *image); 13 | bool write(const QImage &image); 14 | 15 | QByteArray name() const; 16 | 17 | static bool canRead(QIODevice *device); 18 | 19 | QVariant option(ImageOption option) const; 20 | void setOption(ImageOption option, const QVariant &value); 21 | bool supportsOption(ImageOption option) const; 22 | 23 | QSize _scaledSize; 24 | }; 25 | -------------------------------------------------------------------------------- /src/imageIOHandler/QtOIIOPlugin.cpp: -------------------------------------------------------------------------------- 1 | #include "QtOIIOPlugin.hpp" 2 | #include "QtOIIOHandler.hpp" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | namespace oiio = OIIO; 13 | 14 | QtOIIOPlugin::QtOIIOPlugin() 15 | { 16 | qDebug() << "[QtOIIO] init supported extensions."; 17 | 18 | std::string extensionsListStr; 19 | oiio::getattribute("extension_list", extensionsListStr); 20 | 21 | QString extensionsListQStr(QString::fromStdString(extensionsListStr)); 22 | 23 | QStringList formats = extensionsListQStr.split(';'); 24 | for(auto& format: formats) 25 | { 26 | qDebug() << "[QtOIIO] format: " << format << "."; 27 | QStringList keyValues = format.split(":"); 28 | if(keyValues.size() != 2) 29 | { 30 | qDebug() << "[QtOIIO] warning: split OIIO keys: " << keyValues.size() << " for " << format << "."; 31 | } 32 | else 33 | { 34 | _supportedExtensions += keyValues[1].split(","); 35 | } 36 | } 37 | qDebug() << "[QtOIIO] supported extensions: " << _supportedExtensions.join(", "); 38 | qInfo() << "[QtOIIO] Plugin Initialized"; 39 | } 40 | 41 | QtOIIOPlugin::~QtOIIOPlugin() 42 | { 43 | } 44 | 45 | QImageIOPlugin::Capabilities QtOIIOPlugin::capabilities(QIODevice *device, const QByteArray &format) const 46 | { 47 | QFileDevice* d = dynamic_cast(device); 48 | if(!d) 49 | return QImageIOPlugin::Capabilities(); 50 | 51 | const std::string path = d->fileName().toStdString(); 52 | if(path.empty() || path[0] == ':') 53 | return QImageIOPlugin::Capabilities(); 54 | 55 | #ifdef QTOIIO_USE_FORMATS_BLACKLIST 56 | // For performance sake, let Qt handle natively some formats. 57 | static const QStringList blacklist{"jpeg", "jpg", "png", "ico"}; 58 | if(blacklist.contains(format, Qt::CaseSensitivity::CaseInsensitive)) 59 | { 60 | return QImageIOPlugin::Capabilities(); 61 | } 62 | #endif 63 | if (_supportedExtensions.contains(format, Qt::CaseSensitivity::CaseInsensitive)) 64 | { 65 | qDebug() << "[QtOIIO] Capabilities: extension \"" << QString(format) << "\" supported."; 66 | // oiio::ImageOutput *out = oiio::ImageOutput::create(path); // TODO: when writting will be implemented 67 | Capabilities capabilities(CanRead); 68 | // if(out) 69 | // capabilities = Capabilities(CanRead|CanWrite); 70 | // oiio::ImageOutput::destroy(out); 71 | return capabilities; 72 | } 73 | qDebug() << "[QtOIIO] Capabilities: extension \"" << QString(format) << "\" not supported"; 74 | return QImageIOPlugin::Capabilities(); 75 | } 76 | 77 | QImageIOHandler *QtOIIOPlugin::create(QIODevice *device, const QByteArray &format) const 78 | { 79 | QtOIIOHandler *handler = new QtOIIOHandler; 80 | handler->setDevice(device); 81 | handler->setFormat(format); 82 | return handler; 83 | } 84 | -------------------------------------------------------------------------------- /src/imageIOHandler/QtOIIOPlugin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | // QImageIOHandlerFactoryInterface_iid 9 | 10 | // QT_DECL_EXPORT 11 | class QtOIIOPlugin : public QImageIOPlugin 12 | { 13 | public: 14 | Q_OBJECT 15 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "QtOIIOPlugin.json") 16 | 17 | public: 18 | QStringList _supportedExtensions; 19 | 20 | public: 21 | QtOIIOPlugin(); 22 | ~QtOIIOPlugin(); 23 | 24 | Capabilities capabilities(QIODevice *device, const QByteArray &format) const; 25 | QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const; 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/imageIOHandler/QtOIIOPlugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys": [ 3 | "exr", 4 | "bay", "bmq", "cr2", "crw", "cs1", "dc2", "dcr", "dng", "erf", "fff", "hdr", "k25", "kdc", "mdc", "mos", "mrw", "nef", "orf", "pef", "pxn", "raf", "raw", "rdc", "sr2", "srf", "x3f", "arw", "3fr", "cine", "ia", "kc2", "mef", "nrw", "qtk", "rw2", "sti", "rwl", "srw", "drf", "dsc", "ptx", "cap", "iiq", "rwz" 5 | ], 6 | "MimeTypes": [ 7 | "image/exr", 8 | "image/bay", "image/bmq", "image/cr2", "image/crw", "image/cs1", "image/dc2", "image/dcr", "image/dng", "image/erf", "image/fff", "image/hdr", "image/k25", "image/kdc", "image/mdc", "image/mos", "image/mrw", "image/nef", "image/orf", "image/pef", "image/pxn", "image/raf", "image/raw", "image/rdc", "image/sr2", "image/srf", "image/x3f", "image/arw", "image/3fr", "image/cine", "image/ia", "image/kc2", "image/mef", "image/nrw", "image/qtk", "image/rw2", "image/sti", "image/rwl", "image/srw", "image/drf", "image/dsc", "image/ptx", "image/cap", "image/iiq", "image/rwz" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/jetColorMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | static float jetr[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6 | 0, 0, 0.0625, 0.1250, 0.1875, 0.2500, 0.3125, 0.3750, 0.4375, 0.5000, 0.5625, 7 | 0.6250, 0.6875, 0.7500, 0.8125, 0.8750, 0.9375, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 8 | 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 9 | 1.0000, 0.9375, 0.8750, 0.8125, 0.7500, 0.6875, 0.6250, 0.5625, 0.5000}; 10 | 11 | static float jetg[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0.0625, 0.1250, 0.1875, 12 | 0.2500, 0.3125, 0.3750, 0.4375, 0.5000, 0.5625, 0.6250, 0.6875, 0.7500, 0.8125, 0.8750, 13 | 0.9375, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 14 | 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 0.9375, 0.8750, 0.8125, 0.7500, 15 | 0.6875, 0.6250, 0.5625, 0.5000, 0.4375, 0.3750, 0.3125, 0.2500, 0.1875, 0.1250, 0.0625, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0}; 17 | 18 | static float jetb[64] = {0.5625, 0.6250, 0.6875, 0.7500, 0.8125, 0.8750, 0.9375, 1.0000, 1.0000, 1.0000, 1.0000, 19 | 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 20 | 1.0000, 1.0000, 0.9375, 0.8750, 0.8125, 0.7500, 0.6875, 0.6250, 0.5625, 0.5000, 0.4375, 21 | 0.3750, 0.3125, 0.2500, 0.1875, 0.1250, 0.0625, 0, 0, 0, 0, 0, 22 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23 | 0, 0, 0, 0, 0, 0, 0, 0, 0}; 24 | 25 | struct Color32f 26 | { 27 | Color32f() {} 28 | Color32f(float r_, float g_, float b_) 29 | : r(r_) 30 | , g(g_) 31 | , b(b_) 32 | {} 33 | union { 34 | struct 35 | { 36 | float r, g, b; 37 | }; 38 | float m[3]; 39 | }; 40 | }; 41 | 42 | inline Color32f getColor32fFromJetColorMap(float value) 43 | { 44 | if(std::isnan(value)) 45 | return Color32f(1.0f, 0.0f, 1.0f); 46 | if(value <= 0.0f) 47 | return Color32f(0, 0, 0); 48 | if(value >= 1.0f) 49 | return Color32f(1.0f, 1.0f, 1.0f); 50 | float idx_f = value * 63.0f; 51 | float fractA, fractB, integral; 52 | fractB = std::modf(idx_f, &integral); 53 | fractA = 1.0f - fractB; 54 | int idx = static_cast(integral); 55 | Color32f c; 56 | c.r = jetr[idx] * fractA + jetr[idx + 1] * fractB; 57 | c.g = jetg[idx] * fractA + jetg[idx + 1] * fractB; 58 | c.b = jetb[idx] * fractA + jetb[idx + 1] * fractB; 59 | return c; 60 | } 61 | 62 | inline Color32f getColor32fFromJetColorMapClamp(float value) 63 | { 64 | if(std::isnan(value)) 65 | return Color32f(1.0f, 0.0f, 1.0f); 66 | if(value < 0.0f) 67 | value = 0.0f; 68 | if(value > 1.0f) 69 | value = 1.0f; 70 | float idx_f = value * 63.0f; 71 | float fractA, fractB, integral; 72 | fractB = std::modf(idx_f, &integral); 73 | fractA = 1.0f - fractB; 74 | int idx = static_cast(integral); 75 | Color32f c; 76 | c.r = jetr[idx] * fractA + jetr[idx + 1] * fractB; 77 | c.g = jetg[idx] * fractA + jetg[idx + 1] * fractB; 78 | c.b = jetb[idx] * fractA + jetb[idx + 1] * fractB; 79 | return c; 80 | } 81 | --------------------------------------------------------------------------------