├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── example ├── CMakeLists.txt └── main.cpp ├── img ├── B_G.jpg ├── Hand.jpg ├── Histogram.jpg └── Setting.jpg └── src ├── Application ├── CMakeLists.txt ├── DenoiseImageService.cpp ├── DenoiseImageService.hpp ├── EstimateLightDirectionService.cpp ├── EstimateLightDirectionService.hpp ├── ImageEvaluationService.cpp ├── ImageEvaluationService.hpp ├── ImageFileService.cpp ├── ImageFileService.hpp ├── ScaleImageService.cpp ├── ScaleImageService.hpp ├── TakeDifferenceService.cpp ├── TakeDifferenceService.hpp ├── TakeHistogramService.cpp └── TakeHistogramService.hpp ├── CMakeLists.txt ├── Domain ├── CMakeLists.txt ├── DenoiseImageData.cpp ├── DenoiseImageData.hpp ├── DifferentialData.cpp ├── DifferentialData.hpp ├── FloatingPointImageData.cpp ├── FloatingPointImageData.hpp ├── HistogramData.cpp ├── HistogramData.hpp ├── ImageEvaluationData.cpp ├── ImageEvaluationData.hpp ├── ImageFileData.cpp ├── ImageFileData.hpp ├── ImageUtility.cpp ├── ImageUtility.hpp ├── LightEstimationData.cpp ├── LightEstimationData.hpp ├── ScaleImageData.cpp └── ScaleImageData.hpp ├── Infrastructure ├── CMakeLists.txt ├── CircleDenoiseDataRepository.cpp ├── CircleDenoiseDataRepository.hpp ├── EachPixelSpectrumDifferentialDataRepository.cpp ├── EachPixelSpectrumDifferentialDataRepository.hpp ├── EllipseDenoiseDataRepository.cpp ├── EllipseDenoiseDataRepository.hpp ├── GraphicFileDataRepository.cpp ├── GraphicFileDataRepository.hpp ├── HyperEllipseDenoiseDataRepository.cpp ├── HyperEllipseDenoiseDataRepository.hpp ├── NormalizeScaleImageDataRepository.cpp ├── NormalizeScaleImageDataRepository.hpp ├── PSNRIImageEvaluationDataRepository.cpp ├── PSNRIImageEvaluationDataRepository.hpp ├── PhongModelLightDirectionDataRepository.cpp ├── PhongModelLightDirectionDataRepository.hpp ├── RoundOffHistogramDataRepository.cpp ├── RoundOffHistogramDataRepository.hpp ├── SSIMIImageEvaluationDataRepository.cpp ├── SSIMIImageEvaluationDataRepository.hpp ├── WholePixelSpectrumDifferentialDataRepository.cpp └── WholePixelSpectrumDifferentialDataRepository.hpp └── Presentation ├── CMakeLists.txt ├── ImageInformationModel.cpp ├── ImageInformationModel.hpp ├── ImageInformationPresenter.cpp └── ImageInformationPresenter.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | CMakeScripts 4 | Testing 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | compile_commands.json 9 | CTestTestfile.cmake 10 | 11 | build/ 12 | ThirdParty/install/ 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ThirdParty/Eigen"] 2 | path = ThirdParty/Eigen 3 | url = https://github.com/eigenteam/eigen-git-mirror.git 4 | [submodule "ThirdParty/ceres-solver"] 5 | path = ThirdParty/ceres-solver 6 | url = https://github.com/ceres-solver/ceres-solver.git 7 | [submodule "ThirdParty/glog"] 8 | path = ThirdParty/glog 9 | url = https://github.com/google/glog.git 10 | [submodule "ThirdParty/cvui"] 11 | path = ThirdParty/cvui 12 | url = https://github.com/Dovyski/cvui.git 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # CMake version 3 | cmake_minimum_required(VERSION 3.10) 4 | 5 | # Project 6 | project(ImageInformationAnalyzer CXX) 7 | 8 | # C++ Setting 9 | set(CMAKE_CXX_STANDARD 17) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | set(CMAKE_CXX_EXTENSIONS OFF) 12 | 13 | # For OpenCV 14 | find_package(OpenCV REQUIRED) 15 | 16 | # For Eigen 17 | find_package(Eigen3 REQUIRED) 18 | 19 | # For glog 20 | find_package(glog REQUIRED) 21 | 22 | # For Ceres Solver 23 | find_package(Ceres REQUIRED) 24 | 25 | # AVX 26 | option(USE_AVX "Use AVX" ON) 27 | if(USE_AVX) 28 | if(MSVC) 29 | add_compile_options(/arch:AVX) 30 | else() 31 | add_compile_options(-mavx) 32 | endif() 33 | endif() 34 | 35 | # OpenMP 36 | find_package(OpenMP REQUIRED) 37 | if(OpenMP_FOUND) 38 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 39 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 40 | endif() 41 | 42 | # direct path for CVUI 43 | set(CVUI_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/ThirdParty/cvui) 44 | 45 | # Directories 46 | add_subdirectory(src) 47 | add_subdirectory(example) 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ice-github 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ImageInformationAnalyzer 2 | 3 | ## What is this repository? 4 | 5 | An implimentation of the following article 6 | - https://shop.cqpub.co.jp/hanbai/books/MIF/MIF201805.html 7 | - "特別企画 あなたの知らない生体計測の世界" 8 | 9 | **you can detect blood vessels from a RGB JPEG image. No need to use IR camera** 10 | 11 | ## How to build 12 | 13 | ### Clone repository 14 | ``` 15 | git clone https://github.com/ice-github/ImageInformationAnalyzer 16 | cd ImageInformationAnalyzer 17 | git submodule init 18 | git submodule update 19 | ``` 20 | 21 | ### Prepare install dir 22 | ``` 23 | mkdir ThirdParty/install 24 | INSTALL_DIR=`pwd`/ThirdParty/install 25 | ``` 26 | 27 | ### Build Eigen 28 | ``` 29 | cd ThirdParty/Eigen 30 | mkdir build && cd build 31 | cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR .. 32 | make && make install 33 | cd ../../ 34 | ``` 35 | ***you should consider removing "build" directory because CMake may refer the build directory as Eigen3 dir** 36 | 37 | ### Build glog 38 | ``` 39 | cd ThirdParty/glog 40 | mkdir working && cd working 41 | cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DWITH_GFLAGS=false .. 42 | make && make install 43 | cd ../../ 44 | ``` 45 | 46 | ### Build ceres-solver 47 | ``` 48 | cd ThirdParty/ceres-solver 49 | mkdir working && cd working 50 | cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DEIGEN_INCLUDE_DIR=$INSTALL_DIR/include/eigen3 -DMINI GLOG=true -DBUILD_EXAMPLES=false -DBUILD_TESTING=false -DGFLAGS=false .. 51 | make && make install 52 | cd ../../ 53 | ``` 54 | ***you may encount errors about map/set but the errors can be fixed by adding std::, e.g. std::map** 55 | 56 | ### Build Project 57 | ``` 58 | cmake -DOpenCV_DIR=${opencv cmake directory} -DEigen3_DIR=$INSTALL_DIR/share/eigen3/cmake -DCeres_DIR=$INSTALL_DIR/CMake .. 59 | ``` 60 | 61 | ***OpenCV_DIR indicates the directory of OpenCVConfig.cmake file. e.g. opencv/build** 62 | 63 | ## How to run 64 | 65 | ``` 66 | ./sample ${Project directory}/img/Hand.jpg 67 | ``` 68 | ***you can change the luminance by using the setting window and "Apply" button** 69 | 70 | 71 | ![Original Hand](img/Hand.jpg "Original Hand") 72 | * https://ja.m.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Human-Hands-Front-Back.jpg 73 | 74 | ![B-G image](img/B_G.jpg "B-G") 75 | ![Setting image](img/Setting.jpg "Setting") 76 | ![Setting image](img/Histogram.jpg "Histogram") 77 | 78 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(sample main.cpp) 2 | 3 | target_include_directories(sample 4 | PRIVATE 5 | ${PROJECT_SOURCE_DIR}/src/Domain 6 | ${PROJECT_SOURCE_DIR}/src/Application 7 | ${PROJECT_SOURCE_DIR}/src/Presentation 8 | ${EIGEN3_INCLUDE_DIR} 9 | ${CVUI_INCLUDE_DIR} 10 | ) 11 | 12 | target_link_libraries(sample 13 | ImageInformationAnalyzerDomain 14 | ImageInformationAnalyzerApplication 15 | ImageInformationAnalyzerPresentation 16 | ImageInformationAnalyzerInfrastructure 17 | ${OpenCV_LIBS} 18 | ${CERES_LIBRARIES} 19 | ${GLOG_LIBRARIES} 20 | ) 21 | 22 | -------------------------------------------------------------------------------- /example/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "ImageInformationPresenter.hpp" 5 | #include "DenoiseImageService.hpp" 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | if(argc < 2) return -1; 10 | 11 | //TODO: Add https://github.com/google/fruit for DI 12 | using namespace ImageInformationAnalyzer::Presentation; 13 | ImageInformationPresenter iip(DenoiseImageService::Mode::ELLIPSE, ImageEvaluationService::Mode::SSIM, TakeDifferenceService::Mode::WholePixel); 14 | 15 | std::string filepath(argv[1]); 16 | 17 | try 18 | { 19 | iip.LoadImage(filepath); 20 | iip.Scale(); //Must excecute Scaler for Ellipse/HyperEllipse 21 | iip.DenoiseImage(); 22 | iip.Evaluate(); 23 | iip.Diff(); 24 | //iip.LightEstimation(); 25 | iip.TakeHistogram(); 26 | iip.Show(); 27 | } 28 | catch(const std::exception& e) 29 | { 30 | std::cout << "Exception: "s << e.what() << std::endl; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /img/B_G.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/img/B_G.jpg -------------------------------------------------------------------------------- /img/Hand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/img/Hand.jpg -------------------------------------------------------------------------------- /img/Histogram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/img/Histogram.jpg -------------------------------------------------------------------------------- /img/Setting.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/img/Setting.jpg -------------------------------------------------------------------------------- /src/Application/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ImageInformationAnalyzerApplication 2 | STATIC 3 | DenoiseImageService.cpp 4 | EstimateLightDirectionService.cpp 5 | ImageEvaluationService.cpp 6 | ImageFileService.cpp 7 | ScaleImageService.cpp 8 | TakeDifferenceService.cpp 9 | TakeHistogramService.cpp 10 | ) 11 | 12 | 13 | 14 | 15 | target_include_directories(ImageInformationAnalyzerApplication 16 | PRIVATE 17 | ${PROJECT_SOURCE_DIR}/src/Domain 18 | ${PROJECT_SOURCE_DIR}/src/Application 19 | ${PROJECT_SOURCE_DIR}/src/Infrastructure #without DI 20 | ${EIGEN3_INCLUDE_DIR} 21 | ${GLOG_INCLUDE_DIR} 22 | ${CERES_INCLUDE_DIR} 23 | ${OpenCV_INCLUDE_DIRS} 24 | ) 25 | 26 | -------------------------------------------------------------------------------- /src/Application/DenoiseImageService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DenoiseImageService.hpp" 3 | #include "CircleDenoiseDataRepository.hpp" 4 | #include "EllipseDenoiseDataRepository.hpp" 5 | #include "HyperEllipseDenoiseDataRepository.hpp" 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Application 10 | { 11 | using namespace Infrastructure; 12 | 13 | DenoiseImageService::DenoiseImageService(Mode mode) 14 | { 15 | repository_ = nullptr; 16 | 17 | switch(mode) 18 | { 19 | case Mode::CIRCLE: 20 | repository_ = new CircleDenoiseDataRepository(); 21 | break; 22 | case Mode::ELLIPSE: 23 | repository_ = new EllipseDenoiseDataRepository(); 24 | break; 25 | case Mode::HYPER_ELLIPSE: 26 | repository_ = new HyperEllipseDenoiseDataRepository(); 27 | break; 28 | default: 29 | break; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Application/DenoiseImageService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DenoiseImageData.hpp" 4 | 5 | #include 6 | #include //for cout 7 | 8 | namespace ImageInformationAnalyzer 9 | { 10 | namespace Application 11 | { 12 | using namespace Domain; 13 | 14 | class DenoiseImageService 15 | { 16 | public: 17 | enum class Mode 18 | { 19 | CIRCLE, 20 | ELLIPSE, 21 | HYPER_ELLIPSE 22 | }; 23 | 24 | IDenoiseImageDataRepository* repository_; 25 | 26 | public: 27 | explicit DenoiseImageService(Mode mode); 28 | 29 | FloatingPointImageData* Process(const FloatingPointImageData* data) 30 | { 31 | std::atomic processedPixel(0); 32 | 33 | auto done = false; 34 | auto elapsedMillisecounds = 0ll; 35 | 36 | FloatingPointImageData* result = nullptr; 37 | 38 | std::thread thread([&] 39 | { 40 | auto start = std::chrono::system_clock::now(); 41 | { 42 | result = repository_->Process(data, &processedPixel); 43 | } 44 | auto end = std::chrono::system_clock::now(); 45 | elapsedMillisecounds = std::chrono::duration_cast(end - start).count(); 46 | done = true; 47 | }); 48 | 49 | while(!done) 50 | { 51 | #ifdef _DEBUG 52 | std::this_thread::sleep_for(std::chrono::seconds(1)); 53 | #else 54 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 55 | #endif 56 | 57 | std::cout << "Progress: "s << std::setprecision(3) << 100.0 * processedPixel / ((double)data->Width * data->Height) << "%"s << std::endl; 58 | } 59 | thread.join(); 60 | 61 | std::cout << "Denoise completed: "s << elapsedMillisecounds << "ms"s << std::endl; 62 | 63 | return result; 64 | } 65 | 66 | virtual ~DenoiseImageService() 67 | { 68 | delete repository_; 69 | } 70 | }; 71 | } 72 | } -------------------------------------------------------------------------------- /src/Application/EstimateLightDirectionService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "EstimateLightDirectionService.hpp" 3 | #include "PhongModelLightDirectionDataRepository.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Infrastructure; 10 | 11 | EstimateLightDirectionService::EstimateLightDirectionService() 12 | { 13 | repository_ = new PhongModelLightDirectionDataRepository(); 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Application/EstimateLightDirectionService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "LightEstimationData.hpp" 5 | 6 | #include 7 | #include 8 | #include //for cout 9 | 10 | namespace ImageInformationAnalyzer 11 | { 12 | namespace Application 13 | { 14 | using namespace Domain; 15 | 16 | class EstimateLightDirectionService 17 | { 18 | ILightEstimationDataRepository* repository_; 19 | 20 | public: 21 | explicit EstimateLightDirectionService(); 22 | 23 | virtual FloatingPointImageData* Process(const FloatingPointImageData* denoisedR, const FloatingPointImageData* denoisedG, const FloatingPointImageData* denoisedB, const FloatingPointImageData* differentialB_G, const double pixelPitch) 24 | { 25 | if(denoisedR->Width != denoisedG->Width || denoisedR->Width != denoisedB->Width) throw std::invalid_argument("Input image sizes are not the same!"); 26 | if(denoisedR->Height != denoisedG->Height || denoisedR->Height != denoisedB->Height) throw std::invalid_argument("Input image sizes are not the same!"); 27 | 28 | std::atomic progress(0); 29 | 30 | auto done = false; 31 | auto elapsedMillisecounds = 0ll; 32 | 33 | FloatingPointImageData* result = nullptr; 34 | 35 | std::thread thread([&] 36 | { 37 | auto start = std::chrono::system_clock::now(); 38 | { 39 | result = repository_->Process(denoisedR, denoisedG, denoisedB, differentialB_G, pixelPitch, &progress); 40 | } 41 | auto end = std::chrono::system_clock::now(); 42 | elapsedMillisecounds = std::chrono::duration_cast(end - start).count(); 43 | done = true; 44 | }); 45 | 46 | while(!done) 47 | { 48 | #ifdef _DEBUG 49 | std::this_thread::sleep_for(std::chrono::seconds(10)); 50 | #else 51 | std::this_thread::sleep_for(std::chrono::seconds(3)); 52 | #endif 53 | 54 | std::cout << "Progress: "s << std::setprecision(3) << 100.0 * progress << "%"s << std::endl; 55 | } 56 | thread.join(); 57 | 58 | std::cout << "Light estimation completed: "s << elapsedMillisecounds << "ms"s << std::endl; 59 | 60 | return result; 61 | } 62 | 63 | virtual ~EstimateLightDirectionService() 64 | { 65 | delete repository_; 66 | } 67 | }; 68 | } 69 | } -------------------------------------------------------------------------------- /src/Application/ImageEvaluationService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ImageEvaluationService.hpp" 3 | #include "PSNRIImageEvaluationDataRepository.hpp" 4 | #include "SSIMIImageEvaluationDataRepository.hpp" 5 | 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Application 10 | { 11 | using namespace Infrastructure; 12 | 13 | ImageEvaluationService::ImageEvaluationService(Mode mode) : repository_(nullptr) 14 | { 15 | switch(mode) 16 | { 17 | case Mode::PSNR: 18 | repository_ = new PSNRIImageEvaluationDataRepository(); 19 | break; 20 | case Mode::SSIM: 21 | repository_ = new SSIMIImageEvaluationDataRepository(); 22 | break; 23 | } 24 | } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Application/ImageEvaluationService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ImageEvaluationData.hpp" 4 | 5 | #include 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Application 10 | { 11 | using namespace Domain; 12 | 13 | class ImageEvaluationService 14 | { 15 | IImageEvaluationDataRepository* repository_; 16 | public: 17 | enum class Mode 18 | { 19 | PSNR, 20 | SSIM 21 | }; 22 | 23 | public: 24 | explicit ImageEvaluationService(Mode mode); 25 | 26 | ImageEvaluationData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2, const double maxValue) 27 | { 28 | if(data1->Width != data2->Width || data1->Height != data2->Height) 29 | { 30 | throw std::invalid_argument("Image sizes are NOT the same!"); 31 | } 32 | return repository_->Process(data1, data2, maxValue); 33 | } 34 | 35 | virtual ~ImageEvaluationService() 36 | { 37 | delete repository_; 38 | } 39 | }; 40 | } 41 | } -------------------------------------------------------------------------------- /src/Application/ImageFileService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ImageFileService.hpp" 3 | #include "GraphicFileDataRepository.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Infrastructure; 10 | 11 | ImageFileService::ImageFileService() 12 | { 13 | graphicRepository_ = new GraphicFileDataRepository(); 14 | jsonRepository_ = nullptr; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Application/ImageFileService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ImageFileData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Domain; 10 | 11 | class ImageFileService 12 | { 13 | IImageFileDataRepository* graphicRepository_; 14 | IImageFileDataRepository* jsonRepository_; 15 | 16 | public: 17 | explicit ImageFileService(); 18 | 19 | virtual FloatingPointImageData* Load(const std::string& filePath, const IImageFileDataRepository::Channel channel) 20 | { 21 | auto extensionPos = filePath.rfind("."s); 22 | if(extensionPos == std::string::npos) throw std::invalid_argument("invalid image file!"s); 23 | 24 | auto extension = filePath.substr(extensionPos + 1); 25 | if(graphicRepository_->IsExtensionSupported(extension)) 26 | { 27 | return graphicRepository_->Load(filePath, channel); 28 | } 29 | 30 | //if(jsonRepository_->IsExtensionSupported(extension)) 31 | //{ 32 | // return jsonRepository_->Load(filePath, channel); 33 | //} 34 | 35 | throw std::logic_error("file type not supported!"s); 36 | } 37 | virtual bool Store(const FloatingPointImageData* r, const FloatingPointImageData* g, const FloatingPointImageData* b, const std::string& filePath) 38 | { 39 | auto extensionPos = filePath.rfind("."s); 40 | if(extensionPos == std::string::npos) throw std::invalid_argument("invalid image file!"s); 41 | 42 | auto extension = filePath.substr(filePath.length() + 1); 43 | 44 | if(graphicRepository_->IsExtensionSupported(extension)) 45 | { 46 | return graphicRepository_->Store(r, g, b, filePath); 47 | } 48 | 49 | //if(jsonRepository_->IsExtensionSupported(extension)) 50 | //{ 51 | // return jsonRepository_->Store(r, g, b, filePath); 52 | //} 53 | 54 | throw std::logic_error("file type not supported!"s); 55 | } 56 | 57 | virtual ~ImageFileService() 58 | { 59 | delete graphicRepository_; 60 | delete jsonRepository_; 61 | } 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Application/ScaleImageService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ScaleImageService.hpp" 3 | #include "NormalizeScaleImageDataRepository.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Infrastructure; 10 | 11 | ScaleImageService::ScaleImageService() 12 | { 13 | repository_ = new NormalizeScaleImageDataRepository(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Application/ScaleImageService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScaleImageData.hpp" 4 | 5 | class NormalizeScaleImageDataRepository; 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Application 10 | { 11 | using namespace Domain; 12 | 13 | class ScaleImageService 14 | { 15 | IScaleImageDataRepository* repository_; 16 | 17 | public: 18 | explicit ScaleImageService(); 19 | 20 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data, const double oldMinValue, const double oldMaxValue, const double newMinValue, const double newMaxValue) 21 | { 22 | return repository_->Process(data, oldMinValue, oldMaxValue, newMinValue, newMaxValue); 23 | } 24 | 25 | virtual ~ScaleImageService() 26 | { 27 | delete repository_; 28 | } 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Application/TakeDifferenceService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "TakeDifferenceService.hpp" 3 | #include "EachPixelSpectrumDifferentialDataRepository.hpp" 4 | #include "WholePixelSpectrumDifferentialDataRepository.hpp" 5 | 6 | namespace ImageInformationAnalyzer 7 | { 8 | namespace Application 9 | { 10 | using namespace Infrastructure; 11 | 12 | TakeDifferenceService::TakeDifferenceService(Mode mode) 13 | { 14 | repository_ = nullptr; 15 | switch(mode) 16 | { 17 | case Mode::EachPixel: 18 | repository_ = new EachPixelSpectrumDifferentialDataRepository(); 19 | break; 20 | case Mode::WholePixel: 21 | repository_ = new WholePixelSpectrumDifferentialDataRepository(); 22 | break; 23 | } 24 | 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Application/TakeDifferenceService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DifferentialData.hpp" 4 | 5 | #include 6 | #include //for cout 7 | 8 | namespace ImageInformationAnalyzer 9 | { 10 | namespace Application 11 | { 12 | using namespace Domain; 13 | 14 | class TakeDifferenceService 15 | { 16 | IDifferentialDataRepository* repository_; 17 | 18 | public: 19 | enum class Mode 20 | { 21 | EachPixel, //very slow 22 | WholePixel 23 | }; 24 | 25 | explicit TakeDifferenceService(Mode mode); 26 | 27 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2) 28 | { 29 | if(data1->Width != data2->Width || data1->Height != data2->Height) 30 | { 31 | throw std::invalid_argument("Image sizes are NOT the same!"); 32 | } 33 | 34 | std::atomic processedPixel(0); 35 | 36 | auto done = false; 37 | auto elapsedMillisecounds = 0ll; 38 | 39 | FloatingPointImageData* result = nullptr; 40 | 41 | std::thread thread([&] 42 | { 43 | auto start = std::chrono::system_clock::now(); 44 | { 45 | result = repository_->Process(data1, data2, &processedPixel); 46 | } 47 | auto end = std::chrono::system_clock::now(); 48 | elapsedMillisecounds = std::chrono::duration_cast(end - start).count(); 49 | done = true; 50 | }); 51 | 52 | while(!done) 53 | { 54 | #ifdef _DEBUG 55 | std::this_thread::sleep_for(std::chrono::seconds(1)); 56 | #else 57 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 58 | #endif 59 | 60 | std::cout << "Progress: "s << std::setprecision(3) << 100.0 * processedPixel / ((double)data1->Width * data1->Height) << "%"s << std::endl; 61 | } 62 | thread.join(); 63 | 64 | std::cout << "Take image differential completed: "s << elapsedMillisecounds << "ms"s << std::endl; 65 | 66 | return repository_->Process(data1, data2); 67 | } 68 | 69 | virtual ~TakeDifferenceService() 70 | { 71 | delete repository_; 72 | } 73 | }; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Application/TakeHistogramService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "TakeHistogramService.hpp" 3 | #include "RoundOffHistogramDataRepository.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Infrastructure; 10 | 11 | TakeHistogramService::TakeHistogramService() 12 | { 13 | repository_ = new RoundOffHistogramDataRepository(); 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Application/TakeHistogramService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "HistogramData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Application 8 | { 9 | using namespace Domain; 10 | 11 | class TakeHistogramService 12 | { 13 | IHistogramDataRepository* repository_; 14 | 15 | public: 16 | explicit TakeHistogramService(); 17 | 18 | virtual HistogramData* Process(const FloatingPointImageData* data, const int histogramSize, const double histogramMinValue, const double histogramMaxValue) 19 | { 20 | return repository_->Process(data, histogramSize, histogramMinValue, histogramMaxValue); 21 | } 22 | 23 | virtual ~TakeHistogramService() 24 | { 25 | delete repository_; 26 | } 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_subdirectory(Domain) 3 | add_subdirectory(Application) 4 | add_subdirectory(Presentation) 5 | add_subdirectory(Infrastructure) 6 | 7 | -------------------------------------------------------------------------------- /src/Domain/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ImageInformationAnalyzerDomain 2 | STATIC 3 | DenoiseImageData.cpp 4 | DifferentialData.cpp 5 | FloatingPointImageData.cpp 6 | HistogramData.cpp 7 | ImageEvaluationData.cpp 8 | ImageFileData.cpp 9 | ImageUtility.cpp 10 | LightEstimationData.cpp 11 | ScaleImageData.cpp 12 | ) 13 | 14 | target_include_directories(ImageInformationAnalyzerDomain 15 | PRIVATE 16 | ${PROJECT_SOURCE_DIR}/src/Domain 17 | ${EIGEN3_INCLUDE_DIR} 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /src/Domain/DenoiseImageData.cpp: -------------------------------------------------------------------------------- 1 | #include "DenoiseImageData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/DenoiseImageData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "FloatingPointImageData.hpp" 3 | 4 | #include 5 | #include 6 | #include //std::cout 7 | 8 | namespace ImageInformationAnalyzer 9 | { 10 | namespace Domain 11 | { 12 | class IDenoiseImageDataRepository 13 | { 14 | protected: 15 | enum 16 | { 17 | WINDOW_SIZE = 7 18 | }; 19 | 20 | public: 21 | explicit IDenoiseImageDataRepository() 22 | { 23 | 24 | } 25 | virtual ~IDenoiseImageDataRepository() = default; 26 | 27 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data, std::atomic* processedPixel = nullptr) 28 | { 29 | auto width = data->Width; 30 | auto height = data->Height; 31 | 32 | //Prepare buffers 33 | std::vector> imageBuffer; 34 | std::vector> normalBuffer; 35 | imageBuffer.resize(height); 36 | normalBuffer.resize(height); 37 | for(auto y = 0; y < height; ++y) 38 | { 39 | imageBuffer[y].resize(width); 40 | normalBuffer[y].resize(width); 41 | } 42 | 43 | //set to 0% 44 | if(processedPixel != nullptr) *processedPixel = 0; 45 | 46 | //Denoise process 47 | std::vector> processBuffer; 48 | processBuffer.resize((size_t)width * height); 49 | 50 | for(auto y = 0; y < height; ++y) 51 | { 52 | for(auto x = 0; x < width; ++x) 53 | { 54 | processBuffer[(size_t)y * width + x] = std::tuple(x, y, 0.0, Eigen::Vector3d::Zero(), 0.0); 55 | } 56 | } 57 | 58 | //C++17 59 | std::atomic errorPixel(0); 60 | 61 | #ifdef _DEBUG 62 | auto parallelPolicy = std::execution::par; 63 | #else 64 | auto parallelPolicy = std::execution::par; 65 | #endif 66 | std::for_each(parallelPolicy, processBuffer.begin(), processBuffer.end(), [&](std::tuple param) 67 | { 68 | const auto x = std::get<0>(param); 69 | const auto y = std::get<1>(param); 70 | 71 | auto denoisedPixel = 0.0; 72 | auto fittingError = 0.0; 73 | Eigen::Vector3d normal; 74 | 75 | if(!DenoisePixel(data, x, y, WINDOW_SIZE, denoisedPixel, normal, fittingError)) 76 | { 77 | errorPixel++; 78 | } 79 | 80 | //Results 81 | { 82 | std::get<2>(processBuffer[(size_t)y * width + x]) = denoisedPixel; 83 | std::get<3>(processBuffer[(size_t)y * width + x]) = normal; 84 | std::get<4>(processBuffer[(size_t)y * width + x]) = fittingError; 85 | 86 | if(processedPixel != nullptr) (*processedPixel)++; 87 | } 88 | }); 89 | 90 | auto totalFittingError = 0.0; 91 | for(std::tuple param : processBuffer) 92 | { 93 | const auto x = std::get<0>(param); 94 | const auto y = std::get<1>(param); 95 | const auto denoisedPixel = std::get<2>(param); 96 | const auto normal = std::get<3>(param); 97 | const auto fittingError = std::get<4>(param); 98 | //const auto originalPixel = data->ImageBuffer[y][x]; 99 | 100 | totalFittingError += fittingError; 101 | imageBuffer[y][x] = denoisedPixel; 102 | normalBuffer[y][x] = normal; 103 | } 104 | std::cout << "Error Pixel: "s << errorPixel << std::endl; 105 | std::cout << "Fitting error/pixel: "s << totalFittingError / processBuffer.size() << std::endl; 106 | 107 | return new FloatingPointImageData(width, height, imageBuffer, normalBuffer); 108 | } 109 | protected: 110 | virtual inline bool DenoisePixel(const FloatingPointImageData* data, const int x, const int y, const int windowSize, double& denoisedPixel, Eigen::Vector3d& normal, double& fittingError) = 0; 111 | }; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Domain/DifferentialData.cpp: -------------------------------------------------------------------------------- 1 | #include "DifferentialData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/DifferentialData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FloatingPointImageData.hpp" 4 | 5 | #include 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Domain 10 | { 11 | class IDifferentialDataRepository 12 | { 13 | public: 14 | explicit IDifferentialDataRepository() = default; 15 | virtual ~IDifferentialDataRepository() = default; 16 | 17 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2, std::atomic* processedPixel = nullptr) = 0; 18 | }; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Domain/FloatingPointImageData.cpp: -------------------------------------------------------------------------------- 1 | #include "FloatingPointImageData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/FloatingPointImageData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace ImageInformationAnalyzer 9 | { 10 | namespace Domain 11 | { 12 | using namespace std::literals::string_literals; 13 | 14 | class FloatingPointImageData 15 | { 16 | public: 17 | const int Width; 18 | const int Height; 19 | const std::vector> ImageBuffer; 20 | const std::vector> NormalBuffer; 21 | 22 | private: 23 | double maxValue_; 24 | double minValue_; 25 | 26 | public: 27 | explicit FloatingPointImageData::FloatingPointImageData(const int width, const int height 28 | , const std::vector> imageBuffer 29 | , const std::vector> normalBuffer) : Width(width), Height(height), ImageBuffer(imageBuffer), NormalBuffer(normalBuffer) 30 | { 31 | maxValue_ = DBL_MIN; 32 | minValue_ = DBL_MAX; 33 | 34 | for(auto line : imageBuffer) 35 | { 36 | for(auto value : line) 37 | { 38 | if(value > maxValue_) 39 | { 40 | maxValue_ = value; 41 | } 42 | if(value < minValue_) 43 | { 44 | minValue_ = value; 45 | } 46 | } 47 | } 48 | } 49 | 50 | inline double GetMaxValue() const { return maxValue_; } 51 | inline double GetMinValue() const { return minValue_; } 52 | 53 | virtual ~FloatingPointImageData() = default; 54 | }; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Domain/HistogramData.cpp: -------------------------------------------------------------------------------- 1 | #include "HistogramData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/HistogramData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FloatingPointImageData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Domain 8 | { 9 | class HistogramData 10 | { 11 | double maxValue_; 12 | double minValue_; 13 | 14 | public: 15 | const std::vector Data; 16 | 17 | explicit HistogramData(std::vector data) : Data(data) 18 | { 19 | maxValue_ = DBL_MIN; 20 | minValue_ = DBL_MAX; 21 | 22 | for(auto value : data) 23 | { 24 | if(value > maxValue_) 25 | { 26 | maxValue_ = value; 27 | } 28 | if(value < minValue_) 29 | { 30 | minValue_ = value; 31 | } 32 | } 33 | } 34 | 35 | inline double GetMaxValue() const { return maxValue_; } 36 | inline double GetMinValue() const { return minValue_; } 37 | 38 | virtual ~HistogramData() = default; 39 | }; 40 | 41 | class IHistogramDataRepository 42 | { 43 | public: 44 | explicit IHistogramDataRepository() = default; 45 | virtual ~IHistogramDataRepository() = default; 46 | 47 | virtual HistogramData* Process(const FloatingPointImageData* data, const int histogramSize, const double histogramMinValue, const double histogramMaxValue) = 0; 48 | }; 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/Domain/ImageEvaluationData.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageEvaluationData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/ImageEvaluationData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "FloatingPointImageData.hpp" 3 | 4 | namespace ImageInformationAnalyzer 5 | { 6 | namespace Domain 7 | { 8 | class ImageEvaluationData 9 | { 10 | public: 11 | const double Result; 12 | 13 | explicit ImageEvaluationData(const double& result) : Result(result) 14 | { 15 | 16 | } 17 | virtual ~ImageEvaluationData() = default; 18 | }; 19 | 20 | class IImageEvaluationDataRepository 21 | { 22 | public: 23 | explicit IImageEvaluationDataRepository() = default; 24 | virtual ~IImageEvaluationDataRepository() = default; 25 | 26 | virtual ImageEvaluationData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2, const double maxValue) = 0; 27 | }; 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Domain/ImageFileData.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageFileData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/ImageFileData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "FloatingPointImageData.hpp" 3 | 4 | namespace ImageInformationAnalyzer 5 | { 6 | namespace Domain 7 | { 8 | class IImageFileDataRepository 9 | { 10 | public: 11 | enum class Channel 12 | { 13 | B, 14 | G, 15 | R 16 | }; 17 | 18 | explicit IImageFileDataRepository() = default; 19 | virtual ~IImageFileDataRepository() = default; 20 | 21 | virtual FloatingPointImageData* Load(const std::string& filePath, const Channel channel) = 0; 22 | virtual bool Store(const FloatingPointImageData* r, const FloatingPointImageData* g, const FloatingPointImageData* b, const std::string& filePath) = 0; 23 | 24 | virtual bool IsExtensionSupported(const std::string& extension) = 0; 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Domain/ImageUtility.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageUtility.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/ImageUtility.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Domain/ImageUtility.hpp -------------------------------------------------------------------------------- /src/Domain/LightEstimationData.cpp: -------------------------------------------------------------------------------- 1 | #include "LightEstimationData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/LightEstimationData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FloatingPointImageData.hpp" 4 | 5 | #include 6 | 7 | namespace ImageInformationAnalyzer 8 | { 9 | namespace Domain 10 | { 11 | class ILightEstimationDataRepository 12 | { 13 | public: 14 | explicit ILightEstimationDataRepository() = default; 15 | virtual ~ILightEstimationDataRepository() = default; 16 | 17 | virtual FloatingPointImageData* Process(const FloatingPointImageData* denoisedR, const FloatingPointImageData* denoisedG, const FloatingPointImageData* denoisedB, const FloatingPointImageData* differentialB_G, const double pixelPitch, std::atomic* progress = nullptr) = 0; 18 | }; 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Domain/ScaleImageData.cpp: -------------------------------------------------------------------------------- 1 | #include "ScaleImageData.hpp" 2 | -------------------------------------------------------------------------------- /src/Domain/ScaleImageData.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FloatingPointImageData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Domain 8 | { 9 | class IScaleImageDataRepository 10 | { 11 | public: 12 | explicit IScaleImageDataRepository() = default; 13 | virtual ~IScaleImageDataRepository() = default; 14 | 15 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data, const double oldMinValue, const double oldMaxValue, const double newMinValue, const double newMaxValue) = 0; 16 | }; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Infrastructure/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ImageInformationAnalyzerInfrastructure 2 | STATIC 3 | CircleDenoiseDataRepository.cpp 4 | EachPixelSpectrumDifferentialDataRepository.cpp 5 | EllipseDenoiseDataRepository.cpp 6 | GraphicFileDataRepository.cpp 7 | HyperEllipseDenoiseDataRepository.cpp 8 | NormalizeScaleImageDataRepository.cpp 9 | PhongModelLightDirectionDataRepository.cpp 10 | PSNRIImageEvaluationDataRepository.cpp 11 | RoundOffHistogramDataRepository.cpp 12 | SSIMIImageEvaluationDataRepository.cpp 13 | WholePixelSpectrumDifferentialDataRepository.cpp 14 | ) 15 | 16 | 17 | 18 | target_include_directories(ImageInformationAnalyzerInfrastructure 19 | PRIVATE 20 | ${PROJECT_SOURCE_DIR}/src/Domain 21 | ${PROJECT_SOURCE_DIR}/src/Infrastructure 22 | ${EIGEN3_INCLUDE_DIR} 23 | ${OpenCV_INCLUDE_DIRS} 24 | ${GLOG_INCLUDE_DIR} 25 | ${CERES_INCLUDE_DIR} 26 | ) 27 | 28 | -------------------------------------------------------------------------------- /src/Infrastructure/CircleDenoiseDataRepository.cpp: -------------------------------------------------------------------------------- 1 | #include "CircleDenoiseDataRepository.hpp" 2 | 3 | -------------------------------------------------------------------------------- /src/Infrastructure/CircleDenoiseDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/CircleDenoiseDataRepository.hpp -------------------------------------------------------------------------------- /src/Infrastructure/EachPixelSpectrumDifferentialDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "EachPixelSpectrumDifferentialDataRepository.hpp" 3 | 4 | -------------------------------------------------------------------------------- /src/Infrastructure/EachPixelSpectrumDifferentialDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/EachPixelSpectrumDifferentialDataRepository.hpp -------------------------------------------------------------------------------- /src/Infrastructure/EllipseDenoiseDataRepository.cpp: -------------------------------------------------------------------------------- 1 | #include "EllipseDenoiseDataRepository.hpp" 2 | -------------------------------------------------------------------------------- /src/Infrastructure/EllipseDenoiseDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/EllipseDenoiseDataRepository.hpp -------------------------------------------------------------------------------- /src/Infrastructure/GraphicFileDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "GraphicFileDataRepository.hpp" 3 | 4 | -------------------------------------------------------------------------------- /src/Infrastructure/GraphicFileDataRepository.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ImageFileData.hpp" 4 | 5 | #include 6 | #include 7 | 8 | namespace ImageInformationAnalyzer 9 | { 10 | namespace Infrastructure 11 | { 12 | using namespace Domain; 13 | using namespace std::literals::string_literals; 14 | 15 | class GraphicFileDataRepository: public IImageFileDataRepository 16 | { 17 | inline std::vector> ReadCVMat(const cv::Mat& img, const IImageFileDataRepository::Channel channel) 18 | { 19 | if(static_cast(channel) >= img.channels()) throw std::invalid_argument("channel not found!"); 20 | 21 | std::vector> data; 22 | 23 | //Copy 24 | data.resize(img.rows); 25 | for(auto y = 0; y < img.rows; ++y) 26 | { 27 | data[y].resize(img.cols); 28 | for(auto x = 0; x < img.cols; ++x) 29 | { 30 | for(auto c = 0; c < img.channels(); ++c) 31 | { 32 | auto pix = img.data[y * img.step + x * img.elemSize() + c]; 33 | 34 | if(c == static_cast(channel)) 35 | { 36 | data[y][x] = (double)pix; 37 | } 38 | } 39 | } 40 | } 41 | return data; 42 | } 43 | 44 | inline cv::Mat WriteCVMat(const int width, const int height, const std::vector>& r, const std::vector>& g, const std::vector>& b) 45 | { 46 | cv::Mat img(height, width, CV_8UC3); 47 | 48 | for(auto y = 0; y < img.rows; ++y) 49 | { 50 | for(auto x = 0; x < img.cols; ++x) 51 | { 52 | //BGR 53 | img.data[y * img.step + x * img.elemSize() + 0] = static_cast(b[y][x] + 0.5); 54 | img.data[y * img.step + x * img.elemSize() + 1] = static_cast(g[y][x] + 0.5); 55 | img.data[y * img.step + x * img.elemSize() + 2] = static_cast(r[y][x] + 0.5); 56 | } 57 | } 58 | 59 | return img; 60 | } 61 | 62 | public: 63 | explicit GraphicFileDataRepository() = default; 64 | virtual ~GraphicFileDataRepository() = default; 65 | 66 | virtual FloatingPointImageData* Load(const std::string& filePath, const IImageFileDataRepository::Channel channel) override 67 | { 68 | //Read file 69 | auto imgMat = cv::imread(filePath); 70 | if(imgMat.empty()) throw std::invalid_argument("file not found!: "s + filePath); 71 | 72 | auto width = imgMat.cols; 73 | auto height = imgMat.rows; 74 | auto imageBuffer = ReadCVMat(imgMat, channel); 75 | 76 | //Write dummy normal 77 | std::vector> normalBuffer; 78 | normalBuffer.resize(height); 79 | for(auto y = 0; y < height; ++y) 80 | { 81 | normalBuffer[y].resize(width); 82 | for(auto x = 0; x < width; ++x) 83 | { 84 | normalBuffer[y][x] = Eigen::Vector3d(0, 0, 1);//dummy 85 | } 86 | } 87 | 88 | return new FloatingPointImageData(width, height, imageBuffer, normalBuffer); 89 | } 90 | 91 | virtual bool Store(const FloatingPointImageData* r, const FloatingPointImageData* g, const FloatingPointImageData* b, const std::string& filePath) override 92 | { 93 | auto width = r->Width; 94 | auto height = r->Height; 95 | 96 | if(width != g->Width || height != g->Height || width != b->Width || height != b->Height) throw std::invalid_argument("image size mismatched!"); 97 | 98 | auto imgMat = WriteCVMat(width, height, r->ImageBuffer, g->ImageBuffer, b->ImageBuffer); 99 | 100 | //Write to file 101 | cv::imwrite(filePath, imgMat); 102 | 103 | return true; 104 | } 105 | 106 | virtual bool IsExtensionSupported(const std::string& extension) override 107 | { 108 | if(extension == "jpg"s || extension == "jpeg"s || extension == "png"s || extension == "bmp"s) 109 | { 110 | return true; 111 | } 112 | return false; 113 | } 114 | }; 115 | } 116 | } -------------------------------------------------------------------------------- /src/Infrastructure/HyperEllipseDenoiseDataRepository.cpp: -------------------------------------------------------------------------------- 1 | #include "HyperEllipseDenoiseDataRepository.hpp" 2 | 3 | -------------------------------------------------------------------------------- /src/Infrastructure/HyperEllipseDenoiseDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/HyperEllipseDenoiseDataRepository.hpp -------------------------------------------------------------------------------- /src/Infrastructure/NormalizeScaleImageDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NormalizeScaleImageDataRepository.hpp" 3 | 4 | -------------------------------------------------------------------------------- /src/Infrastructure/NormalizeScaleImageDataRepository.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScaleImageData.hpp" 4 | #include "ImageUtility.hpp" 5 | 6 | #include 7 | #include 8 | 9 | namespace ImageInformationAnalyzer 10 | { 11 | namespace Infrastructure 12 | { 13 | using namespace Domain; 14 | using namespace Misc; 15 | using namespace std::literals::string_literals; 16 | 17 | class NormalizeScaleImageDataRepository : public IScaleImageDataRepository 18 | { 19 | public: 20 | explicit NormalizeScaleImageDataRepository() = default; 21 | virtual ~NormalizeScaleImageDataRepository() = default; 22 | 23 | virtual FloatingPointImageData* Process(const FloatingPointImageData* data, const double oldMinValue, const double oldMaxValue, const double newMinValue, const double newMaxValue) override 24 | { 25 | auto width = data->Width; 26 | auto height = data->Height; 27 | 28 | std::vector < std::vector > imageBuffer; 29 | std::vector> normalBuffer; 30 | 31 | imageBuffer.resize(height); 32 | normalBuffer.resize(height); 33 | 34 | for(auto y = 0; y < height; ++y) 35 | { 36 | imageBuffer[y].resize(width); 37 | normalBuffer[y].resize(width); 38 | for(auto x = 0; x < width; ++x) 39 | { 40 | auto value = data->ImageBuffer[y][x]; 41 | 42 | //[OldMinValue, OldMaxValue] => [0, 1] => [NewMinValue, NewMaxValue] 43 | auto normalized = ImageUtility::DoubleSub(value, oldMinValue) / (oldMaxValue - oldMinValue); 44 | 45 | imageBuffer[y][x] = ImageUtility::DoubleAdd(normalized * (newMaxValue - newMinValue), newMinValue); 46 | normalBuffer[y][x] = data->NormalBuffer[y][x]; 47 | } 48 | } 49 | 50 | return new FloatingPointImageData(width, height, imageBuffer, normalBuffer); 51 | } 52 | }; 53 | } 54 | } -------------------------------------------------------------------------------- /src/Infrastructure/PSNRIImageEvaluationDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "PSNRIImageEvaluationDataRepository.hpp" 3 | -------------------------------------------------------------------------------- /src/Infrastructure/PSNRIImageEvaluationDataRepository.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ImageEvaluationData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Infrastructure 8 | { 9 | using namespace Domain; 10 | 11 | class PSNRIImageEvaluationDataRepository : public IImageEvaluationDataRepository 12 | { 13 | public: 14 | explicit PSNRIImageEvaluationDataRepository() = default; 15 | virtual ~PSNRIImageEvaluationDataRepository() = default; 16 | 17 | virtual ImageEvaluationData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2, const double maxValue) override 18 | { 19 | auto width = data1->Width; 20 | auto height = data1->Height; 21 | 22 | auto mse = 0.0; 23 | for(auto y = 0; y < height; ++y) 24 | { 25 | for(auto x = 0; x < width; ++x) 26 | { 27 | auto diff = data1->ImageBuffer[y][x] - data2->ImageBuffer[y][x]; 28 | mse += diff * diff; 29 | } 30 | } 31 | mse /= ((double)width * height); 32 | 33 | //PSNR 34 | auto psnr = 10.0 * std::log10(maxValue * maxValue / mse); 35 | return new ImageEvaluationData(psnr); 36 | } 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Infrastructure/PhongModelLightDirectionDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "PhongModelLightDirectionDataRepository.hpp" 3 | -------------------------------------------------------------------------------- /src/Infrastructure/PhongModelLightDirectionDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/PhongModelLightDirectionDataRepository.hpp -------------------------------------------------------------------------------- /src/Infrastructure/RoundOffHistogramDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RoundOffHistogramDataRepository.hpp" 3 | -------------------------------------------------------------------------------- /src/Infrastructure/RoundOffHistogramDataRepository.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "HistogramData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Infrastructure 8 | { 9 | using namespace Domain; 10 | 11 | class RoundOffHistogramDataRepository : public Domain::IHistogramDataRepository 12 | { 13 | public: 14 | explicit RoundOffHistogramDataRepository() = default; 15 | virtual ~RoundOffHistogramDataRepository() = default; 16 | 17 | virtual Domain::HistogramData* Process(const FloatingPointImageData* data, const int histogramSize, const double histogramMinValue, const double histogramMaxValue) override 18 | { 19 | std::vector histogram; 20 | histogram.resize(histogramSize); 21 | 22 | for(auto y = 0; y < data->Height; ++y) 23 | { 24 | for(auto x = 0; x < data->Width; ++x) 25 | { 26 | auto value = data->ImageBuffer[y][x]; 27 | 28 | if(value < histogramMinValue) continue; 29 | if(value > histogramMaxValue) continue; 30 | 31 | //Convert to [0,1] 32 | auto normalized = (value - histogramMinValue) / (histogramMaxValue - histogramMinValue); 33 | 34 | //Convert to [0, histogramSize-1] 35 | auto index = static_cast(normalized * (histogramSize - 1.0) + 0.5); 36 | 37 | histogram[index] += 1.0; 38 | } 39 | } 40 | 41 | for(auto i = 0; i < histogram.size(); ++i) 42 | { 43 | histogram[i] /= histogram.size(); 44 | } 45 | 46 | return new Domain::HistogramData(histogram); 47 | } 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Infrastructure/SSIMIImageEvaluationDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SSIMIImageEvaluationDataRepository.hpp" 3 | -------------------------------------------------------------------------------- /src/Infrastructure/SSIMIImageEvaluationDataRepository.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ImageEvaluationData.hpp" 4 | 5 | namespace ImageInformationAnalyzer 6 | { 7 | namespace Infrastructure 8 | { 9 | using namespace Domain; 10 | 11 | class SSIMIImageEvaluationDataRepository : public IImageEvaluationDataRepository 12 | { 13 | public: 14 | explicit SSIMIImageEvaluationDataRepository() = default; 15 | virtual ~SSIMIImageEvaluationDataRepository() = default; 16 | 17 | virtual ImageEvaluationData* Process(const FloatingPointImageData* data1, const FloatingPointImageData* data2, const double maxValue) override 18 | { 19 | auto width = data1->Width; 20 | auto height = data1->Height; 21 | 22 | auto average1 = 0.0; 23 | auto average2 = 0.0; 24 | for(auto y = 0; y < height; ++y) 25 | { 26 | for(auto x = 0; x < width; ++x) 27 | { 28 | average1 += data1->ImageBuffer[y][x]; 29 | average2 += data2->ImageBuffer[y][x]; 30 | } 31 | } 32 | average1 /= ((double)width * height); 33 | average2 /= ((double)width * height); 34 | 35 | auto variance1 = 0.0; 36 | auto variance2 = 0.0; 37 | auto covariance = 0.0; 38 | 39 | for(auto y = 0; y < height; ++y) 40 | { 41 | for(auto x = 0; x < width; ++x) 42 | { 43 | variance1 += (data1->ImageBuffer[y][x] - average1) * (data1->ImageBuffer[y][x] - average1); 44 | variance2 += (data2->ImageBuffer[y][x] - average2) * (data2->ImageBuffer[y][x] - average2); 45 | covariance += (data1->ImageBuffer[y][x] - average1) * (data2->ImageBuffer[y][x] - average2); 46 | } 47 | } 48 | variance1 /= ((double)width * height); 49 | variance2 /= ((double)width * height); 50 | covariance /= ((double)width * height); 51 | 52 | constexpr auto K1 = 0.01; 53 | constexpr auto K2 = 0.03; 54 | const auto dynamicRange = maxValue; 55 | 56 | const auto C1 = (K1 * dynamicRange) * (K1 * dynamicRange); 57 | const auto C2 = (K2 * dynamicRange) * (K2 * dynamicRange); 58 | const auto C3 = C2 / 2.0; 59 | 60 | auto l = (2.0 * average1 * average2 + C1) / (average1 * average1 + average2 * average2 + C1); 61 | auto c = (2.0 * std::sqrt(variance1) * std::sqrt(variance2) + C2) / (variance1 * variance2 + C2); 62 | auto s = (covariance + C3) / (std::sqrt(variance1) * std::sqrt(variance2) + C3); 63 | 64 | constexpr auto alpha = 1.0; 65 | constexpr auto beta = 1.0; 66 | constexpr auto gamma = 1.0; 67 | 68 | //SSIM 69 | auto ssim = std::pow(l, alpha) + std::pow(c, beta) + std::pow(s, gamma); 70 | return new ImageEvaluationData(ssim); 71 | } 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Infrastructure/WholePixelSpectrumDifferentialDataRepository.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WholePixelSpectrumDifferentialDataRepository.hpp" 3 | 4 | -------------------------------------------------------------------------------- /src/Infrastructure/WholePixelSpectrumDifferentialDataRepository.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Infrastructure/WholePixelSpectrumDifferentialDataRepository.hpp -------------------------------------------------------------------------------- /src/Presentation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ImageInformationAnalyzerPresentation 2 | STATIC 3 | ImageInformationModel.cpp 4 | ImageInformationPresenter.cpp 5 | ) 6 | 7 | 8 | 9 | target_include_directories(ImageInformationAnalyzerPresentation 10 | PRIVATE 11 | ${PROJECT_SOURCE_DIR}/src/Domain 12 | ${PROJECT_SOURCE_DIR}/src/Application 13 | ${PROJECT_SOURCE_DIR}/src/Presentation 14 | ${EIGEN3_INCLUDE_DIR} 15 | ${OpenCV_INCLUDE_DIRS} 16 | ${CVUI_INCLUDE_DIR} 17 | ) 18 | 19 | -------------------------------------------------------------------------------- /src/Presentation/ImageInformationModel.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ImageInformationModel.hpp" 3 | 4 | -------------------------------------------------------------------------------- /src/Presentation/ImageInformationModel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "FloatingPointImageData.hpp" 4 | #include "ImageEvaluationData.hpp" 5 | #include "HistogramData.hpp" 6 | 7 | #include 8 | 9 | namespace ImageInformationAnalyzer 10 | { 11 | namespace Presentation 12 | { 13 | using namespace ImageInformationAnalyzer::Domain; 14 | 15 | class ImageInformationModel 16 | { 17 | public: 18 | explicit ImageInformationModel() = default; 19 | virtual ~ImageInformationModel() = default; 20 | 21 | std::unique_ptr R; 22 | std::unique_ptr G; 23 | std::unique_ptr B; 24 | 25 | std::unique_ptr DenoisedR; 26 | std::unique_ptr DenoisedG; 27 | std::unique_ptr DenoisedB; 28 | 29 | std::unique_ptr EvaluatedR; 30 | std::unique_ptr EvaluatedG; 31 | std::unique_ptr EvaluatedB; 32 | 33 | std::unique_ptr HistogramR; 34 | std::unique_ptr HistogramG; 35 | std::unique_ptr HistogramB; 36 | std::unique_ptr HistogramDenoisedR; 37 | std::unique_ptr HistogramDenoisedG; 38 | std::unique_ptr HistogramDenoisedB; 39 | 40 | std::unique_ptr DifferentialB_G; 41 | std::unique_ptr DifferentialG_R; 42 | std::unique_ptr DifferentialB_R; 43 | 44 | std::unique_ptr HistogramB_G; 45 | std::unique_ptr HistogramG_R; 46 | std::unique_ptr HistogramB_R; 47 | 48 | std::unique_ptr Surface; 49 | std::unique_ptr HistogramSurface; 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Presentation/ImageInformationPresenter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ImageInformationPresenter.hpp" 3 | -------------------------------------------------------------------------------- /src/Presentation/ImageInformationPresenter.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ice-github/ImageInformationAnalyzer/7065065d54f0d0e56e66210a915b6637d803f52f/src/Presentation/ImageInformationPresenter.hpp --------------------------------------------------------------------------------