From d27d1e26273ddeaa1a8e34efe2f6e00b5351717a Mon Sep 17 00:00:00 2001 From: Andrews Sobral <andrewssobral@gmail.com> Date: Sat, 18 Mar 2017 18:40:18 +0100 Subject: [PATCH] BGSLibrary 2.0.0 --- .gitignore | 6 +- CMakeLists.txt | 103 +- Demo.cpp | 158 +- Demo.py | 84 + Demo2.cpp | 139 +- FrameProcessor.cpp | 452 ++--- FrameProcessor.h | 207 +-- Main.cpp | 2 +- PreProcessor.cpp | 2 +- PreProcessor.h | 1 - README.md | 9 +- VideoAnalysis.cpp | 76 +- VideoCapture.cpp | 58 +- VideoCapture.h | 5 +- config/FrameProcessor.xml | 39 +- dataset/demo.avi | Bin 0 -> 355840 bytes {frames => dataset/frames}/1.png | Bin {frames => dataset/frames}/10.png | Bin {frames => dataset/frames}/11.png | Bin {frames => dataset/frames}/12.png | Bin {frames => dataset/frames}/13.png | Bin {frames => dataset/frames}/14.png | Bin {frames => dataset/frames}/15.png | Bin {frames => dataset/frames}/16.png | Bin {frames => dataset/frames}/17.png | Bin {frames => dataset/frames}/18.png | Bin {frames => dataset/frames}/19.png | Bin {frames => dataset/frames}/2.png | Bin {frames => dataset/frames}/20.png | Bin {frames => dataset/frames}/21.png | Bin {frames => dataset/frames}/22.png | Bin {frames => dataset/frames}/23.png | Bin {frames => dataset/frames}/24.png | Bin {frames => dataset/frames}/25.png | Bin {frames => dataset/frames}/26.png | Bin {frames => dataset/frames}/27.png | Bin {frames => dataset/frames}/28.png | Bin {frames => dataset/frames}/29.png | Bin {frames => dataset/frames}/3.png | Bin {frames => dataset/frames}/30.png | Bin {frames => dataset/frames}/31.png | Bin {frames => dataset/frames}/32.png | Bin {frames => dataset/frames}/33.png | Bin {frames => dataset/frames}/34.png | Bin {frames => dataset/frames}/35.png | Bin {frames => dataset/frames}/36.png | Bin {frames => dataset/frames}/37.png | Bin {frames => dataset/frames}/38.png | Bin {frames => dataset/frames}/39.png | Bin {frames => dataset/frames}/4.png | Bin {frames => dataset/frames}/40.png | Bin {frames => dataset/frames}/41.png | Bin {frames => dataset/frames}/42.png | Bin {frames => dataset/frames}/43.png | Bin {frames => dataset/frames}/44.png | Bin {frames => dataset/frames}/45.png | Bin {frames => dataset/frames}/46.png | Bin {frames => dataset/frames}/47.png | Bin {frames => dataset/frames}/48.png | Bin {frames => dataset/frames}/49.png | Bin {frames => dataset/frames}/5.png | Bin {frames => dataset/frames}/50.png | Bin {frames => dataset/frames}/51.png | Bin {frames => dataset/frames}/6.png | Bin {frames => dataset/frames}/7.png | Bin {frames => dataset/frames}/8.png | Bin {frames => dataset/frames}/9.png | Bin demos/DemoFrameDifferenceBGS.cpp | 49 - demos/DemoMultiLayerBGS.cpp | 49 - demos/linux_ubuntu/.gitignore | 8 + .../linux_ubuntu}/CMakeLists.txt | 7 +- .../linux_ubuntu}/FrameDifferenceTest.cpp | 6 +- .../linux_ubuntu}/README.txt | 0 demos/linux_ubuntu/config/.gitignore | 4 + demos/macosx/.gitignore | 8 + .../macosx}/CMakeLists.txt | 7 +- .../macosx}/FrameDifferenceTest.cpp | 6 +- {example_macosx => demos/macosx}/README.txt | 0 demos/macosx/config/.gitignore | 4 + .../README_CMAKE_USERS_OPENCV2.txt | 39 +- docs/README_CMAKE_USERS_OPENCV3.txt | 77 + .../README_LINUX_USERS.txt | 5 +- .../README_VS2010_OPENCV2.txt | 13 +- example_linux/config/KEEP_THIS_FOLDER | 1 - example_macosx/config/KEEP_THIS_FOLDER | 1 - {java_gui => gui_java}/README.txt | 0 .../_COPY_bgslibrary.exe_HERE_ | 0 {java_gui => gui_java}/bgslibrary_gui.jar | Bin .../bgslibrary_gui.properties | 0 {java_gui => gui_java}/build.xml | 0 {java_gui => gui_java}/config/.gitignore | 0 .../config/FrameProcessor.xml | 0 .../config/PreProcessor.xml | 0 .../config/VideoCapture.xml | 0 .../images/bgslibrary_gui_screen01.png | Bin .../images/bgslibrary_gui_screen02.png | Bin .../images/bgslibrary_gui_screen03.png | Bin .../images/bgslibrary_gui_screen04.png | Bin {java_gui => gui_java}/images/logo.jpg | Bin .../lib/commons-configuration-1.8.jar | Bin {java_gui => gui_java}/lib/commons-io-2.3.jar | Bin .../lib/commons-lang-2.6.jar | Bin .../lib/commons-logging-1.1.1.jar | Bin .../lib/swingx-all-1.6.3.jar | Bin .../lib/swingx-beaninfo-1.6.3.jar | Bin {java_gui => gui_java}/manifest.mf | 0 .../nbproject/build-impl.xml | 0 .../nbproject/genfiles.properties | 0 .../nbproject/private/config.properties | 0 .../nbproject/private/private.properties | 0 .../nbproject/private/private.xml | 0 .../nbproject/project.properties | 0 {java_gui => gui_java}/nbproject/project.xml | 0 {java_gui => gui_java}/run_camera.bat | 0 {java_gui => gui_java}/run_java_gui.bat | 0 .../run_java_gui_with_console.bat | 0 {java_gui => gui_java}/run_video.bat | 0 .../src/br/com/bgslibrary/Main.java | 0 .../src/br/com/bgslibrary/entity/Command.java | 0 .../com/bgslibrary/entity/Configuration.java | 0 .../br/com/bgslibrary/gui/AboutDialog.form | 0 .../br/com/bgslibrary/gui/AboutDialog.java | 0 .../src/br/com/bgslibrary/gui/MainFrame.form | 0 .../src/br/com/bgslibrary/gui/MainFrame.java | 0 .../src/br/com/bgslibrary/resources/logo.jpg | Bin {vs2010mfc => gui_mfc}/.gitignore | 0 {vs2013mfc => gui_mfc}/ReadMe.txt | 0 .../config/AdaptiveBackgroundLearning.xml | 0 .../AdaptiveSelectiveBackgroundLearning.xml | 0 .../config/DPAdaptiveMedianBGS.xml | 0 .../config/DPEigenbackgroundBGS.xml | 0 .../config/DPGrimsonGMMBGS.xml | 0 {vs2010mfc => gui_mfc}/config/DPMeanBGS.xml | 0 .../config/DPPratiMediodBGS.xml | 0 .../config/DPTextureBGS.xml | 0 {vs2010mfc => gui_mfc}/config/DPWrenGABGS.xml | 0 .../config/DPZivkovicAGMMBGS.xml | 0 .../config/FrameDifferenceBGS.xml | 0 .../config/FuzzyChoquetIntegral.xml | 0 .../config/FuzzySugenoIntegral.xml | 0 {vs2010mfc => gui_mfc}/config/GMG.xml | 0 .../config/IndependentMultimodalBGS.xml | 0 {vs2010mfc => gui_mfc}/config/KDE.xml | 0 .../config/LBAdaptiveSOM.xml | 0 .../config/LBFuzzyAdaptiveSOM.xml | 0 .../config/LBFuzzyGaussian.xml | 0 .../config/LBMixtureOfGaussians.xml | 0 .../config/LBSimpleGaussian.xml | 0 {vs2010mfc => gui_mfc}/config/LOBSTERBGS.xml | 0 .../config/MixtureOfGaussianV1BGS.xml | 0 .../config/MixtureOfGaussianV2BGS.xml | 0 {vs2010mfc => gui_mfc}/config/MultiCueBGS.xml | 0 .../config/MultiLayerBGS.xml | 0 .../config/SigmaDeltaBGS.xml | 0 .../config/StaticFrameDifferenceBGS.xml | 0 {vs2010mfc => gui_mfc}/config/SuBSENSEBGS.xml | 0 {vs2010mfc => gui_mfc}/config/T2FGMM_UM.xml | 0 {vs2010mfc => gui_mfc}/config/T2FGMM_UV.xml | 0 {vs2010mfc => gui_mfc}/config/T2FMRF_UM.xml | 0 {vs2010mfc => gui_mfc}/config/T2FMRF_UV.xml | 0 {vs2010mfc => gui_mfc}/config/VuMeter.xml | 0 .../config/WeightedMovingMeanBGS.xml | 0 .../config/WeightedMovingVarianceBGS.xml | 0 {vs2010mfc => gui_mfc}/dataset/video.avi | Bin .../outputs/background/.gitignore | 0 .../outputs/foreground/.gitignore | 0 .../outputs/input/.gitignore | 0 {vs2010mfc => gui_mfc}/src/.gitignore | 0 {vs2010mfc => gui_mfc}/src/App.cpp | 0 {vs2010mfc => gui_mfc}/src/App.h | 0 {vs2010mfc => gui_mfc}/src/Dlg.cpp | 0 {vs2010mfc => gui_mfc}/src/Dlg.h | 0 {vs2013mfc => gui_mfc}/src/ReadMe.txt | 0 .../src/bgslibrary_vs2013_mfc.rc | Bin .../src/bgslibrary_vs2013_mfc.sln | 0 .../src/bgslibrary_vs2013_mfc.vcxproj | 0 .../src/bgslibrary_vs2013_mfc.vcxproj.filters | 0 .../src/bgslibrary_vs2013_mfc.vcxproj.user | 0 .../src/res/bgslibrary_vs2013_mfc.ico | Bin .../src/res/bgslibrary_vs2013_mfc.rc2 | Bin {vs2010mfc => gui_mfc}/src/resource.h | Bin {vs2010mfc => gui_mfc}/src/stdafx.cpp | 0 {vs2010mfc => gui_mfc}/src/stdafx.h | 0 {vs2010mfc => gui_mfc}/src/targetver.h | 0 gui_qt/.gitignore | 9 + gui_qt/CMakeLists.txt | 52 + gui_qt/README.txt | 17 + gui_qt/application.qrc | 10 + gui_qt/bgslibrary_gui.cpp | 38 + gui_qt/bgslibrary_gui.pro | 248 +++ gui_qt/build/.gitignore | 4 + gui_qt/figs/copy.png | Bin 0 -> 1338 bytes gui_qt/figs/cut.png | Bin 0 -> 1323 bytes gui_qt/figs/new.png | Bin 0 -> 852 bytes gui_qt/figs/open.png | Bin 0 -> 2073 bytes gui_qt/figs/paste.png | Bin 0 -> 1645 bytes gui_qt/figs/save.png | Bin 0 -> 1187 bytes gui_qt/mainwindow.cpp | 571 ++++++ gui_qt/mainwindow.h | 110 ++ gui_qt/mainwindow.ui | 631 +++++++ gui_qt/qt_utils.cpp | 74 + gui_qt/qt_utils.h | 99 ++ gui_qt/texteditor.cpp | 320 ++++ gui_qt/texteditor.h | 64 + gui_qt/ui_mainwindow.h | 306 ++++ output/bg/.gitignore | 4 + output/fg/.gitignore | 4 + output/in/.gitignore | 4 + .../PerformanceUtils.cpp | 259 +-- .../PerformanceUtils.h | 16 +- package_analysis/PixelUtils.cpp | 351 ++++ .../tb => package_analysis}/PixelUtils.h | 18 +- package_bgs/AdaptiveBackgroundLearning.cpp | 72 +- package_bgs/AdaptiveBackgroundLearning.h | 55 +- .../AdaptiveSelectiveBackgroundLearning.cpp | 53 +- .../AdaptiveSelectiveBackgroundLearning.h | 54 +- package_bgs/DPAdaptiveMedian.cpp | 110 ++ package_bgs/DPAdaptiveMedian.h | 53 + ...ackgroundBGS.cpp => DPEigenbackground.cpp} | 67 +- package_bgs/DPEigenbackground.h | 55 + .../DPGrimsonGMMBGS.cpp => DPGrimsonGMM.cpp} | 69 +- .../DPEigenbackgroundBGS.h => DPGrimsonGMM.h} | 67 +- package_bgs/{dp/DPMeanBGS.cpp => DPMean.cpp} | 67 +- .../{dp/DPZivkovicAGMMBGS.h => DPMean.h} | 67 +- ...DPPratiMediodBGS.cpp => DPPratiMediod.cpp} | 75 +- .../{dp/DPMeanBGS.h => DPPratiMediod.h} | 68 +- .../{dp/DPTextureBGS.cpp => DPTexture.cpp} | 91 +- package_bgs/DPTexture.h | 59 + .../{dp/DPWrenGABGS.cpp => DPWrenGA.cpp} | 70 +- package_bgs/{dp/DPWrenGABGS.h => DPWrenGA.h} | 67 +- ...ZivkovicAGMMBGS.cpp => DPZivkovicAGMM.cpp} | 69 +- .../DPGrimsonGMMBGS.h => DPZivkovicAGMM.h} | 67 +- package_bgs/FrameDifference.cpp | 84 + ...FrameDifferenceBGS.h => FrameDifference.h} | 45 +- package_bgs/FrameDifferenceBGS.cpp | 83 - package_bgs/{tb => }/FuzzyChoquetIntegral.cpp | 127 +- package_bgs/FuzzyChoquetIntegral.h | 53 + package_bgs/{tb => }/FuzzySugenoIntegral.cpp | 133 +- package_bgs/FuzzySugenoIntegral.h | 53 + package_bgs/GMG.cpp | 49 +- package_bgs/GMG.h | 50 +- package_bgs/IBGS.h | 63 +- package_bgs/{db/imbs.cpp => IMBS/IMBS.cpp} | 254 +-- package_bgs/{db/imbs.hpp => IMBS/IMBS.hpp} | 62 +- package_bgs/IndependentMultimodal.cpp | 74 + ...ifferenceBGS.h => IndependentMultimodal.h} | 46 +- package_bgs/{ae => }/KDE.cpp | 83 +- package_bgs/KDE.h | 57 + package_bgs/{ae => KDE}/KernelTable.cpp | 48 +- package_bgs/{ae => KDE}/KernelTable.h | 22 +- package_bgs/KDE/NPBGSubtractor.cpp | 1160 ++++++++++++ package_bgs/{ae => KDE}/NPBGSubtractor.h | 26 +- package_bgs/{ae => KDE}/NPBGmodel.cpp | 42 +- package_bgs/{ae => KDE}/NPBGmodel.h | 28 +- package_bgs/KNN.cpp | 111 ++ package_bgs/KNN.h | 57 + package_bgs/{lb => }/LBAdaptiveSOM.cpp | 67 +- package_bgs/{lb => }/LBAdaptiveSOM.h | 60 +- package_bgs/{lb => }/LBFuzzyAdaptiveSOM.cpp | 69 +- package_bgs/{lb => }/LBFuzzyAdaptiveSOM.h | 60 +- package_bgs/{lb => }/LBFuzzyGaussian.cpp | 66 +- package_bgs/{lb => }/LBFuzzyGaussian.h | 58 +- package_bgs/{lb => }/LBMixtureOfGaussians.cpp | 68 +- package_bgs/{lb => }/LBMixtureOfGaussians.h | 59 +- package_bgs/{ck/LbpMrf.cpp => LBP_MRF.cpp} | 55 +- .../{WeightedMovingMeanBGS.h => LBP_MRF.h} | 48 +- package_bgs/LBP_MRF/MEDefs.cpp | 57 + package_bgs/{ck => LBP_MRF}/MEDefs.hpp | 29 +- package_bgs/{ck => LBP_MRF}/MEHistogram.cpp | 305 ++-- package_bgs/{ck => LBP_MRF}/MEHistogram.hpp | 30 +- package_bgs/{ck => LBP_MRF}/MEImage.cpp | 963 +++++----- package_bgs/{ck => LBP_MRF}/MEImage.hpp | 38 +- .../{ck => LBP_MRF}/MotionDetection.cpp | 126 +- .../{ck => LBP_MRF}/MotionDetection.hpp | 32 +- package_bgs/{ck => LBP_MRF}/block.h | 268 +-- package_bgs/{ck => LBP_MRF}/graph.cpp | 18 +- package_bgs/{ck => LBP_MRF}/graph.h | 105 +- package_bgs/{ck => LBP_MRF}/maxflow.cpp | 260 +-- package_bgs/LBSP/BackgroundSubtractorLBSP.cpp | 85 + package_bgs/LBSP/BackgroundSubtractorLBSP.h | 101 ++ .../LBSP/BackgroundSubtractorLBSP_.cpp | 79 + package_bgs/LBSP/BackgroundSubtractorLBSP_.h | 107 ++ .../LBSP/BackgroundSubtractorLOBSTER.cpp | 342 ++++ .../LBSP/BackgroundSubtractorLOBSTER.h | 83 + .../LBSP/BackgroundSubtractorPAWCS.cpp | 1349 ++++++++++++++ package_bgs/LBSP/BackgroundSubtractorPAWCS.h | 169 ++ .../LBSP/BackgroundSubtractorSuBSENSE.cpp | 753 ++++++++ .../LBSP/BackgroundSubtractorSuBSENSE.h | 129 ++ package_bgs/LBSP/DistanceUtils.h | 332 ++++ package_bgs/LBSP/LBSP.cpp | 334 ++++ package_bgs/LBSP/LBSP.h | 134 ++ package_bgs/LBSP/LBSP_.cpp | 334 ++++ package_bgs/LBSP/LBSP_.h | 134 ++ .../{pl => LBSP}/LBSP_16bits_dbcross_1ch.i | 0 .../{pl => LBSP}/LBSP_16bits_dbcross_3ch1t.i | 0 .../{pl => LBSP}/LBSP_16bits_dbcross_3ch3t.i | 0 .../{pl => LBSP}/LBSP_16bits_dbcross_s3ch.i | 0 package_bgs/LBSP/RandUtils.h | 112 ++ package_bgs/{lb => }/LBSimpleGaussian.cpp | 62 +- package_bgs/{lb => }/LBSimpleGaussian.h | 56 +- package_bgs/LOBSTER.cpp | 98 ++ package_bgs/LOBSTER.h | 49 + ...ssianV1BGS.cpp => MixtureOfGaussianV1.cpp} | 69 +- ...fGaussianV1BGS.h => MixtureOfGaussianV1.h} | 50 +- ...ssianV2BGS.cpp => MixtureOfGaussianV2.cpp} | 73 +- ...fGaussianV2BGS.h => MixtureOfGaussianV2.h} | 49 +- .../{sjn/SJN_MultiCueBGS.cpp => MultiCue.cpp} | 587 ++++--- package_bgs/MultiCue.h | 254 +++ .../{jmo/MultiLayerBGS.cpp => MultiLayer.cpp} | 133 +- package_bgs/MultiLayer.h | 99 ++ package_bgs/{jmo => MultiLayer}/BGS.h | 8 +- .../BackgroundSubtractionAPI.h | 39 +- .../{jmo => MultiLayer}/BlobExtraction.cpp | 194 +- .../{jmo => MultiLayer}/BlobExtraction.h | 8 +- .../BlobLibraryConfiguration.h | 5 +- package_bgs/MultiLayer/BlobResult.cpp | 847 +++++++++ package_bgs/{jmo => MultiLayer}/BlobResult.h | 60 +- .../{jmo => MultiLayer}/CMultiLayerBGS.cpp | 28 +- .../{jmo => MultiLayer}/CMultiLayerBGS.h | 27 +- .../LocalBinaryPattern.cpp | 16 +- .../{jmo => MultiLayer}/LocalBinaryPattern.h | 9 +- .../OpenCvDataConversion.h | 9 +- package_bgs/MultiLayer/OpenCvLegacyIncludes.h | 50 + package_bgs/MultiLayer/blob.cpp | 1148 ++++++++++++ package_bgs/{jmo => MultiLayer}/blob.h | 120 +- package_bgs/PAWCS.cpp | 93 + package_bgs/PAWCS.h | 48 + package_bgs/PBAS/PBAS.cpp | 585 +++++++ package_bgs/PBAS/PBAS.h | 207 +++ package_bgs/PixelBasedAdaptiveSegmenter.cpp | 126 ++ package_bgs/PixelBasedAdaptiveSegmenter.h | 58 + package_bgs/SigmaDelta.cpp | 101 ++ package_bgs/SigmaDelta.h | 49 + package_bgs/{bl => SigmaDelta}/sdLaMa091.cpp | 84 +- package_bgs/{bl => SigmaDelta}/sdLaMa091.h | 6 +- ...renceBGS.cpp => StaticFrameDifference.cpp} | 52 +- package_bgs/StaticFrameDifference.h | 42 + package_bgs/SuBSENSE.cpp | 96 + package_bgs/SuBSENSE.h | 49 + package_bgs/T2F/FuzzyUtils.cpp | 512 ++++++ package_bgs/{tb => T2F}/FuzzyUtils.h | 15 +- package_bgs/{tb => T2F}/MRF.cpp | 156 +- package_bgs/{tb => T2F}/MRF.h | 11 +- package_bgs/{tb => T2F}/T2FGMM.cpp | 134 +- package_bgs/{tb => T2F}/T2FGMM.h | 26 +- package_bgs/{tb => T2F}/T2FMRF.cpp | 154 +- package_bgs/{tb => T2F}/T2FMRF.h | 30 +- package_bgs/{tb => }/T2FGMM_UM.cpp | 60 +- package_bgs/{tb => }/T2FGMM_UM.h | 71 +- package_bgs/{tb => }/T2FGMM_UV.cpp | 60 +- package_bgs/{tb => }/T2FGMM_UV.h | 71 +- package_bgs/{tb => }/T2FMRF_UM.cpp | 91 +- package_bgs/T2FMRF_UM.h | 64 + package_bgs/{tb => }/T2FMRF_UV.cpp | 91 +- package_bgs/T2FMRF_UV.h | 64 + package_bgs/TwoPoints.cpp | 112 ++ package_bgs/TwoPoints.h | 46 + package_bgs/TwoPoints/two_points.cpp | 394 +++++ package_bgs/TwoPoints/two_points.h | 50 + package_bgs/ViBe.cpp | 98 ++ package_bgs/ViBe.h | 52 + package_bgs/ViBe/LICENSE | 44 + .../ViBe/vibe-background-sequential.cpp | 929 ++++++++++ package_bgs/ViBe/vibe-background-sequential.h | 293 ++++ package_bgs/{av => }/VuMeter.cpp | 79 +- package_bgs/VuMeter.h | 52 + package_bgs/{av => VuMeter}/TBackground.cpp | 36 +- package_bgs/{av => VuMeter}/TBackground.h | 1 - .../{av => VuMeter}/TBackgroundVuMeter.cpp | 132 +- .../{av => VuMeter}/TBackgroundVuMeter.h | 6 +- ...vingMeanBGS.cpp => WeightedMovingMean.cpp} | 85 +- package_bgs/WeightedMovingMean.h | 45 + ...anceBGS.cpp => WeightedMovingVariance.cpp} | 99 +- package_bgs/WeightedMovingVariance.h | 46 + package_bgs/WeightedMovingVarianceBGS.h | 48 - package_bgs/_template_/Amber.cpp | 112 ++ package_bgs/_template_/Amber.h | 45 + package_bgs/_template_/MyBGS.cpp | 44 + .../{ck/LbpMrf.h => _template_/MyBGS.h} | 41 +- package_bgs/_template_/amber/amber.c | 80 + package_bgs/_template_/amber/amber.h | 64 + package_bgs/ae/KDE.h | 58 - package_bgs/ae/NPBGSubtractor.cpp | 1160 ------------ package_bgs/av/VuMeter.h | 53 - package_bgs/bgslibrary.h | 65 + package_bgs/bl/SigmaDeltaBGS.cpp | 85 - package_bgs/bl/SigmaDeltaBGS.h | 42 - package_bgs/bl/stdbool.h | 16 - package_bgs/ck/MEDefs.cpp | 40 - package_bgs/ck/README.TXT | 135 -- package_bgs/db/IndependentMultimodalBGS.cpp | 54 - package_bgs/db/IndependentMultimodalBGS.h | 29 - package_bgs/dp/AdaptiveMedianBGS.cpp | 148 +- package_bgs/dp/AdaptiveMedianBGS.h | 89 +- package_bgs/dp/Bgs.h | 54 +- package_bgs/dp/BgsParams.h | 54 +- package_bgs/dp/DPAdaptiveMedianBGS.cpp | 113 -- package_bgs/dp/DPAdaptiveMedianBGS.h | 56 - package_bgs/dp/DPPratiMediodBGS.h | 57 - package_bgs/dp/DPTextureBGS.h | 60 - package_bgs/dp/Eigenbackground.cpp | 260 +-- package_bgs/dp/Eigenbackground.h | 18 +- package_bgs/dp/Error.h | 7 +- package_bgs/dp/GrimsonGMM.cpp | 486 +++--- package_bgs/dp/GrimsonGMM.h | 206 ++- package_bgs/dp/Image.cpp | 42 +- package_bgs/dp/Image.h | 126 +- package_bgs/dp/MeanBGS.cpp | 150 +- package_bgs/dp/MeanBGS.h | 22 +- package_bgs/dp/PratiMediodBGS.cpp | 380 ++-- package_bgs/dp/PratiMediodBGS.h | 36 +- package_bgs/dp/TextureBGS.cpp | 96 +- package_bgs/dp/TextureBGS.h | 12 +- package_bgs/dp/WrenGA.cpp | 210 +-- package_bgs/dp/WrenGA.h | 30 +- package_bgs/dp/ZivkovicAGMM.cpp | 656 +++---- package_bgs/dp/ZivkovicAGMM.h | 46 +- package_bgs/jmo/BlobResult.cpp | 847 --------- package_bgs/jmo/MultiLayerBGS.h | 101 -- package_bgs/jmo/blob.cpp | 1149 ------------ package_bgs/lb/BGModel.cpp | 24 +- package_bgs/lb/BGModel.h | 16 +- package_bgs/lb/BGModelFuzzyGauss.cpp | 60 +- package_bgs/lb/BGModelFuzzyGauss.h | 8 +- package_bgs/lb/BGModelFuzzySom.cpp | 112 +- package_bgs/lb/BGModelFuzzySom.h | 14 +- package_bgs/lb/BGModelGauss.cpp | 64 +- package_bgs/lb/BGModelGauss.h | 8 +- package_bgs/lb/BGModelMog.cpp | 94 +- package_bgs/lb/BGModelMog.h | 8 +- package_bgs/lb/BGModelSom.cpp | 120 +- package_bgs/lb/BGModelSom.h | 14 +- package_bgs/lb/Types.h | 88 +- package_bgs/my/MyBGS.cpp | 26 - package_bgs/my/MyBGS.h | 22 - package_bgs/pl/BackgroundSubtractorLBSP.cpp | 69 - package_bgs/pl/BackgroundSubtractorLBSP.h | 85 - .../pl/BackgroundSubtractorLOBSTER.cpp | 326 ---- package_bgs/pl/BackgroundSubtractorLOBSTER.h | 67 - .../pl/BackgroundSubtractorSuBSENSE.cpp | 737 -------- package_bgs/pl/BackgroundSubtractorSuBSENSE.h | 113 -- package_bgs/pl/DistanceUtils.h | 316 ---- package_bgs/pl/LBSP.cpp | 318 ---- package_bgs/pl/LBSP.h | 118 -- package_bgs/pl/LOBSTER.cpp | 75 - package_bgs/pl/LOBSTER.h | 33 - package_bgs/pl/RandUtils.h | 96 - package_bgs/pl/SuBSENSE.cpp | 75 - package_bgs/pl/SuBSENSE.h | 32 - package_bgs/sjn/SJN_MultiCueBGS.h | 248 --- package_bgs/tb/FuzzyChoquetIntegral.h | 55 - package_bgs/tb/FuzzySugenoIntegral.h | 55 - package_bgs/tb/FuzzyUtils.cpp | 512 ------ package_bgs/tb/PixelUtils.cpp | 351 ---- package_bgs/tb/T2FMRF_UM.h | 64 - package_bgs/tb/T2FMRF_UV.h | 64 - vs2010/.gitignore | 16 - vs2010/README.txt | 15 - vs2010/bgslibrary.sln | 27 - vs2010/bgslibrary.suo | Bin 11776 -> 0 bytes vs2010/bgslibrary.vcxproj | 279 --- vs2010/bgslibrary.vcxproj.filters | 644 ------- vs2010/bgslibrary.vcxproj.user | 8 - vs2010/bgslibrary_demo.vcxproj | 241 --- vs2010/bgslibrary_demo.vcxproj.filters | 596 ------- vs2010/bgslibrary_demo.vcxproj.user | 4 - vs2010/bgslibrary_demo2.vcxproj | 241 --- vs2010/bgslibrary_demo2.vcxproj.filters | 596 ------- vs2010/bgslibrary_demo2.vcxproj.user | 4 - vs2010mfc/outputs/background/KEEP_THIS_FOLDER | 0 vs2010mfc/outputs/foreground/KEEP_THIS_FOLDER | 0 vs2010mfc/outputs/input/KEEP_THIS_FOLDER | 0 vs2010mfc/src/ReadMe.txt | 100 -- vs2010mfc/src/bgslibrary_vs2010_mfc.rc | Bin 17930 -> 0 bytes vs2010mfc/src/bgslibrary_vs2010_mfc.sln | 20 - vs2010mfc/src/bgslibrary_vs2010_mfc.v12.suo | Bin 29696 -> 0 bytes vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj | 296 ---- .../src/bgslibrary_vs2010_mfc.vcxproj.filters | 581 ------ .../src/bgslibrary_vs2010_mfc.vcxproj.user | 7 - vs2010mfc/src/res/bgslibrary_vs2010_mfc.ico | Bin 67777 -> 0 bytes vs2010mfc/src/res/bgslibrary_vs2010_mfc.rc2 | Bin 826 -> 0 bytes vs2013/.gitignore | 10 - vs2013/README.txt | 8 - vs2013/bgslibrary.sln | 40 - vs2013/bgslibrary.suo | Bin 11776 -> 0 bytes vs2013/bgslibrary.vcxproj | 600 ------- vs2013/bgslibrary.vcxproj.filters | 644 ------- vs2013/bgslibrary.vcxproj.user | 34 - vs2013mfc/.gitignore | 3 - .../config/AdaptiveBackgroundLearning.xml | 9 - .../AdaptiveSelectiveBackgroundLearning.xml | 8 - vs2013mfc/config/DPAdaptiveMedianBGS.xml | 7 - vs2013mfc/config/DPEigenbackgroundBGS.xml | 7 - vs2013mfc/config/DPGrimsonGMMBGS.xml | 7 - vs2013mfc/config/DPMeanBGS.xml | 7 - vs2013mfc/config/DPPratiMediodBGS.xml | 8 - vs2013mfc/config/DPTextureBGS.xml | 4 - vs2013mfc/config/DPWrenGABGS.xml | 7 - vs2013mfc/config/DPZivkovicAGMMBGS.xml | 7 - vs2013mfc/config/FrameDifferenceBGS.xml | 6 - vs2013mfc/config/FuzzyChoquetIntegral.xml | 11 - vs2013mfc/config/FuzzySugenoIntegral.xml | 11 - vs2013mfc/config/GMG.xml | 6 - vs2013mfc/config/IndependentMultimodalBGS.xml | 4 - vs2013mfc/config/KDE.xml | 11 - vs2013mfc/config/LBAdaptiveSOM.xml | 9 - vs2013mfc/config/LBFuzzyAdaptiveSOM.xml | 9 - vs2013mfc/config/LBFuzzyGaussian.xml | 8 - vs2013mfc/config/LBMixtureOfGaussians.xml | 8 - vs2013mfc/config/LBSimpleGaussian.xml | 7 - vs2013mfc/config/LOBSTERBGS.xml | 10 - vs2013mfc/config/MixtureOfGaussianV1BGS.xml | 7 - vs2013mfc/config/MixtureOfGaussianV2BGS.xml | 7 - vs2013mfc/config/MultiCueBGS.xml | 4 - vs2013mfc/config/MultiLayerBGS.xml | 31 - vs2013mfc/config/SigmaDeltaBGS.xml | 7 - vs2013mfc/config/StaticFrameDifferenceBGS.xml | 6 - vs2013mfc/config/SuBSENSEBGS.xml | 10 - vs2013mfc/config/T2FGMM_UM.xml | 9 - vs2013mfc/config/T2FGMM_UV.xml | 9 - vs2013mfc/config/T2FMRF_UM.xml | 9 - vs2013mfc/config/T2FMRF_UV.xml | 9 - vs2013mfc/config/VuMeter.xml | 8 - vs2013mfc/config/WeightedMovingMeanBGS.xml | 8 - .../config/WeightedMovingVarianceBGS.xml | 7 - vs2013mfc/dataset/video.avi | Bin 1049784 -> 0 bytes vs2013mfc/src/.gitignore | 6 - vs2013mfc/src/App.cpp | 94 - vs2013mfc/src/App.h | 32 - vs2013mfc/src/Dlg.cpp | 709 -------- vs2013mfc/src/Dlg.h | 92 - vs2013mfc/src/resource.h | Bin 4240 -> 0 bytes vs2013mfc/src/stdafx.cpp | 8 - vs2013mfc/src/stdafx.h | 104 -- vs2013mfc/src/targetver.h | 8 - wrapper_matlab/.gitignore | 1 + wrapper_matlab/backgroundSubtractor.m | 81 + .../backgroundSubtractor_wrapper.cpp | 395 +++++ wrapper_matlab/compile.m | 94 + wrapper_matlab/config/.gitignore | 4 + wrapper_matlab/demo.m | 65 + wrapper_matlab/mxarray.h | 1555 +++++++++++++++++ wrapper_matlab/mxtypes.h | 345 ++++ wrapper_matlab/run_demo.m | 49 + wrapper_python/bgslibrary_module.cpp | 265 +++ wrapper_python/np_opencv_converter.cpp | 103 ++ wrapper_python/np_opencv_converter.h | 122 ++ wrapper_python/utils/container.h | 208 +++ wrapper_python/utils/conversion.cpp | 349 ++++ wrapper_python/utils/conversion.h | 75 + wrapper_python/utils/template.h | 44 + 551 files changed, 27350 insertions(+), 21312 deletions(-) create mode 100644 Demo.py create mode 100644 dataset/demo.avi rename {frames => dataset/frames}/1.png (100%) rename {frames => dataset/frames}/10.png (100%) rename {frames => dataset/frames}/11.png (100%) rename {frames => dataset/frames}/12.png (100%) rename {frames => dataset/frames}/13.png (100%) rename {frames => dataset/frames}/14.png (100%) rename {frames => dataset/frames}/15.png (100%) rename {frames => dataset/frames}/16.png (100%) rename {frames => dataset/frames}/17.png (100%) rename {frames => dataset/frames}/18.png (100%) rename {frames => dataset/frames}/19.png (100%) rename {frames => dataset/frames}/2.png (100%) rename {frames => dataset/frames}/20.png (100%) rename {frames => dataset/frames}/21.png (100%) rename {frames => dataset/frames}/22.png (100%) rename {frames => dataset/frames}/23.png (100%) rename {frames => dataset/frames}/24.png (100%) rename {frames => dataset/frames}/25.png (100%) rename {frames => dataset/frames}/26.png (100%) rename {frames => dataset/frames}/27.png (100%) rename {frames => dataset/frames}/28.png (100%) rename {frames => dataset/frames}/29.png (100%) rename {frames => dataset/frames}/3.png (100%) rename {frames => dataset/frames}/30.png (100%) rename {frames => dataset/frames}/31.png (100%) rename {frames => dataset/frames}/32.png (100%) rename {frames => dataset/frames}/33.png (100%) rename {frames => dataset/frames}/34.png (100%) rename {frames => dataset/frames}/35.png (100%) rename {frames => dataset/frames}/36.png (100%) rename {frames => dataset/frames}/37.png (100%) rename {frames => dataset/frames}/38.png (100%) rename {frames => dataset/frames}/39.png (100%) rename {frames => dataset/frames}/4.png (100%) rename {frames => dataset/frames}/40.png (100%) rename {frames => dataset/frames}/41.png (100%) rename {frames => dataset/frames}/42.png (100%) rename {frames => dataset/frames}/43.png (100%) rename {frames => dataset/frames}/44.png (100%) rename {frames => dataset/frames}/45.png (100%) rename {frames => dataset/frames}/46.png (100%) rename {frames => dataset/frames}/47.png (100%) rename {frames => dataset/frames}/48.png (100%) rename {frames => dataset/frames}/49.png (100%) rename {frames => dataset/frames}/5.png (100%) rename {frames => dataset/frames}/50.png (100%) rename {frames => dataset/frames}/51.png (100%) rename {frames => dataset/frames}/6.png (100%) rename {frames => dataset/frames}/7.png (100%) rename {frames => dataset/frames}/8.png (100%) rename {frames => dataset/frames}/9.png (100%) delete mode 100644 demos/DemoFrameDifferenceBGS.cpp delete mode 100644 demos/DemoMultiLayerBGS.cpp create mode 100644 demos/linux_ubuntu/.gitignore rename {example_linux => demos/linux_ubuntu}/CMakeLists.txt (66%) rename {example_macosx => demos/linux_ubuntu}/FrameDifferenceTest.cpp (87%) rename {example_linux => demos/linux_ubuntu}/README.txt (100%) create mode 100644 demos/linux_ubuntu/config/.gitignore create mode 100644 demos/macosx/.gitignore rename {example_macosx => demos/macosx}/CMakeLists.txt (79%) rename {example_linux => demos/macosx}/FrameDifferenceTest.cpp (87%) rename {example_macosx => demos/macosx}/README.txt (100%) create mode 100644 demos/macosx/config/.gitignore rename README_CMAKE_USERS.txt => docs/README_CMAKE_USERS_OPENCV2.txt (70%) create mode 100644 docs/README_CMAKE_USERS_OPENCV3.txt rename README_LINUX_USERS.txt => docs/README_LINUX_USERS.txt (85%) rename README_VISUAL_STUDIO_USERS.txt => docs/README_VS2010_OPENCV2.txt (81%) delete mode 100644 example_linux/config/KEEP_THIS_FOLDER delete mode 100644 example_macosx/config/KEEP_THIS_FOLDER rename {java_gui => gui_java}/README.txt (100%) rename {java_gui => gui_java}/_COPY_bgslibrary.exe_HERE_ (100%) rename {java_gui => gui_java}/bgslibrary_gui.jar (100%) rename {java_gui => gui_java}/bgslibrary_gui.properties (100%) rename {java_gui => gui_java}/build.xml (100%) rename {java_gui => gui_java}/config/.gitignore (100%) rename {java_gui => gui_java}/config/FrameProcessor.xml (100%) rename {java_gui => gui_java}/config/PreProcessor.xml (100%) rename {java_gui => gui_java}/config/VideoCapture.xml (100%) rename {java_gui => gui_java}/images/bgslibrary_gui_screen01.png (100%) rename {java_gui => gui_java}/images/bgslibrary_gui_screen02.png (100%) rename {java_gui => gui_java}/images/bgslibrary_gui_screen03.png (100%) rename {java_gui => gui_java}/images/bgslibrary_gui_screen04.png (100%) rename {java_gui => gui_java}/images/logo.jpg (100%) rename {java_gui => gui_java}/lib/commons-configuration-1.8.jar (100%) rename {java_gui => gui_java}/lib/commons-io-2.3.jar (100%) rename {java_gui => gui_java}/lib/commons-lang-2.6.jar (100%) rename {java_gui => gui_java}/lib/commons-logging-1.1.1.jar (100%) rename {java_gui => gui_java}/lib/swingx-all-1.6.3.jar (100%) rename {java_gui => gui_java}/lib/swingx-beaninfo-1.6.3.jar (100%) rename {java_gui => gui_java}/manifest.mf (100%) rename {java_gui => gui_java}/nbproject/build-impl.xml (100%) rename {java_gui => gui_java}/nbproject/genfiles.properties (100%) rename {java_gui => gui_java}/nbproject/private/config.properties (100%) rename {java_gui => gui_java}/nbproject/private/private.properties (100%) rename {java_gui => gui_java}/nbproject/private/private.xml (100%) rename {java_gui => gui_java}/nbproject/project.properties (100%) rename {java_gui => gui_java}/nbproject/project.xml (100%) rename {java_gui => gui_java}/run_camera.bat (100%) rename {java_gui => gui_java}/run_java_gui.bat (100%) rename {java_gui => gui_java}/run_java_gui_with_console.bat (100%) rename {java_gui => gui_java}/run_video.bat (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/Main.java (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/entity/Command.java (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/entity/Configuration.java (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/gui/AboutDialog.form (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/gui/AboutDialog.java (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/gui/MainFrame.form (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/gui/MainFrame.java (100%) rename {java_gui => gui_java}/src/br/com/bgslibrary/resources/logo.jpg (100%) rename {vs2010mfc => gui_mfc}/.gitignore (100%) rename {vs2013mfc => gui_mfc}/ReadMe.txt (100%) rename {vs2010mfc => gui_mfc}/config/AdaptiveBackgroundLearning.xml (100%) rename {vs2010mfc => gui_mfc}/config/AdaptiveSelectiveBackgroundLearning.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPAdaptiveMedianBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPEigenbackgroundBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPGrimsonGMMBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPMeanBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPPratiMediodBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPTextureBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPWrenGABGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/DPZivkovicAGMMBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/FrameDifferenceBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/FuzzyChoquetIntegral.xml (100%) rename {vs2010mfc => gui_mfc}/config/FuzzySugenoIntegral.xml (100%) rename {vs2010mfc => gui_mfc}/config/GMG.xml (100%) rename {vs2010mfc => gui_mfc}/config/IndependentMultimodalBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/KDE.xml (100%) rename {vs2010mfc => gui_mfc}/config/LBAdaptiveSOM.xml (100%) rename {vs2010mfc => gui_mfc}/config/LBFuzzyAdaptiveSOM.xml (100%) rename {vs2010mfc => gui_mfc}/config/LBFuzzyGaussian.xml (100%) rename {vs2010mfc => gui_mfc}/config/LBMixtureOfGaussians.xml (100%) rename {vs2010mfc => gui_mfc}/config/LBSimpleGaussian.xml (100%) rename {vs2010mfc => gui_mfc}/config/LOBSTERBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/MixtureOfGaussianV1BGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/MixtureOfGaussianV2BGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/MultiCueBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/MultiLayerBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/SigmaDeltaBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/StaticFrameDifferenceBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/SuBSENSEBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/T2FGMM_UM.xml (100%) rename {vs2010mfc => gui_mfc}/config/T2FGMM_UV.xml (100%) rename {vs2010mfc => gui_mfc}/config/T2FMRF_UM.xml (100%) rename {vs2010mfc => gui_mfc}/config/T2FMRF_UV.xml (100%) rename {vs2010mfc => gui_mfc}/config/VuMeter.xml (100%) rename {vs2010mfc => gui_mfc}/config/WeightedMovingMeanBGS.xml (100%) rename {vs2010mfc => gui_mfc}/config/WeightedMovingVarianceBGS.xml (100%) rename {vs2010mfc => gui_mfc}/dataset/video.avi (100%) rename {vs2013mfc => gui_mfc}/outputs/background/.gitignore (100%) rename {vs2013mfc => gui_mfc}/outputs/foreground/.gitignore (100%) rename {vs2013mfc => gui_mfc}/outputs/input/.gitignore (100%) rename {vs2010mfc => gui_mfc}/src/.gitignore (100%) rename {vs2010mfc => gui_mfc}/src/App.cpp (100%) rename {vs2010mfc => gui_mfc}/src/App.h (100%) rename {vs2010mfc => gui_mfc}/src/Dlg.cpp (100%) rename {vs2010mfc => gui_mfc}/src/Dlg.h (100%) rename {vs2013mfc => gui_mfc}/src/ReadMe.txt (100%) rename {vs2013mfc => gui_mfc}/src/bgslibrary_vs2013_mfc.rc (100%) rename {vs2013mfc => gui_mfc}/src/bgslibrary_vs2013_mfc.sln (100%) rename {vs2013mfc => gui_mfc}/src/bgslibrary_vs2013_mfc.vcxproj (100%) rename {vs2013mfc => gui_mfc}/src/bgslibrary_vs2013_mfc.vcxproj.filters (100%) rename {vs2013mfc => gui_mfc}/src/bgslibrary_vs2013_mfc.vcxproj.user (100%) rename {vs2013mfc => gui_mfc}/src/res/bgslibrary_vs2013_mfc.ico (100%) rename {vs2013mfc => gui_mfc}/src/res/bgslibrary_vs2013_mfc.rc2 (100%) rename {vs2010mfc => gui_mfc}/src/resource.h (100%) rename {vs2010mfc => gui_mfc}/src/stdafx.cpp (100%) rename {vs2010mfc => gui_mfc}/src/stdafx.h (100%) rename {vs2010mfc => gui_mfc}/src/targetver.h (100%) create mode 100644 gui_qt/.gitignore create mode 100644 gui_qt/CMakeLists.txt create mode 100644 gui_qt/README.txt create mode 100644 gui_qt/application.qrc create mode 100644 gui_qt/bgslibrary_gui.cpp create mode 100644 gui_qt/bgslibrary_gui.pro create mode 100644 gui_qt/build/.gitignore create mode 100644 gui_qt/figs/copy.png create mode 100644 gui_qt/figs/cut.png create mode 100644 gui_qt/figs/new.png create mode 100644 gui_qt/figs/open.png create mode 100644 gui_qt/figs/paste.png create mode 100644 gui_qt/figs/save.png create mode 100644 gui_qt/mainwindow.cpp create mode 100644 gui_qt/mainwindow.h create mode 100644 gui_qt/mainwindow.ui create mode 100644 gui_qt/qt_utils.cpp create mode 100644 gui_qt/qt_utils.h create mode 100644 gui_qt/texteditor.cpp create mode 100644 gui_qt/texteditor.h create mode 100644 gui_qt/ui_mainwindow.h create mode 100644 output/bg/.gitignore create mode 100644 output/fg/.gitignore create mode 100644 output/in/.gitignore rename {package_bgs/tb => package_analysis}/PerformanceUtils.cpp (59%) rename {package_bgs/tb => package_analysis}/PerformanceUtils.h (82%) create mode 100644 package_analysis/PixelUtils.cpp rename {package_bgs/tb => package_analysis}/PixelUtils.h (90%) create mode 100644 package_bgs/DPAdaptiveMedian.cpp create mode 100644 package_bgs/DPAdaptiveMedian.h rename package_bgs/{dp/DPEigenbackgroundBGS.cpp => DPEigenbackground.cpp} (53%) create mode 100644 package_bgs/DPEigenbackground.h rename package_bgs/{dp/DPGrimsonGMMBGS.cpp => DPGrimsonGMM.cpp} (54%) rename package_bgs/{dp/DPEigenbackgroundBGS.h => DPGrimsonGMM.h} (53%) rename package_bgs/{dp/DPMeanBGS.cpp => DPMean.cpp} (55%) rename package_bgs/{dp/DPZivkovicAGMMBGS.h => DPMean.h} (56%) rename package_bgs/{dp/DPPratiMediodBGS.cpp => DPPratiMediod.cpp} (53%) rename package_bgs/{dp/DPMeanBGS.h => DPPratiMediod.h} (52%) rename package_bgs/{dp/DPTextureBGS.cpp => DPTexture.cpp} (65%) create mode 100644 package_bgs/DPTexture.h rename package_bgs/{dp/DPWrenGABGS.cpp => DPWrenGA.cpp} (54%) rename package_bgs/{dp/DPWrenGABGS.h => DPWrenGA.h} (54%) rename package_bgs/{dp/DPZivkovicAGMMBGS.cpp => DPZivkovicAGMM.cpp} (53%) rename package_bgs/{dp/DPGrimsonGMMBGS.h => DPZivkovicAGMM.h} (53%) create mode 100644 package_bgs/FrameDifference.cpp rename package_bgs/{FrameDifferenceBGS.h => FrameDifference.h} (61%) delete mode 100644 package_bgs/FrameDifferenceBGS.cpp rename package_bgs/{tb => }/FuzzyChoquetIntegral.cpp (62%) create mode 100644 package_bgs/FuzzyChoquetIntegral.h rename package_bgs/{tb => }/FuzzySugenoIntegral.cpp (62%) create mode 100644 package_bgs/FuzzySugenoIntegral.h rename package_bgs/{db/imbs.cpp => IMBS/IMBS.cpp} (74%) rename package_bgs/{db/imbs.hpp => IMBS/IMBS.hpp} (77%) create mode 100644 package_bgs/IndependentMultimodal.cpp rename package_bgs/{StaticFrameDifferenceBGS.h => IndependentMultimodal.h} (60%) rename package_bgs/{ae => }/KDE.cpp (56%) create mode 100644 package_bgs/KDE.h rename package_bgs/{ae => KDE}/KernelTable.cpp (75%) rename package_bgs/{ae => KDE}/KernelTable.h (86%) create mode 100644 package_bgs/KDE/NPBGSubtractor.cpp rename package_bgs/{ae => KDE}/NPBGSubtractor.h (87%) rename package_bgs/{ae => KDE}/NPBGmodel.cpp (78%) rename package_bgs/{ae => KDE}/NPBGmodel.h (84%) create mode 100644 package_bgs/KNN.cpp create mode 100644 package_bgs/KNN.h rename package_bgs/{lb => }/LBAdaptiveSOM.cpp (61%) rename package_bgs/{lb => }/LBAdaptiveSOM.h (55%) rename package_bgs/{lb => }/LBFuzzyAdaptiveSOM.cpp (59%) rename package_bgs/{lb => }/LBFuzzyAdaptiveSOM.h (55%) rename package_bgs/{lb => }/LBFuzzyGaussian.cpp (59%) rename package_bgs/{lb => }/LBFuzzyGaussian.h (56%) rename package_bgs/{lb => }/LBMixtureOfGaussians.cpp (59%) rename package_bgs/{lb => }/LBMixtureOfGaussians.h (56%) rename package_bgs/{ck/LbpMrf.cpp => LBP_MRF.cpp} (57%) rename package_bgs/{WeightedMovingMeanBGS.h => LBP_MRF.h} (58%) create mode 100644 package_bgs/LBP_MRF/MEDefs.cpp rename package_bgs/{ck => LBP_MRF}/MEDefs.hpp (73%) rename package_bgs/{ck => LBP_MRF}/MEHistogram.cpp (54%) rename package_bgs/{ck => LBP_MRF}/MEHistogram.hpp (93%) rename package_bgs/{ck => LBP_MRF}/MEImage.cpp (50%) rename package_bgs/{ck => LBP_MRF}/MEImage.hpp (97%) rename package_bgs/{ck => LBP_MRF}/MotionDetection.cpp (91%) rename package_bgs/{ck => LBP_MRF}/MotionDetection.hpp (93%) rename package_bgs/{ck => LBP_MRF}/block.h (51%) rename package_bgs/{ck => LBP_MRF}/graph.cpp (78%) rename package_bgs/{ck => LBP_MRF}/graph.h (60%) rename package_bgs/{ck => LBP_MRF}/maxflow.cpp (67%) create mode 100644 package_bgs/LBSP/BackgroundSubtractorLBSP.cpp create mode 100644 package_bgs/LBSP/BackgroundSubtractorLBSP.h create mode 100644 package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp create mode 100644 package_bgs/LBSP/BackgroundSubtractorLBSP_.h create mode 100644 package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp create mode 100644 package_bgs/LBSP/BackgroundSubtractorLOBSTER.h create mode 100644 package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp create mode 100644 package_bgs/LBSP/BackgroundSubtractorPAWCS.h create mode 100644 package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp create mode 100644 package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h create mode 100644 package_bgs/LBSP/DistanceUtils.h create mode 100644 package_bgs/LBSP/LBSP.cpp create mode 100644 package_bgs/LBSP/LBSP.h create mode 100644 package_bgs/LBSP/LBSP_.cpp create mode 100644 package_bgs/LBSP/LBSP_.h rename package_bgs/{pl => LBSP}/LBSP_16bits_dbcross_1ch.i (100%) rename package_bgs/{pl => LBSP}/LBSP_16bits_dbcross_3ch1t.i (100%) rename package_bgs/{pl => LBSP}/LBSP_16bits_dbcross_3ch3t.i (100%) rename package_bgs/{pl => LBSP}/LBSP_16bits_dbcross_s3ch.i (100%) create mode 100644 package_bgs/LBSP/RandUtils.h rename package_bgs/{lb => }/LBSimpleGaussian.cpp (61%) rename package_bgs/{lb => }/LBSimpleGaussian.h (57%) create mode 100644 package_bgs/LOBSTER.cpp create mode 100644 package_bgs/LOBSTER.h rename package_bgs/{MixtureOfGaussianV1BGS.cpp => MixtureOfGaussianV1.cpp} (53%) rename package_bgs/{MixtureOfGaussianV1BGS.h => MixtureOfGaussianV1.h} (59%) rename package_bgs/{MixtureOfGaussianV2BGS.cpp => MixtureOfGaussianV2.cpp} (60%) rename package_bgs/{MixtureOfGaussianV2BGS.h => MixtureOfGaussianV2.h} (57%) rename package_bgs/{sjn/SJN_MultiCueBGS.cpp => MultiCue.cpp} (83%) create mode 100644 package_bgs/MultiCue.h rename package_bgs/{jmo/MultiLayerBGS.cpp => MultiLayer.cpp} (65%) create mode 100644 package_bgs/MultiLayer.h rename package_bgs/{jmo => MultiLayer}/BGS.h (98%) rename package_bgs/{jmo => MultiLayer}/BackgroundSubtractionAPI.h (89%) rename package_bgs/{jmo => MultiLayer}/BlobExtraction.cpp (91%) rename package_bgs/{jmo => MultiLayer}/BlobExtraction.h (96%) rename package_bgs/{jmo => MultiLayer}/BlobLibraryConfiguration.h (95%) create mode 100644 package_bgs/MultiLayer/BlobResult.cpp rename package_bgs/{jmo => MultiLayer}/BlobResult.h (80%) rename package_bgs/{jmo => MultiLayer}/CMultiLayerBGS.cpp (99%) rename package_bgs/{jmo => MultiLayer}/CMultiLayerBGS.h (96%) rename package_bgs/{jmo => MultiLayer}/LocalBinaryPattern.cpp (95%) rename package_bgs/{jmo => MultiLayer}/LocalBinaryPattern.h (96%) rename package_bgs/{jmo => MultiLayer}/OpenCvDataConversion.h (97%) create mode 100644 package_bgs/MultiLayer/OpenCvLegacyIncludes.h create mode 100644 package_bgs/MultiLayer/blob.cpp rename package_bgs/{jmo => MultiLayer}/blob.h (87%) create mode 100644 package_bgs/PAWCS.cpp create mode 100644 package_bgs/PAWCS.h create mode 100644 package_bgs/PBAS/PBAS.cpp create mode 100644 package_bgs/PBAS/PBAS.h create mode 100644 package_bgs/PixelBasedAdaptiveSegmenter.cpp create mode 100644 package_bgs/PixelBasedAdaptiveSegmenter.h create mode 100644 package_bgs/SigmaDelta.cpp create mode 100644 package_bgs/SigmaDelta.h rename package_bgs/{bl => SigmaDelta}/sdLaMa091.cpp (97%) rename package_bgs/{bl => SigmaDelta}/sdLaMa091.h (96%) rename package_bgs/{StaticFrameDifferenceBGS.cpp => StaticFrameDifference.cpp} (53%) create mode 100644 package_bgs/StaticFrameDifference.h create mode 100644 package_bgs/SuBSENSE.cpp create mode 100644 package_bgs/SuBSENSE.h create mode 100644 package_bgs/T2F/FuzzyUtils.cpp rename package_bgs/{tb => T2F}/FuzzyUtils.h (86%) rename package_bgs/{tb => T2F}/MRF.cpp (58%) rename package_bgs/{tb => T2F}/MRF.h (95%) rename package_bgs/{tb => T2F}/T2FGMM.cpp (69%) rename package_bgs/{tb => T2F}/T2FGMM.h (92%) rename package_bgs/{tb => T2F}/T2FMRF.cpp (70%) rename package_bgs/{tb => T2F}/T2FMRF.h (91%) rename package_bgs/{tb => }/T2FGMM_UM.cpp (64%) rename package_bgs/{tb => }/T2FGMM_UM.h (52%) rename package_bgs/{tb => }/T2FGMM_UV.cpp (64%) rename package_bgs/{tb => }/T2FGMM_UV.h (52%) rename package_bgs/{tb => }/T2FMRF_UM.cpp (59%) create mode 100644 package_bgs/T2FMRF_UM.h rename package_bgs/{tb => }/T2FMRF_UV.cpp (59%) create mode 100644 package_bgs/T2FMRF_UV.h create mode 100644 package_bgs/TwoPoints.cpp create mode 100644 package_bgs/TwoPoints.h create mode 100644 package_bgs/TwoPoints/two_points.cpp create mode 100644 package_bgs/TwoPoints/two_points.h create mode 100644 package_bgs/ViBe.cpp create mode 100644 package_bgs/ViBe.h create mode 100644 package_bgs/ViBe/LICENSE create mode 100644 package_bgs/ViBe/vibe-background-sequential.cpp create mode 100644 package_bgs/ViBe/vibe-background-sequential.h rename package_bgs/{av => }/VuMeter.cpp (52%) create mode 100644 package_bgs/VuMeter.h rename package_bgs/{av => VuMeter}/TBackground.cpp (77%) rename package_bgs/{av => VuMeter}/TBackground.h (99%) rename package_bgs/{av => VuMeter}/TBackgroundVuMeter.cpp (74%) rename package_bgs/{av => VuMeter}/TBackgroundVuMeter.h (95%) rename package_bgs/{WeightedMovingMeanBGS.cpp => WeightedMovingMean.cpp} (51%) create mode 100644 package_bgs/WeightedMovingMean.h rename package_bgs/{WeightedMovingVarianceBGS.cpp => WeightedMovingVariance.cpp} (62%) create mode 100644 package_bgs/WeightedMovingVariance.h delete mode 100644 package_bgs/WeightedMovingVarianceBGS.h create mode 100644 package_bgs/_template_/Amber.cpp create mode 100644 package_bgs/_template_/Amber.h create mode 100644 package_bgs/_template_/MyBGS.cpp rename package_bgs/{ck/LbpMrf.h => _template_/MyBGS.h} (65%) create mode 100644 package_bgs/_template_/amber/amber.c create mode 100644 package_bgs/_template_/amber/amber.h delete mode 100644 package_bgs/ae/KDE.h delete mode 100644 package_bgs/ae/NPBGSubtractor.cpp delete mode 100644 package_bgs/av/VuMeter.h create mode 100644 package_bgs/bgslibrary.h delete mode 100644 package_bgs/bl/SigmaDeltaBGS.cpp delete mode 100644 package_bgs/bl/SigmaDeltaBGS.h delete mode 100644 package_bgs/bl/stdbool.h delete mode 100644 package_bgs/ck/MEDefs.cpp delete mode 100644 package_bgs/ck/README.TXT delete mode 100644 package_bgs/db/IndependentMultimodalBGS.cpp delete mode 100644 package_bgs/db/IndependentMultimodalBGS.h delete mode 100644 package_bgs/dp/DPAdaptiveMedianBGS.cpp delete mode 100644 package_bgs/dp/DPAdaptiveMedianBGS.h delete mode 100644 package_bgs/dp/DPPratiMediodBGS.h delete mode 100644 package_bgs/dp/DPTextureBGS.h delete mode 100644 package_bgs/jmo/BlobResult.cpp delete mode 100644 package_bgs/jmo/MultiLayerBGS.h delete mode 100644 package_bgs/jmo/blob.cpp delete mode 100644 package_bgs/my/MyBGS.cpp delete mode 100644 package_bgs/my/MyBGS.h delete mode 100644 package_bgs/pl/BackgroundSubtractorLBSP.cpp delete mode 100644 package_bgs/pl/BackgroundSubtractorLBSP.h delete mode 100644 package_bgs/pl/BackgroundSubtractorLOBSTER.cpp delete mode 100644 package_bgs/pl/BackgroundSubtractorLOBSTER.h delete mode 100644 package_bgs/pl/BackgroundSubtractorSuBSENSE.cpp delete mode 100644 package_bgs/pl/BackgroundSubtractorSuBSENSE.h delete mode 100644 package_bgs/pl/DistanceUtils.h delete mode 100644 package_bgs/pl/LBSP.cpp delete mode 100644 package_bgs/pl/LBSP.h delete mode 100644 package_bgs/pl/LOBSTER.cpp delete mode 100644 package_bgs/pl/LOBSTER.h delete mode 100644 package_bgs/pl/RandUtils.h delete mode 100644 package_bgs/pl/SuBSENSE.cpp delete mode 100644 package_bgs/pl/SuBSENSE.h delete mode 100644 package_bgs/sjn/SJN_MultiCueBGS.h delete mode 100644 package_bgs/tb/FuzzyChoquetIntegral.h delete mode 100644 package_bgs/tb/FuzzySugenoIntegral.h delete mode 100644 package_bgs/tb/FuzzyUtils.cpp delete mode 100644 package_bgs/tb/PixelUtils.cpp delete mode 100644 package_bgs/tb/T2FMRF_UM.h delete mode 100644 package_bgs/tb/T2FMRF_UV.h delete mode 100644 vs2010/.gitignore delete mode 100644 vs2010/README.txt delete mode 100644 vs2010/bgslibrary.sln delete mode 100644 vs2010/bgslibrary.suo delete mode 100644 vs2010/bgslibrary.vcxproj delete mode 100644 vs2010/bgslibrary.vcxproj.filters delete mode 100644 vs2010/bgslibrary.vcxproj.user delete mode 100644 vs2010/bgslibrary_demo.vcxproj delete mode 100644 vs2010/bgslibrary_demo.vcxproj.filters delete mode 100644 vs2010/bgslibrary_demo.vcxproj.user delete mode 100644 vs2010/bgslibrary_demo2.vcxproj delete mode 100644 vs2010/bgslibrary_demo2.vcxproj.filters delete mode 100644 vs2010/bgslibrary_demo2.vcxproj.user delete mode 100644 vs2010mfc/outputs/background/KEEP_THIS_FOLDER delete mode 100644 vs2010mfc/outputs/foreground/KEEP_THIS_FOLDER delete mode 100644 vs2010mfc/outputs/input/KEEP_THIS_FOLDER delete mode 100644 vs2010mfc/src/ReadMe.txt delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.rc delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.sln delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.v12.suo delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.filters delete mode 100644 vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.user delete mode 100644 vs2010mfc/src/res/bgslibrary_vs2010_mfc.ico delete mode 100644 vs2010mfc/src/res/bgslibrary_vs2010_mfc.rc2 delete mode 100644 vs2013/.gitignore delete mode 100644 vs2013/README.txt delete mode 100644 vs2013/bgslibrary.sln delete mode 100644 vs2013/bgslibrary.suo delete mode 100644 vs2013/bgslibrary.vcxproj delete mode 100644 vs2013/bgslibrary.vcxproj.filters delete mode 100644 vs2013/bgslibrary.vcxproj.user delete mode 100644 vs2013mfc/.gitignore delete mode 100644 vs2013mfc/config/AdaptiveBackgroundLearning.xml delete mode 100644 vs2013mfc/config/AdaptiveSelectiveBackgroundLearning.xml delete mode 100644 vs2013mfc/config/DPAdaptiveMedianBGS.xml delete mode 100644 vs2013mfc/config/DPEigenbackgroundBGS.xml delete mode 100644 vs2013mfc/config/DPGrimsonGMMBGS.xml delete mode 100644 vs2013mfc/config/DPMeanBGS.xml delete mode 100644 vs2013mfc/config/DPPratiMediodBGS.xml delete mode 100644 vs2013mfc/config/DPTextureBGS.xml delete mode 100644 vs2013mfc/config/DPWrenGABGS.xml delete mode 100644 vs2013mfc/config/DPZivkovicAGMMBGS.xml delete mode 100644 vs2013mfc/config/FrameDifferenceBGS.xml delete mode 100644 vs2013mfc/config/FuzzyChoquetIntegral.xml delete mode 100644 vs2013mfc/config/FuzzySugenoIntegral.xml delete mode 100644 vs2013mfc/config/GMG.xml delete mode 100644 vs2013mfc/config/IndependentMultimodalBGS.xml delete mode 100644 vs2013mfc/config/KDE.xml delete mode 100644 vs2013mfc/config/LBAdaptiveSOM.xml delete mode 100644 vs2013mfc/config/LBFuzzyAdaptiveSOM.xml delete mode 100644 vs2013mfc/config/LBFuzzyGaussian.xml delete mode 100644 vs2013mfc/config/LBMixtureOfGaussians.xml delete mode 100644 vs2013mfc/config/LBSimpleGaussian.xml delete mode 100644 vs2013mfc/config/LOBSTERBGS.xml delete mode 100644 vs2013mfc/config/MixtureOfGaussianV1BGS.xml delete mode 100644 vs2013mfc/config/MixtureOfGaussianV2BGS.xml delete mode 100644 vs2013mfc/config/MultiCueBGS.xml delete mode 100644 vs2013mfc/config/MultiLayerBGS.xml delete mode 100644 vs2013mfc/config/SigmaDeltaBGS.xml delete mode 100644 vs2013mfc/config/StaticFrameDifferenceBGS.xml delete mode 100644 vs2013mfc/config/SuBSENSEBGS.xml delete mode 100644 vs2013mfc/config/T2FGMM_UM.xml delete mode 100644 vs2013mfc/config/T2FGMM_UV.xml delete mode 100644 vs2013mfc/config/T2FMRF_UM.xml delete mode 100644 vs2013mfc/config/T2FMRF_UV.xml delete mode 100644 vs2013mfc/config/VuMeter.xml delete mode 100644 vs2013mfc/config/WeightedMovingMeanBGS.xml delete mode 100644 vs2013mfc/config/WeightedMovingVarianceBGS.xml delete mode 100644 vs2013mfc/dataset/video.avi delete mode 100644 vs2013mfc/src/.gitignore delete mode 100644 vs2013mfc/src/App.cpp delete mode 100644 vs2013mfc/src/App.h delete mode 100644 vs2013mfc/src/Dlg.cpp delete mode 100644 vs2013mfc/src/Dlg.h delete mode 100644 vs2013mfc/src/resource.h delete mode 100644 vs2013mfc/src/stdafx.cpp delete mode 100644 vs2013mfc/src/stdafx.h delete mode 100644 vs2013mfc/src/targetver.h create mode 100644 wrapper_matlab/.gitignore create mode 100644 wrapper_matlab/backgroundSubtractor.m create mode 100644 wrapper_matlab/backgroundSubtractor_wrapper.cpp create mode 100644 wrapper_matlab/compile.m create mode 100644 wrapper_matlab/config/.gitignore create mode 100644 wrapper_matlab/demo.m create mode 100644 wrapper_matlab/mxarray.h create mode 100644 wrapper_matlab/mxtypes.h create mode 100644 wrapper_matlab/run_demo.m create mode 100644 wrapper_python/bgslibrary_module.cpp create mode 100644 wrapper_python/np_opencv_converter.cpp create mode 100644 wrapper_python/np_opencv_converter.h create mode 100644 wrapper_python/utils/container.h create mode 100644 wrapper_python/utils/conversion.cpp create mode 100644 wrapper_python/utils/conversion.h create mode 100644 wrapper_python/utils/template.h diff --git a/.gitignore b/.gitignore index 3f5e0f7..f1d9cb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ etc/ build_*/ -binaries/ +dataset_*/ +binaries*/ java_gui/dist/ java_gui/build/ java_gui/bgslibrary.exe @@ -9,4 +10,5 @@ qt_gui/ fet/etc/ *.exe *.pdb -*.suo \ No newline at end of file +*.suo +*.dll diff --git a/CMakeLists.txt b/CMakeLists.txt index d8e60da..6a01cce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,24 +2,44 @@ cmake_minimum_required(VERSION 2.8) project(bgslibrary) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") +# cmake -D BGS_PYTHON_SUPPORT=ON .. +if(NOT DEFINED BGS_PYTHON_SUPPORT) + set(BGS_PYTHON_SUPPORT OFF) +elseif() + # add_definitions(-DBGS_PYTHON_SUPPORT) +endif() +message(STATUS "BGSLIBRARY WITH PYTHON SUPPORT: ${BGS_PYTHON_SUPPORT}") + +if(UNIX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") +endif(UNIX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") #set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) -set( bgs_out_dir "." ) +# compilation mode setup +set(CMAKE_BUILD_TYPE Release) +#set(CMAKE_BUILD_TYPE Debug) + +if(WIN32) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") +endif(WIN32) + +set(bgs_out_dir ".") # First for the generic no-config case (e.g. with mingw) -set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bgs_out_dir} ) -set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir} ) -set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir} ) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${bgs_out_dir}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${bgs_out_dir}) # Second, for multi-config builds (e.g. msvc) -foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) - string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) - set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir} ) - set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir} ) - set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir} ) -endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) - -IF(UNIX) +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${bgs_out_dir}) +endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) + +if(UNIX) # add some standard warnings ADD_DEFINITIONS(-Wno-variadic-macros -Wno-long-long -Wall -Wextra -Winit-self -Woverloaded-virtual -Wsign-promo -Wno-unused-parameter -pedantic -Woverloaded-virtual -Wno-unknown-pragmas) @@ -30,6 +50,7 @@ IF(UNIX) #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) endif(UNIX) +set(OpenCV_STATIC OFF) find_package(OpenCV REQUIRED) message(STATUS "OpenCV library status:") @@ -37,24 +58,50 @@ message(STATUS " version: ${OpenCV_VERSION}") message(STATUS " libraries: ${OpenCV_LIBS}") message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") -if(${OpenCV_VERSION} VERSION_EQUAL 3 OR ${OpenCV_VERSION} VERSION_GREATER 3) - message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") -endif() +# if(${OpenCV_VERSION} VERSION_EQUAL 3 OR ${OpenCV_VERSION} VERSION_GREATER 3) +# message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") +# endif() if(${OpenCV_VERSION} VERSION_LESS 2.3.1) message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") endif() -file(GLOB sources FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp VideoCapture.cpp) -file(GLOB main Main.cpp) +if(BGS_PYTHON_SUPPORT) + set(Boost_USE_STATIC_LIBS OFF) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + + find_package(Boost REQUIRED COMPONENTS python) + find_package(PythonLibs REQUIRED) + + message(STATUS "Boost library status:") + message(STATUS " version: ${Boost_VERSION}") + message(STATUS " libraries: ${Boost_LIBRARIES}") + message(STATUS " include path: ${Boost_INCLUDE_DIRS}") + + message(STATUS "Python library status:") + message(STATUS " version: ${PYTHON_VERSION}") + message(STATUS " libraries: ${PYTHON_LIBRARIES}") + message(STATUS " include path: ${PYTHON_INCLUDE_DIRS}") +endif() + +#file(GLOB sources FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp VideoCapture.cpp) +file(GLOB main Main.cpp FrameProcessor.cpp PreProcessor.cpp VideoAnalysis.cpp VideoCapture.cpp) file(GLOB demo Demo.cpp) file(GLOB demo2 Demo2.cpp) # list(REMOVE_ITEM sources ${demo} ${demo2}) file(GLOB_RECURSE analysis_src package_analysis/*.cpp) -file(GLOB_RECURSE bgs_src package_bgs/*.cpp package_bgs/*.c) -file(GLOB_RECURSE bgs_include package_bgs/*.h) +if(BGS_PYTHON_SUPPORT) + file(GLOB_RECURSE bgs_src package_bgs/*.cpp package_bgs/*.c wrapper_python/*.cpp) + file(GLOB_RECURSE bgs_include package_bgs/*.h wrapper_python/*.h) + include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +else() + file(GLOB_RECURSE bgs_src package_bgs/*.cpp package_bgs/*.c) + file(GLOB_RECURSE bgs_include package_bgs/*.h) + include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) +endif() # GMG is not available in older OpenCV versions if(${OpenCV_VERSION} VERSION_LESS 2.4.3) @@ -62,10 +109,16 @@ if(${OpenCV_VERSION} VERSION_LESS 2.4.3) list(REMOVE_ITEM bgs_src ${gmg}) endif() -include_directories(${CMAKE_SOURCE_DIR}) - -add_library(libbgs STATIC ${sources} ${bgs_src} ${analysis_src}) -target_link_libraries(libbgs ${OpenCV_LIBS}) +if(BGS_PYTHON_SUPPORT) + #add_library(libbgs SHARED ${sources} ${bgs_src} ${analysis_src}) + add_library(libbgs SHARED ${bgs_src} ${analysis_src}) + target_link_libraries(libbgs ${OpenCV_LIBS} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES}) + target_compile_definitions(libbgs PRIVATE BGS_PYTHON_SUPPORT=1) +else() + #add_library(libbgs STATIC ${sources} ${bgs_src} ${analysis_src}) + add_library(libbgs STATIC ${bgs_src} ${analysis_src}) + target_link_libraries(libbgs ${OpenCV_LIBS}) +endif() set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_include}) if(WIN32) # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") @@ -83,7 +136,7 @@ target_link_libraries(bgs_demo ${OpenCV_LIBS} libbgs) add_executable(bgs_demo2 ${demo2}) target_link_libraries(bgs_demo2 ${OpenCV_LIBS} libbgs) -INSTALL(TARGETS libbgs +install(TARGETS libbgs bgslibrary RUNTIME DESTINATION bin COMPONENT app LIBRARY DESTINATION lib COMPONENT runtime diff --git a/Demo.cpp b/Demo.cpp index 61561be..fec54d8 100644 --- a/Demo.cpp +++ b/Demo.cpp @@ -17,178 +17,98 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - -#include "package_bgs/FrameDifferenceBGS.h" -#include "package_bgs/StaticFrameDifferenceBGS.h" -#include "package_bgs/WeightedMovingMeanBGS.h" -#include "package_bgs/WeightedMovingVarianceBGS.h" -#include "package_bgs/MixtureOfGaussianV1BGS.h" -#include "package_bgs/MixtureOfGaussianV2BGS.h" -#include "package_bgs/AdaptiveBackgroundLearning.h" -#include "package_bgs/AdaptiveSelectiveBackgroundLearning.h" - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 -#include "package_bgs/GMG.h" -#endif - -#include "package_bgs/dp/DPAdaptiveMedianBGS.h" -#include "package_bgs/dp/DPGrimsonGMMBGS.h" -#include "package_bgs/dp/DPZivkovicAGMMBGS.h" -#include "package_bgs/dp/DPMeanBGS.h" -#include "package_bgs/dp/DPWrenGABGS.h" -#include "package_bgs/dp/DPPratiMediodBGS.h" -#include "package_bgs/dp/DPEigenbackgroundBGS.h" -#include "package_bgs/dp/DPTextureBGS.h" - -#include "package_bgs/tb/T2FGMM_UM.h" -#include "package_bgs/tb/T2FGMM_UV.h" -#include "package_bgs/tb/T2FMRF_UM.h" -#include "package_bgs/tb/T2FMRF_UV.h" -#include "package_bgs/tb/FuzzySugenoIntegral.h" -#include "package_bgs/tb/FuzzyChoquetIntegral.h" - -#include "package_bgs/lb/LBSimpleGaussian.h" -#include "package_bgs/lb/LBFuzzyGaussian.h" -#include "package_bgs/lb/LBMixtureOfGaussians.h" -#include "package_bgs/lb/LBAdaptiveSOM.h" -#include "package_bgs/lb/LBFuzzyAdaptiveSOM.h" - -#include "package_bgs/ck/LbpMrf.h" -#include "package_bgs/jmo/MultiLayerBGS.h" -// The PBAS algorithm was removed from BGSLibrary because it is -// based on patented algorithm ViBE -// http://www2.ulg.ac.be/telecom/research/vibe/ -//#include "package_bgs/pt/PixelBasedAdaptiveSegmenter.h" -#include "package_bgs/av/VuMeter.h" -#include "package_bgs/ae/KDE.h" -#include "package_bgs/db/IndependentMultimodalBGS.h" -#include "package_bgs/sjn/SJN_MultiCueBGS.h" -#include "package_bgs/bl/SigmaDeltaBGS.h" - -#include "package_bgs/pl/SuBSENSE.h" -#include "package_bgs/pl/LOBSTER.h" +#include "package_bgs/bgslibrary.h" int main(int argc, char **argv) { std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - CvCapture *capture = 0; - int resize_factor = 100; + VideoCapture capture; - if(argc > 1) + if (argc > 1) { std::cout << "Openning: " << argv[1] << std::endl; - capture = cvCaptureFromAVI(argv[1]); + capture.open(argv[1]); } else - { - capture = cvCaptureFromCAM(0); - resize_factor = 50; // set size = 50% of original image - } + capture.open(0); - if(!capture) + if (!capture.isOpened()) { std::cerr << "Cannot initialize video!" << std::endl; return -1; } - - IplImage *frame_aux = cvQueryFrame(capture); - IplImage *frame = cvCreateImage(cvSize((int)((frame_aux->width*resize_factor)/100) , (int)((frame_aux->height*resize_factor)/100)), frame_aux->depth, frame_aux->nChannels); - cvResize(frame_aux, frame); /* Background Subtraction Methods */ IBGS *bgs; - /*** Default Package ***/ - bgs = new FrameDifferenceBGS; - //bgs = new StaticFrameDifferenceBGS; - //bgs = new WeightedMovingMeanBGS; - //bgs = new WeightedMovingVarianceBGS; - //bgs = new MixtureOfGaussianV1BGS; - //bgs = new MixtureOfGaussianV2BGS; + bgs = new FrameDifference; + //bgs = new StaticFrameDifference; + //bgs = new WeightedMovingMean; + //bgs = new WeightedMovingVariance; + //bgs = new MixtureOfGaussianV1; // only on OpenCV 2.x + //bgs = new MixtureOfGaussianV2; //bgs = new AdaptiveBackgroundLearning; //bgs = new AdaptiveSelectiveBackgroundLearning; - //bgs = new GMG; - - /*** DP Package (thanks to Donovan Parks) ***/ - //bgs = new DPAdaptiveMedianBGS; - //bgs = new DPGrimsonGMMBGS; - //bgs = new DPZivkovicAGMMBGS; - //bgs = new DPMeanBGS; - //bgs = new DPWrenGABGS; - //bgs = new DPPratiMediodBGS; - //bgs = new DPEigenbackgroundBGS; - //bgs = new DPTextureBGS; - - /*** TB Package (thanks to Thierry Bouwmans, Fida EL BAF and Zhenjie Zhao) ***/ + //bgs = new GMG; // only on OpenCV 2.x + //bgs = new KNN; // only on OpenCV 3.x + //bgs = new DPAdaptiveMedian; + //bgs = new DPGrimsonGMM; + //bgs = new DPZivkovicAGMM; + //bgs = new DPMean; + //bgs = new DPWrenGA; + //bgs = new DPPratiMediod; + //bgs = new DPEigenbackground; + //bgs = new DPTexture; //bgs = new T2FGMM_UM; //bgs = new T2FGMM_UV; //bgs = new T2FMRF_UM; //bgs = new T2FMRF_UV; //bgs = new FuzzySugenoIntegral; //bgs = new FuzzyChoquetIntegral; - - /*** JMO Package (thanks to Jean-Marc Odobez) ***/ - //bgs = new MultiLayerBGS; - - /*** PT Package (thanks to Martin Hofmann, Philipp Tiefenbacher and Gerhard Rigoll) ***/ + //bgs = new MultiLayer; //bgs = new PixelBasedAdaptiveSegmenter; - - /*** LB Package (thanks to Laurence Bender) ***/ //bgs = new LBSimpleGaussian; //bgs = new LBFuzzyGaussian; //bgs = new LBMixtureOfGaussians; //bgs = new LBAdaptiveSOM; //bgs = new LBFuzzyAdaptiveSOM; - - /*** LBP-MRF Package (thanks to Csaba Kertész) ***/ - //bgs = new LbpMrf; - - /*** AV Package (thanks to Lionel Robinault and Antoine Vacavant) ***/ + //bgs = new LBP_MRF; //bgs = new VuMeter; - - /*** EG Package (thanks to Ahmed Elgammal) ***/ //bgs = new KDE; - - /*** DB Package (thanks to Domenico Daniele Bloisi) ***/ - //bgs = new IndependentMultimodalBGS; - - /*** SJN Package (thanks to SeungJong Noh) ***/ - //bgs = new SJN_MultiCueBGS; - - /*** BL Package (thanks to Benjamin Laugraud) ***/ - //bgs = new SigmaDeltaBGS; - - /*** PL Package (thanks to Pierre-Luc) ***/ - //bgs = new SuBSENSEBGS(); - //bgs = new LOBSTERBGS(); + //bgs = new IndependentMultimodal; + //bgs = new MultiCue; + //bgs = new SigmaDelta; + //bgs = new SuBSENSE; + //bgs = new LOBSTER; + //bgs = new PAWCS; + //bgs = new TwoPoints; + //bgs = new ViBe; int key = 0; - while(key != 'q') + cv::Mat img_input; + while (key != 'q') { - frame_aux = cvQueryFrame(capture); - if(!frame_aux) break; + capture >> img_input; + if (img_input.empty()) break; - cvResize(frame_aux, frame); - - cv::Mat img_input(frame); cv::imshow("input", img_input); cv::Mat img_mask; cv::Mat img_bkgmodel; bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image - + //if(!img_mask.empty()) // cv::imshow("Foreground", img_mask); // do something - + key = cvWaitKey(33); } delete bgs; + capture.release(); cvDestroyAllWindows(); - cvReleaseCapture(&capture); return 0; } diff --git a/Demo.py b/Demo.py new file mode 100644 index 0000000..71bc352 --- /dev/null +++ b/Demo.py @@ -0,0 +1,84 @@ +import numpy as np +import cv2 +import libbgs + +## BGS Library algorithms +bgs = libbgs.FrameDifference() +#bgs = libbgs.StaticFrameDifference() +#bgs = libbgs.AdaptiveBackgroundLearning() +#bgs = libbgs.AdaptiveSelectiveBackgroundLearning() +#bgs = libbgs.DPAdaptiveMedian() +#bgs = libbgs.DPEigenbackground() +#bgs = libbgs.DPGrimsonGMM() +#bgs = libbgs.DPMean() +#bgs = libbgs.DPPratiMediod() +#bgs = libbgs.DPTexture() +#bgs = libbgs.DPWrenGA() +#bgs = libbgs.DPZivkovicAGMM() +#bgs = libbgs.FuzzyChoquetIntegral() +#bgs = libbgs.FuzzySugenoIntegral() +#bgs = libbgs.GMG() # if opencv 2.x +#bgs = libbgs.IndependentMultimodal() +#bgs = libbgs.KDE() +#bgs = libbgs.KNN() # if opencv 3.x +#bgs = libbgs.LBAdaptiveSOM() +#bgs = libbgs.LBFuzzyAdaptiveSOM() +#bgs = libbgs.LBFuzzyGaussian() +#bgs = libbgs.LBMixtureOfGaussians() +#bgs = libbgs.LBSimpleGaussian() +#bgs = libbgs.LBP_MRF() +#bgs = libbgs.LOBSTER() +#bgs = libbgs.MixtureOfGaussianV1() # if opencv 2.x +#bgs = libbgs.MixtureOfGaussianV2() +#bgs = libbgs.MultiCue() +#bgs = libbgs.MultiLayer() +#bgs = libbgs.PAWCS() +#bgs = libbgs.PixelBasedAdaptiveSegmenter() +#bgs = libbgs.SigmaDelta() +#bgs = libbgs.SuBSENSE() +#bgs = libbgs.T2FGMM_UM() +#bgs = libbgs.T2FGMM_UV() +#bgs = libbgs.T2FMRF_UM() +#bgs = libbgs.T2FMRF_UV() +#bgs = libbgs.VuMeter() +#bgs = libbgs.WeightedMovingMean() +#bgs = libbgs.WeightedMovingVariance() +#bgs = libbgs.TwoPoints() +#bgs = libbgs.ViBe() + +video_file = "dataset/video.avi" + +capture = cv2.VideoCapture(video_file) +while not capture.isOpened(): + capture = cv2.VideoCapture(video_file) + cv2.waitKey(1000) + print "Wait for the header" + +pos_frame = capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) +while True: + flag, frame = capture.read() + + if flag: + cv2.imshow('video', frame) + pos_frame = capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) + #print str(pos_frame)+" frames" + + img_output = bgs.apply(frame) + img_bgmodel = bgs.getBackgroundModel(); + + cv2.imshow('img_output', img_output) + cv2.imshow('img_bgmodel', img_bgmodel) + + else: + capture.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1) + print "frame is not ready" + cv2.waitKey(1000) + # break + + if 0xFF & cv2.waitKey(10) == 27: + break + + if capture.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == capture.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT): + break + +cv2.destroyAllWindows() diff --git a/Demo2.cpp b/Demo2.cpp index fe95c52..22c6ffc 100644 --- a/Demo2.cpp +++ b/Demo2.cpp @@ -17,56 +17,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - -#include "package_bgs/FrameDifferenceBGS.h" -#include "package_bgs/StaticFrameDifferenceBGS.h" -#include "package_bgs/WeightedMovingMeanBGS.h" -#include "package_bgs/WeightedMovingVarianceBGS.h" -#include "package_bgs/MixtureOfGaussianV1BGS.h" -#include "package_bgs/MixtureOfGaussianV2BGS.h" -#include "package_bgs/AdaptiveBackgroundLearning.h" -#include "package_bgs/AdaptiveSelectiveBackgroundLearning.h" - -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 -#include "package_bgs/GMG.h" -#endif - -#include "package_bgs/dp/DPAdaptiveMedianBGS.h" -#include "package_bgs/dp/DPGrimsonGMMBGS.h" -#include "package_bgs/dp/DPZivkovicAGMMBGS.h" -#include "package_bgs/dp/DPMeanBGS.h" -#include "package_bgs/dp/DPWrenGABGS.h" -#include "package_bgs/dp/DPPratiMediodBGS.h" -#include "package_bgs/dp/DPEigenbackgroundBGS.h" -#include "package_bgs/dp/DPTextureBGS.h" - -#include "package_bgs/tb/T2FGMM_UM.h" -#include "package_bgs/tb/T2FGMM_UV.h" -#include "package_bgs/tb/T2FMRF_UM.h" -#include "package_bgs/tb/T2FMRF_UV.h" -#include "package_bgs/tb/FuzzySugenoIntegral.h" -#include "package_bgs/tb/FuzzyChoquetIntegral.h" - -#include "package_bgs/lb/LBSimpleGaussian.h" -#include "package_bgs/lb/LBFuzzyGaussian.h" -#include "package_bgs/lb/LBMixtureOfGaussians.h" -#include "package_bgs/lb/LBAdaptiveSOM.h" -#include "package_bgs/lb/LBFuzzyAdaptiveSOM.h" - -#include "package_bgs/ck/LbpMrf.h" -#include "package_bgs/jmo/MultiLayerBGS.h" -// The PBAS algorithm was removed from BGSLibrary because it is -// based on patented algorithm ViBE -// http://www2.ulg.ac.be/telecom/research/vibe/ -//#include "package_bgs/pt/PixelBasedAdaptiveSegmenter.h" -#include "package_bgs/av/VuMeter.h" -#include "package_bgs/ae/KDE.h" -#include "package_bgs/db/IndependentMultimodalBGS.h" -#include "package_bgs/sjn/SJN_MultiCueBGS.h" -#include "package_bgs/bl/SigmaDeltaBGS.h" - -#include "package_bgs/pl/SuBSENSE.h" -#include "package_bgs/pl/LOBSTER.h" +#include "package_bgs/bgslibrary.h" int main(int argc, char **argv) { @@ -75,81 +26,60 @@ int main(int argc, char **argv) /* Background Subtraction Methods */ IBGS *bgs; - /*** Default Package ***/ - bgs = new FrameDifferenceBGS; - //bgs = new StaticFrameDifferenceBGS; - //bgs = new WeightedMovingMeanBGS; - //bgs = new WeightedMovingVarianceBGS; - //bgs = new MixtureOfGaussianV1BGS; - //bgs = new MixtureOfGaussianV2BGS; + bgs = new FrameDifference; + //bgs = new StaticFrameDifference; + //bgs = new WeightedMovingMean; + //bgs = new WeightedMovingVariance; + //bgs = new MixtureOfGaussianV1; // only on OpenCV 2.x + //bgs = new MixtureOfGaussianV2; //bgs = new AdaptiveBackgroundLearning; //bgs = new AdaptiveSelectiveBackgroundLearning; - //bgs = new GMG; - - /*** DP Package (thanks to Donovan Parks) ***/ - //bgs = new DPAdaptiveMedianBGS; - //bgs = new DPGrimsonGMMBGS; - //bgs = new DPZivkovicAGMMBGS; - //bgs = new DPMeanBGS; - //bgs = new DPWrenGABGS; - //bgs = new DPPratiMediodBGS; - //bgs = new DPEigenbackgroundBGS; - //bgs = new DPTextureBGS; - - /*** TB Package (thanks to Thierry Bouwmans, Fida EL BAF and Zhenjie Zhao) ***/ + //bgs = new GMG; // only on OpenCV 2.x + //bgs = new KNN; // only on OpenCV 3.x + //bgs = new DPAdaptiveMedian; + //bgs = new DPGrimsonGMM; + //bgs = new DPZivkovicAGMM; + //bgs = new DPMean; + //bgs = new DPWrenGA; + //bgs = new DPPratiMediod; + //bgs = new DPEigenbackground; + //bgs = new DPTexture; //bgs = new T2FGMM_UM; //bgs = new T2FGMM_UV; //bgs = new T2FMRF_UM; //bgs = new T2FMRF_UV; //bgs = new FuzzySugenoIntegral; //bgs = new FuzzyChoquetIntegral; - - /*** JMO Package (thanks to Jean-Marc Odobez) ***/ - //bgs = new MultiLayerBGS; - - /*** PT Package (thanks to Martin Hofmann, Philipp Tiefenbacher and Gerhard Rigoll) ***/ + //bgs = new MultiLayer; //bgs = new PixelBasedAdaptiveSegmenter; - - /*** LB Package (thanks to Laurence Bender) ***/ //bgs = new LBSimpleGaussian; //bgs = new LBFuzzyGaussian; //bgs = new LBMixtureOfGaussians; //bgs = new LBAdaptiveSOM; //bgs = new LBFuzzyAdaptiveSOM; - - /*** LBP-MRF Package (thanks to Csaba Kertész) ***/ - //bgs = new LbpMrf; - - /*** AV Package (thanks to Lionel Robinault and Antoine Vacavant) ***/ + //bgs = new LBP_MRF; //bgs = new VuMeter; - - /*** EG Package (thanks to Ahmed Elgammal) ***/ //bgs = new KDE; - - /*** DB Package (thanks to Domenico Daniele Bloisi) ***/ - //bgs = new IndependentMultimodalBGS; - - /*** SJN Package (thanks to SeungJong Noh) ***/ - //bgs = new SJN_MultiCueBGS; - - /*** BL Package (thanks to Benjamin Laugraud) ***/ - //bgs = new SigmaDeltaBGS; - - /*** PL Package (thanks to Pierre-Luc) ***/ - //bgs = new SuBSENSEBGS(); - //bgs = new LOBSTERBGS(); + //bgs = new IndependentMultimodal; + //bgs = new MultiCue; + //bgs = new SigmaDelta; + //bgs = new SuBSENSE; + //bgs = new LOBSTER; + //bgs = new PAWCS; + //bgs = new TwoPoints; + //bgs = new ViBe; int frameNumber = 1; int key = 0; - while(key != 'q') + while (key != 'q') { std::stringstream ss; ss << frameNumber; - std::string fileName = "frames/" + ss.str() + ".png"; + std::string fileName = "dataset/frames/" + ss.str() + ".png"; std::cout << "reading " << fileName << std::endl; cv::Mat img_input = cv::imread(fileName, CV_LOAD_IMAGE_COLOR); - + if (img_input.empty()) break; @@ -157,18 +87,19 @@ int main(int argc, char **argv) cv::Mat img_mask; cv::Mat img_bkgmodel; - bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image - + bgs->process(img_input, img_mask, img_bkgmodel); + // by default, "bgs->process(.)" automatically shows the foreground mask image + // or set "bgs->setShowOutput(false)" to disable + //if(!img_mask.empty()) // cv::imshow("Foreground", img_mask); // do something - + key = cvWaitKey(33); frameNumber++; } cvWaitKey(0); delete bgs; - cvDestroyAllWindows(); return 0; diff --git a/FrameProcessor.cpp b/FrameProcessor.cpp index 0cce652..5088121 100644 --- a/FrameProcessor.cpp +++ b/FrameProcessor.cpp @@ -37,23 +37,25 @@ namespace bgslibrary if (enablePreProcessor) preProcessor = new PreProcessor; - if (enableFrameDifferenceBGS) - frameDifference = new FrameDifferenceBGS; + if (enableFrameDifference) + frameDifference = new FrameDifference; - if (enableStaticFrameDifferenceBGS) - staticFrameDifference = new StaticFrameDifferenceBGS; + if (enableStaticFrameDifference) + staticFrameDifference = new StaticFrameDifference; - if (enableWeightedMovingMeanBGS) - weightedMovingMean = new WeightedMovingMeanBGS; + if (enableWeightedMovingMean) + weightedMovingMean = new WeightedMovingMean; - if (enableWeightedMovingVarianceBGS) - weightedMovingVariance = new WeightedMovingVarianceBGS; + if (enableWeightedMovingVariance) + weightedMovingVariance = new WeightedMovingVariance; - if (enableMixtureOfGaussianV1BGS) - mixtureOfGaussianV1BGS = new MixtureOfGaussianV1BGS; +#if CV_MAJOR_VERSION == 2 + if (enableMixtureOfGaussianV1) + mixtureOfGaussianV1 = new MixtureOfGaussianV1; +#endif - if (enableMixtureOfGaussianV2BGS) - mixtureOfGaussianV2BGS = new MixtureOfGaussianV2BGS; + if (enableMixtureOfGaussianV2) + mixtureOfGaussianV2 = new MixtureOfGaussianV2; if (enableAdaptiveBackgroundLearning) adaptiveBackgroundLearning = new AdaptiveBackgroundLearning; @@ -63,29 +65,29 @@ namespace bgslibrary gmg = new GMG; #endif - if (enableDPAdaptiveMedianBGS) - adaptiveMedian = new DPAdaptiveMedianBGS; + if (enableDPAdaptiveMedian) + dpAdaptiveMedian = new DPAdaptiveMedian; - if (enableDPGrimsonGMMBGS) - grimsonGMM = new DPGrimsonGMMBGS; + if (enableDPGrimsonGMM) + dpGrimsonGMM = new DPGrimsonGMM; - if (enableDPZivkovicAGMMBGS) - zivkovicAGMM = new DPZivkovicAGMMBGS; + if (enableDPZivkovicAGMM) + dpZivkovicAGMM = new DPZivkovicAGMM; - if (enableDPMeanBGS) - temporalMean = new DPMeanBGS; + if (enableDPMean) + dpTemporalMean = new DPMean; - if (enableDPWrenGABGS) - wrenGA = new DPWrenGABGS; + if (enableDPWrenGA) + dpWrenGA = new DPWrenGA; - if (enableDPPratiMediodBGS) - pratiMediod = new DPPratiMediodBGS; + if (enableDPPratiMediod) + dpPratiMediod = new DPPratiMediod; - if (enableDPEigenbackgroundBGS) - eigenBackground = new DPEigenbackgroundBGS; + if (enableDPEigenbackground) + dpEigenBackground = new DPEigenbackground; - if (enableDPTextureBGS) - textureBGS = new DPTextureBGS; + if (enableDPTexture) + dpTexture = new DPTexture; if (enableT2FGMM_UM) type2FuzzyGMM_UM = new T2FGMM_UM; @@ -121,13 +123,15 @@ namespace bgslibrary lbFuzzyAdaptiveSOM = new LBFuzzyAdaptiveSOM; if (enableLbpMrf) - lbpMrf = new LbpMrf; + lbpMrf = new LBP_MRF; - if(enableMultiLayerBGS) - multiLayerBGS = new MultiLayerBGS; +#if CV_MAJOR_VERSION == 2 + if (enableMultiLayer) + multiLayer = new MultiLayer; +#endif - //if(enablePBAS) - // pixelBasedAdaptiveSegmenter = new PixelBasedAdaptiveSegmenter; + if (enablePBAS) + pixelBasedAdaptiveSegmenter = new PixelBasedAdaptiveSegmenter; if (enableVuMeter) vuMeter = new VuMeter; @@ -136,19 +140,19 @@ namespace bgslibrary kde = new KDE; if (enableIMBS) - imbs = new IndependentMultimodalBGS; + imbs = new IndependentMultimodal; - if (enableMultiCueBGS) - mcbgs = new SJN_MultiCueBGS; + if (enableMultiCue) + multiCue = new MultiCue; - if (enableSigmaDeltaBGS) - sdbgs = new SigmaDeltaBGS; + if (enableSigmaDelta) + sigmaDelta = new SigmaDelta; - if (enableSuBSENSEBGS) - ssbgs = new SuBSENSEBGS; + if (enableSuBSENSE) + subSENSE = new SuBSENSE; - if (enableLOBSTERBGS) - lobgs = new LOBSTERBGS; + if (enableLOBSTER) + lobster = new LOBSTER; if (enableForegroundMaskAnalysis) foregroundMaskAnalysis = new ForegroundMaskAnalysis; @@ -171,169 +175,177 @@ namespace bgslibrary frameNumber++; if (enablePreProcessor) - preProcessor->process(img_input, img_prep); + preProcessor->process(img_input, img_preProcessor); - if (enableFrameDifferenceBGS) - process("FrameDifferenceBGS", frameDifference, img_prep, img_framediff); + if (enableFrameDifference) + process("FrameDifference", frameDifference, img_preProcessor, img_frameDifference); - if (enableStaticFrameDifferenceBGS) - process("StaticFrameDifferenceBGS", staticFrameDifference, img_prep, img_staticfdiff); + if (enableStaticFrameDifference) + process("StaticFrameDifference", staticFrameDifference, img_preProcessor, img_staticFrameDifference); - if (enableWeightedMovingMeanBGS) - process("WeightedMovingMeanBGS", weightedMovingMean, img_prep, img_wmovmean); + if (enableWeightedMovingMean) + process("WeightedMovingMean", weightedMovingMean, img_preProcessor, img_weightedMovingMean); - if (enableWeightedMovingVarianceBGS) - process("WeightedMovingVarianceBGS", weightedMovingVariance, img_prep, img_movvar); + if (enableWeightedMovingVariance) + process("WeightedMovingVariance", weightedMovingVariance, img_preProcessor, img_weightedMovingVariance); - if (enableMixtureOfGaussianV1BGS) - process("MixtureOfGaussianV1BGS", mixtureOfGaussianV1BGS, img_prep, img_mog1); +#if CV_MAJOR_VERSION == 2 + if (enableMixtureOfGaussianV1) + process("MixtureOfGaussianV1", mixtureOfGaussianV1, img_preProcessor, img_mixtureOfGaussianV1); +#endif - if (enableMixtureOfGaussianV2BGS) - process("MixtureOfGaussianV2BGS", mixtureOfGaussianV2BGS, img_prep, img_mog2); + if (enableMixtureOfGaussianV2) + process("MixtureOfGaussianV2", mixtureOfGaussianV2, img_preProcessor, img_mixtureOfGaussianV2); if (enableAdaptiveBackgroundLearning) - process("AdaptiveBackgroundLearning", adaptiveBackgroundLearning, img_prep, img_bkgl_fgmask); + process("AdaptiveBackgroundLearning", adaptiveBackgroundLearning, img_preProcessor, img_adaptiveBackgroundLearning); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 if (enableGMG) - process("GMG", gmg, img_prep, img_gmg); + process("GMG", gmg, img_preProcessor, img_gmg); #endif - if (enableDPAdaptiveMedianBGS) - process("DPAdaptiveMedianBGS", adaptiveMedian, img_prep, img_adpmed); + if (enableDPAdaptiveMedian) + process("DPAdaptiveMedian", dpAdaptiveMedian, img_preProcessor, img_dpAdaptiveMedian); - if (enableDPGrimsonGMMBGS) - process("DPGrimsonGMMBGS", grimsonGMM, img_prep, img_grigmm); + if (enableDPGrimsonGMM) + process("DPGrimsonGMM", dpGrimsonGMM, img_preProcessor, img_dpGrimsonGMM); - if (enableDPZivkovicAGMMBGS) - process("DPZivkovicAGMMBGS", zivkovicAGMM, img_prep, img_zivgmm); + if (enableDPZivkovicAGMM) + process("DPZivkovicAGMM", dpZivkovicAGMM, img_preProcessor, img_dpZivkovicAGMM); - if (enableDPMeanBGS) - process("DPMeanBGS", temporalMean, img_prep, img_tmpmean); + if (enableDPMean) + process("DPMean", dpTemporalMean, img_preProcessor, img_dpTemporalMean); - if (enableDPWrenGABGS) - process("DPWrenGABGS", wrenGA, img_prep, img_wrenga); + if (enableDPWrenGA) + process("DPWrenGA", dpWrenGA, img_preProcessor, img_dpWrenGA); - if (enableDPPratiMediodBGS) - process("DPPratiMediodBGS", pratiMediod, img_prep, img_pramed); + if (enableDPPratiMediod) + process("DPPratiMediod", dpPratiMediod, img_preProcessor, img_dpPratiMediod); - if (enableDPEigenbackgroundBGS) - process("DPEigenbackgroundBGS", eigenBackground, img_prep, img_eigbkg); + if (enableDPEigenbackground) + process("DPEigenbackground", dpEigenBackground, img_preProcessor, img_dpEigenBackground); - if (enableDPTextureBGS) - process("DPTextureBGS", textureBGS, img_prep, img_texbgs); + if (enableDPTexture) + process("DPTexture", dpTexture, img_preProcessor, img_dpTexture); if (enableT2FGMM_UM) - process("T2FGMM_UM", type2FuzzyGMM_UM, img_prep, img_t2fgmm_um); + process("T2FGMM_UM", type2FuzzyGMM_UM, img_preProcessor, img_type2FuzzyGMM_UM); if (enableT2FGMM_UV) - process("T2FGMM_UV", type2FuzzyGMM_UV, img_prep, img_t2fgmm_uv); + process("T2FGMM_UV", type2FuzzyGMM_UV, img_preProcessor, img_type2FuzzyGMM_UV); if (enableT2FMRF_UM) - process("T2FMRF_UM", type2FuzzyMRF_UM, img_prep, img_t2fmrf_um); + process("T2FMRF_UM", type2FuzzyMRF_UM, img_preProcessor, img_type2FuzzyMRF_UM); if (enableT2FMRF_UV) - process("T2FMRF_UV", type2FuzzyMRF_UV, img_prep, img_t2fmrf_uv); + process("T2FMRF_UV", type2FuzzyMRF_UV, img_preProcessor, img_type2FuzzyMRF_UV); if (enableFuzzySugenoIntegral) - process("FuzzySugenoIntegral", fuzzySugenoIntegral, img_prep, img_fsi); + process("FuzzySugenoIntegral", fuzzySugenoIntegral, img_preProcessor, img_fuzzySugenoIntegral); if (enableFuzzyChoquetIntegral) - process("FuzzyChoquetIntegral", fuzzyChoquetIntegral, img_prep, img_fci); + process("FuzzyChoquetIntegral", fuzzyChoquetIntegral, img_preProcessor, img_fuzzyChoquetIntegral); if (enableLBSimpleGaussian) - process("LBSimpleGaussian", lbSimpleGaussian, img_prep, img_lb_sg); + process("LBSimpleGaussian", lbSimpleGaussian, img_preProcessor, img_lbSimpleGaussian); if (enableLBFuzzyGaussian) - process("LBFuzzyGaussian", lbFuzzyGaussian, img_prep, img_lb_fg); + process("LBFuzzyGaussian", lbFuzzyGaussian, img_preProcessor, img_lbFuzzyGaussian); if (enableLBMixtureOfGaussians) - process("LBMixtureOfGaussians", lbMixtureOfGaussians, img_prep, img_lb_mog); + process("LBMixtureOfGaussians", lbMixtureOfGaussians, img_preProcessor, img_lbMixtureOfGaussians); if (enableLBAdaptiveSOM) - process("LBAdaptiveSOM", lbAdaptiveSOM, img_prep, img_lb_som); + process("LBAdaptiveSOM", lbAdaptiveSOM, img_preProcessor, img_lbAdaptiveSOM); if (enableLBFuzzyAdaptiveSOM) - process("LBFuzzyAdaptiveSOM", lbFuzzyAdaptiveSOM, img_prep, img_lb_fsom); + process("LBFuzzyAdaptiveSOM", lbFuzzyAdaptiveSOM, img_preProcessor, img_lbFuzzyAdaptiveSOM); if (enableLbpMrf) - process("LbpMrf", lbpMrf, img_prep, img_lbp_mrf); + process("LbpMrf", lbpMrf, img_preProcessor, img_lbpMrf); - if(enableMultiLayerBGS) +#if CV_MAJOR_VERSION == 2 + if (enableMultiLayer) { - multiLayerBGS->setStatus(MultiLayerBGS::MLBGS_LEARN); - //multiLayerBGS->setStatus(MultiLayerBGS::MLBGS_DETECT); - process("MultiLayerBGS", multiLayerBGS, img_prep, img_mlbgs); + multiLayer->setStatus(MultiLayer::MLBGS_LEARN); + //multiLayer->setStatus(MultiLayer::MLBGS_DETECT); + process("MultiLayer", multiLayer, img_preProcessor, img_multiLayer); } +#endif - //if(enablePBAS) - // process("PBAS", pixelBasedAdaptiveSegmenter, img_prep, img_pt_pbas); + if (enablePBAS) + process("PBAS", pixelBasedAdaptiveSegmenter, img_preProcessor, img_pixelBasedAdaptiveSegmenter); if (enableVuMeter) - process("VuMeter", vuMeter, img_prep, img_vumeter); + process("VuMeter", vuMeter, img_preProcessor, img_vumeter); if (enableKDE) - process("KDE", kde, img_prep, img_kde); + process("KDE", kde, img_preProcessor, img_kde); if (enableIMBS) - process("IMBS", imbs, img_prep, img_imbs); + process("IMBS", imbs, img_preProcessor, img_imbs); - if (enableMultiCueBGS) - process("MultiCueBGS", mcbgs, img_prep, img_mcbgs); + if (enableMultiCue) + process("MultiCue", multiCue, img_preProcessor, img_multiCue); - if (enableSigmaDeltaBGS) - process("SigmaDeltaBGS", sdbgs, img_prep, img_sdbgs); + if (enableSigmaDelta) + process("SigmaDelta", sigmaDelta, img_preProcessor, img_sigmaDelta); - if (enableSuBSENSEBGS) - process("SuBSENSEBGS", ssbgs, img_prep, img_ssbgs); + if (enableSuBSENSE) + process("SuBSENSE", subSENSE, img_preProcessor, img_subSENSE); - if (enableLOBSTERBGS) - process("LOBSTERBGS", lobgs, img_prep, img_lobgs); + if (enableLOBSTER) + process("LOBSTER", lobster, img_preProcessor, img_lobster); if (enableForegroundMaskAnalysis) { foregroundMaskAnalysis->stopAt = frameToStop; foregroundMaskAnalysis->img_ref_path = imgref; - foregroundMaskAnalysis->process(frameNumber, "FrameDifferenceBGS", img_framediff); - foregroundMaskAnalysis->process(frameNumber, "StaticFrameDifferenceBGS", img_staticfdiff); - foregroundMaskAnalysis->process(frameNumber, "WeightedMovingMeanBGS", img_wmovmean); - foregroundMaskAnalysis->process(frameNumber, "WeightedMovingVarianceBGS", img_movvar); - foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV1BGS", img_mog1); - foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV2BGS", img_mog2); - foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_bkgl_fgmask); + foregroundMaskAnalysis->process(frameNumber, "FrameDifference", img_frameDifference); + foregroundMaskAnalysis->process(frameNumber, "StaticFrameDifference", img_staticFrameDifference); + foregroundMaskAnalysis->process(frameNumber, "WeightedMovingMean", img_weightedMovingMean); + foregroundMaskAnalysis->process(frameNumber, "WeightedMovingVariance", img_weightedMovingVariance); +#if CV_MAJOR_VERSION == 2 + foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV1", img_mixtureOfGaussianV1); +#endif + foregroundMaskAnalysis->process(frameNumber, "MixtureOfGaussianV2", img_mixtureOfGaussianV2); + foregroundMaskAnalysis->process(frameNumber, "AdaptiveBackgroundLearning", img_adaptiveBackgroundLearning); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 foregroundMaskAnalysis->process(frameNumber, "GMG", img_gmg); #endif - foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedianBGS", img_adpmed); - foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMMBGS", img_grigmm); - foregroundMaskAnalysis->process(frameNumber, "DPZivkovicAGMMBGS", img_zivgmm); - foregroundMaskAnalysis->process(frameNumber, "DPMeanBGS", img_tmpmean); - foregroundMaskAnalysis->process(frameNumber, "DPWrenGABGS", img_wrenga); - foregroundMaskAnalysis->process(frameNumber, "DPPratiMediodBGS", img_pramed); - foregroundMaskAnalysis->process(frameNumber, "DPEigenbackgroundBGS", img_eigbkg); - foregroundMaskAnalysis->process(frameNumber, "DPTextureBGS", img_texbgs); - foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UM", img_t2fgmm_um); - foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UV", img_t2fgmm_uv); - foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UM", img_t2fmrf_um); - foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UV", img_t2fmrf_uv); - foregroundMaskAnalysis->process(frameNumber, "FuzzySugenoIntegral", img_fsi); - foregroundMaskAnalysis->process(frameNumber, "FuzzyChoquetIntegral", img_fci); - foregroundMaskAnalysis->process(frameNumber, "LBSimpleGaussian", img_lb_sg); - foregroundMaskAnalysis->process(frameNumber, "LBFuzzyGaussian", img_lb_fg); - foregroundMaskAnalysis->process(frameNumber, "LBMixtureOfGaussians", img_lb_mog); - foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lb_som); - foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lb_fsom); - foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbp_mrf); - foregroundMaskAnalysis->process(frameNumber, "MultiLayerBGS", img_mlbgs); - //foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pt_pbas); + foregroundMaskAnalysis->process(frameNumber, "DPAdaptiveMedian", img_dpAdaptiveMedian); + foregroundMaskAnalysis->process(frameNumber, "DPGrimsonGMM", img_dpGrimsonGMM); + foregroundMaskAnalysis->process(frameNumber, "DPZivkovicAGMM", img_dpZivkovicAGMM); + foregroundMaskAnalysis->process(frameNumber, "DPMean", img_dpTemporalMean); + foregroundMaskAnalysis->process(frameNumber, "DPWrenGA", img_dpWrenGA); + foregroundMaskAnalysis->process(frameNumber, "DPPratiMediod", img_dpPratiMediod); + foregroundMaskAnalysis->process(frameNumber, "DPEigenbackground", img_dpEigenBackground); + foregroundMaskAnalysis->process(frameNumber, "DPTexture", img_dpTexture); + foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UM", img_type2FuzzyGMM_UM); + foregroundMaskAnalysis->process(frameNumber, "T2FGMM_UV", img_type2FuzzyGMM_UV); + foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UM", img_type2FuzzyMRF_UM); + foregroundMaskAnalysis->process(frameNumber, "T2FMRF_UV", img_type2FuzzyMRF_UV); + foregroundMaskAnalysis->process(frameNumber, "FuzzySugenoIntegral", img_fuzzySugenoIntegral); + foregroundMaskAnalysis->process(frameNumber, "FuzzyChoquetIntegral", img_fuzzyChoquetIntegral); + foregroundMaskAnalysis->process(frameNumber, "LBSimpleGaussian", img_lbSimpleGaussian); + foregroundMaskAnalysis->process(frameNumber, "LBFuzzyGaussian", img_lbFuzzyGaussian); + foregroundMaskAnalysis->process(frameNumber, "LBMixtureOfGaussians", img_lbMixtureOfGaussians); + foregroundMaskAnalysis->process(frameNumber, "LBAdaptiveSOM", img_lbAdaptiveSOM); + foregroundMaskAnalysis->process(frameNumber, "LBFuzzyAdaptiveSOM", img_lbFuzzyAdaptiveSOM); + foregroundMaskAnalysis->process(frameNumber, "LbpMrf", img_lbpMrf); +#if CV_MAJOR_VERSION == 2 + foregroundMaskAnalysis->process(frameNumber, "MultiLayer", img_multiLayer); +#endif + foregroundMaskAnalysis->process(frameNumber, "PBAS", img_pixelBasedAdaptiveSegmenter); foregroundMaskAnalysis->process(frameNumber, "VuMeter", img_vumeter); foregroundMaskAnalysis->process(frameNumber, "KDE", img_kde); foregroundMaskAnalysis->process(frameNumber, "IMBS", img_imbs); - foregroundMaskAnalysis->process(frameNumber, "MultiCueBGS", img_mcbgs); - foregroundMaskAnalysis->process(frameNumber, "SigmaDeltaBGS", img_sdbgs); - foregroundMaskAnalysis->process(frameNumber, "SuBSENSEBGS", img_ssbgs); - foregroundMaskAnalysis->process(frameNumber, "LOBSTERBGS", img_lobgs); + foregroundMaskAnalysis->process(frameNumber, "MultiCue", img_multiCue); + foregroundMaskAnalysis->process(frameNumber, "SigmaDelta", img_sigmaDelta); + foregroundMaskAnalysis->process(frameNumber, "SuBSENSE", img_subSENSE); + foregroundMaskAnalysis->process(frameNumber, "LOBSTER", img_lobster); } firstTime = false; @@ -341,8 +353,8 @@ namespace bgslibrary void FrameProcessor::finish(void) { - /*if(enableMultiLayerBGS) - multiLayerBGS->finish(); + /*if(enableMultiLayer) + multiLayer->finish(); if(enableLBSimpleGaussian) lbSimpleGaussian->finish(); @@ -362,17 +374,17 @@ namespace bgslibrary if (enableForegroundMaskAnalysis) delete foregroundMaskAnalysis; - if (enableLOBSTERBGS) - delete lobgs; + if (enableLOBSTER) + delete lobster; - if (enableSuBSENSEBGS) - delete ssbgs; + if (enableSuBSENSE) + delete subSENSE; - if (enableSigmaDeltaBGS) - delete sdbgs; + if (enableSigmaDelta) + delete sigmaDelta; - if (enableMultiCueBGS) - delete mcbgs; + if (enableMultiCue) + delete multiCue; if (enableIMBS) delete imbs; @@ -383,11 +395,13 @@ namespace bgslibrary if (enableVuMeter) delete vuMeter; - //if(enablePBAS) - // delete pixelBasedAdaptiveSegmenter; + if (enablePBAS) + delete pixelBasedAdaptiveSegmenter; - if (enableMultiLayerBGS) - delete multiLayerBGS; +#if CV_MAJOR_VERSION == 2 + if (enableMultiLayer) + delete multiLayer; +#endif if (enableLBFuzzyAdaptiveSOM) delete lbFuzzyAdaptiveSOM; @@ -409,7 +423,7 @@ namespace bgslibrary delete lbpMrf; #endif - if(enableFuzzyChoquetIntegral) + if (enableFuzzyChoquetIntegral) delete fuzzyChoquetIntegral; if (enableFuzzySugenoIntegral) @@ -427,29 +441,29 @@ namespace bgslibrary if (enableT2FGMM_UM) delete type2FuzzyGMM_UM; - if (enableDPTextureBGS) - delete textureBGS; + if (enableDPTexture) + delete dpTexture; - if (enableDPEigenbackgroundBGS) - delete eigenBackground; + if (enableDPEigenbackground) + delete dpEigenBackground; - if (enableDPPratiMediodBGS) - delete pratiMediod; + if (enableDPPratiMediod) + delete dpPratiMediod; - if (enableDPWrenGABGS) - delete wrenGA; + if (enableDPWrenGA) + delete dpWrenGA; - if (enableDPMeanBGS) - delete temporalMean; + if (enableDPMean) + delete dpTemporalMean; - if (enableDPZivkovicAGMMBGS) - delete zivkovicAGMM; + if (enableDPZivkovicAGMM) + delete dpZivkovicAGMM; - if (enableDPGrimsonGMMBGS) - delete grimsonGMM; + if (enableDPGrimsonGMM) + delete dpGrimsonGMM; - if (enableDPAdaptiveMedianBGS) - delete adaptiveMedian; + if (enableDPAdaptiveMedian) + delete dpAdaptiveMedian; #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 if (enableGMG) @@ -459,22 +473,24 @@ namespace bgslibrary if (enableAdaptiveBackgroundLearning) delete adaptiveBackgroundLearning; - if (enableMixtureOfGaussianV2BGS) - delete mixtureOfGaussianV2BGS; + if (enableMixtureOfGaussianV2) + delete mixtureOfGaussianV2; - if (enableMixtureOfGaussianV1BGS) - delete mixtureOfGaussianV1BGS; +#if CV_MAJOR_VERSION == 2 + if (enableMixtureOfGaussianV1) + delete mixtureOfGaussianV1; +#endif - if (enableWeightedMovingVarianceBGS) + if (enableWeightedMovingVariance) delete weightedMovingVariance; - if (enableWeightedMovingMeanBGS) + if (enableWeightedMovingMean) delete weightedMovingMean; - if (enableStaticFrameDifferenceBGS) + if (enableStaticFrameDifference) delete staticFrameDifference; - if (enableFrameDifferenceBGS) + if (enableFrameDifference) delete frameDifference; if (enablePreProcessor) @@ -503,25 +519,27 @@ namespace bgslibrary cvWriteInt(fs, "enableForegroundMaskAnalysis", enableForegroundMaskAnalysis); - cvWriteInt(fs, "enableFrameDifferenceBGS", enableFrameDifferenceBGS); - cvWriteInt(fs, "enableStaticFrameDifferenceBGS", enableStaticFrameDifferenceBGS); - cvWriteInt(fs, "enableWeightedMovingMeanBGS", enableWeightedMovingMeanBGS); - cvWriteInt(fs, "enableWeightedMovingVarianceBGS", enableWeightedMovingVarianceBGS); - cvWriteInt(fs, "enableMixtureOfGaussianV1BGS", enableMixtureOfGaussianV1BGS); - cvWriteInt(fs, "enableMixtureOfGaussianV2BGS", enableMixtureOfGaussianV2BGS); + cvWriteInt(fs, "enableFrameDifference", enableFrameDifference); + cvWriteInt(fs, "enableStaticFrameDifference", enableStaticFrameDifference); + cvWriteInt(fs, "enableWeightedMovingMean", enableWeightedMovingMean); + cvWriteInt(fs, "enableWeightedMovingVariance", enableWeightedMovingVariance); +#if CV_MAJOR_VERSION == 2 + cvWriteInt(fs, "enableMixtureOfGaussianV1", enableMixtureOfGaussianV1); +#endif + cvWriteInt(fs, "enableMixtureOfGaussianV2", enableMixtureOfGaussianV2); cvWriteInt(fs, "enableAdaptiveBackgroundLearning", enableAdaptiveBackgroundLearning); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 cvWriteInt(fs, "enableGMG", enableGMG); #endif - cvWriteInt(fs, "enableDPAdaptiveMedianBGS", enableDPAdaptiveMedianBGS); - cvWriteInt(fs, "enableDPGrimsonGMMBGS", enableDPGrimsonGMMBGS); - cvWriteInt(fs, "enableDPZivkovicAGMMBGS", enableDPZivkovicAGMMBGS); - cvWriteInt(fs, "enableDPMeanBGS", enableDPMeanBGS); - cvWriteInt(fs, "enableDPWrenGABGS", enableDPWrenGABGS); - cvWriteInt(fs, "enableDPPratiMediodBGS", enableDPPratiMediodBGS); - cvWriteInt(fs, "enableDPEigenbackgroundBGS", enableDPEigenbackgroundBGS); - cvWriteInt(fs, "enableDPTextureBGS", enableDPTextureBGS); + cvWriteInt(fs, "enableDPAdaptiveMedian", enableDPAdaptiveMedian); + cvWriteInt(fs, "enableDPGrimsonGMM", enableDPGrimsonGMM); + cvWriteInt(fs, "enableDPZivkovicAGMM", enableDPZivkovicAGMM); + cvWriteInt(fs, "enableDPMean", enableDPMean); + cvWriteInt(fs, "enableDPWrenGA", enableDPWrenGA); + cvWriteInt(fs, "enableDPPratiMediod", enableDPPratiMediod); + cvWriteInt(fs, "enableDPEigenbackground", enableDPEigenbackground); + cvWriteInt(fs, "enableDPTexture", enableDPTexture); cvWriteInt(fs, "enableT2FGMM_UM", enableT2FGMM_UM); cvWriteInt(fs, "enableT2FGMM_UV", enableT2FGMM_UV); @@ -538,15 +556,17 @@ namespace bgslibrary cvWriteInt(fs, "enableLbpMrf", enableLbpMrf); - cvWriteInt(fs, "enableMultiLayerBGS", enableMultiLayerBGS); - //cvWriteInt(fs, "enablePBAS", enablePBAS); +#if CV_MAJOR_VERSION == 2 + cvWriteInt(fs, "enableMultiLayer", enableMultiLayer); +#endif + cvWriteInt(fs, "enablePBAS", enablePBAS); cvWriteInt(fs, "enableVuMeter", enableVuMeter); cvWriteInt(fs, "enableKDE", enableKDE); cvWriteInt(fs, "enableIMBS", enableIMBS); - cvWriteInt(fs, "enableMultiCueBGS", enableMultiCueBGS); - cvWriteInt(fs, "enableSigmaDeltaBGS", enableSigmaDeltaBGS); - cvWriteInt(fs, "enableSuBSENSEBGS", enableSuBSENSEBGS); - cvWriteInt(fs, "enableLOBSTERBGS", enableLOBSTERBGS); + cvWriteInt(fs, "enableMultiCue", enableMultiCue); + cvWriteInt(fs, "enableSigmaDelta", enableSigmaDelta); + cvWriteInt(fs, "enableSuBSENSE", enableSuBSENSE); + cvWriteInt(fs, "enableLOBSTER", enableLOBSTER); cvReleaseFileStorage(&fs); } @@ -561,25 +581,27 @@ namespace bgslibrary enableForegroundMaskAnalysis = cvReadIntByName(fs, 0, "enableForegroundMaskAnalysis", false); - enableFrameDifferenceBGS = cvReadIntByName(fs, 0, "enableFrameDifferenceBGS", false); - enableStaticFrameDifferenceBGS = cvReadIntByName(fs, 0, "enableStaticFrameDifferenceBGS", false); - enableWeightedMovingMeanBGS = cvReadIntByName(fs, 0, "enableWeightedMovingMeanBGS", false); - enableWeightedMovingVarianceBGS = cvReadIntByName(fs, 0, "enableWeightedMovingVarianceBGS", false); - enableMixtureOfGaussianV1BGS = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV1BGS", false); - enableMixtureOfGaussianV2BGS = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV2BGS", false); + enableFrameDifference = cvReadIntByName(fs, 0, "enableFrameDifference", false); + enableStaticFrameDifference = cvReadIntByName(fs, 0, "enableStaticFrameDifference", false); + enableWeightedMovingMean = cvReadIntByName(fs, 0, "enableWeightedMovingMean", false); + enableWeightedMovingVariance = cvReadIntByName(fs, 0, "enableWeightedMovingVariance", false); +#if CV_MAJOR_VERSION == 2 + enableMixtureOfGaussianV1 = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV1", false); +#endif + enableMixtureOfGaussianV2 = cvReadIntByName(fs, 0, "enableMixtureOfGaussianV2", false); enableAdaptiveBackgroundLearning = cvReadIntByName(fs, 0, "enableAdaptiveBackgroundLearning", false); #if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 enableGMG = cvReadIntByName(fs, 0, "enableGMG", false); #endif - enableDPAdaptiveMedianBGS = cvReadIntByName(fs, 0, "enableDPAdaptiveMedianBGS", false); - enableDPGrimsonGMMBGS = cvReadIntByName(fs, 0, "enableDPGrimsonGMMBGS", false); - enableDPZivkovicAGMMBGS = cvReadIntByName(fs, 0, "enableDPZivkovicAGMMBGS", false); - enableDPMeanBGS = cvReadIntByName(fs, 0, "enableDPMeanBGS", false); - enableDPWrenGABGS = cvReadIntByName(fs, 0, "enableDPWrenGABGS", false); - enableDPPratiMediodBGS = cvReadIntByName(fs, 0, "enableDPPratiMediodBGS", false); - enableDPEigenbackgroundBGS = cvReadIntByName(fs, 0, "enableDPEigenbackgroundBGS", false); - enableDPTextureBGS = cvReadIntByName(fs, 0, "enableDPTextureBGS", false); + enableDPAdaptiveMedian = cvReadIntByName(fs, 0, "enableDPAdaptiveMedian", false); + enableDPGrimsonGMM = cvReadIntByName(fs, 0, "enableDPGrimsonGMM", false); + enableDPZivkovicAGMM = cvReadIntByName(fs, 0, "enableDPZivkovicAGMM", false); + enableDPMean = cvReadIntByName(fs, 0, "enableDPMean", false); + enableDPWrenGA = cvReadIntByName(fs, 0, "enableDPWrenGA", false); + enableDPPratiMediod = cvReadIntByName(fs, 0, "enableDPPratiMediod", false); + enableDPEigenbackground = cvReadIntByName(fs, 0, "enableDPEigenbackground", false); + enableDPTexture = cvReadIntByName(fs, 0, "enableDPTexture", false); enableT2FGMM_UM = cvReadIntByName(fs, 0, "enableT2FGMM_UM", false); enableT2FGMM_UV = cvReadIntByName(fs, 0, "enableT2FGMM_UV", false); @@ -596,15 +618,17 @@ namespace bgslibrary enableLbpMrf = cvReadIntByName(fs, 0, "enableLbpMrf", false); - enableMultiLayerBGS = cvReadIntByName(fs, 0, "enableMultiLayerBGS", false); - //enablePBAS = cvReadIntByName(fs, 0, "enablePBAS", false); +#if CV_MAJOR_VERSION == 2 + enableMultiLayer = cvReadIntByName(fs, 0, "enableMultiLayer", false); +#endif + enablePBAS = cvReadIntByName(fs, 0, "enablePBAS", false); enableVuMeter = cvReadIntByName(fs, 0, "enableVuMeter", false); enableKDE = cvReadIntByName(fs, 0, "enableKDE", false); enableIMBS = cvReadIntByName(fs, 0, "enableIMBS", false); - enableMultiCueBGS = cvReadIntByName(fs, 0, "enableMultiCueBGS", false); - enableSigmaDeltaBGS = cvReadIntByName(fs, 0, "enableSigmaDeltaBGS", false); - enableSuBSENSEBGS = cvReadIntByName(fs, 0, "enableSuBSENSEBGS", false); - enableLOBSTERBGS = cvReadIntByName(fs, 0, "enableLOBSTERBGS", false); + enableMultiCue = cvReadIntByName(fs, 0, "enableMultiCue", false); + enableSigmaDelta = cvReadIntByName(fs, 0, "enableSigmaDelta", false); + enableSuBSENSE = cvReadIntByName(fs, 0, "enableSuBSENSE", false); + enableLOBSTER = cvReadIntByName(fs, 0, "enableLOBSTER", false); cvReleaseFileStorage(&fs); } diff --git a/FrameProcessor.h b/FrameProcessor.h index 0bb854e..228fa4c 100644 --- a/FrameProcessor.h +++ b/FrameProcessor.h @@ -21,56 +21,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include "PreProcessor.h" #include "package_bgs/IBGS.h" - -#include "package_bgs/FrameDifferenceBGS.h" -#include "package_bgs/StaticFrameDifferenceBGS.h" -#include "package_bgs/WeightedMovingMeanBGS.h" -#include "package_bgs/WeightedMovingVarianceBGS.h" -#include "package_bgs/MixtureOfGaussianV1BGS.h" -#include "package_bgs/MixtureOfGaussianV2BGS.h" -#include "package_bgs/AdaptiveBackgroundLearning.h" -#if CV_MAJOR_VERSION >= 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 -#include "package_bgs/GMG.h" -#endif - -#include "package_bgs/dp/DPAdaptiveMedianBGS.h" -#include "package_bgs/dp/DPGrimsonGMMBGS.h" -#include "package_bgs/dp/DPZivkovicAGMMBGS.h" -#include "package_bgs/dp/DPMeanBGS.h" -#include "package_bgs/dp/DPWrenGABGS.h" -#include "package_bgs/dp/DPPratiMediodBGS.h" -#include "package_bgs/dp/DPEigenbackgroundBGS.h" -#include "package_bgs/dp/DPTextureBGS.h" - -#include "package_bgs/tb/T2FGMM_UM.h" -#include "package_bgs/tb/T2FGMM_UV.h" -#include "package_bgs/tb/T2FMRF_UM.h" -#include "package_bgs/tb/T2FMRF_UV.h" -#include "package_bgs/tb/FuzzySugenoIntegral.h" -#include "package_bgs/tb/FuzzyChoquetIntegral.h" - -#include "package_bgs/lb/LBSimpleGaussian.h" -#include "package_bgs/lb/LBFuzzyGaussian.h" -#include "package_bgs/lb/LBMixtureOfGaussians.h" -#include "package_bgs/lb/LBAdaptiveSOM.h" -#include "package_bgs/lb/LBFuzzyAdaptiveSOM.h" - -#include "package_bgs/ck/LbpMrf.h" - -#include "package_bgs/jmo/MultiLayerBGS.h" -// The PBAS algorithm was removed from BGSLibrary because it is -// based on patented algorithm ViBE -// http://www2.ulg.ac.be/telecom/research/vibe/ -//#include "package_bgs/pt/PixelBasedAdaptiveSegmenter.h" -#include "package_bgs/av/VuMeter.h" -#include "package_bgs/ae/KDE.h" -#include "package_bgs/db/IndependentMultimodalBGS.h" -#include "package_bgs/sjn/SJN_MultiCueBGS.h" -#include "package_bgs/bl/SigmaDeltaBGS.h" - -#include "package_bgs/pl/SuBSENSE.h" -#include "package_bgs/pl/LOBSTER.h" - +#include "package_bgs/bgslibrary.h" #include "package_analysis/ForegroundMaskAnalysis.h" namespace bgslibrary @@ -84,35 +35,37 @@ namespace bgslibrary double duration; std::string tictoc; - cv::Mat img_prep; + cv::Mat img_preProcessor; PreProcessor* preProcessor; bool enablePreProcessor; - cv::Mat img_framediff; - FrameDifferenceBGS* frameDifference; - bool enableFrameDifferenceBGS; + cv::Mat img_frameDifference; + FrameDifference* frameDifference; + bool enableFrameDifference; - cv::Mat img_staticfdiff; - StaticFrameDifferenceBGS* staticFrameDifference; - bool enableStaticFrameDifferenceBGS; + cv::Mat img_staticFrameDifference; + StaticFrameDifference* staticFrameDifference; + bool enableStaticFrameDifference; - cv::Mat img_wmovmean; - WeightedMovingMeanBGS* weightedMovingMean; - bool enableWeightedMovingMeanBGS; + cv::Mat img_weightedMovingMean; + WeightedMovingMean* weightedMovingMean; + bool enableWeightedMovingMean; - cv::Mat img_movvar; - WeightedMovingVarianceBGS* weightedMovingVariance; - bool enableWeightedMovingVarianceBGS; + cv::Mat img_weightedMovingVariance; + WeightedMovingVariance* weightedMovingVariance; + bool enableWeightedMovingVariance; - cv::Mat img_mog1; - MixtureOfGaussianV1BGS* mixtureOfGaussianV1BGS; - bool enableMixtureOfGaussianV1BGS; +#if CV_MAJOR_VERSION == 2 + cv::Mat img_mixtureOfGaussianV1; + MixtureOfGaussianV1* mixtureOfGaussianV1; + bool enableMixtureOfGaussianV1; +#endif - cv::Mat img_mog2; - MixtureOfGaussianV2BGS* mixtureOfGaussianV2BGS; - bool enableMixtureOfGaussianV2BGS; + cv::Mat img_mixtureOfGaussianV2; + MixtureOfGaussianV2* mixtureOfGaussianV2; + bool enableMixtureOfGaussianV2; - cv::Mat img_bkgl_fgmask; + cv::Mat img_adaptiveBackgroundLearning; AdaptiveBackgroundLearning* adaptiveBackgroundLearning; bool enableAdaptiveBackgroundLearning; @@ -122,93 +75,95 @@ namespace bgslibrary bool enableGMG; #endif - cv::Mat img_adpmed; - DPAdaptiveMedianBGS* adaptiveMedian; - bool enableDPAdaptiveMedianBGS; + cv::Mat img_dpAdaptiveMedian; + DPAdaptiveMedian* dpAdaptiveMedian; + bool enableDPAdaptiveMedian; - cv::Mat img_grigmm; - DPGrimsonGMMBGS* grimsonGMM; - bool enableDPGrimsonGMMBGS; + cv::Mat img_dpGrimsonGMM; + DPGrimsonGMM* dpGrimsonGMM; + bool enableDPGrimsonGMM; - cv::Mat img_zivgmm; - DPZivkovicAGMMBGS* zivkovicAGMM; - bool enableDPZivkovicAGMMBGS; + cv::Mat img_dpZivkovicAGMM; + DPZivkovicAGMM* dpZivkovicAGMM; + bool enableDPZivkovicAGMM; - cv::Mat img_tmpmean; - DPMeanBGS* temporalMean; - bool enableDPMeanBGS; + cv::Mat img_dpTemporalMean; + DPMean* dpTemporalMean; + bool enableDPMean; - cv::Mat img_wrenga; - DPWrenGABGS* wrenGA; - bool enableDPWrenGABGS; + cv::Mat img_dpWrenGA; + DPWrenGA* dpWrenGA; + bool enableDPWrenGA; - cv::Mat img_pramed; - DPPratiMediodBGS* pratiMediod; - bool enableDPPratiMediodBGS; + cv::Mat img_dpPratiMediod; + DPPratiMediod* dpPratiMediod; + bool enableDPPratiMediod; - cv::Mat img_eigbkg; - DPEigenbackgroundBGS* eigenBackground; - bool enableDPEigenbackgroundBGS; + cv::Mat img_dpEigenBackground; + DPEigenbackground* dpEigenBackground; + bool enableDPEigenbackground; - cv::Mat img_texbgs; - DPTextureBGS* textureBGS; - bool enableDPTextureBGS; + cv::Mat img_dpTexture; + DPTexture* dpTexture; + bool enableDPTexture; - cv::Mat img_t2fgmm_um; + cv::Mat img_type2FuzzyGMM_UM; T2FGMM_UM* type2FuzzyGMM_UM; bool enableT2FGMM_UM; - cv::Mat img_t2fgmm_uv; + cv::Mat img_type2FuzzyGMM_UV; T2FGMM_UV* type2FuzzyGMM_UV; bool enableT2FGMM_UV; - cv::Mat img_t2fmrf_um; + cv::Mat img_type2FuzzyMRF_UM; T2FMRF_UM* type2FuzzyMRF_UM; bool enableT2FMRF_UM; - cv::Mat img_t2fmrf_uv; + cv::Mat img_type2FuzzyMRF_UV; T2FMRF_UV* type2FuzzyMRF_UV; bool enableT2FMRF_UV; - cv::Mat img_fsi; + cv::Mat img_fuzzySugenoIntegral; FuzzySugenoIntegral* fuzzySugenoIntegral; bool enableFuzzySugenoIntegral; - cv::Mat img_fci; + cv::Mat img_fuzzyChoquetIntegral; FuzzyChoquetIntegral* fuzzyChoquetIntegral; bool enableFuzzyChoquetIntegral; - cv::Mat img_lb_sg; + cv::Mat img_lbSimpleGaussian; LBSimpleGaussian* lbSimpleGaussian; bool enableLBSimpleGaussian; - cv::Mat img_lb_fg; + cv::Mat img_lbFuzzyGaussian; LBFuzzyGaussian* lbFuzzyGaussian; bool enableLBFuzzyGaussian; - cv::Mat img_lb_mog; + cv::Mat img_lbMixtureOfGaussians; LBMixtureOfGaussians* lbMixtureOfGaussians; bool enableLBMixtureOfGaussians; - cv::Mat img_lb_som; + cv::Mat img_lbAdaptiveSOM; LBAdaptiveSOM* lbAdaptiveSOM; bool enableLBAdaptiveSOM; - cv::Mat img_lb_fsom; + cv::Mat img_lbFuzzyAdaptiveSOM; LBFuzzyAdaptiveSOM* lbFuzzyAdaptiveSOM; bool enableLBFuzzyAdaptiveSOM; - cv::Mat img_lbp_mrf; - LbpMrf* lbpMrf; + cv::Mat img_lbpMrf; + LBP_MRF* lbpMrf; bool enableLbpMrf; - cv::Mat img_mlbgs; - MultiLayerBGS* multiLayerBGS; - bool enableMultiLayerBGS; +#if CV_MAJOR_VERSION == 2 + cv::Mat img_multiLayer; + MultiLayer* multiLayer; + bool enableMultiLayer; +#endif - //cv::Mat img_pt_pbas; - //PixelBasedAdaptiveSegmenter* pixelBasedAdaptiveSegmenter; - //bool enablePBAS; + cv::Mat img_pixelBasedAdaptiveSegmenter; + PixelBasedAdaptiveSegmenter* pixelBasedAdaptiveSegmenter; + bool enablePBAS; cv::Mat img_vumeter; VuMeter* vuMeter; @@ -219,24 +174,24 @@ namespace bgslibrary bool enableKDE; cv::Mat img_imbs; - IndependentMultimodalBGS* imbs; + IndependentMultimodal* imbs; bool enableIMBS; - cv::Mat img_mcbgs; - SJN_MultiCueBGS* mcbgs; - bool enableMultiCueBGS; + cv::Mat img_multiCue; + MultiCue* multiCue; + bool enableMultiCue; - cv::Mat img_sdbgs; - SigmaDeltaBGS* sdbgs; - bool enableSigmaDeltaBGS; + cv::Mat img_sigmaDelta; + SigmaDelta* sigmaDelta; + bool enableSigmaDelta; - cv::Mat img_ssbgs; - SuBSENSEBGS* ssbgs; - bool enableSuBSENSEBGS; + cv::Mat img_subSENSE; + SuBSENSE* subSENSE; + bool enableSuBSENSE; - cv::Mat img_lobgs; - LOBSTERBGS* lobgs; - bool enableLOBSTERBGS; + cv::Mat img_lobster; + LOBSTER* lobster; + bool enableLOBSTER; ForegroundMaskAnalysis* foregroundMaskAnalysis; bool enableForegroundMaskAnalysis; diff --git a/Main.cpp b/Main.cpp index 1d170ad..7a406d9 100644 --- a/Main.cpp +++ b/Main.cpp @@ -29,7 +29,7 @@ namespace bgslibrary static void start(int argc, const char **argv) { std::cout << "-----------------------------------------" << std::endl; - std::cout << "Background Subtraction Library v1.9.2 " << std::endl; + std::cout << "Background Subtraction Library v2.0.0 " << std::endl; std::cout << "http://code.google.com/p/bgslibrary " << std::endl; std::cout << "by: " << std::endl; std::cout << "Andrews Sobral (andrewssobral@gmail.com) " << std::endl; diff --git a/PreProcessor.cpp b/PreProcessor.cpp index 6f4ebbe..4c13f7e 100644 --- a/PreProcessor.cpp +++ b/PreProcessor.cpp @@ -95,7 +95,7 @@ namespace bgslibrary cv2DRotationMatrix(center, angle, 1.0, mapMatrix); cvWarpAffine(image, rotatedImage, mapMatrix, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvScalarAll(0)); - cv::Mat img_rot(rotatedImage); + cv::Mat img_rot = cv::cvarrToMat(rotatedImage); img_rot.copyTo(img_output); cvReleaseImage(&image); diff --git a/PreProcessor.h b/PreProcessor.h index da46cce..2e6e61c 100644 --- a/PreProcessor.h +++ b/PreProcessor.h @@ -19,7 +19,6 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - namespace bgslibrary { class PreProcessor diff --git a/README.md b/README.md index a35389a..3b8a3cb 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ A Background Subtraction Library [](https://youtu.be/_UbERwuQ0OU) -Last Page Update: **12/03/2017** +Last Page Update: **18/03/2017** -Latest Library Version: **1.9.2** (see [Release Notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes) for more info) +Latest Library Version: **2.0.0** (see [Release Notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes) for more info) -The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsite.com/home) and provides an easy-to-use C++ framework based on [OpenCV](http://www.opencv.org/) to perform foreground-background separation in videos. The bgslibrary compiles under Windows, Linux, and Mac OS X. Currently the library contains **37** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is free and open source for academic purposes. +The **BGSLibrary** was developed by [Andrews Sobral](http://andrewssobral.wixsite.com/home) and provides an easy-to-use C++ framework based on [OpenCV](http://www.opencv.org/) to perform foreground-background separation in videos. The bgslibrary is compatible with OpenCV 2.x and 3.x, and compiles under Windows, Linux, and Mac OS X. Currently the library contains **40** algorithms. The source code is available under [GNU GPLv3 license](https://www.gnu.org/licenses/gpl-3.0.en.html), the library is free and open source for academic purposes. -Note: the BGSLibrary is based on OpenCV 2.X, if you want to use with OpenCV 3.x please check-out our [opencv3](https://github.com/andrewssobral/bgslibrary/tree/opencv3) branch. +***Note: The [opencv3](https://github.com/andrewssobral/bgslibrary/tree/opencv3) branch will be deprecated.*** * [List of available algorithms](https://github.com/andrewssobral/bgslibrary/wiki/List-of-available-algorithms) * [Algorithms benchmark](https://github.com/andrewssobral/bgslibrary/wiki/Algorithms-benchmark) @@ -77,6 +77,7 @@ Some algorithms of the BGSLibrary were used successfully in the following papers * (2013) Sobral, Andrews; Oliveira, Luciano; Schnitman, Leizer; Souza, Felippe. (**Best Paper Award**) Highway Traffic Congestion Classification Using Holistic Properties. In International Conference on Signal Processing, Pattern Recognition and Applications (SPPRA'2013), Innsbruck, Austria, Feb 2013. ([Online](http://dx.doi.org/10.2316/P.2013.798-105)) ([PDF](http://www.researchgate.net/publication/233427564_HIGHWAY_TRAFFIC_CONGESTION_CLASSIFICATION_USING_HOLISTIC_PROPERTIES)) + Videos ------ diff --git a/VideoAnalysis.cpp b/VideoAnalysis.cpp index 1e46542..9c8020a 100644 --- a/VideoAnalysis.cpp +++ b/VideoAnalysis.cpp @@ -18,7 +18,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. namespace bgslibrary { - VideoAnalysis::VideoAnalysis() : use_file(false), use_camera(false), cameraIndex(0), use_comp(false), frameToStop(0) + VideoAnalysis::VideoAnalysis() : + use_file(false), use_camera(false), cameraIndex(0), + use_comp(false), frameToStop(0) { std::cout << "VideoAnalysis()" << std::endl; } @@ -32,8 +34,9 @@ namespace bgslibrary { bool flag = false; +#if CV_MAJOR_VERSION == 2 const char* keys = - "{hp|help|false|Print help message}" + "{hp|help|false|Print this message}" "{uf|use_file|false|Use video file}" "{fn|filename||Specify video file}" "{uc|use_cam|false|Use camera}" @@ -42,21 +45,63 @@ namespace bgslibrary "{st|stopAt|0|Frame number to stop}" "{im|imgref||Specify image file}" ; +#elif CV_MAJOR_VERSION == 3 + const std::string keys = + "{h help ? | | Print this message }" + "{uf use_file |false| Use a video file }" + "{fn filename | | Specify a video file }" + "{uc use_cam |false| Use a webcamera }" + "{ca camera | 0 | Specify camera index }" + "{co use_comp |false| Use mask comparator }" + "{st stopAt | 0 | Frame number to stop }" + "{im imgref | | Specify a image file }" + ; +#endif + cv::CommandLineParser cmd(argc, argv, keys); +#if CV_MAJOR_VERSION == 2 if (argc <= 1 || cmd.get<bool>("help") == true) { std::cout << "Usage: " << argv[0] << " [options]" << std::endl; - std::cout << "Avaible options:" << std::endl; + std::cout << "Available options:" << std::endl; cmd.printParams(); return false; } +#elif CV_MAJOR_VERSION == 3 + if (argc <= 1 || cmd.has("help")) + { + std::cout << "Usage: " << argv[0] << " [options]" << std::endl; + std::cout << "Available options:" << std::endl; + cmd.printMessage(); + return false; + } + if (!cmd.check()) + { + cmd.printErrors(); + return false; + } +#endif + + use_file = cmd.get<bool>("uf"); //use_file + filename = cmd.get<std::string>("fn"); //filename + use_camera = cmd.get<bool>("uc"); //use_cam + cameraIndex = cmd.get<int>("ca"); //camera + use_comp = cmd.get<bool>("co"); //use_comp + frameToStop = cmd.get<int>("st"); //stopAt + imgref = cmd.get<std::string>("im"); //imgref + + std::cout << "use_file: " << use_file << std::endl; + std::cout << "filename: " << filename << std::endl; + std::cout << "use_camera: " << use_camera << std::endl; + std::cout << "cameraIndex: " << cameraIndex << std::endl; + std::cout << "use_comp: " << use_comp << std::endl; + std::cout << "frameToStop: " << frameToStop << std::endl; + std::cout << "imgref: " << imgref << std::endl; + //return false; - use_file = cmd.get<bool>("use_file"); if (use_file) { - filename = cmd.get<std::string>("filename"); - if (filename.empty()) { std::cout << "Specify filename" << std::endl; @@ -66,26 +111,15 @@ namespace bgslibrary flag = true; } - use_camera = cmd.get<bool>("use_cam"); if (use_camera) - { - cameraIndex = cmd.get<int>("camera"); flag = true; - } - if (flag == true) + if (flag && use_comp) { - use_comp = cmd.get<bool>("use_comp"); - if (use_comp) + if (imgref.empty()) { - frameToStop = cmd.get<int>("stopAt"); - imgref = cmd.get<std::string>("imgref"); - - if (imgref.empty()) - { - std::cout << "Specify image reference" << std::endl; - return false; - } + std::cout << "Specify image reference" << std::endl; + return false; } } diff --git a/VideoCapture.cpp b/VideoCapture.cpp index 4de5b90..b302a3f 100644 --- a/VideoCapture.cpp +++ b/VideoCapture.cpp @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "VideoCapture.h" +#include <opencv2/highgui/highgui_c.h> namespace bgslibrary { @@ -74,8 +75,11 @@ namespace bgslibrary } } - VideoCapture::VideoCapture() : key(0), start_time(0), delta_time(0), freq(0), fps(0), frameNumber(0), stopAt(0), - useCamera(false), useVideo(false), input_resize_percent(100), showOutput(true), enableFlip(false) + VideoCapture::VideoCapture() : + key(0), start_time(0), delta_time(0), freq(0), + fps(0), frameNumber(0), stopAt(0), useCamera(false), + useVideo(false), input_resize_percent(100), showOutput(true), + enableFlip(false), cameraIndex(0) { std::cout << "VideoCapture()" << std::endl; } @@ -101,10 +105,10 @@ namespace bgslibrary void VideoCapture::setUpCamera() { std::cout << "Camera index:" << cameraIndex << std::endl; - capture = cvCaptureFromCAM(cameraIndex); + capture.open(cameraIndex); - if (!capture) - std::cerr << "Cannot open initialize webcam!\n" << std::endl; + if (!capture.isOpened()) + std::cerr << "Cannot initialize webcam!\n" << std::endl; } void VideoCapture::setVideo(std::string filename) @@ -117,10 +121,13 @@ namespace bgslibrary void VideoCapture::setUpVideo() { - capture = cvCaptureFromFile(videoFileName.c_str()); + std::cout << "Openning: " << videoFileName << std::endl; + capture.open(videoFileName.c_str()); - if (!capture) + if (!capture.isOpened()) std::cerr << "Cannot open video file " << videoFileName << std::endl; + else + std::cout << "OK" << std::endl; } void VideoCapture::start() @@ -129,17 +136,21 @@ namespace bgslibrary if (useCamera) setUpCamera(); if (useVideo) setUpVideo(); - if (!capture) std::cerr << "Capture error..." << std::endl; + //if (!capture) std::cerr << "Capture error..." << std::endl; - int input_fps = cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); + int input_fps = capture.get(CV_CAP_PROP_FPS); std::cout << "input->fps:" << input_fps << std::endl; + /* IplImage* frame1 = cvQueryFrame(capture); - frame = cvCreateImage(cvSize((int)((frame1->width*input_resize_percent) / 100), (int)((frame1->height*input_resize_percent) / 100)), frame1->depth, frame1->nChannels); + frame = cvCreateImage(cvSize( + (int)((frame1->width*input_resize_percent) / 100), + (int)((frame1->height*input_resize_percent) / 100)), frame1->depth, frame1->nChannels); //cvCreateImage(cvSize(frame1->width/input_resize_factor, frame1->height/input_resize_factor), frame1->depth, frame1->nChannels); std::cout << "input->resize_percent:" << input_resize_percent << std::endl; std::cout << "input->width:" << frame->width << std::endl; std::cout << "input->height:" << frame->height << std::endl; + */ double loopDelay = 33.333; if (input_fps > 0) @@ -152,13 +163,14 @@ namespace bgslibrary { frameNumber++; - frame1 = cvQueryFrame(capture); - if (!frame1) break; + cv::Mat frame; + capture >> frame; + if (frame.empty()) break; - cvResize(frame1, frame); + //cvResize(frame1, frame); - if (enableFlip) - cvFlip(frame, frame, 0); + //if (enableFlip) + // cvFlip(frame, frame, 0); if (VC_ROI::use_roi == true && VC_ROI::roi_defined == false && firstTime == true) { @@ -166,7 +178,9 @@ namespace bgslibrary do { - cv::Mat img_input(frame); + //cv::Mat img_input = cv::cvarrToMat(frame); + cv::Mat img_input; + frame.copyTo(img_input); if (showOutput) { @@ -202,11 +216,13 @@ namespace bgslibrary if (VC_ROI::use_roi == true && VC_ROI::roi_defined == true) { - CvRect rect = cvRect(VC_ROI::roi_x0, VC_ROI::roi_y0, VC_ROI::roi_x1 - VC_ROI::roi_x0, VC_ROI::roi_y1 - VC_ROI::roi_y0); - cvSetImageROI(frame, rect); + cv::Rect roi(VC_ROI::roi_x0, VC_ROI::roi_y0, VC_ROI::roi_x1 - VC_ROI::roi_x0, VC_ROI::roi_y1 - VC_ROI::roi_y0); + frame = frame(roi); } - cv::Mat img_input(frame); + //cv::Mat img_input = cv::cvarrToMat(frame); + cv::Mat img_input; + frame.copyTo(img_input); if (showOutput) cv::imshow("Input", img_input); @@ -221,7 +237,7 @@ namespace bgslibrary fps = freq / delta_time; //std::cout << "FPS: " << fps << std::endl; - cvResetImageROI(frame); + //cvResetImageROI(frame); key = cvWaitKey(loopDelay); //std::cout << "key: " << key << std::endl; @@ -238,7 +254,7 @@ namespace bgslibrary firstTime = false; } while (1); - cvReleaseCapture(&capture); + capture.release(); } void VideoCapture::saveConfig() diff --git a/VideoCapture.h b/VideoCapture.h index a8ba2ff..0e88c87 100644 --- a/VideoCapture.h +++ b/VideoCapture.h @@ -18,7 +18,8 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - +#include <opencv2/imgproc/imgproc_c.h> +#include <opencv2/imgproc/types_c.h> #include "Config.h" #include "IFrameProcessor.h" @@ -29,7 +30,7 @@ namespace bgslibrary { private: IFrameProcessor* frameProcessor; - CvCapture* capture; + cv::VideoCapture capture; IplImage* frame; int key; int64 start_time; diff --git a/config/FrameProcessor.xml b/config/FrameProcessor.xml index 5155bbf..3cf398c 100644 --- a/config/FrameProcessor.xml +++ b/config/FrameProcessor.xml @@ -3,22 +3,22 @@ <tictoc>""</tictoc> <enablePreProcessor>1</enablePreProcessor> <enableForegroundMaskAnalysis>0</enableForegroundMaskAnalysis> -<enableFrameDifferenceBGS>1</enableFrameDifferenceBGS> -<enableStaticFrameDifferenceBGS>0</enableStaticFrameDifferenceBGS> -<enableWeightedMovingMeanBGS>0</enableWeightedMovingMeanBGS> -<enableWeightedMovingVarianceBGS>0</enableWeightedMovingVarianceBGS> -<enableMixtureOfGaussianV1BGS>0</enableMixtureOfGaussianV1BGS> -<enableMixtureOfGaussianV2BGS>0</enableMixtureOfGaussianV2BGS> +<enableFrameDifference>1</enableFrameDifference> +<enableStaticFrameDifference>0</enableStaticFrameDifference> +<enableWeightedMovingMean>0</enableWeightedMovingMean> +<enableWeightedMovingVariance>0</enableWeightedMovingVariance> +<enableMixtureOfGaussianV1>0</enableMixtureOfGaussianV1> +<enableMixtureOfGaussianV2>0</enableMixtureOfGaussianV2> <enableAdaptiveBackgroundLearning>0</enableAdaptiveBackgroundLearning> <enableGMG>0</enableGMG> -<enableDPAdaptiveMedianBGS>0</enableDPAdaptiveMedianBGS> -<enableDPGrimsonGMMBGS>0</enableDPGrimsonGMMBGS> -<enableDPZivkovicAGMMBGS>0</enableDPZivkovicAGMMBGS> -<enableDPMeanBGS>0</enableDPMeanBGS> -<enableDPWrenGABGS>0</enableDPWrenGABGS> -<enableDPPratiMediodBGS>0</enableDPPratiMediodBGS> -<enableDPEigenbackgroundBGS>0</enableDPEigenbackgroundBGS> -<enableDPTextureBGS>0</enableDPTextureBGS> +<enableDPAdaptiveMedian>0</enableDPAdaptiveMedian> +<enableDPGrimsonGMM>0</enableDPGrimsonGMM> +<enableDPZivkovicAGMM>0</enableDPZivkovicAGMM> +<enableDPMean>0</enableDPMean> +<enableDPWrenGA>0</enableDPWrenGA> +<enableDPPratiMediod>0</enableDPPratiMediod> +<enableDPEigenbackground>0</enableDPEigenbackground> +<enableDPTexture>0</enableDPTexture> <enableT2FGMM_UM>0</enableT2FGMM_UM> <enableT2FGMM_UV>0</enableT2FGMM_UV> <enableT2FMRF_UM>0</enableT2FMRF_UM> @@ -31,12 +31,13 @@ <enableLBAdaptiveSOM>0</enableLBAdaptiveSOM> <enableLBFuzzyAdaptiveSOM>0</enableLBFuzzyAdaptiveSOM> <enableLbpMrf>0</enableLbpMrf> -<enableMultiLayerBGS>0</enableMultiLayerBGS> +<enableMultiLayer>0</enableMultiLayer> +<enablePBAS>0</enablePBAS> <enableVuMeter>0</enableVuMeter> <enableKDE>0</enableKDE> <enableIMBS>0</enableIMBS> -<enableMultiCueBGS>0</enableMultiCueBGS> -<enableSigmaDeltaBGS>0</enableSigmaDeltaBGS> -<enableSuBSENSEBGS>0</enableSuBSENSEBGS> -<enableLOBSTERBGS>0</enableLOBSTERBGS> +<enableMultiCue>0</enableMultiCue> +<enableSigmaDelta>0</enableSigmaDelta> +<enableSuBSENSE>0</enableSuBSENSE> +<enableLOBSTER>0</enableLOBSTER> </opencv_storage> diff --git a/dataset/demo.avi b/dataset/demo.avi new file mode 100644 index 0000000000000000000000000000000000000000..df20707af3b0a2cbcaaae127b982e1886b1d2aa7 GIT binary patch literal 355840 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%0ARRuY(3^J^^4ZI%= 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 G6bu0PUwMlF literal 0 HcmV?d00001 diff --git a/frames/1.png b/dataset/frames/1.png similarity index 100% rename from frames/1.png rename to dataset/frames/1.png diff --git a/frames/10.png b/dataset/frames/10.png similarity index 100% rename from frames/10.png rename to dataset/frames/10.png diff --git a/frames/11.png b/dataset/frames/11.png similarity index 100% rename from frames/11.png rename to dataset/frames/11.png diff --git a/frames/12.png b/dataset/frames/12.png similarity index 100% rename from frames/12.png rename to dataset/frames/12.png diff --git a/frames/13.png b/dataset/frames/13.png similarity index 100% rename from frames/13.png rename to dataset/frames/13.png diff --git a/frames/14.png b/dataset/frames/14.png similarity index 100% rename from frames/14.png rename to dataset/frames/14.png diff --git a/frames/15.png b/dataset/frames/15.png similarity index 100% rename from frames/15.png rename to dataset/frames/15.png diff --git a/frames/16.png b/dataset/frames/16.png similarity index 100% rename from frames/16.png rename to dataset/frames/16.png diff --git a/frames/17.png b/dataset/frames/17.png similarity index 100% rename from frames/17.png rename to dataset/frames/17.png diff --git a/frames/18.png b/dataset/frames/18.png similarity index 100% rename from frames/18.png rename to dataset/frames/18.png diff --git a/frames/19.png b/dataset/frames/19.png similarity index 100% rename from frames/19.png rename to dataset/frames/19.png diff --git a/frames/2.png b/dataset/frames/2.png similarity index 100% rename from frames/2.png rename to dataset/frames/2.png diff --git a/frames/20.png b/dataset/frames/20.png similarity index 100% rename from frames/20.png rename to dataset/frames/20.png diff --git a/frames/21.png b/dataset/frames/21.png similarity index 100% rename from frames/21.png rename to dataset/frames/21.png diff --git a/frames/22.png b/dataset/frames/22.png similarity index 100% rename from frames/22.png rename to dataset/frames/22.png diff --git a/frames/23.png b/dataset/frames/23.png similarity index 100% rename from frames/23.png rename to dataset/frames/23.png diff --git a/frames/24.png b/dataset/frames/24.png similarity index 100% rename from frames/24.png rename to dataset/frames/24.png diff --git a/frames/25.png b/dataset/frames/25.png similarity index 100% rename from frames/25.png rename to dataset/frames/25.png diff --git a/frames/26.png b/dataset/frames/26.png similarity index 100% rename from frames/26.png rename to dataset/frames/26.png diff --git a/frames/27.png b/dataset/frames/27.png similarity index 100% rename from frames/27.png rename to dataset/frames/27.png diff --git a/frames/28.png b/dataset/frames/28.png similarity index 100% rename from frames/28.png rename to dataset/frames/28.png diff --git a/frames/29.png b/dataset/frames/29.png similarity index 100% rename from frames/29.png rename to dataset/frames/29.png diff --git a/frames/3.png b/dataset/frames/3.png similarity index 100% rename from frames/3.png rename to dataset/frames/3.png diff --git a/frames/30.png b/dataset/frames/30.png similarity index 100% rename from frames/30.png rename to dataset/frames/30.png diff --git a/frames/31.png b/dataset/frames/31.png similarity index 100% rename from frames/31.png rename to dataset/frames/31.png diff --git a/frames/32.png b/dataset/frames/32.png similarity index 100% rename from frames/32.png rename to dataset/frames/32.png diff --git a/frames/33.png b/dataset/frames/33.png similarity index 100% rename from frames/33.png rename to dataset/frames/33.png diff --git a/frames/34.png b/dataset/frames/34.png similarity index 100% rename from frames/34.png rename to dataset/frames/34.png diff --git a/frames/35.png b/dataset/frames/35.png similarity index 100% rename from frames/35.png rename to dataset/frames/35.png diff --git a/frames/36.png b/dataset/frames/36.png similarity index 100% rename from frames/36.png rename to dataset/frames/36.png diff --git a/frames/37.png b/dataset/frames/37.png similarity index 100% rename from frames/37.png rename to dataset/frames/37.png diff --git a/frames/38.png b/dataset/frames/38.png similarity index 100% rename from frames/38.png rename to dataset/frames/38.png diff --git a/frames/39.png b/dataset/frames/39.png similarity index 100% rename from frames/39.png rename to dataset/frames/39.png diff --git a/frames/4.png b/dataset/frames/4.png similarity index 100% rename from frames/4.png rename to dataset/frames/4.png diff --git a/frames/40.png b/dataset/frames/40.png similarity index 100% rename from frames/40.png rename to dataset/frames/40.png diff --git a/frames/41.png b/dataset/frames/41.png similarity index 100% rename from frames/41.png rename to dataset/frames/41.png diff --git a/frames/42.png b/dataset/frames/42.png similarity index 100% rename from frames/42.png rename to dataset/frames/42.png diff --git a/frames/43.png b/dataset/frames/43.png similarity index 100% rename from frames/43.png rename to dataset/frames/43.png diff --git a/frames/44.png b/dataset/frames/44.png similarity index 100% rename from frames/44.png rename to dataset/frames/44.png diff --git a/frames/45.png b/dataset/frames/45.png similarity index 100% rename from frames/45.png rename to dataset/frames/45.png diff --git a/frames/46.png b/dataset/frames/46.png similarity index 100% rename from frames/46.png rename to dataset/frames/46.png diff --git a/frames/47.png b/dataset/frames/47.png similarity index 100% rename from frames/47.png rename to dataset/frames/47.png diff --git a/frames/48.png b/dataset/frames/48.png similarity index 100% rename from frames/48.png rename to dataset/frames/48.png diff --git a/frames/49.png b/dataset/frames/49.png similarity index 100% rename from frames/49.png rename to dataset/frames/49.png diff --git a/frames/5.png b/dataset/frames/5.png similarity index 100% rename from frames/5.png rename to dataset/frames/5.png diff --git a/frames/50.png b/dataset/frames/50.png similarity index 100% rename from frames/50.png rename to dataset/frames/50.png diff --git a/frames/51.png b/dataset/frames/51.png similarity index 100% rename from frames/51.png rename to dataset/frames/51.png diff --git a/frames/6.png b/dataset/frames/6.png similarity index 100% rename from frames/6.png rename to dataset/frames/6.png diff --git a/frames/7.png b/dataset/frames/7.png similarity index 100% rename from frames/7.png rename to dataset/frames/7.png diff --git a/frames/8.png b/dataset/frames/8.png similarity index 100% rename from frames/8.png rename to dataset/frames/8.png diff --git a/frames/9.png b/dataset/frames/9.png similarity index 100% rename from frames/9.png rename to dataset/frames/9.png diff --git a/demos/DemoFrameDifferenceBGS.cpp b/demos/DemoFrameDifferenceBGS.cpp deleted file mode 100644 index 5a449e2..0000000 --- a/demos/DemoFrameDifferenceBGS.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "package_bgs/FrameDifferenceBGS.h" - -int main(int argc, char **argv) -{ - CvCapture *capture = 0; - - capture = cvCaptureFromCAM(0); - //capture = cvCaptureFromAVI("video.avi"); - - if(!capture){ - std::cerr << "Cannot open initialize webcam!" << std::endl; - return 1; - } - - IplImage *frame = cvQueryFrame(capture); - - FrameDifferenceBGS* bgs = new FrameDifferenceBGS; - - int key = 0; - while(key != 'q') - { - frame = cvQueryFrame(capture); - - if(!frame) break; - - cv::Mat img_input(frame,true); - cv::resize(img_input,img_input,cv::Size(320,240)); - cv::imshow("input", img_input); - - cv::Mat img_mask; - bgs->process(img_input, img_mask); // automatically shows the foreground mask image - - //if(!img_mask.empty()) - // do something - - key = cvWaitKey(1); - } - - delete bgs; - - cvDestroyAllWindows(); - cvReleaseCapture(&capture); - - return 0; -} diff --git a/demos/DemoMultiLayerBGS.cpp b/demos/DemoMultiLayerBGS.cpp deleted file mode 100644 index 08abe30..0000000 --- a/demos/DemoMultiLayerBGS.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "package_bgs/jmo/MultiLayerBGS.h" - -int main(int argc, char **argv) -{ - CvCapture *capture = 0; - - capture = cvCaptureFromCAM(0); - //capture = cvCaptureFromAVI("video.avi"); - - if(!capture){ - std::cerr << "Cannot open initialize webcam!" << std::endl; - return 1; - } - - IplImage *frame = cvQueryFrame(capture); - - MultiLayerBGS* bgs = new MultiLayerBGS; - - int key = 0; - while(key != 'q') - { - frame = cvQueryFrame(capture); - - if(!frame) break; - - cv::Mat img_input(frame,true); - cv::resize(img_input,img_input,cv::Size(320,240)); - cv::imshow("input", img_input); - - cv::Mat img_mask; - bgs->process(img_input, img_mask); // automatically shows the foreground mask image - - //if(!img_mask.empty()) - // do something - - key = cvWaitKey(1); - } - - delete bgs; - - cvDestroyAllWindows(); - cvReleaseCapture(&capture); - - return 0; -} diff --git a/demos/linux_ubuntu/.gitignore b/demos/linux_ubuntu/.gitignore new file mode 100644 index 0000000..46d4288 --- /dev/null +++ b/demos/linux_ubuntu/.gitignore @@ -0,0 +1,8 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore +!CMakeLists.txt +!FrameDifferenceTest.cpp +!README.txt +!config/ diff --git a/example_linux/CMakeLists.txt b/demos/linux_ubuntu/CMakeLists.txt similarity index 66% rename from example_linux/CMakeLists.txt rename to demos/linux_ubuntu/CMakeLists.txt index 9317e55..8cc38e8 100644 --- a/example_linux/CMakeLists.txt +++ b/demos/linux_ubuntu/CMakeLists.txt @@ -9,15 +9,14 @@ find_package(OpenCV REQUIRED) file(GLOB source FrameDifferenceTest.cpp) -file(GLOB_RECURSE bgs_src ../package_bgs/*.cpp ../package_bgs/*.c) -file(GLOB_RECURSE bgs_include ../package_bgs/*.h) +file(GLOB_RECURSE bgs_src ../../package_bgs/*.cpp ../../package_bgs/*.c ../../package_analysis/*.cpp) +file(GLOB_RECURSE bgs_inc ../../package_bgs/*.h ../../package_analysis/*.h) include_directories(${CMAKE_SOURCE_DIR}) add_library(bgs SHARED ${bgs_src}) target_link_libraries(bgs ${OpenCV_LIBS}) -set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_include}) +set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_inc}) add_executable(FrameDifferenceTest ${source}) target_link_libraries(FrameDifferenceTest ${OpenCV_LIBS} bgs) - diff --git a/example_macosx/FrameDifferenceTest.cpp b/demos/linux_ubuntu/FrameDifferenceTest.cpp similarity index 87% rename from example_macosx/FrameDifferenceTest.cpp rename to demos/linux_ubuntu/FrameDifferenceTest.cpp index 56f1e7c..7ebe8b1 100644 --- a/example_macosx/FrameDifferenceTest.cpp +++ b/demos/linux_ubuntu/FrameDifferenceTest.cpp @@ -2,7 +2,9 @@ #include <cv.h> #include <highgui.h> -#include "../package_bgs/FrameDifferenceBGS.h" +#include "../../package_bgs/FrameDifference.h" + +using namespace bgslibrary::algorithms; int main(int argc, char **argv) { @@ -15,7 +17,7 @@ int main(int argc, char **argv) } IBGS *bgs; - bgs = new FrameDifferenceBGS; + bgs = new FrameDifference; IplImage *frame; while(1) diff --git a/example_linux/README.txt b/demos/linux_ubuntu/README.txt similarity index 100% rename from example_linux/README.txt rename to demos/linux_ubuntu/README.txt diff --git a/demos/linux_ubuntu/config/.gitignore b/demos/linux_ubuntu/config/.gitignore new file mode 100644 index 0000000..8ee04a0 --- /dev/null +++ b/demos/linux_ubuntu/config/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore \ No newline at end of file diff --git a/demos/macosx/.gitignore b/demos/macosx/.gitignore new file mode 100644 index 0000000..46d4288 --- /dev/null +++ b/demos/macosx/.gitignore @@ -0,0 +1,8 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore +!CMakeLists.txt +!FrameDifferenceTest.cpp +!README.txt +!config/ diff --git a/example_macosx/CMakeLists.txt b/demos/macosx/CMakeLists.txt similarity index 79% rename from example_macosx/CMakeLists.txt rename to demos/macosx/CMakeLists.txt index 107303f..a9775d8 100644 --- a/example_macosx/CMakeLists.txt +++ b/demos/macosx/CMakeLists.txt @@ -20,15 +20,14 @@ find_package(OpenCV REQUIRED) file(GLOB source FrameDifferenceTest.cpp) -file(GLOB_RECURSE bgs_src ../package_bgs/*.cpp ../package_bgs/*.c) -file(GLOB_RECURSE bgs_include ../package_bgs/*.h) +file(GLOB_RECURSE bgs_src ../../package_bgs/*.cpp ../../package_bgs/*.c ../../package_analysis/*.cpp) +file(GLOB_RECURSE bgs_inc ../../package_bgs/*.h ../../package_analysis/*.h) include_directories(${CMAKE_SOURCE_DIR}) add_library(bgs SHARED ${bgs_src}) target_link_libraries(bgs ${OpenCV_LIBS}) -set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_include}) +set_property(TARGET bgs PROPERTY PUBLIC_HEADER ${bgs_inc}) add_executable(FrameDifferenceTest ${source}) target_link_libraries(FrameDifferenceTest ${OpenCV_LIBS} bgs) - diff --git a/example_linux/FrameDifferenceTest.cpp b/demos/macosx/FrameDifferenceTest.cpp similarity index 87% rename from example_linux/FrameDifferenceTest.cpp rename to demos/macosx/FrameDifferenceTest.cpp index 56f1e7c..7ebe8b1 100644 --- a/example_linux/FrameDifferenceTest.cpp +++ b/demos/macosx/FrameDifferenceTest.cpp @@ -2,7 +2,9 @@ #include <cv.h> #include <highgui.h> -#include "../package_bgs/FrameDifferenceBGS.h" +#include "../../package_bgs/FrameDifference.h" + +using namespace bgslibrary::algorithms; int main(int argc, char **argv) { @@ -15,7 +17,7 @@ int main(int argc, char **argv) } IBGS *bgs; - bgs = new FrameDifferenceBGS; + bgs = new FrameDifference; IplImage *frame; while(1) diff --git a/example_macosx/README.txt b/demos/macosx/README.txt similarity index 100% rename from example_macosx/README.txt rename to demos/macosx/README.txt diff --git a/demos/macosx/config/.gitignore b/demos/macosx/config/.gitignore new file mode 100644 index 0000000..8ee04a0 --- /dev/null +++ b/demos/macosx/config/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore \ No newline at end of file diff --git a/README_CMAKE_USERS.txt b/docs/README_CMAKE_USERS_OPENCV2.txt similarity index 70% rename from README_CMAKE_USERS.txt rename to docs/README_CMAKE_USERS_OPENCV2.txt index 974e941..26c6997 100644 --- a/README_CMAKE_USERS.txt +++ b/docs/README_CMAKE_USERS_OPENCV2.txt @@ -15,18 +15,17 @@ Please follow the instructions below: 1) Go to Windows console. 2) Clone BGSLibrary git repository: -e.g.: git clone https://github.com/andrewssobral/bgslibrary.git +git clone https://github.com/andrewssobral/bgslibrary.git 3) Go to bgslibrary/build folder. -e.g.: C:\bgslibrary\build>_ -2) Set your OpenCV PATH: -e.g.: -\> setlocal -\> set OpenCV_DIR=C:\OpenCV2.4.10\build -\> cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 12" .. -or: -\> cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 12 Win64" .. +4) Set your OpenCV PATH: +setlocal +set OpenCV_DIR=C:\OpenCV2.4.10\build + +5) Launch CMAKE: +(For Windows x86 32bits) cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 12" .. +(For Windows x64 64bits) cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 12 Win64" .. Now, you will see something like (for win64): ------------------------------------------------- @@ -52,27 +51,25 @@ Now, you will see something like (for win64): -- Build files have been written to: C:/bgslibrary/build ------------------------------------------------- -3) Include OpenCV binaries in the system path: -\> set PATH=%PATH%;%OpenCV_DIR%\x86\vc12\bin -or: -\> set PATH=%PATH%;%OpenCV_DIR%\x64\vc12\bin +6) Include OpenCV binaries in the system path: +(For Windows x86 32bits) set PATH=%PATH%;%OpenCV_DIR%\x86\vc12\bin +(For Windows x64 64bits) set PATH=%PATH%;%OpenCV_DIR%\x64\vc12\bin -4) Open 'bgs.sln' in Visual Studio and switch to 'RELEASE' mode -4.1) Note if you are using a Visual Studio version superior than 2013, you will need to CANCEL the project wizard update. However, you can go to step (2) and change the Visual Studio version, e.g.: -G "Visual Studio XX", where XX is your Visual Studio version. +7) Open 'bgs.sln' in Visual Studio and switch to 'RELEASE' mode +7.1) Note if you are using a Visual Studio version superior than 2013, you will need to CANCEL the project wizard update. However, you can go to step (5) and change the Visual Studio version, e.g.: -G "Visual Studio XX", where XX is your Visual Studio version. -5) Click on 'ALL_BUILD' project and build! +8) Click on 'ALL_BUILD' project and build! -6) If everything goes well, you can run bgslibrary in the Windows console as follows: +9) If everything goes well, you can run bgslibrary in the Windows console as follows: -6.1) Running BGSLibrary with a webcamera: +9.1) Running BGSLibrary with a webcamera: C:\bgslibrary> build\bgslibrary.exe --use_cam --camera=0 -6.2) Running demo code: +9.2) Running demo code: C:\bgslibrary> build\bgs_demo.exe dataset/video.avi -6.3) Running demo2 code: +9.3) Running demo2 code: C:\bgslibrary> build\bgs_demo2.exe Additional information: * Note that bgslibrary requires a 'config' folder in the working directory. -e.g.: C:\bgslibrary\config diff --git a/docs/README_CMAKE_USERS_OPENCV3.txt b/docs/README_CMAKE_USERS_OPENCV3.txt new file mode 100644 index 0000000..543fd86 --- /dev/null +++ b/docs/README_CMAKE_USERS_OPENCV3.txt @@ -0,0 +1,77 @@ +------------------------------------------------- +-------------- WINDOWS CMAKE USERS -------------- + +How to build BGSLibrary with OpenCV 3.2.0 and Visual Studio 2015 from CMAKE. + +For Linux users, please see the instruction in README_LINUX_USERS.txt file. + +Dependencies: +* GIT (tested with git version 2.7.2.windows.1). +* CMAKE for Windows (tested with cmake version 3.1.1). +* Microsoft Visual Studio (tested with VS2015). + +Please follow the instructions below: + +1) Go to Windows console. + +2) Clone BGSLibrary git repository: +git clone https://github.com/andrewssobral/bgslibrary.git + +3) Go to bgslibrary/build folder. + +4) Set your OpenCV PATH: +setlocal +set OpenCV_DIR=C:\OpenCV3.2.0\build + +5) Launch CMAKE: +cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" .. + +Now, you will see something like: +------------------------------------------------- +-- The C compiler identification is MSVC 19.0.24215.1 +-- The CXX compiler identification is MSVC 19.0.24215.1 +-- Check for working C compiler using: Visual Studio 14 2015 Win64 +-- Check for working C compiler using: Visual Studio 14 2015 Win64 -- works +-- Detecting C compiler ABI info +-- Detecting C compiler ABI info - done +-- Check for working CXX compiler using: Visual Studio 14 2015 Win64 +-- Check for working CXX compiler using: Visual Studio 14 2015 Win64 -- works +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Detecting CXX compile features +-- Detecting CXX compile features - done +-- OpenCV ARCH: x64 +-- OpenCV RUNTIME: vc14 +-- OpenCV STATIC: ON +-- Found OpenCV 3.2.0 in C:/OpenCV3.2.0/build/x64/vc14/lib +-- You might need to add C:\OpenCV3.2.0\build\x64\vc14\bin to your PATH to be able to run your applications. +-- OpenCV library status: +-- version: 3.2.0 +-- libraries: opencv_world;opencv_videostab;opencv_videoio;opencv_video;opencv_superres;opencv_stitching;opencv_shape;opencv_photo;opencv_objdetect;opencv_ml;opencv_imgproc;opencv_imgcodecs;opencv_highgui;opencv_flann;opencv_features2d;opencv_core;opencv_calib3d +-- include path: C:/OpenCV3.2.0/build/include;C:/OpenCV3.2.0/build/include/opencv +-- Configuring done +-- Generating done +-- Build files have been written to: C:/bgslibrary/build +------------------------------------------------- + +6) Include OpenCV binaries in the system path: +set PATH=%PATH%;%OpenCV_DIR%\x64\vc14\bin + +7) Open 'bgs.sln' in Visual Studio and switch to 'RELEASE' mode +7.1) Note if you are using a Visual Studio version superior than 2015, you will need to CANCEL the project wizard update. However, you can go to step (2) and change the Visual Studio version, e.g.: -G "Visual Studio XX", where XX is your Visual Studio version. + +8) Click on 'ALL_BUILD' project and build! + +9) If everything goes well, you can run bgslibrary in the Windows console as follows: + +9.1) Running BGSLibrary with a webcamera: +C:\bgslibrary> build\bgslibrary.exe --use_cam --camera=0 + +9.2) Running demo code: +C:\bgslibrary> build\bgs_demo.exe dataset/video.avi + +9.3) Running demo2 code: +C:\bgslibrary> build\bgs_demo2.exe + +Additional information: +* Note that bgslibrary requires a 'config' folder in the working directory. diff --git a/README_LINUX_USERS.txt b/docs/README_LINUX_USERS.txt similarity index 85% rename from README_LINUX_USERS.txt rename to docs/README_LINUX_USERS.txt index 5a2611f..9482f33 100644 --- a/README_LINUX_USERS.txt +++ b/docs/README_LINUX_USERS.txt @@ -4,6 +4,8 @@ # Requirements: # cmake >= 2.8 # opencv >= 2.3.1 +# +# Tested with: Ubuntu 14.04 and Ubuntu 16.04 cd build cmake .. @@ -17,7 +19,8 @@ export LD_LIBRARY_PATH # Now you can run bgslibrary by: bgs -i video.avi ######################## cd .. -chmod +x run_video.sh run_camera.sh run_demo.sh +chmod +x *.sh ./run_video.sh ./run_camera.sh ./run_demo.sh +./run_demo2.sh diff --git a/README_VISUAL_STUDIO_USERS.txt b/docs/README_VS2010_OPENCV2.txt similarity index 81% rename from README_VISUAL_STUDIO_USERS.txt rename to docs/README_VS2010_OPENCV2.txt index ee9fe12..66ee0f4 100644 --- a/README_VISUAL_STUDIO_USERS.txt +++ b/docs/README_VS2010_OPENCV2.txt @@ -1,16 +1,13 @@ --------------------------------------------------- BGSLibrary with Visual Studio 2010 and Opencv 2.4.x --------------------------------------------------- - -1) Clone our VS2010 example project at [vs2010] folder -https://github.com/andrewssobral/bgslibrary/tree/master/vs2010 - -Or configure manually by: +--- Tutorial for Windows x86 32 bits --- +---------------------------------------- 1) Install OpenCV 1.a) Download OpenCV 2.4.x from http://opencv.org/ -2.b) Install in: C:\OpenCV2.4.x -2.c) Add OpenCV binaries in your Path +1.b) Install in: C:\OpenCV2.4.x +1.c) Add OpenCV binaries in your Path C:\OpenCV2.4.x\build\x86\vc10\bin 2) Download BGSLibrary @@ -22,7 +19,7 @@ C:\OpenCV2.4.x\build\x86\vc10\bin 3.c) Set project location: C:\bgslibrary 3.d) Set project name: bgslibrary 3.e) Set Empty project -3.f) Add Demo.cpp in [Source Files] +3.f) Add Main.cpp in [Source Files] 3.g) Add content of c:\bgslibrary\package_bgs\*.* in [Header Files] 3.h) Add content of c:\bgslibrary\package_analysis\*.* in [Header Files] 3.i) Change to [Release] [Win32] mode diff --git a/example_linux/config/KEEP_THIS_FOLDER b/example_linux/config/KEEP_THIS_FOLDER deleted file mode 100644 index 24353bc..0000000 --- a/example_linux/config/KEEP_THIS_FOLDER +++ /dev/null @@ -1 +0,0 @@ -bgslibrary uses this folder to store the configuration files \ No newline at end of file diff --git a/example_macosx/config/KEEP_THIS_FOLDER b/example_macosx/config/KEEP_THIS_FOLDER deleted file mode 100644 index 24353bc..0000000 --- a/example_macosx/config/KEEP_THIS_FOLDER +++ /dev/null @@ -1 +0,0 @@ -bgslibrary uses this folder to store the configuration files \ No newline at end of file diff --git a/java_gui/README.txt b/gui_java/README.txt similarity index 100% rename from java_gui/README.txt rename to gui_java/README.txt diff --git a/java_gui/_COPY_bgslibrary.exe_HERE_ b/gui_java/_COPY_bgslibrary.exe_HERE_ similarity index 100% rename from java_gui/_COPY_bgslibrary.exe_HERE_ rename to gui_java/_COPY_bgslibrary.exe_HERE_ diff --git a/java_gui/bgslibrary_gui.jar b/gui_java/bgslibrary_gui.jar similarity index 100% rename from java_gui/bgslibrary_gui.jar rename to gui_java/bgslibrary_gui.jar diff --git a/java_gui/bgslibrary_gui.properties b/gui_java/bgslibrary_gui.properties similarity index 100% rename from java_gui/bgslibrary_gui.properties rename to gui_java/bgslibrary_gui.properties diff --git a/java_gui/build.xml b/gui_java/build.xml similarity index 100% rename from java_gui/build.xml rename to gui_java/build.xml diff --git a/java_gui/config/.gitignore b/gui_java/config/.gitignore similarity index 100% rename from java_gui/config/.gitignore rename to gui_java/config/.gitignore diff --git a/java_gui/config/FrameProcessor.xml b/gui_java/config/FrameProcessor.xml similarity index 100% rename from java_gui/config/FrameProcessor.xml rename to gui_java/config/FrameProcessor.xml diff --git a/java_gui/config/PreProcessor.xml b/gui_java/config/PreProcessor.xml similarity index 100% rename from java_gui/config/PreProcessor.xml rename to gui_java/config/PreProcessor.xml diff --git a/java_gui/config/VideoCapture.xml b/gui_java/config/VideoCapture.xml similarity index 100% rename from java_gui/config/VideoCapture.xml rename to gui_java/config/VideoCapture.xml diff --git a/java_gui/images/bgslibrary_gui_screen01.png b/gui_java/images/bgslibrary_gui_screen01.png similarity index 100% rename from java_gui/images/bgslibrary_gui_screen01.png rename to gui_java/images/bgslibrary_gui_screen01.png diff --git a/java_gui/images/bgslibrary_gui_screen02.png b/gui_java/images/bgslibrary_gui_screen02.png similarity index 100% rename from java_gui/images/bgslibrary_gui_screen02.png rename to gui_java/images/bgslibrary_gui_screen02.png diff --git a/java_gui/images/bgslibrary_gui_screen03.png b/gui_java/images/bgslibrary_gui_screen03.png similarity index 100% rename from java_gui/images/bgslibrary_gui_screen03.png rename to gui_java/images/bgslibrary_gui_screen03.png diff --git a/java_gui/images/bgslibrary_gui_screen04.png b/gui_java/images/bgslibrary_gui_screen04.png similarity index 100% rename from java_gui/images/bgslibrary_gui_screen04.png rename to gui_java/images/bgslibrary_gui_screen04.png diff --git a/java_gui/images/logo.jpg b/gui_java/images/logo.jpg similarity index 100% rename from java_gui/images/logo.jpg rename to gui_java/images/logo.jpg diff --git a/java_gui/lib/commons-configuration-1.8.jar b/gui_java/lib/commons-configuration-1.8.jar similarity index 100% rename from java_gui/lib/commons-configuration-1.8.jar rename to gui_java/lib/commons-configuration-1.8.jar diff --git a/java_gui/lib/commons-io-2.3.jar b/gui_java/lib/commons-io-2.3.jar similarity index 100% rename from java_gui/lib/commons-io-2.3.jar rename to gui_java/lib/commons-io-2.3.jar diff --git a/java_gui/lib/commons-lang-2.6.jar b/gui_java/lib/commons-lang-2.6.jar similarity index 100% rename from java_gui/lib/commons-lang-2.6.jar rename to gui_java/lib/commons-lang-2.6.jar diff --git a/java_gui/lib/commons-logging-1.1.1.jar b/gui_java/lib/commons-logging-1.1.1.jar similarity index 100% rename from java_gui/lib/commons-logging-1.1.1.jar rename to gui_java/lib/commons-logging-1.1.1.jar diff --git a/java_gui/lib/swingx-all-1.6.3.jar b/gui_java/lib/swingx-all-1.6.3.jar similarity index 100% rename from java_gui/lib/swingx-all-1.6.3.jar rename to gui_java/lib/swingx-all-1.6.3.jar diff --git a/java_gui/lib/swingx-beaninfo-1.6.3.jar b/gui_java/lib/swingx-beaninfo-1.6.3.jar similarity index 100% rename from java_gui/lib/swingx-beaninfo-1.6.3.jar rename to gui_java/lib/swingx-beaninfo-1.6.3.jar diff --git a/java_gui/manifest.mf b/gui_java/manifest.mf similarity index 100% rename from java_gui/manifest.mf rename to gui_java/manifest.mf diff --git a/java_gui/nbproject/build-impl.xml b/gui_java/nbproject/build-impl.xml similarity index 100% rename from java_gui/nbproject/build-impl.xml rename to gui_java/nbproject/build-impl.xml diff --git a/java_gui/nbproject/genfiles.properties b/gui_java/nbproject/genfiles.properties similarity index 100% rename from java_gui/nbproject/genfiles.properties rename to gui_java/nbproject/genfiles.properties diff --git a/java_gui/nbproject/private/config.properties b/gui_java/nbproject/private/config.properties similarity index 100% rename from java_gui/nbproject/private/config.properties rename to gui_java/nbproject/private/config.properties diff --git a/java_gui/nbproject/private/private.properties b/gui_java/nbproject/private/private.properties similarity index 100% rename from java_gui/nbproject/private/private.properties rename to gui_java/nbproject/private/private.properties diff --git a/java_gui/nbproject/private/private.xml b/gui_java/nbproject/private/private.xml similarity index 100% rename from java_gui/nbproject/private/private.xml rename to gui_java/nbproject/private/private.xml diff --git a/java_gui/nbproject/project.properties b/gui_java/nbproject/project.properties similarity index 100% rename from java_gui/nbproject/project.properties rename to gui_java/nbproject/project.properties diff --git a/java_gui/nbproject/project.xml b/gui_java/nbproject/project.xml similarity index 100% rename from java_gui/nbproject/project.xml rename to gui_java/nbproject/project.xml diff --git a/java_gui/run_camera.bat b/gui_java/run_camera.bat similarity index 100% rename from java_gui/run_camera.bat rename to gui_java/run_camera.bat diff --git a/java_gui/run_java_gui.bat b/gui_java/run_java_gui.bat similarity index 100% rename from java_gui/run_java_gui.bat rename to gui_java/run_java_gui.bat diff --git a/java_gui/run_java_gui_with_console.bat b/gui_java/run_java_gui_with_console.bat similarity index 100% rename from java_gui/run_java_gui_with_console.bat rename to gui_java/run_java_gui_with_console.bat diff --git a/java_gui/run_video.bat b/gui_java/run_video.bat similarity index 100% rename from java_gui/run_video.bat rename to gui_java/run_video.bat diff --git a/java_gui/src/br/com/bgslibrary/Main.java b/gui_java/src/br/com/bgslibrary/Main.java similarity index 100% rename from java_gui/src/br/com/bgslibrary/Main.java rename to gui_java/src/br/com/bgslibrary/Main.java diff --git a/java_gui/src/br/com/bgslibrary/entity/Command.java b/gui_java/src/br/com/bgslibrary/entity/Command.java similarity index 100% rename from java_gui/src/br/com/bgslibrary/entity/Command.java rename to gui_java/src/br/com/bgslibrary/entity/Command.java diff --git a/java_gui/src/br/com/bgslibrary/entity/Configuration.java b/gui_java/src/br/com/bgslibrary/entity/Configuration.java similarity index 100% rename from java_gui/src/br/com/bgslibrary/entity/Configuration.java rename to gui_java/src/br/com/bgslibrary/entity/Configuration.java diff --git a/java_gui/src/br/com/bgslibrary/gui/AboutDialog.form b/gui_java/src/br/com/bgslibrary/gui/AboutDialog.form similarity index 100% rename from java_gui/src/br/com/bgslibrary/gui/AboutDialog.form rename to gui_java/src/br/com/bgslibrary/gui/AboutDialog.form diff --git a/java_gui/src/br/com/bgslibrary/gui/AboutDialog.java b/gui_java/src/br/com/bgslibrary/gui/AboutDialog.java similarity index 100% rename from java_gui/src/br/com/bgslibrary/gui/AboutDialog.java rename to gui_java/src/br/com/bgslibrary/gui/AboutDialog.java diff --git a/java_gui/src/br/com/bgslibrary/gui/MainFrame.form b/gui_java/src/br/com/bgslibrary/gui/MainFrame.form similarity index 100% rename from java_gui/src/br/com/bgslibrary/gui/MainFrame.form rename to gui_java/src/br/com/bgslibrary/gui/MainFrame.form diff --git a/java_gui/src/br/com/bgslibrary/gui/MainFrame.java b/gui_java/src/br/com/bgslibrary/gui/MainFrame.java similarity index 100% rename from java_gui/src/br/com/bgslibrary/gui/MainFrame.java rename to gui_java/src/br/com/bgslibrary/gui/MainFrame.java diff --git a/java_gui/src/br/com/bgslibrary/resources/logo.jpg b/gui_java/src/br/com/bgslibrary/resources/logo.jpg similarity index 100% rename from java_gui/src/br/com/bgslibrary/resources/logo.jpg rename to gui_java/src/br/com/bgslibrary/resources/logo.jpg diff --git a/vs2010mfc/.gitignore b/gui_mfc/.gitignore similarity index 100% rename from vs2010mfc/.gitignore rename to gui_mfc/.gitignore diff --git a/vs2013mfc/ReadMe.txt b/gui_mfc/ReadMe.txt similarity index 100% rename from vs2013mfc/ReadMe.txt rename to gui_mfc/ReadMe.txt diff --git a/vs2010mfc/config/AdaptiveBackgroundLearning.xml b/gui_mfc/config/AdaptiveBackgroundLearning.xml similarity index 100% rename from vs2010mfc/config/AdaptiveBackgroundLearning.xml rename to gui_mfc/config/AdaptiveBackgroundLearning.xml diff --git a/vs2010mfc/config/AdaptiveSelectiveBackgroundLearning.xml b/gui_mfc/config/AdaptiveSelectiveBackgroundLearning.xml similarity index 100% rename from vs2010mfc/config/AdaptiveSelectiveBackgroundLearning.xml rename to gui_mfc/config/AdaptiveSelectiveBackgroundLearning.xml diff --git a/vs2010mfc/config/DPAdaptiveMedianBGS.xml b/gui_mfc/config/DPAdaptiveMedianBGS.xml similarity index 100% rename from vs2010mfc/config/DPAdaptiveMedianBGS.xml rename to gui_mfc/config/DPAdaptiveMedianBGS.xml diff --git a/vs2010mfc/config/DPEigenbackgroundBGS.xml b/gui_mfc/config/DPEigenbackgroundBGS.xml similarity index 100% rename from vs2010mfc/config/DPEigenbackgroundBGS.xml rename to gui_mfc/config/DPEigenbackgroundBGS.xml diff --git a/vs2010mfc/config/DPGrimsonGMMBGS.xml b/gui_mfc/config/DPGrimsonGMMBGS.xml similarity index 100% rename from vs2010mfc/config/DPGrimsonGMMBGS.xml rename to gui_mfc/config/DPGrimsonGMMBGS.xml diff --git a/vs2010mfc/config/DPMeanBGS.xml b/gui_mfc/config/DPMeanBGS.xml similarity index 100% rename from vs2010mfc/config/DPMeanBGS.xml rename to gui_mfc/config/DPMeanBGS.xml diff --git a/vs2010mfc/config/DPPratiMediodBGS.xml b/gui_mfc/config/DPPratiMediodBGS.xml similarity index 100% rename from vs2010mfc/config/DPPratiMediodBGS.xml rename to gui_mfc/config/DPPratiMediodBGS.xml diff --git a/vs2010mfc/config/DPTextureBGS.xml b/gui_mfc/config/DPTextureBGS.xml similarity index 100% rename from vs2010mfc/config/DPTextureBGS.xml rename to gui_mfc/config/DPTextureBGS.xml diff --git a/vs2010mfc/config/DPWrenGABGS.xml b/gui_mfc/config/DPWrenGABGS.xml similarity index 100% rename from vs2010mfc/config/DPWrenGABGS.xml rename to gui_mfc/config/DPWrenGABGS.xml diff --git a/vs2010mfc/config/DPZivkovicAGMMBGS.xml b/gui_mfc/config/DPZivkovicAGMMBGS.xml similarity index 100% rename from vs2010mfc/config/DPZivkovicAGMMBGS.xml rename to gui_mfc/config/DPZivkovicAGMMBGS.xml diff --git a/vs2010mfc/config/FrameDifferenceBGS.xml b/gui_mfc/config/FrameDifferenceBGS.xml similarity index 100% rename from vs2010mfc/config/FrameDifferenceBGS.xml rename to gui_mfc/config/FrameDifferenceBGS.xml diff --git a/vs2010mfc/config/FuzzyChoquetIntegral.xml b/gui_mfc/config/FuzzyChoquetIntegral.xml similarity index 100% rename from vs2010mfc/config/FuzzyChoquetIntegral.xml rename to gui_mfc/config/FuzzyChoquetIntegral.xml diff --git a/vs2010mfc/config/FuzzySugenoIntegral.xml b/gui_mfc/config/FuzzySugenoIntegral.xml similarity index 100% rename from vs2010mfc/config/FuzzySugenoIntegral.xml rename to gui_mfc/config/FuzzySugenoIntegral.xml diff --git a/vs2010mfc/config/GMG.xml b/gui_mfc/config/GMG.xml similarity index 100% rename from vs2010mfc/config/GMG.xml rename to gui_mfc/config/GMG.xml diff --git a/vs2010mfc/config/IndependentMultimodalBGS.xml b/gui_mfc/config/IndependentMultimodalBGS.xml similarity index 100% rename from vs2010mfc/config/IndependentMultimodalBGS.xml rename to gui_mfc/config/IndependentMultimodalBGS.xml diff --git a/vs2010mfc/config/KDE.xml b/gui_mfc/config/KDE.xml similarity index 100% rename from vs2010mfc/config/KDE.xml rename to gui_mfc/config/KDE.xml diff --git a/vs2010mfc/config/LBAdaptiveSOM.xml b/gui_mfc/config/LBAdaptiveSOM.xml similarity index 100% rename from vs2010mfc/config/LBAdaptiveSOM.xml rename to gui_mfc/config/LBAdaptiveSOM.xml diff --git a/vs2010mfc/config/LBFuzzyAdaptiveSOM.xml b/gui_mfc/config/LBFuzzyAdaptiveSOM.xml similarity index 100% rename from vs2010mfc/config/LBFuzzyAdaptiveSOM.xml rename to gui_mfc/config/LBFuzzyAdaptiveSOM.xml diff --git a/vs2010mfc/config/LBFuzzyGaussian.xml b/gui_mfc/config/LBFuzzyGaussian.xml similarity index 100% rename from vs2010mfc/config/LBFuzzyGaussian.xml rename to gui_mfc/config/LBFuzzyGaussian.xml diff --git a/vs2010mfc/config/LBMixtureOfGaussians.xml b/gui_mfc/config/LBMixtureOfGaussians.xml similarity index 100% rename from vs2010mfc/config/LBMixtureOfGaussians.xml rename to gui_mfc/config/LBMixtureOfGaussians.xml diff --git a/vs2010mfc/config/LBSimpleGaussian.xml b/gui_mfc/config/LBSimpleGaussian.xml similarity index 100% rename from vs2010mfc/config/LBSimpleGaussian.xml rename to gui_mfc/config/LBSimpleGaussian.xml diff --git a/vs2010mfc/config/LOBSTERBGS.xml b/gui_mfc/config/LOBSTERBGS.xml similarity index 100% rename from vs2010mfc/config/LOBSTERBGS.xml rename to gui_mfc/config/LOBSTERBGS.xml diff --git a/vs2010mfc/config/MixtureOfGaussianV1BGS.xml b/gui_mfc/config/MixtureOfGaussianV1BGS.xml similarity index 100% rename from vs2010mfc/config/MixtureOfGaussianV1BGS.xml rename to gui_mfc/config/MixtureOfGaussianV1BGS.xml diff --git a/vs2010mfc/config/MixtureOfGaussianV2BGS.xml b/gui_mfc/config/MixtureOfGaussianV2BGS.xml similarity index 100% rename from vs2010mfc/config/MixtureOfGaussianV2BGS.xml rename to gui_mfc/config/MixtureOfGaussianV2BGS.xml diff --git a/vs2010mfc/config/MultiCueBGS.xml b/gui_mfc/config/MultiCueBGS.xml similarity index 100% rename from vs2010mfc/config/MultiCueBGS.xml rename to gui_mfc/config/MultiCueBGS.xml diff --git a/vs2010mfc/config/MultiLayerBGS.xml b/gui_mfc/config/MultiLayerBGS.xml similarity index 100% rename from vs2010mfc/config/MultiLayerBGS.xml rename to gui_mfc/config/MultiLayerBGS.xml diff --git a/vs2010mfc/config/SigmaDeltaBGS.xml b/gui_mfc/config/SigmaDeltaBGS.xml similarity index 100% rename from vs2010mfc/config/SigmaDeltaBGS.xml rename to gui_mfc/config/SigmaDeltaBGS.xml diff --git a/vs2010mfc/config/StaticFrameDifferenceBGS.xml b/gui_mfc/config/StaticFrameDifferenceBGS.xml similarity index 100% rename from vs2010mfc/config/StaticFrameDifferenceBGS.xml rename to gui_mfc/config/StaticFrameDifferenceBGS.xml diff --git a/vs2010mfc/config/SuBSENSEBGS.xml b/gui_mfc/config/SuBSENSEBGS.xml similarity index 100% rename from vs2010mfc/config/SuBSENSEBGS.xml rename to gui_mfc/config/SuBSENSEBGS.xml diff --git a/vs2010mfc/config/T2FGMM_UM.xml b/gui_mfc/config/T2FGMM_UM.xml similarity index 100% rename from vs2010mfc/config/T2FGMM_UM.xml rename to gui_mfc/config/T2FGMM_UM.xml diff --git a/vs2010mfc/config/T2FGMM_UV.xml b/gui_mfc/config/T2FGMM_UV.xml similarity index 100% rename from vs2010mfc/config/T2FGMM_UV.xml rename to gui_mfc/config/T2FGMM_UV.xml diff --git a/vs2010mfc/config/T2FMRF_UM.xml b/gui_mfc/config/T2FMRF_UM.xml similarity index 100% rename from vs2010mfc/config/T2FMRF_UM.xml rename to gui_mfc/config/T2FMRF_UM.xml diff --git a/vs2010mfc/config/T2FMRF_UV.xml b/gui_mfc/config/T2FMRF_UV.xml similarity index 100% rename from vs2010mfc/config/T2FMRF_UV.xml rename to gui_mfc/config/T2FMRF_UV.xml diff --git a/vs2010mfc/config/VuMeter.xml b/gui_mfc/config/VuMeter.xml similarity index 100% rename from vs2010mfc/config/VuMeter.xml rename to gui_mfc/config/VuMeter.xml diff --git a/vs2010mfc/config/WeightedMovingMeanBGS.xml b/gui_mfc/config/WeightedMovingMeanBGS.xml similarity index 100% rename from vs2010mfc/config/WeightedMovingMeanBGS.xml rename to gui_mfc/config/WeightedMovingMeanBGS.xml diff --git a/vs2010mfc/config/WeightedMovingVarianceBGS.xml b/gui_mfc/config/WeightedMovingVarianceBGS.xml similarity index 100% rename from vs2010mfc/config/WeightedMovingVarianceBGS.xml rename to gui_mfc/config/WeightedMovingVarianceBGS.xml diff --git a/vs2010mfc/dataset/video.avi b/gui_mfc/dataset/video.avi similarity index 100% rename from vs2010mfc/dataset/video.avi rename to gui_mfc/dataset/video.avi diff --git a/vs2013mfc/outputs/background/.gitignore b/gui_mfc/outputs/background/.gitignore similarity index 100% rename from vs2013mfc/outputs/background/.gitignore rename to gui_mfc/outputs/background/.gitignore diff --git a/vs2013mfc/outputs/foreground/.gitignore b/gui_mfc/outputs/foreground/.gitignore similarity index 100% rename from vs2013mfc/outputs/foreground/.gitignore rename to gui_mfc/outputs/foreground/.gitignore diff --git a/vs2013mfc/outputs/input/.gitignore b/gui_mfc/outputs/input/.gitignore similarity index 100% rename from vs2013mfc/outputs/input/.gitignore rename to gui_mfc/outputs/input/.gitignore diff --git a/vs2010mfc/src/.gitignore b/gui_mfc/src/.gitignore similarity index 100% rename from vs2010mfc/src/.gitignore rename to gui_mfc/src/.gitignore diff --git a/vs2010mfc/src/App.cpp b/gui_mfc/src/App.cpp similarity index 100% rename from vs2010mfc/src/App.cpp rename to gui_mfc/src/App.cpp diff --git a/vs2010mfc/src/App.h b/gui_mfc/src/App.h similarity index 100% rename from vs2010mfc/src/App.h rename to gui_mfc/src/App.h diff --git a/vs2010mfc/src/Dlg.cpp b/gui_mfc/src/Dlg.cpp similarity index 100% rename from vs2010mfc/src/Dlg.cpp rename to gui_mfc/src/Dlg.cpp diff --git a/vs2010mfc/src/Dlg.h b/gui_mfc/src/Dlg.h similarity index 100% rename from vs2010mfc/src/Dlg.h rename to gui_mfc/src/Dlg.h diff --git a/vs2013mfc/src/ReadMe.txt b/gui_mfc/src/ReadMe.txt similarity index 100% rename from vs2013mfc/src/ReadMe.txt rename to gui_mfc/src/ReadMe.txt diff --git a/vs2013mfc/src/bgslibrary_vs2013_mfc.rc b/gui_mfc/src/bgslibrary_vs2013_mfc.rc similarity index 100% rename from vs2013mfc/src/bgslibrary_vs2013_mfc.rc rename to gui_mfc/src/bgslibrary_vs2013_mfc.rc diff --git a/vs2013mfc/src/bgslibrary_vs2013_mfc.sln b/gui_mfc/src/bgslibrary_vs2013_mfc.sln similarity index 100% rename from vs2013mfc/src/bgslibrary_vs2013_mfc.sln rename to gui_mfc/src/bgslibrary_vs2013_mfc.sln diff --git a/vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj b/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj similarity index 100% rename from vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj rename to gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj diff --git a/vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters b/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters similarity index 100% rename from vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters rename to gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.filters diff --git a/vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj.user b/gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.user similarity index 100% rename from vs2013mfc/src/bgslibrary_vs2013_mfc.vcxproj.user rename to gui_mfc/src/bgslibrary_vs2013_mfc.vcxproj.user diff --git a/vs2013mfc/src/res/bgslibrary_vs2013_mfc.ico b/gui_mfc/src/res/bgslibrary_vs2013_mfc.ico similarity index 100% rename from vs2013mfc/src/res/bgslibrary_vs2013_mfc.ico rename to gui_mfc/src/res/bgslibrary_vs2013_mfc.ico diff --git a/vs2013mfc/src/res/bgslibrary_vs2013_mfc.rc2 b/gui_mfc/src/res/bgslibrary_vs2013_mfc.rc2 similarity index 100% rename from vs2013mfc/src/res/bgslibrary_vs2013_mfc.rc2 rename to gui_mfc/src/res/bgslibrary_vs2013_mfc.rc2 diff --git a/vs2010mfc/src/resource.h b/gui_mfc/src/resource.h similarity index 100% rename from vs2010mfc/src/resource.h rename to gui_mfc/src/resource.h diff --git a/vs2010mfc/src/stdafx.cpp b/gui_mfc/src/stdafx.cpp similarity index 100% rename from vs2010mfc/src/stdafx.cpp rename to gui_mfc/src/stdafx.cpp diff --git a/vs2010mfc/src/stdafx.h b/gui_mfc/src/stdafx.h similarity index 100% rename from vs2010mfc/src/stdafx.h rename to gui_mfc/src/stdafx.h diff --git a/vs2010mfc/src/targetver.h b/gui_mfc/src/targetver.h similarity index 100% rename from vs2010mfc/src/targetver.h rename to gui_mfc/src/targetver.h diff --git a/gui_qt/.gitignore b/gui_qt/.gitignore new file mode 100644 index 0000000..9c28032 --- /dev/null +++ b/gui_qt/.gitignore @@ -0,0 +1,9 @@ +_*/ +debug/ +release/ +build_*/ +dataset*/ +binaries*/ +Makefile* +*.exe +*.dll diff --git a/gui_qt/CMakeLists.txt b/gui_qt/CMakeLists.txt new file mode 100644 index 0000000..83c8920 --- /dev/null +++ b/gui_qt/CMakeLists.txt @@ -0,0 +1,52 @@ +cmake_minimum_required(VERSION 2.8.11) + +project(bgslibrary_gui) + +# Find includes in corresponding build directories +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Instruct CMake to run moc automatically when needed. +set(CMAKE_AUTOMOC ON) + +# Handle the Qt uic code generator automatically +set(CMAKE_AUTOUIC ON) + +# Find the Qt5Widgets library +find_package(Qt5Widgets) + +SET(app_RESOURCES application.qrc) +QT5_ADD_RESOURCES(app_RESOURCES_RCC ${app_RESOURCES}) + +# Find the OpenCV library +set(OpenCV_STATIC OFF) +find_package(OpenCV REQUIRED) + +message(STATUS "OpenCV library status:") +message(STATUS " version: ${OpenCV_VERSION}") +message(STATUS " libraries: ${OpenCV_LIBS}") +message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}") + +file(GLOB main bgslibrary_gui.cpp mainwindow.cpp qt_utils.cpp texteditor.cpp) + +file(GLOB_RECURSE analysis_src ../package_analysis/*.cpp) +file(GLOB_RECURSE analysis_inc ../package_analysis/*.h) +file(GLOB_RECURSE bgs_src ../package_bgs/*.cpp ../package_bgs/*.c) +file(GLOB_RECURSE bgs_inc ../package_bgs/*.h) + +include_directories(${CMAKE_SOURCE_DIR} ${OpenCV_INCLUDE_DIRS}) + +add_library(libbgs STATIC ${bgs_src} ${analysis_src}) +target_link_libraries(libbgs ${OpenCV_LIBS}) +set_property(TARGET libbgs PROPERTY PUBLIC_HEADER ${bgs_inc} ${analysis_inc}) + +if(WIN32) + # set_property(TARGET libbgs PROPERTY SUFFIX ".lib") +else() + set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") +endif() + +# Tell CMake to create the bgslibrary_gui executable +add_executable(bgslibrary_gui ${main} ${app_RESOURCES_RCC}) + +# Use the Widgets module from Qt 5. +target_link_libraries(bgslibrary_gui Qt5::Widgets ${OpenCV_LIBS} libbgs) diff --git a/gui_qt/README.txt b/gui_qt/README.txt new file mode 100644 index 0000000..41a4cd2 --- /dev/null +++ b/gui_qt/README.txt @@ -0,0 +1,17 @@ +#------------------------------------------------- +# +# Project created with Qt 5.6.2 +# +# Compiling BGSLibrary QT GUI with CMAKE +# +#------------------------------------------------- +# Qt 5.x 64-bit for Desktop (MSVC 2015) +#------------------------------------------------- + +mkdir build + +cd build + +set OpenCV_DIR=C:\OpenCV3.2.0\build + +cmake -DOpenCV_DIR=%OpenCV_DIR% -G "Visual Studio 14 Win64" .. diff --git a/gui_qt/application.qrc b/gui_qt/application.qrc new file mode 100644 index 0000000..3e8687f --- /dev/null +++ b/gui_qt/application.qrc @@ -0,0 +1,10 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>figs/copy.png</file> + <file>figs/cut.png</file> + <file>figs/new.png</file> + <file>figs/open.png</file> + <file>figs/paste.png</file> + <file>figs/save.png</file> +</qresource> +</RCC> \ No newline at end of file diff --git a/gui_qt/bgslibrary_gui.cpp b/gui_qt/bgslibrary_gui.cpp new file mode 100644 index 0000000..e886262 --- /dev/null +++ b/gui_qt/bgslibrary_gui.cpp @@ -0,0 +1,38 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + std::cout << "--------------------------------------------" << std::endl; + std::cout << "Background Subtraction Library v2.0.0 " << std::endl; + std::cout << "https://github.com/andrewssobral/bgslibrary " << std::endl; + std::cout << "by: " << std::endl; + std::cout << "Andrews Sobral (andrewssobral@gmail.com) " << std::endl; + std::cout << "--------------------------------------------" << std::endl; + std::cout << "Using OpenCV version " << CV_VERSION << std::endl; + + QApplication a(argc, argv); + + QCoreApplication::setApplicationName("BGSLibrary"); + QCoreApplication::setApplicationVersion("2.0.0"); + + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/gui_qt/bgslibrary_gui.pro b/gui_qt/bgslibrary_gui.pro new file mode 100644 index 0000000..feedbf6 --- /dev/null +++ b/gui_qt/bgslibrary_gui.pro @@ -0,0 +1,248 @@ +#------------------------------------------------- +# +# Project created by QtCreator +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = bgslibrary_gui +TEMPLATE = app + +# For Windows x64 + Visual Studio 2015 + OpenCV 3.1.0 +#INCLUDEPATH += C:/OpenCV3.1.0/build/include +#LIBS += -LC:/OpenCV3.1.0/build/x64/vc14/lib -lopencv_world310 + +# For Windows x64 + Visual Studio 2015 + OpenCV 3.2.0 +INCLUDEPATH += C:/OpenCV3.2.0/build/include +LIBS += -LC:/OpenCV3.2.0/build/x64/vc14/lib -lopencv_world320 + +# For Linux +# INCLUDEPATH += /usr/local/include/opencv +# LIBS += -L/usr/local/lib + +RESOURCES = application.qrc + +SOURCES += bgslibrary_gui.cpp\ + mainwindow.cpp \ + qt_utils.cpp \ + texteditor.cpp \ + ../package_analysis/ForegroundMaskAnalysis.cpp \ + ../package_analysis/PerformanceUtils.cpp \ + ../package_analysis/PixelUtils.cpp \ + ../package_bgs/_template_/Amber.cpp \ + ../package_bgs/_template_/MyBGS.cpp \ + ../package_bgs/dp/AdaptiveMedianBGS.cpp \ + ../package_bgs/dp/Eigenbackground.cpp \ + ../package_bgs/dp/Error.cpp \ + ../package_bgs/dp/GrimsonGMM.cpp \ + ../package_bgs/dp/Image.cpp \ + ../package_bgs/dp/MeanBGS.cpp \ + ../package_bgs/dp/PratiMediodBGS.cpp \ + ../package_bgs/dp/TextureBGS.cpp \ + ../package_bgs/dp/WrenGA.cpp \ + ../package_bgs/dp/ZivkovicAGMM.cpp \ + ../package_bgs/IMBS/IMBS.cpp \ + ../package_bgs/KDE/KernelTable.cpp \ + ../package_bgs/KDE/NPBGmodel.cpp \ + ../package_bgs/KDE/NPBGSubtractor.cpp \ + ../package_bgs/lb/BGModel.cpp \ + ../package_bgs/lb/BGModelFuzzyGauss.cpp \ + ../package_bgs/lb/BGModelFuzzySom.cpp \ + ../package_bgs/lb/BGModelGauss.cpp \ + ../package_bgs/lb/BGModelMog.cpp \ + ../package_bgs/lb/BGModelSom.cpp \ + ../package_bgs/LBP_MRF/graph.cpp \ + ../package_bgs/LBP_MRF/maxflow.cpp \ + ../package_bgs/LBP_MRF/MEDefs.cpp \ + ../package_bgs/LBP_MRF/MEHistogram.cpp \ + ../package_bgs/LBP_MRF/MEImage.cpp \ + ../package_bgs/LBP_MRF/MotionDetection.cpp \ + ../package_bgs/LBSP/BackgroundSubtractorLBSP.cpp \ + ../package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp \ + ../package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp \ + ../package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp \ + ../package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp \ + ../package_bgs/LBSP/LBSP.cpp \ + ../package_bgs/LBSP/LBSP_.cpp \ + ../package_bgs/MultiLayer/blob.cpp \ + ../package_bgs/MultiLayer/BlobExtraction.cpp \ + ../package_bgs/MultiLayer/BlobResult.cpp \ + ../package_bgs/MultiLayer/CMultiLayerBGS.cpp \ + ../package_bgs/MultiLayer/LocalBinaryPattern.cpp \ + ../package_bgs/PBAS/PBAS.cpp \ + ../package_bgs/SigmaDelta/sdLaMa091.cpp \ + ../package_bgs/T2F/FuzzyUtils.cpp \ + ../package_bgs/T2F/MRF.cpp \ + ../package_bgs/T2F/T2FGMM.cpp \ + ../package_bgs/T2F/T2FMRF.cpp \ + ../package_bgs/TwoPoints/two_points.cpp \ + ../package_bgs/ViBe/vibe-background-sequential.cpp \ + ../package_bgs/VuMeter/TBackground.cpp \ + ../package_bgs/VuMeter/TBackgroundVuMeter.cpp \ + ../package_bgs/AdaptiveBackgroundLearning.cpp \ + ../package_bgs/AdaptiveSelectiveBackgroundLearning.cpp \ + ../package_bgs/DPAdaptiveMedian.cpp \ + ../package_bgs/DPEigenbackground.cpp \ + ../package_bgs/DPGrimsonGMM.cpp \ + ../package_bgs/DPMean.cpp \ + ../package_bgs/DPPratiMediod.cpp \ + ../package_bgs/DPTexture.cpp \ + ../package_bgs/DPWrenGA.cpp \ + ../package_bgs/DPZivkovicAGMM.cpp \ + ../package_bgs/FrameDifference.cpp \ + ../package_bgs/FuzzyChoquetIntegral.cpp \ + ../package_bgs/FuzzySugenoIntegral.cpp \ + ../package_bgs/GMG.cpp \ + ../package_bgs/IndependentMultimodal.cpp \ + ../package_bgs/KDE.cpp \ + ../package_bgs/KNN.cpp \ + ../package_bgs/LBAdaptiveSOM.cpp \ + ../package_bgs/LBFuzzyAdaptiveSOM.cpp \ + ../package_bgs/LBFuzzyGaussian.cpp \ + ../package_bgs/LBMixtureOfGaussians.cpp \ + ../package_bgs/LBP_MRF.cpp \ + ../package_bgs/LBSimpleGaussian.cpp \ + ../package_bgs/LOBSTER.cpp \ + ../package_bgs/MixtureOfGaussianV1.cpp \ + ../package_bgs/MixtureOfGaussianV2.cpp \ + ../package_bgs/MultiCue.cpp \ + ../package_bgs/MultiLayer.cpp \ + ../package_bgs/PAWCS.cpp \ + ../package_bgs/PixelBasedAdaptiveSegmenter.cpp \ + ../package_bgs/SigmaDelta.cpp \ + ../package_bgs/StaticFrameDifference.cpp \ + ../package_bgs/SuBSENSE.cpp \ + ../package_bgs/T2FGMM_UM.cpp \ + ../package_bgs/T2FGMM_UV.cpp \ + ../package_bgs/T2FMRF_UM.cpp \ + ../package_bgs/T2FMRF_UV.cpp \ + ../package_bgs/TwoPoints.cpp \ + ../package_bgs/ViBe.cpp \ + ../package_bgs/VuMeter.cpp \ + ../package_bgs/WeightedMovingMean.cpp \ + ../package_bgs/WeightedMovingVariance.cpp \ + ../package_bgs/_template_/amber/amber.c + +HEADERS += mainwindow.h \ + qt_utils.h \ + texteditor.h \ + ../package_analysis/ForegroundMaskAnalysis.h \ + ../package_analysis/PerformanceUtils.h \ + ../package_analysis/PixelUtils.h \ + ../package_bgs/_template_/amber/amber.h \ + ../package_bgs/_template_/Amber.h \ + ../package_bgs/_template_/MyBGS.h \ + ../package_bgs/dp/AdaptiveMedianBGS.h \ + ../package_bgs/dp/Bgs.h \ + ../package_bgs/dp/BgsParams.h \ + ../package_bgs/dp/Eigenbackground.h \ + ../package_bgs/dp/Error.h \ + ../package_bgs/dp/GrimsonGMM.h \ + ../package_bgs/dp/Image.h \ + ../package_bgs/dp/MeanBGS.h \ + ../package_bgs/dp/PratiMediodBGS.h \ + ../package_bgs/dp/TextureBGS.h \ + ../package_bgs/dp/WrenGA.h \ + ../package_bgs/dp/ZivkovicAGMM.h \ + ../package_bgs/IMBS/IMBS.hpp \ + ../package_bgs/KDE/KernelTable.h \ + ../package_bgs/KDE/NPBGmodel.h \ + ../package_bgs/KDE/NPBGSubtractor.h \ + ../package_bgs/lb/BGModel.h \ + ../package_bgs/lb/BGModelFuzzyGauss.h \ + ../package_bgs/lb/BGModelFuzzySom.h \ + ../package_bgs/lb/BGModelGauss.h \ + ../package_bgs/lb/BGModelMog.h \ + ../package_bgs/lb/BGModelSom.h \ + ../package_bgs/lb/Types.h \ + ../package_bgs/LBP_MRF/block.h \ + ../package_bgs/LBP_MRF/graph.h \ + ../package_bgs/LBP_MRF/MEDefs.hpp \ + ../package_bgs/LBP_MRF/MEHistogram.hpp \ + ../package_bgs/LBP_MRF/MEImage.hpp \ + ../package_bgs/LBP_MRF/MotionDetection.hpp \ + ../package_bgs/LBSP/BackgroundSubtractorLBSP.h \ + ../package_bgs/LBSP/BackgroundSubtractorLBSP_.h \ + ../package_bgs/LBSP/BackgroundSubtractorLOBSTER.h \ + ../package_bgs/LBSP/BackgroundSubtractorPAWCS.h \ + ../package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h \ + ../package_bgs/LBSP/DistanceUtils.h \ + ../package_bgs/LBSP/LBSP.h \ + ../package_bgs/LBSP/LBSP_.h \ + ../package_bgs/LBSP/RandUtils.h \ + ../package_bgs/MultiLayer/BackgroundSubtractionAPI.h \ + ../package_bgs/MultiLayer/BGS.h \ + ../package_bgs/MultiLayer/blob.h \ + ../package_bgs/MultiLayer/BlobExtraction.h \ + ../package_bgs/MultiLayer/BlobLibraryConfiguration.h \ + ../package_bgs/MultiLayer/BlobResult.h \ + ../package_bgs/MultiLayer/CMultiLayerBGS.h \ + ../package_bgs/MultiLayer/LocalBinaryPattern.h \ + ../package_bgs/MultiLayer/OpenCvDataConversion.h \ + ../package_bgs/MultiLayer/OpenCvLegacyIncludes.h \ + ../package_bgs/PBAS/PBAS.h \ + ../package_bgs/SigmaDelta/sdLaMa091.h \ + ../package_bgs/T2F/FuzzyUtils.h \ + ../package_bgs/T2F/MRF.h \ + ../package_bgs/T2F/T2FGMM.h \ + ../package_bgs/T2F/T2FMRF.h \ + ../package_bgs/TwoPoints/two_points.h \ + ../package_bgs/ViBe/vibe-background-sequential.h \ + ../package_bgs/VuMeter/TBackground.h \ + ../package_bgs/VuMeter/TBackgroundVuMeter.h \ + ../package_bgs/AdaptiveBackgroundLearning.h \ + ../package_bgs/AdaptiveSelectiveBackgroundLearning.h \ + ../package_bgs/bgslibrary.h \ + ../package_bgs/DPAdaptiveMedian.h \ + ../package_bgs/DPEigenbackground.h \ + ../package_bgs/DPGrimsonGMM.h \ + ../package_bgs/DPMean.h \ + ../package_bgs/DPPratiMediod.h \ + ../package_bgs/DPTexture.h \ + ../package_bgs/DPWrenGA.h \ + ../package_bgs/DPZivkovicAGMM.h \ + ../package_bgs/FrameDifference.h \ + ../package_bgs/FuzzyChoquetIntegral.h \ + ../package_bgs/FuzzySugenoIntegral.h \ + ../package_bgs/GMG.h \ + ../package_bgs/IBGS.h \ + ../package_bgs/IndependentMultimodal.h \ + ../package_bgs/KDE.h \ + ../package_bgs/KNN.h \ + ../package_bgs/LBAdaptiveSOM.h \ + ../package_bgs/LBFuzzyAdaptiveSOM.h \ + ../package_bgs/LBFuzzyGaussian.h \ + ../package_bgs/LBMixtureOfGaussians.h \ + ../package_bgs/LBP_MRF.h \ + ../package_bgs/LBSimpleGaussian.h \ + ../package_bgs/LOBSTER.h \ + ../package_bgs/MixtureOfGaussianV1.h \ + ../package_bgs/MixtureOfGaussianV2.h \ + ../package_bgs/MultiCue.h \ + ../package_bgs/MultiLayer.h \ + ../package_bgs/PAWCS.h \ + ../package_bgs/PixelBasedAdaptiveSegmenter.h \ + ../package_bgs/SigmaDelta.h \ + ../package_bgs/StaticFrameDifference.h \ + ../package_bgs/SuBSENSE.h \ + ../package_bgs/T2FGMM_UM.h \ + ../package_bgs/T2FGMM_UV.h \ + ../package_bgs/T2FMRF_UM.h \ + ../package_bgs/T2FMRF_UV.h \ + ../package_bgs/TwoPoints.h \ + ../package_bgs/ViBe.h \ + ../package_bgs/VuMeter.h \ + ../package_bgs/WeightedMovingMean.h \ + ../package_bgs/WeightedMovingVariance.h + +FORMS += mainwindow.ui + +DISTFILES += \ + ../package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i \ + ../package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i \ + ../package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i \ + ../package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i \ + ../package_bgs/ViBe/LICENSE diff --git a/gui_qt/build/.gitignore b/gui_qt/build/.gitignore new file mode 100644 index 0000000..4e2a98b --- /dev/null +++ b/gui_qt/build/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore diff --git a/gui_qt/figs/copy.png b/gui_qt/figs/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..2aeb28288f58ddffdd1d75115f170c5bf2773814 GIT binary patch literal 1338 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmUfZd~z?Fk)a} zkSuYHC<)F_D=AMbN@Z|N$xljE@XSq2PYp^<OsOn9nQFtpz;edZ#W5t}@Yd<EKGCT% z$IA2f+<YqJsZe-b?XjQmj)IG=E_(wW3rIZG)>HFhQEyw-J@dhZMLCjfmg0A$#AY-& z<ScVOrJ&s`r*Y=i#c7u=c~$>nTzcWXnB4vUw`Gr?VbN-zY-5?PIOq9yoA>Vg?F=%f z+|KX)^>VjQlv*NxR>G;9FDq}(vX2e;wDjQ1{^j9^9SoRS7D=u>Zq%jT7@<_WzcTxl zw?Gk-O!f0Mw`6Xdm?7lQGPCuu<U~VFDepwpDJ~YXoQm6z?GrxopJ{^7<Vux~Cn6@D zmv4#fIrNlMNyvNgm&5OUO-dsfH@v=Kc6Gu$t3PLUK9AQEv=5u->Ke+cHS^y3wTI_! z>^#n}W}E7toiEz6MI*kk2yh&`w0_RMg87azH$@v_+h<C3b#<MY6crtPcggzDwg1+K z++W7V#%5?~+In-R<qI{nfPjDo#k2V}_dJ*VWIZz@M&`gnf5$JaADq{pJIj#ujVZu6 z?Z(rt<Bva7?e$oGdB&VME~%-eY3aRt8rjpNOD>D?IT-0ye7M^i*uRG1VS$9(;)(si zD@E#Fy>)%8K0mR|(PG-2fb!DEKF-SLOy?edJFzfkkDZSGfn&$mzEu59cBrlW8(`FN z!A&M@Hh0s(j+K(aYxo4G?@GyQU|4p;>PDTblHe3=ErWH!4$oO~!*8uJ*;f<%%+w*x zYA)a5!-rp_e*OOayYuR+i&pJoOD_L9flsS^!dsSYe7AO|vMs3Ge*3M2l$29?x_VVr zl|_JOret2`SApvc`5YU5GNd!?xS(o$;Mz5@`<#sq42v`lz5kw^o6EagWa@=K>z=PX zS#ywkhONWwI}EoS&CJbzmMsYr5xx52cj$wavW@Nx&#n0x8qTOTs2KaJ2x(}qf5cF~ zgQ0r{;{vm&tLz4>|7WOAwz2i~Jh{?~Z^8D>%$>GJe~24wWT+|p%D}MX)yWwm-A4nK zt!S$9I50zUM>gxTIWvDh4^Ls4a49&8sl#pY9UBp@g*&z|U1wvxlh*!Z0i#UH5f%;W z6gCgrImJRVFYk0vIGP%|<A&~ndaLAhwG%QQEH0bL@GsVOsoL6g>xw$IdubKy3_oBi zy`yd(<GVA=>3VO49ahbC>F%3!xzOi6qqeqoM11^n0rg1c`z4$K{tWxiq)P2DVl#QO zobhDDt=B1jnVOceE-VgTFQ30x6WuuNHIsi`smzW-{vU-p^Xm5c<t{T{wT59{icYS% zkt)MQ<xfw9&Pc0^X1o_%uqQ3L-rw|*P2sHleVO0?c&RZ?SgDe^HQ33BpRKuIXUv@m zab7PrAAj6<`|Yuh!s}J%*DjpnV?Cp5W}n^33U`L7UPl?1i0Yj+mkbKB`mVY4@WTg6 zkB=U8<@@^R<Mfy>ayuu#T*siRtDE;SVd0fa(|LQRPoMtq^Us9MH-FS-W_CIYF!XYB zbD!PBaADD;pvi*0Fa7RUgjky<Y>le?dWGxnxda21PoF-$+ng?QQ`{jqcyjctbT5A; z;Z?JaiFMC3cbM<)?yj7hn|tripBmxcw;h*l+B@sNx<hfX@q8vPcYzT5P<wm(^RKUE zm`vQY%j)^zEwMiG2C`?5Rk$-O4SHE-HFr;vmsh^slr8)A-J3aivhqx^^x)DkhTh)Z zyzZk-jg5^Sxw&hN&CSEZF5hMNQSat+$Z=-g_5042VG^wcCs-I57#KWV{an^LB{Ts5 D=#61Q literal 0 HcmV?d00001 diff --git a/gui_qt/figs/cut.png b/gui_qt/figs/cut.png new file mode 100644 index 0000000000000000000000000000000000000000..54638e9386dc8af40dcc9a3ee2f57c62e248e406 GIT binary patch literal 1323 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmUfZd~z?Fk)a} zkSuYHC<)F_D=AMbN@Z|N$xljE@XSq2PYp^<OsOn9nQFtpz_QoV#W5t}@Z0cgpUL48 zcFKh(jb4gPUlEdOF_%g78*{tSWX3d|=z=2#{}UGJNm<GIG4C?$jNaUElc$AAGD1eA zyLD63)VL>U+<k^W4!fP!Z4|w;;*gB=_N>f_pWf|hU(a)A2XErdO_OcjPXAo{_ulh8 z??1<RF*N*{tni<Usf1I*MdYSPp$Mb4Tf@4$DR+;hDf#@EdZgR^#KOzpPxMW<wlGT6 zc2sDcv(Lao?{0&ngVE|r-!J=q7YS#iuuWu%TO9a>?Om(;*9&`_Px~s&p8L(AM1QZC zk*z|fy~k1=X~rJI%7eS-c6cAVeoT#TfxyncPXCT-o4NG}#rQEzUcP)e@0rV%J7*-D ziEv$dvRK<up+|F`)_rsL*LSM7p6Q(D;4&?wSzCwO%*}&C_-l$*wO$A_;}2%@{Rj9= zv_kGDbp&12iC`{~72{y3at-}@VnJ@np)1AT755bfPMxr>|AO%Or&F5Sw=m5+qsM%O z?e6-Sr#Gx$zus>DrG%}w-!}ZHd}4PbZuOR(9r|qz>X#3s|Ll|ens7bNcvso2;&&N0 zjvsfQzk2lsK7QVV0_~f=={=uj{=K|7@y6a4aSi%uvlg`7Uuov_{R8t2$@y2#FMTf6 zHAA=VU+(k}sqFZ8`5hN77PBW6iH7+dX`g<j$3Wzz=yo{^89s+4*CY++wa#X(%U!7| z6+QhX&oe!)&nhDK&HAeM%3VC`bb>Q~C5z3)y<w|G1<LECTRu;U*&Vd9<=3w&gPA@& zrT0w_25wA|I2q_-x2^2V76<>y@pYH4-M`OoG?T|gNpMAo)&#Gm3od3Tct>0AdpY%i z{Ep!Dl{%jpruQk$JKpvzSX1&_Qxns(M++7xJos3Vurb0RI*#%8c{Lv0Wx?mtr<~{X zX?_%4{p?V}tW6>!T&x{OlTMsD)3RuhQo!n~7jE7>negV{$(<)}FE7>Ge%`xb-S!)r z1$+mxrmv~!I91>DNVAjAZo0N&^fZ3<<j3wU@@h9G6{Ym$OYLW0e33(Ut?q}@2NYy1 zKJH`PoOF;SCbOlrwZ-j@+H<2dI_HhI3cs;_yz8>@`lhG<syf-`-TRXy{oQ6#Z*|&g z|L9YuZzG(YZB0x}8kTMsHxfB|`18vHsWy|IYRof>eL6?WsG{~uvtCq=kRgw>>Z`)< z`lr?3v$n_oyZpq3+b848NxRaiay)FzTefdMeErxo!*z|EX&=pUEi!C8t*laiBsDg> z><xF`#uYbP>+qDA4Nm;4RkpCq_gXdE+1ya$ivK6B<0V$ISFT-aI$3jjXX5Pd@vo9L zJ*}HlD$o0Q(-pr@-!{J1+qQ1X;R!j@Ll1g~uWp#*n-_IK#&hq+=N%i~p9()35EaEG zYyZuMg{{5BW)=6L7PnsZ6ZuRxf3B*V_0hns&rD(c9<K`LOomAsvNO(3-CTLN)^`6- zm#k&6defbQy|rCrs=uH6BBHwPW7pU6IbREy4&CJMyx7R>-}n8_rOfA_@0b3`7tu4j z^!|o;rsqDLxhF19vtG_`*rR&v{`_6#@r9-f9CNmE^!%Li@xcdU?^!h&!clwAExwuU z@9~|7e*^!&&+R9E>c89RnaA+0+V1Ul4mmBm*rySzKDtMJ-4@9$D7)GD<U|Wj%bzQ! pDgKI);yu6l|9|s8{=z?GpSMfybUDm;o`HdZ!PC{xWt~$(697N`YZL$g literal 0 HcmV?d00001 diff --git a/gui_qt/figs/new.png b/gui_qt/figs/new.png new file mode 100644 index 0000000000000000000000000000000000000000..12131b01008a3ec29ec69f8b3f65c4b3c15b60d6 GIT binary patch literal 852 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmUfZd~z?Fk)a} zkSuYHC<)F_D=AMbN@Z|N$xljE@XSq2PYp^<OsOn9nQFtp!1T=1#W5t}@YU&O{e%-m z+FqMZnOa@=@Y0b7tUDg@#q9XP6tmIb6|2NFwWNq08zx35T%5bVbBV~tpd}uzQ~q6G za{j+;uH>@RhR2oFzgh#mnocUVdET32y!`Xo-*Z0u&h~5RQ2HM{v6%6|@v9T^{xAK# z=D4kG3hzp$4~9lIHhZ#6tgLoPhS|uiSDSn?%xZ3#aHmUlLW08C?7R%7B^H++J}jKM z>;3kVn{;m7zpvi*vEr=6>n<q=`_CI>jxY5|+sQ4$!gw@kqt*KA0;!H*Mj07_^72hN zw-^5Wc|L{jdg;rbM_k06SQ*r+51w3QF5`9XZ19hQSpIJD5QZiJhjf3Db8nZq%crNk z{5pHP$ox4=R<6vf`u>mEb@9d2xOzv{1MdaiZc}Y*o%NV?O6=K-PrhhZ8U33w?`Yfw zpCrC+@lb|ajS^pl6>R=b$U18#YQB1keqL~Aa_{!m>ve&QA1cqBjg{May!!UL`PTcM zbj0r1`|i<{Q^pTUpByU<Pr4ys`RbXm%N54uY!ALzt+iB|F(ad>VMca9@LUE4E!~}l zkNkpr1bA6K<^I;#R^!Sr+xm9apUgg+oDQjVmck8I{o6y7wXPp!VPj)3)tDo`dXMVv zQ^E&)6Zu57it^6XMKNV$-Cg@}iaJB^9ht)1XorMZt7S^(y>4_Abr(F4)oI9ct(--H zCq*r3TV`qZidCEe+m7zJ!2DyMW^%h`0*^$C3`4Z9D?<r$@Qk%nj><fDdnUthqA+&l zLXL*Nf5L={jTt#iC7fQ|s_D~Q;l~ioz<gpxx)}?D(X-ZjKg7BJ=-lXHkVv=k-x4CC zJcEgWiO25u(O``a&O6dPzi0mpYQMfOgz-dZ|1Q6^-h30*x8B=+Xp*h}vd#AvZ!CO$ z>%v#j8JqJ~GUS*n$(H#4K(IbaJot(*cVzyPcY7Z#J$Tx?Cby@w-E_sT?J{>$Z`$<B zOa7a8Ue0{)$z2s{`ECpupZ+(_oHFmF{eDSCr^{dd?42`jX&rN5j_SfmQ@P3+7#J8l MUHx3vIVCg!0FlRhxBvhE literal 0 HcmV?d00001 diff --git a/gui_qt/figs/open.png b/gui_qt/figs/open.png new file mode 100644 index 0000000000000000000000000000000000000000..45fa2883a71fcb891f1ef7c0c217d71eeae284bc GIT binary patch literal 2073 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 A0{{R3 literal 0 HcmV?d00001 diff --git a/gui_qt/figs/paste.png b/gui_qt/figs/paste.png new file mode 100644 index 0000000000000000000000000000000000000000..c14425cad1ff1b2c5628be5769c9e9e52b78635f GIT binary patch literal 1645 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 S=v)Q{1_n=8KbLh*2~7Z8_zf)p literal 0 HcmV?d00001 diff --git a/gui_qt/figs/save.png b/gui_qt/figs/save.png new file mode 100644 index 0000000000000000000000000000000000000000..daba865fafd22fa18e7c0488eb699b79d3554170 GIT binary patch literal 1187 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmUfZd~z?Fk)a} zkSuYHC<)F_D=AMbN@Z|N$xljE@XSq2PYp^<OsOn9nQFtpz+&p@;usQf`04bs{UNR* zN9(u0x>mjZcHZ%y4s$!*d`)J$^h$ZmIMO38{g25f<|Dg=n4WJ;cEsVnBfZk%=bAD~ z9AhMSA00WyV4DySD4D>th>xfF^53}cQ@U5Z`<d{Jw<S<4ENJDq>g})RS$)5<vg*~| z=XGXJ?Y7%B#O^NJ%lzhV|0h3Fsb1#Sk~en0-@DjaUcQWBj*Zp%Gt<o@=DfcXyzJJ3 zPj|AJ_v}a)Xy~pNtNHOxuHiOA!JjuW_w5Z>D)j#DIPh=#x%|^b{IZp^xRs|}o-d#B z=W6ZjYzNm3Vh$ArI?AUv<uV!=OiSzykggF?R#g(wz9BL3>eS-r=bE*4uv`+^#B)if z$CJxb=w7+igy$2sFTC1RrrnpTQMBoo#Wk+S>-TtOfBf}~VU6e-QI-vEH}+OP7t4O# zwyq&+MOfpj+`!)TEL)qtFId*Xn9ge2#Ib^Fs?K3$1v!obALR6z?kNkYiPm%|A5oOE zQH*o&jgWA-?$yb*X2GpwhFQk@S-XPSGnuBcY%=-ABE;^u@P$L1gLeO3R&UEK#V5E! z+6!$Nw4SOK7&=@vu>5)H8rNsL3+u&JNq2v{p`MtyS4LG;f#E}AuZizstHYaT2zKVM z-%92Tn-Q<+_9yXdQGKGU?!^Wx&Ja%te-r%&b6bxnb{<aWoRoP(u=9~{dqns9vWa^d z_AtL?x}T-|mgy7I{PF-<*Q*K@R<A=UX0y#PuHa|xSK0IL)93Px7iJkt_I-SP?9cs; zEJ1NiF23<C{k%&po^LzaF;BvKXW3?Ej=4dCt0wFScpr7tpmyVFhoc+#zNoDY{~4<H z@ZqsbMqkeq)Shh7ed#4BFh}Y@@zb>F+UC301cuvRUzJjKRDF@=8dlN6bGWybFUt{M zad4%=2`SU{vrVP?BMs;MtA6=jgyCb;``Hl&+TmeLp^6tL{COUH|I_Q4!aBP5b}auD zp2ckQ^^M=W%0wpq6~@tq0?ak--@orac<2z*_Po1`G`L(?vURUTg@}e8wQOINwD#zX z5BHxwP5or^{=4$opF2M3N)&_zh)ditwAxnWZ&5er<;%<-!;1GaXUs?_D*DtHdBf1^ z+Woe5S2#lp%+@RlTmL=V(%AU$g$n}LqV{|@nSFLQQ^4x$1s6NET<H**!>t~(K#O5T z*y@zXYs+_--^(nPS}E@6z1BkR_+I5L*Lw^*T<-T<?N~i~z3B?x&)+2UZ2Ouub01&5 zEwu9c)3BViUncVP@f`m2{x;Ktg%cC69NMZqJ#x<eeXPu8KMo|UW#Ybl_&~tgLvN0H z&-wdK`rQ0E^O%>Ju_UO(d9ey{zn!SQ(v~M*-r_{s@kVv4k6O=7<%}9dG<FsId=+}m zr0?RNU)?)z%KOPO@#S+o*xYaTVEJYB@R=`fEp7{awp)%x+9qB$zoz_M|IK(l#&+r6 zWAW0AGiLq!^0@wMaZc?gQ-(*|Z#DkEd;O!m?+5RlFWfrUGcYhPc)I$ztaD0e0s!<8 BBlrLS literal 0 HcmV?d00001 diff --git a/gui_qt/mainwindow.cpp b/gui_qt/mainwindow.cpp new file mode 100644 index 0000000..bb7eac8 --- /dev/null +++ b/gui_qt/mainwindow.cpp @@ -0,0 +1,571 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +namespace bgslibrary +{ + //template<typename T> IBGS* createInstance() { return new T; } + //typedef std::map<std::string, IBGS*(*)()> map_ibgs; + + IBGS* get_alg(std::string alg_name) { + map_ibgs map; + map["FrameDifference"] = &createInstance<FrameDifference>; + map["StaticFrameDifference"] = &createInstance<StaticFrameDifference>; + map["WeightedMovingMean"] = &createInstance<WeightedMovingMean>; + map["WeightedMovingVariance"] = &createInstance<WeightedMovingVariance>; +#if CV_MAJOR_VERSION == 2 + map["MixtureOfGaussianV1"] = &createInstance<MixtureOfGaussianV1>; // only for OpenCV 2.x +#endif + map["MixtureOfGaussianV2"] = &createInstance<MixtureOfGaussianV2>; + map["AdaptiveBackgroundLearning"] = &createInstance<AdaptiveBackgroundLearning>; + map["AdaptiveSelectiveBackgroundLearning"] = &createInstance<AdaptiveSelectiveBackgroundLearning>; +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + map["GMG"] = &createInstance<GMG>; // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION == 3 + map["KNN"] = &createInstance<KNN>; // only on OpenCV 3.x +#endif + map["DPAdaptiveMedian"] = &createInstance<DPAdaptiveMedian>; + map["DPGrimsonGMM"] = &createInstance<DPGrimsonGMM>; + map["DPZivkovicAGMM"] = &createInstance<DPZivkovicAGMM>; + map["DPMean"] = &createInstance<DPMean>; + map["DPWrenGA"] = &createInstance<DPWrenGA>; + map["DPPratiMediod"] = &createInstance<DPPratiMediod>; + map["DPEigenbackground"] = &createInstance<DPEigenbackground>; + map["DPTexture"] = &createInstance<DPTexture>; + map["T2FGMM_UM"] = &createInstance<T2FGMM_UM>; + map["T2FGMM_UV"] = &createInstance<T2FGMM_UV>; + map["T2FMRF_UM"] = &createInstance<T2FMRF_UM>; + map["T2FMRF_UV"] = &createInstance<T2FMRF_UV>; + map["FuzzySugenoIntegral"] = &createInstance<FuzzySugenoIntegral>; + map["FuzzyChoquetIntegral"] = &createInstance<FuzzyChoquetIntegral>; + map["MultiLayer"] = &createInstance<MultiLayer>; + map["PixelBasedAdaptiveSegmenter"] = &createInstance<PixelBasedAdaptiveSegmenter>; + map["LBSimpleGaussian"] = &createInstance<LBSimpleGaussian>; + map["LBFuzzyGaussian"] = &createInstance<LBFuzzyGaussian>; + map["LBMixtureOfGaussians"] = &createInstance<LBMixtureOfGaussians>; + map["LBAdaptiveSOM"] = &createInstance<LBAdaptiveSOM>; + map["LBFuzzyAdaptiveSOM"] = &createInstance<LBFuzzyAdaptiveSOM>; + map["LBP_MRF"] = &createInstance<LBP_MRF>; + map["VuMeter"] = &createInstance<VuMeter>; + map["KDE"] = &createInstance<KDE>; + map["IndependentMultimodal"] = &createInstance<IndependentMultimodal>; + map["MultiCue"] = &createInstance<MultiCue>; + map["SigmaDelta"] = &createInstance<SigmaDelta>; + map["SuBSENSE"] = &createInstance<SuBSENSE>; + map["LOBSTER"] = &createInstance<LOBSTER>; + map["PAWCS"] = &createInstance<PAWCS>; + map["TwoPoints"] = &createInstance<TwoPoints>; + map["ViBe"] = &createInstance<ViBe>; + + return map[alg_name](); + } + + QStringList get_algs_name() + { + QStringList stringList; + stringList.append("FrameDifference"); + stringList.append("StaticFrameDifference"); + stringList.append("WeightedMovingMean"); + stringList.append("WeightedMovingVariance"); +#if CV_MAJOR_VERSION == 2 + stringList.append("MixtureOfGaussianV1"); // only for OpenCV 2.x +#endif + stringList.append("MixtureOfGaussianV2"); + stringList.append("AdaptiveBackgroundLearning"); + stringList.append("AdaptiveSelectiveBackgroundLearning"); +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + stringList.append("GMG"); // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION == 3 + stringList.append("KNN"); // only on OpenCV 3.x +#endif + stringList.append("DPAdaptiveMedian"); + stringList.append("DPGrimsonGMM"); + stringList.append("DPZivkovicAGMM"); + stringList.append("DPMean"); + stringList.append("DPWrenGA"); + stringList.append("DPPratiMediod"); + stringList.append("DPEigenbackground"); + stringList.append("DPTexture"); + stringList.append("T2FGMM_UM"); + stringList.append("T2FGMM_UV"); + stringList.append("T2FMRF_UM"); + stringList.append("T2FMRF_UV"); + stringList.append("FuzzySugenoIntegral"); + stringList.append("FuzzyChoquetIntegral"); + stringList.append("MultiLayer"); + stringList.append("PixelBasedAdaptiveSegmenter"); + stringList.append("LBSimpleGaussian"); + stringList.append("LBFuzzyGaussian"); + stringList.append("LBMixtureOfGaussians"); + stringList.append("LBAdaptiveSOM"); + stringList.append("LBFuzzyAdaptiveSOM"); + stringList.append("LBP_MRF"); + stringList.append("VuMeter"); + stringList.append("KDE"); + stringList.append("IndependentMultimodal"); + stringList.append("MultiCue"); + stringList.append("SigmaDelta"); + stringList.append("SuBSENSE"); + stringList.append("LOBSTER"); + stringList.append("PAWCS"); + stringList.append("TwoPoints"); + stringList.append("ViBe"); + return stringList; + } +} + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + //QDir applicationPath(QCoreApplication::applicationDirPath()); + fileName = QDir(".").filePath("dataset/video.avi"); + //fileName = applicationPath.absolutePath() + "dataset"; + ui->lineEdit_inputdata->setText(fileName); + //fileName = ui->lineEdit_inputdata->text(); + timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(startCapture())); + QStringListModel* listModel = new QStringListModel(bgslibrary::get_algs_name(), NULL); + listModel->sort(0); + ui->listView_algorithms->setModel(listModel); + QModelIndex index = listModel->index(0); + ui->listView_algorithms->selectionModel()->select(index, QItemSelectionModel::Select); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_actionExit_triggered() +{ + this->close(); +} + +void MainWindow::on_pushButton_inputdata_clicked() +{ + QFileDialog dialog(this); + + if (ui->checkBox_imageseq->isChecked()) + dialog.setFileMode(QFileDialog::Directory); + else + dialog.setFileMode(QFileDialog::ExistingFile); + //dialog.setFileMode(QFileDialog::AnyFile); + + dialog.exec(); + QStringList list = dialog.selectedFiles(); + /* + for(int index = 0; index < list.length(); index++) + std::cout << list.at(index).toStdString() << std::endl; + */ + if (list.size() > 0) + { + fileName = list.at(0); + ui->lineEdit_inputdata->setText(fileName); + } +} + +void MainWindow::on_pushButton_out_in_clicked() +{ + QFileDialog dialog(this); + dialog.setDirectory("."); + dialog.setFileMode(QFileDialog::Directory); + dialog.exec(); + QStringList list = dialog.selectedFiles(); + if (list.size() > 0) + { + fileName = list.at(0); + ui->lineEdit_out_in->setText(fileName); + } +} + +void MainWindow::on_pushButton_out_fg_clicked() +{ + QFileDialog dialog(this); + dialog.setDirectory("."); + dialog.setFileMode(QFileDialog::Directory); + dialog.exec(); + QStringList list = dialog.selectedFiles(); + if (list.size() > 0) + { + fileName = list.at(0); + ui->lineEdit_out_fg->setText(fileName); + } +} + +void MainWindow::on_pushButton_out_bg_clicked() +{ + QFileDialog dialog(this); + dialog.setDirectory("."); + dialog.setFileMode(QFileDialog::Directory); + dialog.exec(); + QStringList list = dialog.selectedFiles(); + if (list.size() > 0) + { + fileName = list.at(0); + ui->lineEdit_out_bg->setText(fileName); + } +} + +void MainWindow::on_pushButton_start_clicked() +{ + useCamera = false; + useVideo = false; + useSequence = false; + + if (ui->checkBox_webcamera->isChecked()) + useCamera = true; + else + { + if (ui->checkBox_imageseq->isChecked()) + useSequence = true; + else + useVideo = true; + } + + if (!timer->isActive() && setUpCapture()) + { + createBGS(); + startTimer(); + } +} + +void MainWindow::on_pushButton_stop_clicked() +{ + stopTimer(); +} + +void MainWindow::createBGS() +{ + QString algorithm_name = getSelectedAlgorithmName(); + bgs = bgslibrary::get_alg(algorithm_name.toStdString()); + bgs->setShowOutput(false); +} + +void MainWindow::destroyBGS() +{ + delete bgs; +} + +void MainWindow::startTimer() +{ + std::cout << "startTimer()" << std::endl; + + ui->progressBar->setValue(0); + setFrameNumber(0); + frameNumber_aux = 0; + timer->start(33); + + // disable options +} + +void MainWindow::stopTimer() +{ + if (!timer->isActive()) + return; + + std::cout << "stopTimer()" << std::endl; + + timer->stop(); + //setFrameNumber(0); + //ui->progressBar->setValue(0); + + destroyBGS(); + + if (useCamera || useVideo) + capture.release(); + + // enable options +} + +void MainWindow::setFrameNumber(long long _frameNumber) +{ + //std::cout << "setFrameNumber()" << std::endl; + frameNumber = _frameNumber; + QString txt_frameNumber = QString::fromStdString(its(frameNumber)); + ui->label_framenumber_txt->setText(txt_frameNumber); +} + +bool MainWindow::setUpCapture() +{ + capture_length = 0; + + if (useCamera && !setUpCamera()) { + std::cout << "Cannot initialize webcamera!" << std::endl; + return false; + } + + if (useVideo && !setUpVideo()) { + std::cout << "Cannot open video file " << fileName.toStdString() << std::endl; + return false; + } + + if (useSequence && !setUpSequence()) { + std::cout << "Cannot process images at " << fileName.toStdString() << std::endl; + return false; + } + + if (useCamera || useVideo) { + int capture_fps = capture.get(CV_CAP_PROP_FPS); + std::cout << "capture_fps: " << capture_fps << std::endl; + } + + if (useVideo) { + capture_length = capture.get(CV_CAP_PROP_FRAME_COUNT); + std::cout << "capture_length: " << capture_length << std::endl; + } + + std::cout << "OK!" << std::endl; + return true; +} + +void MainWindow::startCapture() +{ + //std::cout << "startCapture()" << std::endl; + setFrameNumber(frameNumber + 1); + cv::Mat cv_frame; + + if (useCamera || useVideo) + capture >> cv_frame; + + if (useSequence && (frameNumber - 1) < entryList.length()) + { + QString file = entryList.at(frameNumber - 1); + QString filePath = QDir(fileName).filePath(file); + + std::cout << "Processing: " << filePath.toStdString() << std::endl; + if (fileExists(filePath)) + cv_frame = cv::imread(filePath.toStdString()); + } + + if (cv_frame.empty()) + { + stopTimer(); + return; + } + + if (frameNumber == 1) + { + int frame_width = cv_frame.size().width; + int frame_height = cv_frame.size().height; + ui->label_frameresw_txt->setText(QString::fromStdString(its(frame_width))); + ui->label_frameresh_txt->setText(QString::fromStdString(its(frame_height))); + } + + if (useVideo && capture_length > 0) + { + double perc = (double(frameNumber) / double(capture_length)) * 100.0; + //std::cout << "perc: " << perc << std::endl; + ui->progressBar->setValue(perc); + } + + int startAt = ui->spinBox_startat->value(); + if (startAt > 0 && frameNumber < startAt) + { + timer->setInterval(1); + return; + } + else + timer->setInterval(33); + + int stopAt = ui->spinBox_stopat->value(); + if (stopAt > 0 && frameNumber >= stopAt) + { + stopTimer(); + return; + } + + cv::Mat cv_frame_small; + cv::resize(cv_frame, cv_frame_small, cv::Size(250, 250)); + + QImage qt_frame = cv2qimage(cv_frame_small); + ui->label_img_in->setPixmap(QPixmap::fromImage(qt_frame, Qt::MonoOnly)); + + processFrame(cv_frame); +} + +QImage MainWindow::cv2qimage(const cv::Mat &cv_frame) +{ + if (cv_frame.channels() == 3) + return Mat2QImage(cv_frame); + else + return GrayMat2QImage(cv_frame); +} + +void MainWindow::processFrame(const cv::Mat &cv_frame) +{ + cv::Mat cv_fg; + cv::Mat cv_bg; + tic(); + bgs->process(cv_frame, cv_fg, cv_bg); + toc(); + ui->label_fps_txt->setText(QString::fromStdString(its(fps()))); + + cv::Mat cv_fg_small; + cv::resize(cv_fg, cv_fg_small, cv::Size(250, 250)); + QImage qt_fg = cv2qimage(cv_fg_small); + ui->label_img_fg->setPixmap(QPixmap::fromImage(qt_fg, Qt::MonoOnly)); + + cv::Mat cv_bg_small; + cv::resize(cv_bg, cv_bg_small, cv::Size(250, 250)); + QImage qt_bg = cv2qimage(cv_bg_small); + ui->label_img_bg->setPixmap(QPixmap::fromImage(qt_bg, Qt::MonoOnly)); + + if (ui->checkBox_save_im->isChecked() || ui->checkBox_save_fg->isChecked() || ui->checkBox_save_bg->isChecked()) + { + if (ui->checkBox_kfn->isChecked()) + frameNumber_aux = frameNumber; + else + frameNumber_aux = frameNumber_aux + 1; + } + if (ui->checkBox_save_im->isChecked()) + { + QString out_im_path = ui->lineEdit_out_in->text(); + QString out_im_file = QDir(out_im_path).filePath(QString::number(frameNumber_aux) + ".png"); + cv::imwrite(out_im_file.toStdString(), cv_frame); + } + if (ui->checkBox_save_fg->isChecked()) + { + QString out_im_path = ui->lineEdit_out_fg->text(); + QString out_im_file = QDir(out_im_path).filePath(QString::number(frameNumber_aux) + ".png"); + cv::imwrite(out_im_file.toStdString(), cv_fg); + } + if (ui->checkBox_save_bg->isChecked()) + { + QString out_im_path = ui->lineEdit_out_bg->text(); + QString out_im_file = QDir(out_im_path).filePath(QString::number(frameNumber) + ".png"); + cv::imwrite(out_im_file.toStdString(), cv_bg); + } +} + +void MainWindow::tic() +{ + duration = static_cast<double>(cv::getTickCount()); +} + +void MainWindow::toc() +{ + duration = (static_cast<double>(cv::getTickCount()) - duration) / cv::getTickFrequency(); + //std::cout << "time(sec):" << std::fixed << std::setprecision(6) << duration << std::endl; + //std::cout << duration << std::endl; +} + +double MainWindow::fps() +{ + //double fps = frameNumber / duration; + double fps = 1 / duration; + //std::cout << "Estimated frames per second : " << fps << std::endl; + return fps; +} + +bool MainWindow::setUpCamera() +{ + int cameraIndex = ui->spinBox_webcamera->value(); + std::cout << "Camera index: " << cameraIndex << std::endl; + + capture.open(cameraIndex); + return capture.isOpened(); +} + +bool MainWindow::setUpVideo() +{ + std::string videoFileName = fileName.toStdString(); + std::cout << "Openning: " << videoFileName << std::endl; + capture.open(videoFileName.c_str()); + return capture.isOpened(); +} + +bool MainWindow::setUpSequence() +{ + std::cout << "Directory path: " << fileName.toStdString() << std::endl; + if (QDir(fileName).exists()) + { + QDir dir(fileName); + QStringList filters; + filters << "*.png" << "*.jpg" << "*.bmp" << "*.gif"; + dir.setNameFilters(filters); + //entryList = dir.entryList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst); + //entryList = dir.entryList(QDir::Filter::Files, QDir::SortFlag::NoSort); + dir.setFilter(QDir::Files | QDir::NoSymLinks); + dir.setSorting(QDir::NoSort); // will sort manually with std::sort + //dir.setSorting(QDir::LocaleAware); + entryList = dir.entryList(); + + std::cout << entryList.length() << std::endl; + if (entryList.length() == 0) + { + QMessageBox::warning(this, "Warning", "No image found! (png, jpg, bmp, gif)"); + return false; + } + + QCollator collator; + collator.setNumericMode(true); + std::sort( + entryList.begin(), + entryList.end(), + [&collator](const QString &file1, const QString &file2) + { + return collator.compare(file1, file2) < 0; + }); + + // for(int i = 0; i < entryList.length(); i++) + // { + // QString file = entryList.at(i); + // std::cout << file.toStdString() << std::endl; + // } + return true; + } + else + { + QMessageBox::warning(this, "Warning", "Directory path doesn't exist!"); + return false; + } +} + +QString MainWindow::getSelectedAlgorithmName() +{ + QModelIndex index = ui->listView_algorithms->currentIndex(); + QString algorithm_name = index.data(Qt::DisplayRole).toString(); + return algorithm_name; +} + +void MainWindow::on_listView_algorithms_doubleClicked(const QModelIndex &index) +{ + QString algorithm_name = index.data(Qt::DisplayRole).toString(); + std::cout << "Selected algorithm: " << algorithm_name.toStdString() << std::endl; + + // CodeEditor editor; + // editor.setWindowTitle(QObject::tr("Code Editor Example")); + // editor.show(); + + QString configFileName = QDir(".").filePath("config/" + algorithm_name + ".xml"); + std::cout << "Looking for: " << configFileName.toStdString() << std::endl; + + if (fileExists(configFileName)) + { + textEditor.loadFile(configFileName); + textEditor.show(); + } + else + { + QMessageBox::warning(this, "Warning", "XML configuration file not found!\nPlease run the algorithm first!"); + return; + } +} diff --git a/gui_qt/mainwindow.h b/gui_qt/mainwindow.h new file mode 100644 index 0000000..a834882 --- /dev/null +++ b/gui_qt/mainwindow.h @@ -0,0 +1,110 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <QApplication> +#include <QCommandLineParser> +#include <QCommandLineOption> +#include <QMainWindow> +#include <QFileDialog> +#include <QDebug> +#include <QFile> +#include <QMessageBox> +#include <QImage> +#include <QTimer> +#include <QStringList> +#include <QStringListModel> +#include <QCollator> + +#include <opencv2/opencv.hpp> + +#include "qt_utils.h" +#include "texteditor.h" +#include "../package_bgs/bgslibrary.h" + +namespace bgslibrary +{ + template<typename T> IBGS * createInstance() { return new T; } + typedef std::map<std::string, IBGS*(*)()> map_ibgs; + + IBGS* get_alg(std::string alg_name); + QStringList get_algs_name(); +} + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + + private slots: + void on_actionExit_triggered(); + + void on_pushButton_inputdata_clicked(); + + void on_pushButton_start_clicked(); + + void on_pushButton_stop_clicked(); + + void on_pushButton_out_in_clicked(); + + void on_pushButton_out_fg_clicked(); + + void on_pushButton_out_bg_clicked(); + + void on_listView_algorithms_doubleClicked(const QModelIndex &index); + +private: + Ui::MainWindow *ui; + QString fileName; + cv::VideoCapture capture; + bool useCamera = false; + bool useVideo = false; + bool useSequence = false; + QStringList entryList; + long long frameNumber = 0; + long long frameNumber_aux = 0; + bool setUpCapture(); + bool setUpCamera(); + bool setUpVideo(); + bool setUpSequence(); + QString getSelectedAlgorithmName(); + QTimer* timer; + void startTimer(); + void stopTimer(); + void setFrameNumber(long long frameNumber); + QImage cv2qimage(const cv::Mat &cv_frame); + void processFrame(const cv::Mat &cv_frame); + IBGS *bgs; + void createBGS(); + void destroyBGS(); + double duration = 0; + void tic(); + void toc(); + double fps(); + int capture_length = 0; + TextEditor textEditor; + + public slots: + void startCapture(); +}; diff --git a/gui_qt/mainwindow.ui b/gui_qt/mainwindow.ui new file mode 100644 index 0000000..75e9e61 --- /dev/null +++ b/gui_qt/mainwindow.ui @@ -0,0 +1,631 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1070</width> + <height>559</height> + </rect> + </property> + <property name="windowTitle"> + <string>BGSLibrary QT GUI</string> + </property> + <widget class="QWidget" name="centralWidget"> + <widget class="QLabel" name="label_algorithms"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>251</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Algorithms</string> + </property> + </widget> + <widget class="QListView" name="listView_algorithms"> + <property name="geometry"> + <rect> + <x>10</x> + <y>30</y> + <width>256</width> + <height>361</height> + </rect> + </property> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + </widget> + <widget class="QLabel" name="label_inputdata"> + <property name="geometry"> + <rect> + <x>280</x> + <y>10</y> + <width>601</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Input (specify a video file or a directory path containing the sequence of images)</string> + </property> + </widget> + <widget class="QLineEdit" name="lineEdit_inputdata"> + <property name="geometry"> + <rect> + <x>280</x> + <y>30</y> + <width>721</width> + <height>22</height> + </rect> + </property> + <property name="text"> + <string>./dataset/video.avi</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_inputdata"> + <property name="geometry"> + <rect> + <x>1010</x> + <y>30</y> + <width>40</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_webcamera"> + <property name="geometry"> + <rect> + <x>280</x> + <y>60</y> + <width>131</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Use web camera</string> + </property> + </widget> + <widget class="QSpinBox" name="spinBox_webcamera"> + <property name="geometry"> + <rect> + <x>410</x> + <y>60</y> + <width>42</width> + <height>20</height> + </rect> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_imageseq"> + <property name="geometry"> + <rect> + <x>470</x> + <y>60</y> + <width>151</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Sequence of images?</string> + </property> + </widget> + <widget class="QLabel" name="label_startat"> + <property name="geometry"> + <rect> + <x>945</x> + <y>60</y> + <width>55</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Start at:</string> + </property> + </widget> + <widget class="QSpinBox" name="spinBox_startat"> + <property name="geometry"> + <rect> + <x>1000</x> + <y>60</y> + <width>50</width> + <height>20</height> + </rect> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + <widget class="QLabel" name="label_stopat"> + <property name="geometry"> + <rect> + <x>945</x> + <y>85</y> + <width>55</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Stop at:</string> + </property> + </widget> + <widget class="QSpinBox" name="spinBox_stopat"> + <property name="geometry"> + <rect> + <x>1000</x> + <y>85</y> + <width>50</width> + <height>20</height> + </rect> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + <widget class="QLabel" name="label_input"> + <property name="geometry"> + <rect> + <x>280</x> + <y>120</y> + <width>250</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Input</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_img_in"> + <property name="geometry"> + <rect> + <x>280</x> + <y>140</y> + <width>250</width> + <height>250</height> + </rect> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>IMG_INPUT</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_img_fg"> + <property name="geometry"> + <rect> + <x>540</x> + <y>140</y> + <width>250</width> + <height>250</height> + </rect> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>IMG_FOREGROUND</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_img_bg"> + <property name="geometry"> + <rect> + <x>800</x> + <y>140</y> + <width>250</width> + <height>250</height> + </rect> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>IMG_BACKGROUND</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_foreground"> + <property name="geometry"> + <rect> + <x>540</x> + <y>120</y> + <width>250</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Foreground mask</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_background"> + <property name="geometry"> + <rect> + <x>800</x> + <y>120</y> + <width>250</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Background model</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_save_im"> + <property name="geometry"> + <rect> + <x>280</x> + <y>400</y> + <width>52</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Save</string> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_save_fg"> + <property name="geometry"> + <rect> + <x>540</x> + <y>400</y> + <width>52</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Save</string> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_save_bg"> + <property name="geometry"> + <rect> + <x>800</x> + <y>400</y> + <width>52</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Save</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_stop"> + <property name="geometry"> + <rect> + <x>960</x> + <y>470</y> + <width>93</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>Stop</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_start"> + <property name="geometry"> + <rect> + <x>850</x> + <y>470</y> + <width>93</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>Start</string> + </property> + </widget> + <widget class="QProgressBar" name="progressBar"> + <property name="geometry"> + <rect> + <x>280</x> + <y>470</y> + <width>550</width> + <height>23</height> + </rect> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + <widget class="QLabel" name="label_exectime"> + <property name="geometry"> + <rect> + <x>10</x> + <y>400</y> + <width>121</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Estimated FPS:</string> + </property> + </widget> + <widget class="QLabel" name="label_fps_txt"> + <property name="geometry"> + <rect> + <x>210</x> + <y>400</y> + <width>55</width> + <height>16</height> + </rect> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_framenumber"> + <property name="geometry"> + <rect> + <x>10</x> + <y>420</y> + <width>121</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Frame number:</string> + </property> + </widget> + <widget class="QLabel" name="label_framenumber_txt"> + <property name="geometry"> + <rect> + <x>210</x> + <y>420</y> + <width>55</width> + <height>16</height> + </rect> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_status"> + <property name="geometry"> + <rect> + <x>209</x> + <y>470</y> + <width>61</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>Progress:</string> + </property> + </widget> + <widget class="QLabel" name="label_frameres"> + <property name="geometry"> + <rect> + <x>10</x> + <y>440</y> + <width>121</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Frame resolution:</string> + </property> + </widget> + <widget class="QLabel" name="label_frameresw_txt"> + <property name="geometry"> + <rect> + <x>140</x> + <y>440</y> + <width>55</width> + <height>16</height> + </rect> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_frameresh_txt"> + <property name="geometry"> + <rect> + <x>210</x> + <y>440</y> + <width>55</width> + <height>16</height> + </rect> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLabel" name="label_frameres_2"> + <property name="geometry"> + <rect> + <x>193</x> + <y>440</y> + <width>21</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>x</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QLineEdit" name="lineEdit_out_in"> + <property name="geometry"> + <rect> + <x>348</x> + <y>400</y> + <width>140</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>./output/in/</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_out_in"> + <property name="geometry"> + <rect> + <x>490</x> + <y>400</y> + <width>40</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="QLineEdit" name="lineEdit_out_fg"> + <property name="geometry"> + <rect> + <x>608</x> + <y>400</y> + <width>140</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>./output/fg/</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_out_fg"> + <property name="geometry"> + <rect> + <x>750</x> + <y>400</y> + <width>40</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="QPushButton" name="pushButton_out_bg"> + <property name="geometry"> + <rect> + <x>1010</x> + <y>400</y> + <width>40</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + <widget class="QLineEdit" name="lineEdit_out_bg"> + <property name="geometry"> + <rect> + <x>868</x> + <y>400</y> + <width>140</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>./output/bg/</string> + </property> + </widget> + <widget class="QCheckBox" name="checkBox_kfn"> + <property name="geometry"> + <rect> + <x>280</x> + <y>420</y> + <width>141</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Keep frame number</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>1070</width> + <height>26</height> + </rect> + </property> + <widget class="QMenu" name="menuBGSLibrary"> + <property name="title"> + <string>BGSLibrary</string> + </property> + <addaction name="actionExit"/> + </widget> + <addaction name="menuBGSLibrary"/> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <action name="actionExit"> + <property name="text"> + <string>Exit</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/gui_qt/qt_utils.cpp b/gui_qt/qt_utils.cpp new file mode 100644 index 0000000..2464d78 --- /dev/null +++ b/gui_qt/qt_utils.cpp @@ -0,0 +1,74 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "qt_utils.h" + +QImage GrayMat2QImage(cv::Mat const& src) { + cv::Mat temp; + src.copyTo(temp); + QImage dest((const uchar *)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_Indexed8); + dest.bits(); + return dest; +} +QImage Mat2QImage(cv::Mat const& src) { + cv::Mat temp; + cvtColor(src, temp, CV_BGR2RGB); + QImage dest((const uchar *)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888); + dest.bits(); + return dest; +} +cv::Mat QImage2Mat(QImage const& src) { + cv::Mat tmp(src.height(), src.width(), CV_8UC3, (uchar*)src.bits(), src.bytesPerLine()); + cv::Mat result; + cvtColor(tmp, result, CV_RGB2BGR); + return result; +} + +QString base64_encode(const QString string) { + QByteArray ba; + ba.append(string); + return ba.toBase64(); +} +QString base64_decode(const QString string) { + QByteArray ba; + ba.append(string); + return QByteArray::fromBase64(ba); +} +QString md5_encode(const QString string) { + QByteArray ba; + ba.append(string); + return QString(QCryptographicHash::hash((ba), QCryptographicHash::Md5).toHex()); +} + +int sti(const std::string &s) { + int i; + std::stringstream ss; + ss << s; + ss >> i; + return i; +} +std::string its(int i) { + std::stringstream ss; + ss << i; + return ss.str(); +} + +bool fileExists(QString path) { + QFileInfo check_file(path); + // check if file exists and if yes: Is it really a file and no directory? + return check_file.exists() && check_file.isFile(); +} diff --git a/gui_qt/qt_utils.h b/gui_qt/qt_utils.h new file mode 100644 index 0000000..84128c5 --- /dev/null +++ b/gui_qt/qt_utils.h @@ -0,0 +1,99 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <sstream> +#include <string> +#include <QByteArray> +#include <QImage> +#include <QCryptographicHash> +#include <QFileInfo> +#include <opencv2/opencv.hpp> + +QImage GrayMat2QImage(cv::Mat const& src); +QImage Mat2QImage(cv::Mat const& src); +cv::Mat QImage2Mat(QImage const& src); + +QString base64_encode(const QString string); +QString base64_decode(const QString string); +QString md5_encode(const QString); + +int sti(const std::string &s); +std::string its(int i); + +bool fileExists(QString path); + +/* +#include <QFileDialog> +#include <QApplication> +#include <QWidget> +#include <QTreeWidget> +#include <QPushButton> +#include <QStringList> +#include <QModelIndex> +#include <QDir> +#include <QDebug> + +class FileDialog : public QFileDialog +{ + Q_OBJECT + public: + explicit FileDialog(QWidget *parent = Q_NULLPTR) + : QFileDialog(parent) + { + setOption(QFileDialog::DontUseNativeDialog); + setFileMode(QFileDialog::Directory); + //setFileMode(QFileDialog::ExistingFiles); + //setFileMode(QFileDialog::Directory|QFileDialog::ExistingFiles); + for (auto *pushButton : findChildren<QPushButton*>()) { + qDebug() << pushButton->text(); + if (pushButton->text() == "&Open" || pushButton->text() == "&Choose") { + openButton = pushButton; + break; + } + } + disconnect(openButton, SIGNAL(clicked(bool))); + connect(openButton, &QPushButton::clicked, this, &FileDialog::openClicked); + treeView = findChild<QTreeView*>(); + } + + QStringList selected() const + { + return selectedFilePaths; + } + + public slots: + void openClicked() + { + selectedFilePaths.clear(); + qDebug() << treeView->selectionModel()->selection(); + for (const auto& modelIndex : treeView->selectionModel()->selectedIndexes()) { + qDebug() << modelIndex.column(); + if (modelIndex.column() == 0) + selectedFilePaths.append(directory().absolutePath() + modelIndex.data().toString()); + } + emit filesSelected(selectedFilePaths); + hide(); + qDebug() << selectedFilePaths; + } + + private: + QTreeView *treeView; + QPushButton *openButton; + QStringList selectedFilePaths; +}; +*/ diff --git a/gui_qt/texteditor.cpp b/gui_qt/texteditor.cpp new file mode 100644 index 0000000..80f45e1 --- /dev/null +++ b/gui_qt/texteditor.cpp @@ -0,0 +1,320 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <QtWidgets> + +#include "texteditor.h" + +TextEditor::TextEditor() + : textEdit(new QPlainTextEdit) +{ + setCentralWidget(textEdit); + + createActions(); + createStatusBar(); + + readSettings(); + + connect(textEdit->document(), &QTextDocument::contentsChanged, + this, &TextEditor::documentWasModified); + +#ifndef QT_NO_SESSIONMANAGER + QGuiApplication::setFallbackSessionManagementEnabled(false); + connect(qApp, &QGuiApplication::commitDataRequest, + this, &TextEditor::commitData); +#endif + + setCurrentFile(QString()); + setUnifiedTitleAndToolBarOnMac(true); +} + +void TextEditor::closeEvent(QCloseEvent *event) +{ + if (maybeSave()) { + writeSettings(); + event->accept(); + } + else { + event->ignore(); + } +} + +void TextEditor::newFile() +{ + if (maybeSave()) { + textEdit->clear(); + setCurrentFile(QString()); + } +} + +void TextEditor::open() +{ + if (maybeSave()) { + QString fileName = QFileDialog::getOpenFileName(this); + if (!fileName.isEmpty()) + loadFile(fileName); + } +} + +bool TextEditor::save() +{ + if (curFile.isEmpty()) { + return saveAs(); + } + else { + return saveFile(curFile); + } +} + +bool TextEditor::saveAs() +{ + QFileDialog dialog(this); + dialog.setWindowModality(Qt::WindowModal); + dialog.setAcceptMode(QFileDialog::AcceptSave); + if (dialog.exec() != QDialog::Accepted) + return false; + return saveFile(dialog.selectedFiles().first()); +} + +void TextEditor::about() +{ + QMessageBox::about(this, tr("About BGSLibrary"), + tr("The <b>BGSLibrary</b> provides an easy-to-use framework " + "to perform foreground-background separation in videos.")); +} + +void TextEditor::documentWasModified() +{ + setWindowModified(textEdit->document()->isModified()); +} + +void TextEditor::createActions() +{ + + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + QToolBar *fileToolBar = addToolBar(tr("File")); + const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/figs/new.png")); + QAction *newAct = new QAction(newIcon, tr("&New"), this); + newAct->setShortcuts(QKeySequence::New); + newAct->setStatusTip(tr("Create a new file")); + connect(newAct, &QAction::triggered, this, &TextEditor::newFile); + fileMenu->addAction(newAct); + fileToolBar->addAction(newAct); + + const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/figs/open.png")); + QAction *openAct = new QAction(openIcon, tr("&Open..."), this); + openAct->setShortcuts(QKeySequence::Open); + openAct->setStatusTip(tr("Open an existing file")); + connect(openAct, &QAction::triggered, this, &TextEditor::open); + fileMenu->addAction(openAct); + fileToolBar->addAction(openAct); + + const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/figs/save.png")); + QAction *saveAct = new QAction(saveIcon, tr("&Save"), this); + saveAct->setShortcuts(QKeySequence::Save); + saveAct->setStatusTip(tr("Save the document to disk")); + connect(saveAct, &QAction::triggered, this, &TextEditor::save); + fileMenu->addAction(saveAct); + fileToolBar->addAction(saveAct); + + const QIcon saveAsIcon = QIcon::fromTheme("document-save-as"); + QAction *saveAsAct = fileMenu->addAction(saveAsIcon, tr("Save &As..."), this, &TextEditor::saveAs); + saveAsAct->setShortcuts(QKeySequence::SaveAs); + saveAsAct->setStatusTip(tr("Save the document under a new name")); + + + fileMenu->addSeparator(); + + const QIcon exitIcon = QIcon::fromTheme("application-exit"); + QAction *exitAct = fileMenu->addAction(exitIcon, tr("E&xit"), this, &QWidget::close); + exitAct->setShortcuts(QKeySequence::Quit); + exitAct->setStatusTip(tr("Exit the application")); + + QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); + QToolBar *editToolBar = addToolBar(tr("Edit")); +#ifndef QT_NO_CLIPBOARD + const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/figs/cut.png")); + QAction *cutAct = new QAction(cutIcon, tr("Cu&t"), this); + cutAct->setShortcuts(QKeySequence::Cut); + cutAct->setStatusTip(tr("Cut the current selection's contents to the " + "clipboard")); + connect(cutAct, &QAction::triggered, textEdit, &QPlainTextEdit::cut); + editMenu->addAction(cutAct); + editToolBar->addAction(cutAct); + + const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/figs/copy.png")); + QAction *copyAct = new QAction(copyIcon, tr("&Copy"), this); + copyAct->setShortcuts(QKeySequence::Copy); + copyAct->setStatusTip(tr("Copy the current selection's contents to the " + "clipboard")); + connect(copyAct, &QAction::triggered, textEdit, &QPlainTextEdit::copy); + editMenu->addAction(copyAct); + editToolBar->addAction(copyAct); + + const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/figs/paste.png")); + QAction *pasteAct = new QAction(pasteIcon, tr("&Paste"), this); + pasteAct->setShortcuts(QKeySequence::Paste); + pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current " + "selection")); + connect(pasteAct, &QAction::triggered, textEdit, &QPlainTextEdit::paste); + editMenu->addAction(pasteAct); + editToolBar->addAction(pasteAct); + + menuBar()->addSeparator(); + +#endif // !QT_NO_CLIPBOARD + + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &TextEditor::about); + aboutAct->setStatusTip(tr("Show the application's About box")); + + + QAction *aboutQtAct = helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); + aboutQtAct->setStatusTip(tr("Show the Qt library's About box")); + +#ifndef QT_NO_CLIPBOARD + cutAct->setEnabled(false); + copyAct->setEnabled(false); + connect(textEdit, &QPlainTextEdit::copyAvailable, cutAct, &QAction::setEnabled); + connect(textEdit, &QPlainTextEdit::copyAvailable, copyAct, &QAction::setEnabled); +#endif // !QT_NO_CLIPBOARD +} + +void TextEditor::createStatusBar() +{ + statusBar()->showMessage(tr("Ready")); +} + +void TextEditor::readSettings() +{ + QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); + const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray(); + if (geometry.isEmpty()) { + const QRect availableGeometry = QApplication::desktop()->availableGeometry(this); + resize(availableGeometry.width() / 3, availableGeometry.height() / 2); + move((availableGeometry.width() - width()) / 2, + (availableGeometry.height() - height()) / 2); + } + else { + restoreGeometry(geometry); + } +} + +void TextEditor::writeSettings() +{ + QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); + settings.setValue("geometry", saveGeometry()); +} + +bool TextEditor::maybeSave() +{ + if (!textEdit->document()->isModified()) + return true; + const QMessageBox::StandardButton ret + = QMessageBox::warning(this, tr("Application"), + tr("The document has been modified.\n" + "Do you want to save your changes?"), + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + switch (ret) { + case QMessageBox::Save: + return save(); + case QMessageBox::Cancel: + return false; + default: + break; + } + return true; +} + +void TextEditor::loadFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly | QFile::Text)) { + QMessageBox::warning(this, tr("Application"), + tr("Cannot read file %1:\n%2.") + .arg(QDir::toNativeSeparators(fileName), file.errorString())); + return; + } + + QTextStream in(&file); +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor(Qt::WaitCursor); +#endif + textEdit->setPlainText(in.readAll()); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + + setCurrentFile(fileName); + statusBar()->showMessage(tr("File loaded"), 2000); +} + +bool TextEditor::saveFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) { + QMessageBox::warning(this, tr("Application"), + tr("Cannot write file %1:\n%2.") + .arg(QDir::toNativeSeparators(fileName), + file.errorString())); + return false; + } + + QTextStream out(&file); +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor(Qt::WaitCursor); +#endif + out << textEdit->toPlainText(); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + + setCurrentFile(fileName); + statusBar()->showMessage(tr("File saved"), 2000); + return true; +} + +void TextEditor::setCurrentFile(const QString &fileName) +{ + curFile = fileName; + textEdit->document()->setModified(false); + setWindowModified(false); + + QString shownName = curFile; + if (curFile.isEmpty()) + shownName = "untitled.txt"; + setWindowFilePath(shownName); +} + +QString TextEditor::strippedName(const QString &fullFileName) +{ + return QFileInfo(fullFileName).fileName(); +} +#ifndef QT_NO_SESSIONMANAGER +void TextEditor::commitData(QSessionManager &manager) +{ + if (manager.allowsInteraction()) { + if (!maybeSave()) + manager.cancel(); + } + else { + // Non-interactive: save without asking + if (textEdit->document()->isModified()) + save(); + } +} +#endif diff --git a/gui_qt/texteditor.h b/gui_qt/texteditor.h new file mode 100644 index 0000000..c0d5d8f --- /dev/null +++ b/gui_qt/texteditor.h @@ -0,0 +1,64 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#ifndef TEXTEDITOR_H +#define TEXTEDITOR_H + +#include <QMainWindow> + +class QAction; +class QMenu; +class QPlainTextEdit; +class QSessionManager; + +class TextEditor : public QMainWindow +{ + Q_OBJECT + +public: + TextEditor(); + + void loadFile(const QString &fileName); + +protected: + void closeEvent(QCloseEvent *event) override; + + private slots: + void newFile(); + void open(); + bool save(); + bool saveAs(); + void about(); + void documentWasModified(); +#ifndef QT_NO_SESSIONMANAGER + void commitData(QSessionManager &); +#endif + +private: + void createActions(); + void createStatusBar(); + void readSettings(); + void writeSettings(); + bool maybeSave(); + bool saveFile(const QString &fileName); + void setCurrentFile(const QString &fileName); + QString strippedName(const QString &fullFileName); + + QPlainTextEdit *textEdit; + QString curFile; +}; + +#endif // TEXTEDITOR_H diff --git a/gui_qt/ui_mainwindow.h b/gui_qt/ui_mainwindow.h new file mode 100644 index 0000000..eb3f468 --- /dev/null +++ b/gui_qt/ui_mainwindow.h @@ -0,0 +1,306 @@ +/******************************************************************************** +** Form generated from reading UI file 'mainwindow.ui' +** +** Created by: Qt User Interface Compiler version 5.6.2 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_MAINWINDOW_H +#define UI_MAINWINDOW_H + +#include <QtCore/QVariant> +#include <QtWidgets/QAction> +#include <QtWidgets/QApplication> +#include <QtWidgets/QButtonGroup> +#include <QtWidgets/QCheckBox> +#include <QtWidgets/QHeaderView> +#include <QtWidgets/QLabel> +#include <QtWidgets/QLineEdit> +#include <QtWidgets/QListView> +#include <QtWidgets/QMainWindow> +#include <QtWidgets/QMenu> +#include <QtWidgets/QMenuBar> +#include <QtWidgets/QProgressBar> +#include <QtWidgets/QPushButton> +#include <QtWidgets/QSpinBox> +#include <QtWidgets/QStatusBar> +#include <QtWidgets/QWidget> + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QAction *actionExit; + QWidget *centralWidget; + QLabel *label_algorithms; + QListView *listView_algorithms; + QLabel *label_inputdata; + QLineEdit *lineEdit_inputdata; + QPushButton *pushButton_inputdata; + QCheckBox *checkBox_webcamera; + QSpinBox *spinBox_webcamera; + QCheckBox *checkBox_imageseq; + QLabel *label_startat; + QSpinBox *spinBox_startat; + QLabel *label_stopat; + QSpinBox *spinBox_stopat; + QLabel *label_input; + QLabel *label_img_in; + QLabel *label_img_fg; + QLabel *label_img_bg; + QLabel *label_foreground; + QLabel *label_background; + QCheckBox *checkBox_save_im; + QCheckBox *checkBox_save_fg; + QCheckBox *checkBox_save_bg; + QPushButton *pushButton_stop; + QPushButton *pushButton_start; + QProgressBar *progressBar; + QLabel *label_exectime; + QLabel *label_fps_txt; + QLabel *label_framenumber; + QLabel *label_framenumber_txt; + QLabel *label_status; + QLabel *label_frameres; + QLabel *label_frameresw_txt; + QLabel *label_frameresh_txt; + QLabel *label_frameres_2; + QLineEdit *lineEdit_out_in; + QPushButton *pushButton_out_in; + QLineEdit *lineEdit_out_fg; + QPushButton *pushButton_out_fg; + QPushButton *pushButton_out_bg; + QLineEdit *lineEdit_out_bg; + QCheckBox *checkBox_kfn; + QMenuBar *menuBar; + QMenu *menuBGSLibrary; + QStatusBar *statusBar; + + void setupUi(QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QStringLiteral("MainWindow")); + MainWindow->resize(1070, 559); + actionExit = new QAction(MainWindow); + actionExit->setObjectName(QStringLiteral("actionExit")); + centralWidget = new QWidget(MainWindow); + centralWidget->setObjectName(QStringLiteral("centralWidget")); + label_algorithms = new QLabel(centralWidget); + label_algorithms->setObjectName(QStringLiteral("label_algorithms")); + label_algorithms->setGeometry(QRect(10, 10, 251, 16)); + listView_algorithms = new QListView(centralWidget); + listView_algorithms->setObjectName(QStringLiteral("listView_algorithms")); + listView_algorithms->setGeometry(QRect(10, 30, 256, 361)); + listView_algorithms->setEditTriggers(QAbstractItemView::NoEditTriggers); + label_inputdata = new QLabel(centralWidget); + label_inputdata->setObjectName(QStringLiteral("label_inputdata")); + label_inputdata->setGeometry(QRect(280, 10, 601, 16)); + lineEdit_inputdata = new QLineEdit(centralWidget); + lineEdit_inputdata->setObjectName(QStringLiteral("lineEdit_inputdata")); + lineEdit_inputdata->setGeometry(QRect(280, 30, 721, 22)); + pushButton_inputdata = new QPushButton(centralWidget); + pushButton_inputdata->setObjectName(QStringLiteral("pushButton_inputdata")); + pushButton_inputdata->setGeometry(QRect(1010, 30, 40, 21)); + checkBox_webcamera = new QCheckBox(centralWidget); + checkBox_webcamera->setObjectName(QStringLiteral("checkBox_webcamera")); + checkBox_webcamera->setGeometry(QRect(280, 60, 131, 20)); + spinBox_webcamera = new QSpinBox(centralWidget); + spinBox_webcamera->setObjectName(QStringLiteral("spinBox_webcamera")); + spinBox_webcamera->setGeometry(QRect(410, 60, 42, 20)); + checkBox_imageseq = new QCheckBox(centralWidget); + checkBox_imageseq->setObjectName(QStringLiteral("checkBox_imageseq")); + checkBox_imageseq->setGeometry(QRect(470, 60, 151, 20)); + label_startat = new QLabel(centralWidget); + label_startat->setObjectName(QStringLiteral("label_startat")); + label_startat->setGeometry(QRect(945, 60, 55, 20)); + spinBox_startat = new QSpinBox(centralWidget); + spinBox_startat->setObjectName(QStringLiteral("spinBox_startat")); + spinBox_startat->setGeometry(QRect(1000, 60, 50, 20)); + spinBox_startat->setMaximum(9999); + label_stopat = new QLabel(centralWidget); + label_stopat->setObjectName(QStringLiteral("label_stopat")); + label_stopat->setGeometry(QRect(945, 85, 55, 20)); + spinBox_stopat = new QSpinBox(centralWidget); + spinBox_stopat->setObjectName(QStringLiteral("spinBox_stopat")); + spinBox_stopat->setGeometry(QRect(1000, 85, 50, 20)); + spinBox_stopat->setMaximum(9999); + label_input = new QLabel(centralWidget); + label_input->setObjectName(QStringLiteral("label_input")); + label_input->setGeometry(QRect(280, 120, 250, 16)); + label_input->setAlignment(Qt::AlignCenter); + label_img_in = new QLabel(centralWidget); + label_img_in->setObjectName(QStringLiteral("label_img_in")); + label_img_in->setGeometry(QRect(280, 140, 250, 250)); + label_img_in->setFrameShape(QFrame::Box); + label_img_in->setAlignment(Qt::AlignCenter); + label_img_fg = new QLabel(centralWidget); + label_img_fg->setObjectName(QStringLiteral("label_img_fg")); + label_img_fg->setGeometry(QRect(540, 140, 250, 250)); + label_img_fg->setFrameShape(QFrame::Box); + label_img_fg->setAlignment(Qt::AlignCenter); + label_img_bg = new QLabel(centralWidget); + label_img_bg->setObjectName(QStringLiteral("label_img_bg")); + label_img_bg->setGeometry(QRect(800, 140, 250, 250)); + label_img_bg->setFrameShape(QFrame::Box); + label_img_bg->setAlignment(Qt::AlignCenter); + label_foreground = new QLabel(centralWidget); + label_foreground->setObjectName(QStringLiteral("label_foreground")); + label_foreground->setGeometry(QRect(540, 120, 250, 16)); + label_foreground->setAlignment(Qt::AlignCenter); + label_background = new QLabel(centralWidget); + label_background->setObjectName(QStringLiteral("label_background")); + label_background->setGeometry(QRect(800, 120, 250, 16)); + label_background->setAlignment(Qt::AlignCenter); + checkBox_save_im = new QCheckBox(centralWidget); + checkBox_save_im->setObjectName(QStringLiteral("checkBox_save_im")); + checkBox_save_im->setGeometry(QRect(280, 400, 52, 20)); + checkBox_save_fg = new QCheckBox(centralWidget); + checkBox_save_fg->setObjectName(QStringLiteral("checkBox_save_fg")); + checkBox_save_fg->setGeometry(QRect(540, 400, 52, 20)); + checkBox_save_bg = new QCheckBox(centralWidget); + checkBox_save_bg->setObjectName(QStringLiteral("checkBox_save_bg")); + checkBox_save_bg->setGeometry(QRect(800, 400, 52, 20)); + pushButton_stop = new QPushButton(centralWidget); + pushButton_stop->setObjectName(QStringLiteral("pushButton_stop")); + pushButton_stop->setGeometry(QRect(960, 470, 93, 23)); + pushButton_start = new QPushButton(centralWidget); + pushButton_start->setObjectName(QStringLiteral("pushButton_start")); + pushButton_start->setGeometry(QRect(850, 470, 93, 23)); + progressBar = new QProgressBar(centralWidget); + progressBar->setObjectName(QStringLiteral("progressBar")); + progressBar->setGeometry(QRect(280, 470, 550, 23)); + progressBar->setValue(0); + label_exectime = new QLabel(centralWidget); + label_exectime->setObjectName(QStringLiteral("label_exectime")); + label_exectime->setGeometry(QRect(10, 400, 121, 16)); + label_fps_txt = new QLabel(centralWidget); + label_fps_txt->setObjectName(QStringLiteral("label_fps_txt")); + label_fps_txt->setGeometry(QRect(210, 400, 55, 16)); + label_fps_txt->setLayoutDirection(Qt::LeftToRight); + label_fps_txt->setFrameShape(QFrame::Box); + label_fps_txt->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + label_framenumber = new QLabel(centralWidget); + label_framenumber->setObjectName(QStringLiteral("label_framenumber")); + label_framenumber->setGeometry(QRect(10, 420, 121, 16)); + label_framenumber_txt = new QLabel(centralWidget); + label_framenumber_txt->setObjectName(QStringLiteral("label_framenumber_txt")); + label_framenumber_txt->setGeometry(QRect(210, 420, 55, 16)); + label_framenumber_txt->setLayoutDirection(Qt::LeftToRight); + label_framenumber_txt->setFrameShape(QFrame::Box); + label_framenumber_txt->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + label_status = new QLabel(centralWidget); + label_status->setObjectName(QStringLiteral("label_status")); + label_status->setGeometry(QRect(209, 470, 61, 23)); + label_frameres = new QLabel(centralWidget); + label_frameres->setObjectName(QStringLiteral("label_frameres")); + label_frameres->setGeometry(QRect(10, 440, 121, 16)); + label_frameresw_txt = new QLabel(centralWidget); + label_frameresw_txt->setObjectName(QStringLiteral("label_frameresw_txt")); + label_frameresw_txt->setGeometry(QRect(140, 440, 55, 16)); + label_frameresw_txt->setLayoutDirection(Qt::LeftToRight); + label_frameresw_txt->setFrameShape(QFrame::Box); + label_frameresw_txt->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + label_frameresh_txt = new QLabel(centralWidget); + label_frameresh_txt->setObjectName(QStringLiteral("label_frameresh_txt")); + label_frameresh_txt->setGeometry(QRect(210, 440, 55, 16)); + label_frameresh_txt->setLayoutDirection(Qt::LeftToRight); + label_frameresh_txt->setFrameShape(QFrame::Box); + label_frameresh_txt->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + label_frameres_2 = new QLabel(centralWidget); + label_frameres_2->setObjectName(QStringLiteral("label_frameres_2")); + label_frameres_2->setGeometry(QRect(193, 440, 21, 16)); + label_frameres_2->setAlignment(Qt::AlignCenter); + lineEdit_out_in = new QLineEdit(centralWidget); + lineEdit_out_in->setObjectName(QStringLiteral("lineEdit_out_in")); + lineEdit_out_in->setGeometry(QRect(348, 400, 140, 20)); + pushButton_out_in = new QPushButton(centralWidget); + pushButton_out_in->setObjectName(QStringLiteral("pushButton_out_in")); + pushButton_out_in->setGeometry(QRect(490, 400, 40, 20)); + lineEdit_out_fg = new QLineEdit(centralWidget); + lineEdit_out_fg->setObjectName(QStringLiteral("lineEdit_out_fg")); + lineEdit_out_fg->setGeometry(QRect(608, 400, 140, 20)); + pushButton_out_fg = new QPushButton(centralWidget); + pushButton_out_fg->setObjectName(QStringLiteral("pushButton_out_fg")); + pushButton_out_fg->setGeometry(QRect(750, 400, 40, 20)); + pushButton_out_bg = new QPushButton(centralWidget); + pushButton_out_bg->setObjectName(QStringLiteral("pushButton_out_bg")); + pushButton_out_bg->setGeometry(QRect(1010, 400, 40, 20)); + lineEdit_out_bg = new QLineEdit(centralWidget); + lineEdit_out_bg->setObjectName(QStringLiteral("lineEdit_out_bg")); + lineEdit_out_bg->setGeometry(QRect(868, 400, 140, 20)); + checkBox_kfn = new QCheckBox(centralWidget); + checkBox_kfn->setObjectName(QStringLiteral("checkBox_kfn")); + checkBox_kfn->setGeometry(QRect(280, 420, 141, 20)); + checkBox_kfn->setChecked(true); + MainWindow->setCentralWidget(centralWidget); + menuBar = new QMenuBar(MainWindow); + menuBar->setObjectName(QStringLiteral("menuBar")); + menuBar->setGeometry(QRect(0, 0, 1070, 26)); + menuBGSLibrary = new QMenu(menuBar); + menuBGSLibrary->setObjectName(QStringLiteral("menuBGSLibrary")); + MainWindow->setMenuBar(menuBar); + statusBar = new QStatusBar(MainWindow); + statusBar->setObjectName(QStringLiteral("statusBar")); + MainWindow->setStatusBar(statusBar); + + menuBar->addAction(menuBGSLibrary->menuAction()); + menuBGSLibrary->addAction(actionExit); + + retranslateUi(MainWindow); + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "BGSLibrary QT GUI", 0)); + actionExit->setText(QApplication::translate("MainWindow", "Exit", 0)); + label_algorithms->setText(QApplication::translate("MainWindow", "Algorithms", 0)); + label_inputdata->setText(QApplication::translate("MainWindow", "Input (specify a video file or a directory path containing the sequence of images)", 0)); + lineEdit_inputdata->setText(QApplication::translate("MainWindow", "./dataset/video.avi", 0)); + pushButton_inputdata->setText(QApplication::translate("MainWindow", "...", 0)); + checkBox_webcamera->setText(QApplication::translate("MainWindow", "Use web camera", 0)); + checkBox_imageseq->setText(QApplication::translate("MainWindow", "Sequence of images?", 0)); + label_startat->setText(QApplication::translate("MainWindow", "Start at:", 0)); + label_stopat->setText(QApplication::translate("MainWindow", "Stop at:", 0)); + label_input->setText(QApplication::translate("MainWindow", "Input", 0)); + label_img_in->setText(QApplication::translate("MainWindow", "IMG_INPUT", 0)); + label_img_fg->setText(QApplication::translate("MainWindow", "IMG_FOREGROUND", 0)); + label_img_bg->setText(QApplication::translate("MainWindow", "IMG_BACKGROUND", 0)); + label_foreground->setText(QApplication::translate("MainWindow", "Foreground mask", 0)); + label_background->setText(QApplication::translate("MainWindow", "Background model", 0)); + checkBox_save_im->setText(QApplication::translate("MainWindow", "Save", 0)); + checkBox_save_fg->setText(QApplication::translate("MainWindow", "Save", 0)); + checkBox_save_bg->setText(QApplication::translate("MainWindow", "Save", 0)); + pushButton_stop->setText(QApplication::translate("MainWindow", "Stop", 0)); + pushButton_start->setText(QApplication::translate("MainWindow", "Start", 0)); + label_exectime->setText(QApplication::translate("MainWindow", "Estimated FPS:", 0)); + label_fps_txt->setText(QApplication::translate("MainWindow", "0", 0)); + label_framenumber->setText(QApplication::translate("MainWindow", "Frame number:", 0)); + label_framenumber_txt->setText(QApplication::translate("MainWindow", "0", 0)); + label_status->setText(QApplication::translate("MainWindow", "Progress:", 0)); + label_frameres->setText(QApplication::translate("MainWindow", "Frame resolution:", 0)); + label_frameresw_txt->setText(QApplication::translate("MainWindow", "0", 0)); + label_frameresh_txt->setText(QApplication::translate("MainWindow", "0", 0)); + label_frameres_2->setText(QApplication::translate("MainWindow", "x", 0)); + lineEdit_out_in->setText(QApplication::translate("MainWindow", "./output/in/", 0)); + pushButton_out_in->setText(QApplication::translate("MainWindow", "...", 0)); + lineEdit_out_fg->setText(QApplication::translate("MainWindow", "./output/fg/", 0)); + pushButton_out_fg->setText(QApplication::translate("MainWindow", "...", 0)); + pushButton_out_bg->setText(QApplication::translate("MainWindow", "...", 0)); + lineEdit_out_bg->setText(QApplication::translate("MainWindow", "./output/bg/", 0)); + checkBox_kfn->setText(QApplication::translate("MainWindow", "Keep frame number", 0)); + menuBGSLibrary->setTitle(QApplication::translate("MainWindow", "BGSLibrary", 0)); + } // retranslateUi + +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAINWINDOW_H diff --git a/output/bg/.gitignore b/output/bg/.gitignore new file mode 100644 index 0000000..4e2a98b --- /dev/null +++ b/output/bg/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore diff --git a/output/fg/.gitignore b/output/fg/.gitignore new file mode 100644 index 0000000..4e2a98b --- /dev/null +++ b/output/fg/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore diff --git a/output/in/.gitignore b/output/in/.gitignore new file mode 100644 index 0000000..4e2a98b --- /dev/null +++ b/output/in/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore diff --git a/package_bgs/tb/PerformanceUtils.cpp b/package_analysis/PerformanceUtils.cpp similarity index 59% rename from package_bgs/tb/PerformanceUtils.cpp rename to package_analysis/PerformanceUtils.cpp index 0d7cf77..6ad5e5f 100644 --- a/package_bgs/tb/PerformanceUtils.cpp +++ b/package_analysis/PerformanceUtils.cpp @@ -15,15 +15,16 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "PerformanceUtils.h" -#include <opencv2/legacy/compat.hpp> +//#include <opencv2/legacy/compat.hpp> +//#include <opencv2/highgui/highgui_c.h> -PerformanceUtils::PerformanceUtils(void){} +PerformanceUtils::PerformanceUtils(void) {} -PerformanceUtils::~PerformanceUtils(void){} +PerformanceUtils::~PerformanceUtils(void) {} float PerformanceUtils::NrPixels(IplImage *image) { - return (float) (image->width * image->height); + return (float)(image->width * image->height); } float PerformanceUtils::NrAllDetectedPixNotNULL(IplImage *image, IplImage *ground_truth) @@ -31,19 +32,19 @@ float PerformanceUtils::NrAllDetectedPixNotNULL(IplImage *image, IplImage *groun //Nombre de tous les pixels non nuls dans Groundthruth et dans image float Union12 = 0.0; - unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char*)malloc(1 * sizeof(unsigned char)); PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) - { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + for (int x = 0; x < image->width; x++) + { + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] != 0) || (pixelI[0] != 0)) + if ((pixelGT[0] != 0) || (pixelI[0] != 0)) Union12++; } } @@ -51,44 +52,44 @@ float PerformanceUtils::NrAllDetectedPixNotNULL(IplImage *image, IplImage *groun free(pixelGT); free(pixelI); - return Union12; + return Union12; } float PerformanceUtils::NrTruePositives(IplImage *image, IplImage *ground_truth, bool debug) { float nTP = 0.0; - unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char*)malloc(1 * sizeof(unsigned char)); IplImage *TPimage = 0; - if(debug) + if (debug) { - TPimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels); - cvFillImage(TPimage,0.0); + TPimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); + cvSetZero(TPimage); } PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) - { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + for (int x = 0; x < image->width; x++) + { + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] != 0) && (pixelI[0] != 0)) + if ((pixelGT[0] != 0) && (pixelI[0] != 0)) { - if(debug) - p.PutGrayPixel(TPimage,x,y,*pixelI); + if (debug) + p.PutGrayPixel(TPimage, x, y, *pixelI); nTP++; } } } - if(debug) + if (debug) { cvNamedWindow("TPImage", 0); cvShowImage("TPImage", TPimage); @@ -101,46 +102,46 @@ float PerformanceUtils::NrTruePositives(IplImage *image, IplImage *ground_truth, free(pixelGT); free(pixelI); - return nTP; + return nTP; } float PerformanceUtils::NrTrueNegatives(IplImage* image, IplImage* ground_truth, bool debug) { float nTN = 0.0; - unsigned char *pixelGT = (unsigned char *)malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char *)malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char *)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char *)malloc(1 * sizeof(unsigned char)); IplImage *TNimage = 0; - if(debug) + if (debug) { - TNimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels); - cvFillImage(TNimage, 0.0); + TNimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); + cvSetZero(TNimage); } PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) + for (int x = 0; x < image->width; x++) { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] == 0) && (pixelI[0] == 0.0)) + if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) { *pixelI = 255; - if(debug) - p.PutGrayPixel(TNimage,x,y,*pixelI); + if (debug) + p.PutGrayPixel(TNimage, x, y, *pixelI); nTN++; - } + } } } - if(debug) + if (debug) { cvNamedWindow("TNImage", 0); cvShowImage("TNImage", TNimage); @@ -156,41 +157,41 @@ float PerformanceUtils::NrTrueNegatives(IplImage* image, IplImage* ground_truth, return nTN; } -float PerformanceUtils::NrFalsePositives(IplImage *image, IplImage *ground_truth,bool debug) +float PerformanceUtils::NrFalsePositives(IplImage *image, IplImage *ground_truth, bool debug) { float nFP = 0.0; - unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char*)malloc(1 * sizeof(unsigned char)); IplImage *FPimage = 0; - if(debug) + if (debug) { - FPimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels); - cvFillImage(FPimage, 0.0); + FPimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); + cvSetZero(FPimage); } PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) + for (int x = 0; x < image->width; x++) { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] == 0) && (pixelI[0] != 0)) + if ((pixelGT[0] == 0) && (pixelI[0] != 0)) { - if(debug) - p.PutGrayPixel(FPimage,x,y,*pixelI); + if (debug) + p.PutGrayPixel(FPimage, x, y, *pixelI); nFP++; } } } - if(debug) + if (debug) { cvNamedWindow("FPImage", 0); cvShowImage("FPImage", FPimage); @@ -203,44 +204,44 @@ float PerformanceUtils::NrFalsePositives(IplImage *image, IplImage *ground_truth free(pixelGT); free(pixelI); - return nFP; + return nFP; } float PerformanceUtils::NrFalseNegatives(IplImage * image, IplImage *ground_truth, bool debug) { float nFN = 0.0; - unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char*)malloc(1 * sizeof(unsigned char)); IplImage *FNimage = 0; - if(debug) + if (debug) { - FNimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels); - cvFillImage(FNimage, 0.0); + FNimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); + cvSetZero(FNimage); } PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) + for (int x = 0; x < image->width; x++) { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] != 0) && (pixelI[0] == 0)) + if ((pixelGT[0] != 0) && (pixelI[0] == 0)) { - if(debug) - p.PutGrayPixel(FNimage,x,y,*pixelGT); + if (debug) + p.PutGrayPixel(FNimage, x, y, *pixelGT); nFN++; } } } - if(debug) + if (debug) { cvNamedWindow("FNImage", 0); cvShowImage("FNImage", FNimage); @@ -253,19 +254,19 @@ float PerformanceUtils::NrFalseNegatives(IplImage * image, IplImage *ground_trut free(pixelGT); free(pixelI); - return nFN; + return nFN; } float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug) { - cv::Mat img_input(image,true); - cv::Mat img_ref(ground_truth,true); + cv::Mat img_input = cv::cvarrToMat(image, true); + cv::Mat img_ref = cv::cvarrToMat(ground_truth, true); int rn = cv::countNonZero(img_ref); cv::Mat i; cv::Mat u; - if(rn > 0) + if (rn > 0) { i = img_input & img_ref; u = img_input | img_ref; @@ -278,16 +279,16 @@ float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_trut int in = cv::countNonZero(i); int un = cv::countNonZero(u); - + double s = (((double)in) / ((double)un)); - - if(debug) + + if (debug) { cv::imshow("A^B", i); cv::imshow("AvB", u); //std::cout << "Similarity Measure: " << s << std::endl; - + //<< " press ENTER to continue" << std::endl; //cv::waitKey(0); } @@ -295,45 +296,45 @@ float PerformanceUtils::SimilarityMeasure(IplImage *image, IplImage *ground_trut return s; } -void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults, char* filename) +void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults, std::string filename) { - unsigned char *pixelGT = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelI = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelGT = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelI = (unsigned char*)malloc(1 * sizeof(unsigned char)); - IplImage *ROCimage = cvCreateImage(cvSize(image->width,image->height),image->depth,image->nChannels); - cvFillImage(ROCimage, 0.0); + IplImage *ROCimage = cvCreateImage(cvSize(image->width, image->height), image->depth, image->nChannels); + cvSetZero(ROCimage); PixelUtils p; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) + for (int x = 0; x < image->width; x++) { - p.GetGrayPixel(ground_truth,x,y,pixelGT); - p.GetGrayPixel(image,x,y,pixelI); + p.GetGrayPixel(ground_truth, x, y, pixelGT); + p.GetGrayPixel(image, x, y, pixelI); - if((pixelGT[0] != 0) && (pixelI[0] != 0)) // TP + if ((pixelGT[0] != 0) && (pixelI[0] != 0)) // TP { *pixelI = 30; - p.PutGrayPixel(ROCimage,x,y,*pixelI); + p.PutGrayPixel(ROCimage, x, y, *pixelI); } - if((pixelGT[0] == 0) && (pixelI[0] == 0.0)) // TN + if ((pixelGT[0] == 0) && (pixelI[0] == 0.0)) // TN { *pixelI = 0; - p.PutGrayPixel(ROCimage,x,y,*pixelI); - } + p.PutGrayPixel(ROCimage, x, y, *pixelI); + } - if((pixelGT[0] == 0) && (pixelI[0] != 0)) // FP + if ((pixelGT[0] == 0) && (pixelI[0] != 0)) // FP { *pixelI = 255; - p.PutGrayPixel(ROCimage,x,y,*pixelI); + p.PutGrayPixel(ROCimage, x, y, *pixelI); } - if((pixelGT[0] != 0) && (pixelI[0] == 0)) // FN + if ((pixelGT[0] != 0) && (pixelI[0] == 0)) // FN { *pixelI = 100; - p.PutGrayPixel(ROCimage,x,y,*pixelI); + p.PutGrayPixel(ROCimage, x, y, *pixelI); } } } @@ -341,10 +342,10 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa cvNamedWindow("ROC image", 0); cvShowImage("ROC image", ROCimage); - if(saveResults) + if (saveResults) { - unsigned char *pixelOI = (unsigned char*) malloc(1*sizeof(unsigned char)); - unsigned char *pixelROC = (unsigned char*) malloc(1*sizeof(unsigned char)); + unsigned char *pixelOI = (unsigned char*)malloc(1 * sizeof(unsigned char)); + unsigned char *pixelROC = (unsigned char*)malloc(1 * sizeof(unsigned char)); float** freq; float nTP = 0.0; @@ -352,45 +353,45 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa float nFP = 0.0; float nFN = 0.0; - freq = (float**) malloc(256*(sizeof(float*))); - for(int i = 0; i < 256; i++) - freq[i] = (float*) malloc(7 * (sizeof(float))); + freq = (float**)malloc(256 * (sizeof(float*))); + for (int i = 0; i < 256; i++) + freq[i] = (float*)malloc(7 * (sizeof(float))); - for(int i = 0; i < 256; i++) - for(int j = 0; j < 6; j++) + for (int i = 0; i < 256; i++) + for (int j = 0; j < 6; j++) freq[i][j] = 0.0; - for(int y = 0; y < image->height; y++) + for (int y = 0; y < image->height; y++) { - for(int x = 0; x < image->width; x++) + for (int x = 0; x < image->width; x++) { - for(int i = 0; i < 256; i++) + for (int i = 0; i < 256; i++) { - p.GetGrayPixel(image,x,y,pixelOI); - p.GetGrayPixel(ROCimage,x,y,pixelROC); + p.GetGrayPixel(image, x, y, pixelOI); + p.GetGrayPixel(ROCimage, x, y, pixelROC); - if((pixelOI[0] == i) && (pixelROC[0] == 30.0)) // TP + if ((pixelOI[0] == i) && (pixelROC[0] == 30.0)) // TP { nTP++; freq[i][0] = nTP; break; } - if((pixelOI[0] == i) && (pixelROC[0] == 0.0)) // TN + if ((pixelOI[0] == i) && (pixelROC[0] == 0.0)) // TN { nTN++; freq[i][1] = nTN; break; } - if((pixelOI[0] == i) && (pixelROC[0] == 255.0)) // FP + if ((pixelOI[0] == i) && (pixelROC[0] == 255.0)) // FP { nFP++; freq[i][2] = nFP; break; } - if((pixelOI[0] == i) && (pixelROC[0] == 100)) // FN + if ((pixelOI[0] == i) && (pixelROC[0] == 100)) // FN { nFN++; freq[i][3] = nFN; @@ -409,17 +410,17 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa std::ofstream f(filename); - if(!f.is_open()) + if (!f.is_open()) std::cout << "Failed to open file " << filename << " for writing!" << std::endl; else { f << " I TP TN FP FN FPR FNR DR \n" << std::endl; - - for(int i = 0; i < 256; i++) + + for (int i = 0; i < 256; i++) { //printf("%4d - TP:%5.0f, TN:%5.0f, FP:%5.0f, FN:%5.0f,", i, freq[i][0], freq[i][1], freq[i][2], freq[i][3]); - if((freq[i][3] + freq[i][0] != 0.0) && (freq[i][2] + freq[i][1] != 0.0)) + if ((freq[i][3] + freq[i][0] != 0.0) && (freq[i][2] + freq[i][1] != 0.0)) { freq[i][4] = freq[i][3] / (freq[i][3] + freq[i][0]); // FNR = FN / (TP + FN); freq[i][5] = freq[i][2] / (freq[i][2] + freq[i][1]); // FPR = FP / (FP + TN); @@ -429,12 +430,12 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa ////fprintf(f," %4d %1.6f %1.6f\n",i,freq[i][5],freq[i][4]); ////fprintf(f," %1.6f %1.6f\n",freq[i][5],freq[i][4]); char line[255]; - sprintf(line,"%3d %6.0f %6.0f %6.0f %6.0f %1.6f %1.6f %1.6f\n", + sprintf(line, "%3d %6.0f %6.0f %6.0f %6.0f %1.6f %1.6f %1.6f\n", i, freq[i][0], freq[i][1], freq[i][2], freq[i][3], freq[i][5], freq[i][4], freq[i][6]); f << line; } //else - //printf("\n"); + //printf("\n"); } std::cout << "Results saved in " << filename << std::endl; @@ -454,36 +455,36 @@ void PerformanceUtils::ImageROC(IplImage *image, IplImage* ground_truth, bool sa free(pixelI); } -void PerformanceUtils::PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults, char* filename, bool debug) +void PerformanceUtils::PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults, std::string filename, bool debug) { float N = 0; N = NrPixels(image); float U = 0; U = NrAllDetectedPixNotNULL(image, ground_truth); - + float TP = 0; TP = NrTruePositives(image, ground_truth, debug); - + float TN = 0; TN = NrTrueNegatives(image, ground_truth, debug); - + float FP = 0; FP = NrFalsePositives(image, ground_truth, debug); - + float FN = 0; FN = NrFalseNegatives(image, ground_truth, debug); - + float DetectionRate = TP / (TP + FN); float Precision = TP / (TP + FP); float Fmeasure = (2 * DetectionRate * Precision) / (DetectionRate + Precision); float Accuracy = (TN + TP) / N; float FalseNegativeRate = FN / (TP + FN); - + float FalsePositiveRate = FP / (FP + TN); float TruePositiveRate = TP / (TP + FN); - + float SM = 0; SM = SimilarityMeasure(image, ground_truth, debug); @@ -506,11 +507,11 @@ void PerformanceUtils::PerformanceEvaluation(IplImage *image, IplImage *ground_t std::string results = sstm.str(); std::cout << results; - if(saveResults) + if (saveResults) { std::ofstream f(filename); - if(!f.is_open()) + if (!f.is_open()) std::cout << "Failed to open file " << filename << " for writing!" << std::endl; else { diff --git a/package_bgs/tb/PerformanceUtils.h b/package_analysis/PerformanceUtils.h similarity index 82% rename from package_bgs/tb/PerformanceUtils.h rename to package_analysis/PerformanceUtils.h index 9257098..4be392f 100644 --- a/package_bgs/tb/PerformanceUtils.h +++ b/package_analysis/PerformanceUtils.h @@ -15,23 +15,11 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -/* -Code provided by Thierry BOUWMANS - -Maitre de Conf�rences -Laboratoire MIA -Universit� de La Rochelle -17000 La Rochelle -France -tbouwman@univ-lr.fr -http://sites.google.com/site/thierrybouwmans/ -*/ #include <stdio.h> #include <fstream> #include <opencv2/opencv.hpp> - #include "PixelUtils.h" class PerformanceUtils @@ -48,7 +36,7 @@ public: float NrFalseNegatives(IplImage *image, IplImage *ground_truth, bool debug = false); float SimilarityMeasure(IplImage *image, IplImage *ground_truth, bool debug = false); - void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, char* filename = ""); - void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, char* filename = "", bool debug = false); + void ImageROC(IplImage *image, IplImage* ground_truth, bool saveResults = false, std::string filename = ""); + void PerformanceEvaluation(IplImage *image, IplImage *ground_truth, bool saveResults = false, std::string filename = "", bool debug = false); }; diff --git a/package_analysis/PixelUtils.cpp b/package_analysis/PixelUtils.cpp new file mode 100644 index 0000000..adce122 --- /dev/null +++ b/package_analysis/PixelUtils.cpp @@ -0,0 +1,351 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "PixelUtils.h" + +PixelUtils::PixelUtils(void) {} +PixelUtils::~PixelUtils(void) {} + +void PixelUtils::ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space) +{ + // Space Color RGB - Nothing to do! + if (color_space == 1) + cvCopy(RGBImage, ConvertedImage); + + // Space Color Ohta + if (color_space == 2) + cvttoOTHA(RGBImage, ConvertedImage); + + // Space Color HSV - V Intensity - (H,S) Chromaticity + if (color_space == 3) + cvCvtColor(RGBImage, ConvertedImage, CV_BGR2HSV); + + // Space Color YCrCb - Y Intensity - (Cr,Cb) Chromaticity + if (color_space == 4) + cvCvtColor(RGBImage, ConvertedImage, CV_BGR2YCrCb); +} + +void PixelUtils::cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage) +{ + float* OhtaPixel = (float*)malloc(3 * (sizeof(float))); + float* RGBPixel = (float*)malloc(3 * (sizeof(float))); + + for (int i = 0; i < RGBImage->width; i++) + { + for (int j = 0; j < RGBImage->height; j++) + { + GetPixel(RGBImage, i, j, RGBPixel); + + // I1 = (R + G + B) / 3 + *OhtaPixel = (*(RGBPixel)+(*(RGBPixel + 1)) + (*(RGBPixel + 2))) / 3.0; + + // I2 = (R - B) / 2 + *(OhtaPixel + 1) = (*RGBPixel - (*(RGBPixel + 2))) / 2.0; + + // I3 = (2G - R - B) / 4 + *(OhtaPixel + 2) = (2 * (*(RGBPixel + 1)) - (*RGBPixel) - (*(RGBPixel + 2))) / 4.0; + + PutPixel(OthaImage, i, j, OhtaPixel); + } + } + + free(OhtaPixel); + free(RGBPixel); +} + +void PixelUtils::PostProcessing(IplImage *InputImage) +{ + IplImage *ResultImage = cvCreateImage(cvSize(InputImage->width, InputImage->height), IPL_DEPTH_32F, 3); + + cvErode(InputImage, ResultImage, NULL, 1); + cvDilate(ResultImage, InputImage, NULL, 0); + + cvReleaseImage(&ResultImage); +} + +void PixelUtils::GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant) +{ + for (int k = 0; k < 3; k++) + pixelcourant[k] = ((unsigned char*)(image->imageData + image->widthStep*n))[m * 3 + k]; +} + +void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant) +{ + *pixelcourant = ((unsigned char*)(image->imageData + image->widthStep*n))[m]; +} + +void PixelUtils::PutPixel(IplImage *image, int p, int q, unsigned char *pixelcourant) +{ + for (int r = 0; r < 3; r++) + ((unsigned char*)(image->imageData + image->widthStep*q))[p * 3 + r] = pixelcourant[r]; +} + +void PixelUtils::PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant) +{ + ((unsigned char*)(image->imageData + image->widthStep*q))[p] = pixelcourant; +} + +void PixelUtils::GetPixel(IplImage *image, int m, int n, float *pixelcourant) +{ + for (int k = 0; k < 3; k++) + pixelcourant[k] = ((float*)(image->imageData + image->widthStep*n))[m * 3 + k]; +} + +void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant) +{ + *pixelcourant = ((float*)(image->imageData + image->widthStep*n))[m]; +} + +void PixelUtils::PutPixel(IplImage *image, int p, int q, float *pixelcourant) +{ + for (int r = 0; r < 3; r++) + ((float*)(image->imageData + image->widthStep*q))[p * 3 + r] = pixelcourant[r]; +} + +void PixelUtils::PutGrayPixel(IplImage *image, int p, int q, float pixelcourant) +{ + ((float*)(image->imageData + image->widthStep*q))[p] = pixelcourant; +} + +void PixelUtils::getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel) +{ + int i, j, k; + + float* pixelCourant = (float*)malloc(1 * (sizeof(float))); + + //le calcul de voisinage pour les 4 coins; + /* 1.*/ + if (x == 0 && y == 0) + { + k = 0; + for (i = x; i < x + 2; i++) + for (j = y; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + /* 2.*/ + if (x == 0 && y == InputImage->width) + { + k = 0; + for (i = x; i < x + 2; i++) + for (j = y - 1; j < y + 1; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + /* 3.*/ + if (x == InputImage->height && y == 0) + { + k = 0; + for (i = x - 1; i < x + 1; i++) + for (j = y; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + /* 4.*/ + if (x == InputImage->height && y == InputImage->width) + { + k = 0; + for (i = x - 1; i < x + 1; i++) + for (j = y - 1; j < y + 1; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + // Voisinage de la premiere ligne : L(0) + if (x == 0 && (y != 0 && y != InputImage->width)) + { + k = 0; + for (i = x + 1; i >= x; i--) + for (j = y - 1; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + // Voisinage de la dernière colonne : C(w) + if ((x != 0 && x != InputImage->height) && y == InputImage->width) + { + k = 0; + for (i = x + 1; i > x - 2; i--) + for (j = y - 1; j < y + 1; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + // Voisinage de la dernière ligne : L(h) + if (x == InputImage->height && (y != 0 && y != InputImage->width)) + { + k = 0; + for (i = x; i > x - 2; i--) + for (j = y - 1; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + // Voisinage de la premiere colonne : C(0) + if ((x != 0 && x != InputImage->height) && y == 0) + { + k = 0; + for (i = x - 1; i < x + 2; i++) + for (j = y; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + //le calcul du voisinage pour le reste des elementes d'image + if ((x != 0 && x != InputImage->height) && (y != 0 && y != InputImage->width)) + { + k = 0; + for (i = x + 1; i > x - 2; i--) + for (j = y - 1; j < y + 2; j++) + { + GetGrayPixel(InputImage, i, j, pixelCourant); + *(neighberPixel + k) = *pixelCourant; + k++; + } + } + + free(pixelCourant); +} + +void PixelUtils::ForegroundMinimum(IplImage *Foreground, float *Minimum, int n) +{ + int i, j, k; + float *pixelcourant; + + pixelcourant = (float *)malloc(n * sizeof(float)); + + for (k = 0; k < n; k++) + *(Minimum + k) = 255; + + for (i = 0; i < Foreground->width; i++) + for (j = 0; j < Foreground->height; j++) + { + if (n == 3) + { + GetPixel(Foreground, i, j, pixelcourant); + + for (k = 0; k < n; k++) + if (*(pixelcourant + k) < *(Minimum + k)) + *(Minimum + k) = *(pixelcourant + k); + } + + if (n == 1) + { + GetGrayPixel(Foreground, i, j, pixelcourant); + + if (*pixelcourant < *Minimum) + *Minimum = *pixelcourant; + } + } + + free(pixelcourant); +} + +void PixelUtils::ForegroundMaximum(IplImage *Foreground, float *Maximum, int n) +{ + int i, j, k; + float *pixelcourant; + + pixelcourant = (float *)malloc(n * sizeof(float)); + + for (k = 0; k < n; k++) + *(Maximum + k) = 0; + + for (i = 0; i < Foreground->width; i++) + for (j = 0; j < Foreground->height; j++) + { + if (n == 3) + { + GetPixel(Foreground, i, j, pixelcourant); + + for (k = 0; k < n; k++) + if (*(pixelcourant + k) > *(Maximum + k)) + *(Maximum + k) = *(pixelcourant + k); + } + + if (n == 1) + { + GetGrayPixel(Foreground, i, j, pixelcourant); + + if (*pixelcourant > *Maximum) + *Maximum = *pixelcourant; + } + } + + free(pixelcourant); +} + +void PixelUtils::ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n) +{ + int i, j, k; + float *pixelcourant, *pixelcourant1; + + pixelcourant = (float *)malloc(n * sizeof(float)); + pixelcourant1 = (float *)malloc(n * sizeof(float)); + + for (i = 0; i < AlphaImage->width; i++) + for (j = 0; j < AlphaImage->height; j++) + { + if (n == 1) + { + GetGrayPixel(AlphaImage, i, j, pixelcourant); + *pixelcourant1 = 1 - *(pixelcourant); + PutGrayPixel(ComplementaryAlphaImage, i, j, *pixelcourant1); + } + + if (n == 3) + { + GetPixel(AlphaImage, i, j, pixelcourant); + for (k = 0; k < 3; k++) + { + *pixelcourant1 = 1.0 - *(pixelcourant); + *(pixelcourant1 + 1) = 1.0 - *(pixelcourant + 1); + *(pixelcourant1 + 2) = 1.0 - *(pixelcourant + 2); + } + PutPixel(ComplementaryAlphaImage, i, j, pixelcourant1); + } + } + + free(pixelcourant); + free(pixelcourant1); +} diff --git a/package_bgs/tb/PixelUtils.h b/package_analysis/PixelUtils.h similarity index 90% rename from package_bgs/tb/PixelUtils.h rename to package_analysis/PixelUtils.h index a2d3a4a..0e35c40 100644 --- a/package_bgs/tb/PixelUtils.h +++ b/package_analysis/PixelUtils.h @@ -15,22 +15,10 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -/* -Code provided by Thierry BOUWMANS - -Maitre de Conf�rences -Laboratoire MIA -Universit� de La Rochelle -17000 La Rochelle -France -tbouwman@univ-lr.fr -http://sites.google.com/site/thierrybouwmans/ -*/ #include <stdio.h> #include <opencv2/opencv.hpp> - class PixelUtils { public: @@ -39,9 +27,9 @@ public: void ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space); void cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage); - + void PostProcessing(IplImage *InputImage); - + void GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); void GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant); @@ -58,4 +46,4 @@ public: void ForegroundMaximum(IplImage *Foreground, float *Maximum, int n); void ForegroundMinimum(IplImage *Foreground, float *Minimum, int n); void ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n); -}; \ No newline at end of file +}; diff --git a/package_bgs/AdaptiveBackgroundLearning.cpp b/package_bgs/AdaptiveBackgroundLearning.cpp index b111e65..d2cb8a0 100644 --- a/package_bgs/AdaptiveBackgroundLearning.cpp +++ b/package_bgs/AdaptiveBackgroundLearning.cpp @@ -16,10 +16,14 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "AdaptiveBackgroundLearning.h" -AdaptiveBackgroundLearning::AdaptiveBackgroundLearning() : firstTime(true), alpha(0.05), limit(-1), counter(0), minVal(0.0), maxVal(1.0), - enableThreshold(true), threshold(15), showForeground(true), showBackground(true) +using namespace bgslibrary::algorithms; + +AdaptiveBackgroundLearning::AdaptiveBackgroundLearning() : + alpha(0.05), limit(-1), counter(0), minVal(0.0), maxVal(1.0), + enableThreshold(true), threshold(15) { std::cout << "AdaptiveBackgroundLearning()" << std::endl; + setup("./config/AdaptiveBackgroundLearning.xml"); } AdaptiveBackgroundLearning::~AdaptiveBackgroundLearning() @@ -29,52 +33,48 @@ AdaptiveBackgroundLearning::~AdaptiveBackgroundLearning() void AdaptiveBackgroundLearning::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); - if(img_background.empty()) + if (img_background.empty()) img_input.copyTo(img_background); cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1./255.); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); cv::Mat img_background_f(img_background.size(), CV_32F); - img_background.convertTo(img_background_f, CV_32F, 1./255.); + img_background.convertTo(img_background_f, CV_32F, 1. / 255.); cv::Mat img_diff_f(img_input.size(), CV_32F); cv::absdiff(img_input_f, img_background_f, img_diff_f); - if((limit > 0 && limit < counter) || limit == -1) + if ((limit > 0 && limit < counter) || limit == -1) { - img_background_f = alpha*img_input_f + (1-alpha)*img_background_f; - + img_background_f = alpha*img_input_f + (1 - alpha)*img_background_f; + cv::Mat img_new_background(img_input.size(), CV_8U); - img_background_f.convertTo(img_new_background, CV_8U, 255.0/(maxVal - minVal), -minVal); + img_background_f.convertTo(img_new_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); img_new_background.copyTo(img_background); - if(limit > 0 && limit < counter) + if (limit > 0 && limit < counter) counter++; } - - cv::Mat img_foreground(img_input.size(), CV_8U); - img_diff_f.convertTo(img_foreground, CV_8U, 255.0/(maxVal - minVal), -minVal); - if(img_foreground.channels() == 3) + //cv::Mat img_foreground(img_input.size(), CV_8U); + img_diff_f.convertTo(img_foreground, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); + + if (img_foreground.channels() == 3) cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - - if(showForeground) - cv::imshow("A-Learning FG", img_foreground); - if(showBackground) +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + cv::imshow("A-Learning FG", img_foreground); cv::imshow("A-Learning BG", img_background); + } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -84,28 +84,26 @@ void AdaptiveBackgroundLearning::process(const cv::Mat &img_input, cv::Mat &img_ void AdaptiveBackgroundLearning::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveBackgroundLearning.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), 0, CV_STORAGE_WRITE); cvWriteReal(fs, "alpha", alpha); cvWriteInt(fs, "limit", limit); cvWriteInt(fs, "enableThreshold", enableThreshold); cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showForeground", showForeground); - cvWriteInt(fs, "showBackground", showBackground); + cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); } void AdaptiveBackgroundLearning::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveBackgroundLearning.xml", 0, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, 0, "alpha", 0.05); - limit = cvReadIntByName(fs, 0, "limit", -1); - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showForeground = cvReadIntByName(fs, 0, "showForeground", true); - showBackground = cvReadIntByName(fs, 0, "showBackground", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); + limit = cvReadIntByName(fs, nullptr, "limit", -1); + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/AdaptiveBackgroundLearning.h b/package_bgs/AdaptiveBackgroundLearning.h index 4bbac54..3cfc686 100644 --- a/package_bgs/AdaptiveBackgroundLearning.h +++ b/package_bgs/AdaptiveBackgroundLearning.h @@ -16,35 +16,32 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - #include "IBGS.h" -class AdaptiveBackgroundLearning : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Mat img_background; - double alpha; - long limit; - long counter; - double minVal; - double maxVal; - bool enableThreshold; - int threshold; - bool showForeground; - bool showBackground; - -public: - AdaptiveBackgroundLearning(); - ~AdaptiveBackgroundLearning(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class AdaptiveBackgroundLearning : public IBGS + { + private: + double alpha; + long limit; + long counter; + double minVal; + double maxVal; + bool enableThreshold; + int threshold; + + public: + AdaptiveBackgroundLearning(); + ~AdaptiveBackgroundLearning(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp b/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp index cd3e7d3..2f6f9fe 100644 --- a/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp +++ b/package_bgs/AdaptiveSelectiveBackgroundLearning.cpp @@ -16,11 +16,14 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "AdaptiveSelectiveBackgroundLearning.h" -AdaptiveSelectiveBackgroundLearning::AdaptiveSelectiveBackgroundLearning() : firstTime(true), -alphaLearn(0.05), alphaDetection(0.05), learningFrames(-1), counter(0), minVal(0.0), maxVal(1.0), -threshold(15), showOutput(true) +using namespace bgslibrary::algorithms; + +AdaptiveSelectiveBackgroundLearning::AdaptiveSelectiveBackgroundLearning() : + alphaLearn(0.05), alphaDetection(0.05), learningFrames(-1), counter(0), minVal(0.0), maxVal(1.0), + threshold(15) { std::cout << "AdaptiveSelectiveBackgroundLearning()" << std::endl; + setup("./config/AdaptiveSelectiveBackgroundLearning.xml"); } AdaptiveSelectiveBackgroundLearning::~AdaptiveSelectiveBackgroundLearning() @@ -30,8 +33,7 @@ AdaptiveSelectiveBackgroundLearning::~AdaptiveSelectiveBackgroundLearning() void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input_.empty()) - return; + init(img_input_, img_output, img_bgmodel); cv::Mat img_input; if (img_input_.channels() == 3) @@ -39,24 +41,19 @@ void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv: else img_input_.copyTo(img_input); - loadConfig(); - - if(firstTime) - saveConfig(); - - if(img_background.empty()) + if (img_background.empty()) img_input.copyTo(img_background); cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1./255.); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); cv::Mat img_background_f(img_background.size(), CV_32F); - img_background.convertTo(img_background_f, CV_32F, 1./255.); + img_background.convertTo(img_background_f, CV_32F, 1. / 255.); cv::Mat img_diff_f(img_input.size(), CV_32F); cv::absdiff(img_input_f, img_background_f, img_diff_f); - cv::Mat img_foreground(img_input.size(), CV_8U); + //cv::Mat img_foreground(img_input.size(), CV_8U); img_diff_f.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal); cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); @@ -88,15 +85,17 @@ void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv: } } - cv::Mat img_new_background(img_input.size(), CV_8U); - img_background_f.convertTo(img_new_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); - img_new_background.copyTo(img_background); - - if(showOutput) + //cv::Mat img_new_background(img_input.size(), CV_8U); + img_background_f.convertTo(img_background, CV_8UC1, 255.0 / (maxVal - minVal), -minVal); + //img_new_background.copyTo(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("AS-Learning FG", img_foreground); cv::imshow("AS-Learning BG", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -106,7 +105,7 @@ void AdaptiveSelectiveBackgroundLearning::process(const cv::Mat &img_input_, cv: void AdaptiveSelectiveBackgroundLearning::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveSelectiveBackgroundLearning.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "learningFrames", learningFrames); cvWriteReal(fs, "alphaLearn", alphaLearn); @@ -119,13 +118,13 @@ void AdaptiveSelectiveBackgroundLearning::saveConfig() void AdaptiveSelectiveBackgroundLearning::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/AdaptiveSelectiveBackgroundLearning.xml", 0, CV_STORAGE_READ); - - learningFrames = cvReadIntByName(fs, 0, "learningFrames", 90); - alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.05); - alphaDetection = cvReadRealByName(fs, 0, "alphaDetection", 0.05); - threshold = cvReadIntByName(fs, 0, "threshold", 25); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), 0, CV_STORAGE_READ); + + learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 90); + alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.05); + alphaDetection = cvReadRealByName(fs, nullptr, "alphaDetection", 0.05); + threshold = cvReadIntByName(fs, nullptr, "threshold", 25); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/AdaptiveSelectiveBackgroundLearning.h b/package_bgs/AdaptiveSelectiveBackgroundLearning.h index 2276747..24da44c 100644 --- a/package_bgs/AdaptiveSelectiveBackgroundLearning.h +++ b/package_bgs/AdaptiveSelectiveBackgroundLearning.h @@ -16,34 +16,32 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - #include "IBGS.h" -class AdaptiveSelectiveBackgroundLearning : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Mat img_background; - double alphaLearn; - double alphaDetection; - long learningFrames; - long counter; - double minVal; - double maxVal; - int threshold; - bool showOutput; - -public: - AdaptiveSelectiveBackgroundLearning(); - ~AdaptiveSelectiveBackgroundLearning(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class AdaptiveSelectiveBackgroundLearning : public IBGS + { + private: + double alphaLearn; + double alphaDetection; + long learningFrames; + long counter; + double minVal; + double maxVal; + int threshold; + + public: + AdaptiveSelectiveBackgroundLearning(); + ~AdaptiveSelectiveBackgroundLearning(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/DPAdaptiveMedian.cpp b/package_bgs/DPAdaptiveMedian.cpp new file mode 100644 index 0000000..0885580 --- /dev/null +++ b/package_bgs/DPAdaptiveMedian.cpp @@ -0,0 +1,110 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "DPAdaptiveMedian.h" + +using namespace bgslibrary::algorithms; + +DPAdaptiveMedian::DPAdaptiveMedian() : + frameNumber(0), threshold(40), samplingRate(7), learningFrames(30) +{ + std::cout << "DPAdaptiveMedian()" << std::endl; + setup("./config/DPAdaptiveMedian.xml"); +} + +DPAdaptiveMedian::~DPAdaptiveMedian() +{ + std::cout << "~DPAdaptiveMedian()" << std::endl; +} + +void DPAdaptiveMedian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + frame = new IplImage(img_input); + + if (firstTime) + frame_data.ReleaseMemory(false); + frame_data = frame; + + if (firstTime) + { + int width = img_input.size().width; + int height = img_input.size().height; + + lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); + highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; + + params.SetFrameSize(width, height); + params.LowThreshold() = threshold; + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing + params.SamplingRate() = samplingRate; + params.LearningFrames() = learningFrames; + + bgs.Initalize(params); + bgs.InitModel(frame_data); + } + + bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); + lowThresholdMask.Clear(); + bgs.Update(frameNumber, frame_data, lowThresholdMask); + + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + //bitwise_not(img_foreground, img_foreground); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + cv::imshow("Adaptive Median FG (McFarlane&Schofield)", img_foreground); + cv::imshow("Adaptive Median BG (McFarlane&Schofield)", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + delete frame; + firstTime = false; + frameNumber++; +} + +void DPAdaptiveMedian::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "threshold", threshold); + cvWriteInt(fs, "samplingRate", samplingRate); + cvWriteInt(fs, "learningFrames", learningFrames); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void DPAdaptiveMedian::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadIntByName(fs, nullptr, "threshold", 40); + samplingRate = cvReadIntByName(fs, nullptr, "samplingRate", 7); + learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/DPAdaptiveMedian.h b/package_bgs/DPAdaptiveMedian.h new file mode 100644 index 0000000..7d2b7fa --- /dev/null +++ b/package_bgs/DPAdaptiveMedian.h @@ -0,0 +1,53 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "dp/AdaptiveMedianBGS.h" + +using namespace Algorithms::BackgroundSubtraction; + +namespace bgslibrary +{ + namespace algorithms + { + class DPAdaptiveMedian : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + AdaptiveMedianParams params; + AdaptiveMedianBGS bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + int threshold; + int samplingRate; + int learningFrames; + + public: + DPAdaptiveMedian(); + ~DPAdaptiveMedian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPEigenbackgroundBGS.cpp b/package_bgs/DPEigenbackground.cpp similarity index 53% rename from package_bgs/dp/DPEigenbackgroundBGS.cpp rename to package_bgs/DPEigenbackground.cpp index 630d9cc..75763ce 100644 --- a/package_bgs/dp/DPEigenbackgroundBGS.cpp +++ b/package_bgs/DPEigenbackground.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPEigenbackgroundBGS.h" +#include "DPEigenbackground.h" -DPEigenbackgroundBGS::DPEigenbackgroundBGS() : firstTime(true), frameNumber(0), threshold(225), historySize(20), embeddedDim(10), showOutput(true) +using namespace bgslibrary::algorithms; + +DPEigenbackground::DPEigenbackground() : + frameNumber(0), threshold(225), historySize(20), embeddedDim(10) { - std::cout << "DPEigenbackgroundBGS()" << std::endl; + std::cout << "DPEigenbackground()" << std::endl; + setup("./config/DPEigenbackground.xml"); } -DPEigenbackgroundBGS::~DPEigenbackgroundBGS() +DPEigenbackground::~DPEigenbackground() { - std::cout << "~DPEigenbackgroundBGS()" << std::endl; + std::cout << "~DPEigenbackground()" << std::endl; } -void DPEigenbackgroundBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPEigenbackground::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPEigenbackgroundBGS::process(const cv::Mat &img_input, cv::Mat &img_output params.SetFrameSize(width, height); params.LowThreshold() = threshold; //15*15; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing //params.HistorySize() = 100; params.HistorySize() = historySize; //params.EmbeddedDim() = 20; @@ -68,22 +66,27 @@ void DPEigenbackgroundBGS::process(const cv::Mat &img_input, cv::Mat &img_output bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("Eigenbackground (Oliver)", foreground); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Eigenbackground (Oliver)", img_foreground); +#endif - foreground.copyTo(img_output); + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPEigenbackgroundBGS::saveConfig() +void DPEigenbackground::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPEigenbackgroundBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "threshold", threshold); cvWriteInt(fs, "historySize", historySize); @@ -93,14 +96,14 @@ void DPEigenbackgroundBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPEigenbackgroundBGS::loadConfig() +void DPEigenbackground::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPEigenbackgroundBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, 0, "threshold", 225); - historySize = cvReadIntByName(fs, 0, "historySize", 20); - embeddedDim = cvReadIntByName(fs, 0, "embeddedDim", 10); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadIntByName(fs, nullptr, "threshold", 225); + historySize = cvReadIntByName(fs, nullptr, "historySize", 20); + embeddedDim = cvReadIntByName(fs, nullptr, "embeddedDim", 10); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/DPEigenbackground.h b/package_bgs/DPEigenbackground.h new file mode 100644 index 0000000..f84fee7 --- /dev/null +++ b/package_bgs/DPEigenbackground.h @@ -0,0 +1,55 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "dp/Eigenbackground.h" + +using namespace Algorithms::BackgroundSubtraction; + +namespace bgslibrary +{ + namespace algorithms + { + class DPEigenbackground : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + EigenbackgroundParams params; + Eigenbackground bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + int threshold; + int historySize; + int embeddedDim; + + public: + DPEigenbackground(); + ~DPEigenbackground(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPGrimsonGMMBGS.cpp b/package_bgs/DPGrimsonGMM.cpp similarity index 54% rename from package_bgs/dp/DPGrimsonGMMBGS.cpp rename to package_bgs/DPGrimsonGMM.cpp index ae54860..c72b4d2 100644 --- a/package_bgs/dp/DPGrimsonGMMBGS.cpp +++ b/package_bgs/DPGrimsonGMM.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPGrimsonGMMBGS.h" +#include "DPGrimsonGMM.h" -DPGrimsonGMMBGS::DPGrimsonGMMBGS() : firstTime(true), frameNumber(0), threshold(9.0), alpha(0.01), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +DPGrimsonGMM::DPGrimsonGMM() : + frameNumber(0), threshold(9.0), alpha(0.01), gaussians(3) { - std::cout << "DPGrimsonGMMBGS()" << std::endl; + std::cout << "DPGrimsonGMM()" << std::endl; + setup("./config/DPGrimsonGMM.xml"); } -DPGrimsonGMMBGS::~DPGrimsonGMMBGS() +DPGrimsonGMM::~DPGrimsonGMM() { - std::cout << "~DPGrimsonGMMBGS()" << std::endl; + std::cout << "~DPGrimsonGMM()" << std::endl; } -void DPGrimsonGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPGrimsonGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPGrimsonGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv: params.SetFrameSize(width, height); params.LowThreshold() = threshold; //3.0f*3.0f; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing //params.Alpha() = 0.001f; params.Alpha() = alpha; //0.01f; params.MaxModes() = gaussians; //3; @@ -67,22 +65,27 @@ void DPGrimsonGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv: bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("GMM (Grimson)", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("GMM (Grimson)", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPGrimsonGMMBGS::saveConfig() +void DPGrimsonGMM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPGrimsonGMMBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -92,14 +95,14 @@ void DPGrimsonGMMBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPGrimsonGMMBGS::loadConfig() +void DPGrimsonGMM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPGrimsonGMMBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 9.0); - alpha = cvReadRealByName(fs, 0, "alpha", 0.01); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/dp/DPEigenbackgroundBGS.h b/package_bgs/DPGrimsonGMM.h similarity index 53% rename from package_bgs/dp/DPEigenbackgroundBGS.h rename to package_bgs/DPGrimsonGMM.h index cd4e54c..dcc05eb 100644 --- a/package_bgs/dp/DPEigenbackgroundBGS.h +++ b/package_bgs/DPGrimsonGMM.h @@ -16,41 +16,40 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "Eigenbackground.h" +#include "IBGS.h" +#include "dp/GrimsonGMM.h" using namespace Algorithms::BackgroundSubtraction; -class DPEigenbackgroundBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - EigenbackgroundParams params; - Eigenbackground bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - int historySize; - int embeddedDim; - bool showOutput; - -public: - DPEigenbackgroundBGS(); - ~DPEigenbackgroundBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class DPGrimsonGMM : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + GrimsonParams params; + GrimsonGMM bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + int gaussians; + + public: + DPGrimsonGMM(); + ~DPGrimsonGMM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPMeanBGS.cpp b/package_bgs/DPMean.cpp similarity index 55% rename from package_bgs/dp/DPMeanBGS.cpp rename to package_bgs/DPMean.cpp index 13260b4..3af1fb6 100644 --- a/package_bgs/dp/DPMeanBGS.cpp +++ b/package_bgs/DPMean.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPMeanBGS.h" +#include "DPMean.h" -DPMeanBGS::DPMeanBGS() : firstTime(true), frameNumber(0), threshold(2700), alpha(1e-6f), learningFrames(30), showOutput(true) +using namespace bgslibrary::algorithms; + +DPMean::DPMean() : + frameNumber(0), threshold(2700), alpha(1e-6f), learningFrames(30) { - std::cout << "DPMeanBGS()" << std::endl; + std::cout << "DPMean()" << std::endl; + setup("./config/DPMean.xml"); } -DPMeanBGS::~DPMeanBGS() +DPMean::~DPMean() { - std::cout << "~DPMeanBGS()" << std::endl; + std::cout << "~DPMean()" << std::endl; } -void DPMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.SetFrameSize(width, height); params.LowThreshold() = threshold; //3*30*30; // 2700 - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing //params.Alpha() = 1e-6f; params.Alpha() = alpha; params.LearningFrames() = learningFrames;//30; @@ -67,22 +65,27 @@ void DPMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("Temporal Mean (Donovan Parks)", foreground); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Temporal Mean (Donovan Parks)", img_foreground); +#endif - foreground.copyTo(img_output); + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPMeanBGS::saveConfig() +void DPMean::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPMeanBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -92,14 +95,14 @@ void DPMeanBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPMeanBGS::loadConfig() +void DPMean::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPMeanBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, 0, "threshold", 2700); - alpha = cvReadRealByName(fs, 0, "alpha", 1e-6f); - learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadIntByName(fs, nullptr, "threshold", 2700); + alpha = cvReadRealByName(fs, nullptr, "alpha", 1e-6f); + learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/dp/DPZivkovicAGMMBGS.h b/package_bgs/DPMean.h similarity index 56% rename from package_bgs/dp/DPZivkovicAGMMBGS.h rename to package_bgs/DPMean.h index 775226a..6029968 100644 --- a/package_bgs/dp/DPZivkovicAGMMBGS.h +++ b/package_bgs/DPMean.h @@ -16,41 +16,40 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "ZivkovicAGMM.h" +#include "IBGS.h" +#include "dp/MeanBGS.h" using namespace Algorithms::BackgroundSubtraction; -class DPZivkovicAGMMBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - ZivkovicParams params; - ZivkovicAGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int gaussians; - bool showOutput; - -public: - DPZivkovicAGMMBGS(); - ~DPZivkovicAGMMBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class DPMean : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + MeanParams params; + MeanBGS bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + int threshold; + double alpha; + int learningFrames; + + public: + DPMean(); + ~DPMean(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPPratiMediodBGS.cpp b/package_bgs/DPPratiMediod.cpp similarity index 53% rename from package_bgs/dp/DPPratiMediodBGS.cpp rename to package_bgs/DPPratiMediod.cpp index ba1d6be..d1942c5 100644 --- a/package_bgs/dp/DPPratiMediodBGS.cpp +++ b/package_bgs/DPPratiMediod.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPPratiMediodBGS.h" +#include "DPPratiMediod.h" -DPPratiMediodBGS::DPPratiMediodBGS() : firstTime(true), frameNumber(0), threshold(30), samplingRate(5), historySize(16), weight(5), showOutput(true) +using namespace bgslibrary::algorithms; + +DPPratiMediod::DPPratiMediod() : + frameNumber(0), threshold(30), samplingRate(5), historySize(16), weight(5) { - std::cout << "DPPratiMediodBGS()" << std::endl; + std::cout << "DPPratiMediod()" << std::endl; + setup("./config/DPPratiMediod.xml"); } -DPPratiMediodBGS::~DPPratiMediodBGS() +DPPratiMediod::~DPPratiMediod() { - std::cout << "~DPPratiMediodBGS()" << std::endl; + std::cout << "~DPPratiMediod()" << std::endl; } -void DPPratiMediodBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPPratiMediod::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPPratiMediodBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv params.SetFrameSize(width, height); params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing params.SamplingRate() = samplingRate; params.HistorySize() = historySize; params.Weight() = weight; @@ -67,26 +65,29 @@ void DPPratiMediodBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - cv::Mat background(bgs.Background()->Ptr()); - if(showOutput){ - cv::imshow("Temporal Median FG (Cucchiara&Calderara)", foreground); - cv::imshow("Temporal Median BG (Cucchiara&Calderara)", background); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + cv::imshow("Temporal Median FG (Cucchiara&Calderara)", img_foreground); + cv::imshow("Temporal Median BG (Cucchiara&Calderara)", img_background); } +#endif - foreground.copyTo(img_output); - background.copyTo(img_bgmodel); + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPPratiMediodBGS::saveConfig() +void DPPratiMediod::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPPratiMediodBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "threshold", threshold); cvWriteInt(fs, "samplingRate", samplingRate); @@ -97,15 +98,15 @@ void DPPratiMediodBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPPratiMediodBGS::loadConfig() +void DPPratiMediod::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPPratiMediodBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, 0, "threshold", 30); - samplingRate = cvReadIntByName(fs, 0, "samplingRate", 5); - historySize = cvReadIntByName(fs, 0, "historySize", 16); - weight = cvReadIntByName(fs, 0, "weight", 5); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadIntByName(fs, nullptr, "threshold", 30); + samplingRate = cvReadIntByName(fs, nullptr, "samplingRate", 5); + historySize = cvReadIntByName(fs, nullptr, "historySize", 16); + weight = cvReadIntByName(fs, nullptr, "weight", 5); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/dp/DPMeanBGS.h b/package_bgs/DPPratiMediod.h similarity index 52% rename from package_bgs/dp/DPMeanBGS.h rename to package_bgs/DPPratiMediod.h index 8829686..d37a77a 100644 --- a/package_bgs/dp/DPMeanBGS.h +++ b/package_bgs/DPPratiMediod.h @@ -16,41 +16,41 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "MeanBGS.h" +#include "IBGS.h" +#include "dp/PratiMediodBGS.h" using namespace Algorithms::BackgroundSubtraction; -class DPMeanBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - MeanParams params; - MeanBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - double alpha; - int learningFrames; - bool showOutput; - -public: - DPMeanBGS(); - ~DPMeanBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class DPPratiMediod : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + PratiParams params; + PratiMediodBGS bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + int threshold; + int samplingRate; + int historySize; + int weight; + + public: + DPPratiMediod(); + ~DPPratiMediod(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPTextureBGS.cpp b/package_bgs/DPTexture.cpp similarity index 65% rename from package_bgs/dp/DPTextureBGS.cpp rename to package_bgs/DPTexture.cpp index 2d34342..3285ccf 100644 --- a/package_bgs/dp/DPTextureBGS.cpp +++ b/package_bgs/DPTexture.cpp @@ -14,15 +14,18 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPTextureBGS.h" +#include "DPTexture.h" -DPTextureBGS::DPTextureBGS() : firstTime(true), showOutput(true) - //, enableFiltering(true) +using namespace bgslibrary::algorithms; + +DPTexture::DPTexture() +// : enableFiltering(true) { - std::cout << "DPTextureBGS()" << std::endl; + std::cout << "DPTexture()" << std::endl; + setup("./config/DPTexture.xml"); } -DPTextureBGS::~DPTextureBGS() +DPTexture::~DPTexture() { delete[] bgModel; // ~10Kb (25.708-15.968) delete[] modeArray; @@ -33,34 +36,31 @@ DPTextureBGS::~DPTextureBGS() fgMask.ReleaseImage(); tempMask.ReleaseImage(); texture.ReleaseImage(); - std::cout << "~DPTextureBGS()" << std::endl; + std::cout << "~DPTexture()" << std::endl; } -void DPTextureBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPTexture::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) { - width = img_input.size().width; + width = img_input.size().width; height = img_input.size().height; size = width * height; // input image image = cvCreateImage(cvSize(width, height), 8, 3); - cvCopy(frame, image.Ptr()); + cvCopy(frame, image.Ptr()); // foreground masks fgMask = cvCreateImage(cvSize(width, height), 8, 1); tempMask = cvCreateImage(cvSize(width, height), 8, 1); cvZero(fgMask.Ptr()); cvZero(tempMask.Ptr()); - + // create background model bgModel = new TextureArray[size]; texture = cvCreateImage(cvSize(width, height), 8, 3); @@ -71,16 +71,16 @@ void DPTextureBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Ma // initialize background model bgs.LBP(image, texture); bgs.Histogram(texture, curTextureHist); - for(int y = REGION_R+TEXTURE_R; y < height-REGION_R-TEXTURE_R; ++y) + for (int y = REGION_R + TEXTURE_R; y < height - REGION_R - TEXTURE_R; ++y) { - for(int x = REGION_R+TEXTURE_R; x < width-REGION_R-TEXTURE_R; ++x) + for (int x = REGION_R + TEXTURE_R; x < width - REGION_R - TEXTURE_R; ++x) { - int index = x+y*width; - - for(int m = 0; m < NUM_MODES; ++m) + int index = x + y*width; + + for (int m = 0; m < NUM_MODES; ++m) { - for(int i = 0; i < NUM_BINS; ++i) - { + for (int i = 0; i < NUM_BINS; ++i) + { bgModel[index].mode[m].r[i] = curTextureHist[index].r[i]; bgModel[index].mode[m].g[i] = curTextureHist[index].g[i]; bgModel[index].mode[m].b[i] = curTextureHist[index].b[i]; @@ -91,18 +91,16 @@ void DPTextureBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Ma //dilateElement = cvCreateStructuringElementEx(7, 7, 3, 3, CV_SHAPE_RECT); //erodeElement = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_RECT); - - saveConfig(); firstTime = false; } - - cvCopy(frame, image.Ptr()); + + cvCopy(frame, image.Ptr()); // perform background subtraction bgs.LBP(image, texture); bgs.Histogram(texture, curTextureHist); bgs.BgsCompare(bgModel, curTextureHist, modeArray, THRESHOLD, fgMask); - + //if(enableFiltering) //{ // // size filtering @@ -120,22 +118,27 @@ void DPTextureBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Ma // cvErode(fgMask.Ptr(), fgMask.Ptr(), erodeElement, 1); //} - cv::Mat foreground(fgMask.Ptr()); - if(!foreground.empty()) - foreground.copyTo(img_output); - - if(showOutput) - cv::imshow("Texture BGS (Donovan Parks)", foreground); + img_foreground = cv::cvarrToMat(fgMask.Ptr()); + //img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Texture BGS (Donovan Parks)", img_foreground); +#endif - // update background subtraction + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + // update background subtraction bgs.UpdateModel(fgMask, bgModel, curTextureHist, modeArray); - + delete frame; } -void DPTextureBGS::saveConfig() +void DPTexture::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPTextureBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); //cvWriteReal(fs, "alpha", alpha); //cvWriteInt(fs, "enableFiltering", enableFiltering); @@ -144,13 +147,13 @@ void DPTextureBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPTextureBGS::loadConfig() +void DPTexture::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPTextureBGS.xml", 0, CV_STORAGE_READ); - - //alpha = cvReadRealByName(fs, 0, "alpha", 1e-6f); - //enableFiltering = cvReadIntByName(fs, 0, "enableFiltering", true); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + //alpha = cvReadRealByName(fs, nullptr, "alpha", 1e-6f); + //enableFiltering = cvReadIntByName(fs, nullptr, "enableFiltering", true); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/DPTexture.h b/package_bgs/DPTexture.h new file mode 100644 index 0000000..3cfdcea --- /dev/null +++ b/package_bgs/DPTexture.h @@ -0,0 +1,59 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "dp/TextureBGS.h" +//#include "ConnectedComponents.h" + +namespace bgslibrary +{ + namespace algorithms + { + class DPTexture : public IBGS + { + private: + int width; + int height; + int size; + TextureBGS bgs; + IplImage* frame; + RgbImage image; + BwImage fgMask; + BwImage tempMask; + TextureArray* bgModel; + RgbImage texture; + unsigned char* modeArray; + TextureHistogram* curTextureHist; + //ConnectedComponents cc; + //CBlobResult largeBlobs; + //IplConvKernel* dilateElement; + //IplConvKernel* erodeElement; + //bool enableFiltering; + + public: + DPTexture(); + ~DPTexture(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPWrenGABGS.cpp b/package_bgs/DPWrenGA.cpp similarity index 54% rename from package_bgs/dp/DPWrenGABGS.cpp rename to package_bgs/DPWrenGA.cpp index d7241b1..7fc3313 100644 --- a/package_bgs/dp/DPWrenGABGS.cpp +++ b/package_bgs/DPWrenGA.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPWrenGABGS.h" +#include "DPWrenGA.h" -DPWrenGABGS::DPWrenGABGS() : firstTime(true), frameNumber(0), threshold(12.25f), alpha(0.005f), learningFrames(30), showOutput(true) +using namespace bgslibrary::algorithms; + +DPWrenGA::DPWrenGA() : + frameNumber(0), threshold(12.25f), alpha(0.005f), learningFrames(30) { - std::cout << "DPWrenGABGS()" << std::endl; + std::cout << "DPWrenGA()" << std::endl; + setup("./config/DPWrenGA.xml"); } -DPWrenGABGS::~DPWrenGABGS() +DPWrenGA::~DPWrenGA() { - std::cout << "~DPWrenGABGS()" << std::endl; + std::cout << "~DPWrenGA()" << std::endl; } -void DPWrenGABGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPWrenGA::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPWrenGABGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat params.SetFrameSize(width, height); params.LowThreshold() = threshold; //3.5f*3.5f; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing params.Alpha() = alpha; //0.005f; params.LearningFrames() = learningFrames; //30; @@ -66,22 +64,27 @@ void DPWrenGABGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("Gaussian Average (Wren)", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Gaussian Average (Wren)", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPWrenGABGS::saveConfig() +void DPWrenGA::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPWrenGABGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -91,15 +94,14 @@ void DPWrenGABGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPWrenGABGS::loadConfig() +void DPWrenGA::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPWrenGABGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 12.25f); - alpha = cvReadRealByName(fs, 0, "alpha", 0.005f); - learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 12.25f); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.005f); + learningFrames = cvReadIntByName(fs, nullptr, "learningFrames", 30); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } - diff --git a/package_bgs/dp/DPWrenGABGS.h b/package_bgs/DPWrenGA.h similarity index 54% rename from package_bgs/dp/DPWrenGABGS.h rename to package_bgs/DPWrenGA.h index 30ab614..e4b0b5f 100644 --- a/package_bgs/dp/DPWrenGABGS.h +++ b/package_bgs/DPWrenGA.h @@ -16,41 +16,40 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "WrenGA.h" +#include "IBGS.h" +#include "dp/WrenGA.h" using namespace Algorithms::BackgroundSubtraction; -class DPWrenGABGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - WrenParams params; - WrenGA bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int learningFrames; - bool showOutput; - -public: - DPWrenGABGS(); - ~DPWrenGABGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class DPWrenGA : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + WrenParams params; + WrenGA bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + int learningFrames; + + public: + DPWrenGA(); + ~DPWrenGA(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/dp/DPZivkovicAGMMBGS.cpp b/package_bgs/DPZivkovicAGMM.cpp similarity index 53% rename from package_bgs/dp/DPZivkovicAGMMBGS.cpp rename to package_bgs/DPZivkovicAGMM.cpp index e8276f6..a5a9735 100644 --- a/package_bgs/dp/DPZivkovicAGMMBGS.cpp +++ b/package_bgs/DPZivkovicAGMM.cpp @@ -14,37 +14,35 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "DPZivkovicAGMMBGS.h" +#include "DPZivkovicAGMM.h" -DPZivkovicAGMMBGS::DPZivkovicAGMMBGS() : firstTime(true), frameNumber(0), threshold(25.0f), alpha(0.001f), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +DPZivkovicAGMM::DPZivkovicAGMM() : + frameNumber(0), threshold(25.0f), alpha(0.001f), gaussians(3) { - std::cout << "DPZivkovicAGMMBGS()" << std::endl; + std::cout << "DPZivkovicAGMM()" << std::endl; + setup("./config/DPZivkovicAGMM.xml"); } -DPZivkovicAGMMBGS::~DPZivkovicAGMMBGS() +DPZivkovicAGMM::~DPZivkovicAGMM() { - std::cout << "~DPZivkovicAGMMBGS()" << std::endl; + std::cout << "~DPZivkovicAGMM()" << std::endl; } -void DPZivkovicAGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void DPZivkovicAGMM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +53,7 @@ void DPZivkovicAGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, c params.SetFrameSize(width, height); params.LowThreshold() = threshold; //5.0f*5.0f; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.HighThreshold() = 2 * params.LowThreshold(); // Note: high threshold is used by post-processing params.Alpha() = alpha; //0.001f; params.MaxModes() = gaussians; //3; @@ -66,22 +64,27 @@ void DPZivkovicAGMMBGS::process(const cv::Mat &img_input, cv::Mat &img_output, c bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("Gaussian Mixture Model (Zivkovic)", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Gaussian Mixture Model (Zivkovic)", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; frameNumber++; } -void DPZivkovicAGMMBGS::saveConfig() +void DPZivkovicAGMM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPZivkovicAGMMBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -91,14 +94,14 @@ void DPZivkovicAGMMBGS::saveConfig() cvReleaseFileStorage(&fs); } -void DPZivkovicAGMMBGS::loadConfig() +void DPZivkovicAGMM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/DPZivkovicAGMMBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 25.0f); - alpha = cvReadRealByName(fs, 0, "alpha", 0.001f); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 25.0f); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.001f); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/dp/DPGrimsonGMMBGS.h b/package_bgs/DPZivkovicAGMM.h similarity index 53% rename from package_bgs/dp/DPGrimsonGMMBGS.h rename to package_bgs/DPZivkovicAGMM.h index 4f955b9..f35504b 100644 --- a/package_bgs/dp/DPGrimsonGMMBGS.h +++ b/package_bgs/DPZivkovicAGMM.h @@ -16,41 +16,40 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "GrimsonGMM.h" +#include "IBGS.h" +#include "dp/ZivkovicAGMM.h" using namespace Algorithms::BackgroundSubtraction; -class DPGrimsonGMMBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - GrimsonParams params; - GrimsonGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - int gaussians; - bool showOutput; - -public: - DPGrimsonGMMBGS(); - ~DPGrimsonGMMBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class DPZivkovicAGMM : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + ZivkovicParams params; + ZivkovicAGMM bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + int gaussians; + + public: + DPZivkovicAGMM(); + ~DPZivkovicAGMM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/FrameDifference.cpp b/package_bgs/FrameDifference.cpp new file mode 100644 index 0000000..4d5c076 --- /dev/null +++ b/package_bgs/FrameDifference.cpp @@ -0,0 +1,84 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "FrameDifference.h" + +using namespace bgslibrary::algorithms; + +FrameDifference::FrameDifference() : + enableThreshold(true), threshold(15) +{ + std::cout << "FrameDifference()" << std::endl; + setup("./config/FrameDifference.xml"); +} + +FrameDifference::~FrameDifference() +{ + std::cout << "~FrameDifference()" << std::endl; +} + +void FrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_background.empty()) + { + img_input.copyTo(img_background); + return; + } + + cv::absdiff(img_background, img_input, img_foreground); + + if (img_foreground.channels() == 3) + cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); + + if (enableThreshold) + cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Frame Difference", img_foreground); +#endif + + img_foreground.copyTo(img_output); + + img_input.copyTo(img_background); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void FrameDifference::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "enableThreshold", enableThreshold); + cvWriteInt(fs, "threshold", threshold); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void FrameDifference::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/FrameDifferenceBGS.h b/package_bgs/FrameDifference.h similarity index 61% rename from package_bgs/FrameDifferenceBGS.h rename to package_bgs/FrameDifference.h index 338979f..07bed8e 100644 --- a/package_bgs/FrameDifferenceBGS.h +++ b/package_bgs/FrameDifference.h @@ -16,29 +16,28 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - #include "IBGS.h" -class FrameDifferenceBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Mat img_input_prev; - cv::Mat img_foreground; - bool enableThreshold; - int threshold; - bool showOutput; - -public: - FrameDifferenceBGS(); - ~FrameDifferenceBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class FrameDifference : public IBGS + { + private: + bool enableThreshold; + int threshold; + + public: + FrameDifference(); + ~FrameDifference(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} + diff --git a/package_bgs/FrameDifferenceBGS.cpp b/package_bgs/FrameDifferenceBGS.cpp deleted file mode 100644 index e871651..0000000 --- a/package_bgs/FrameDifferenceBGS.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "FrameDifferenceBGS.h" - -FrameDifferenceBGS::FrameDifferenceBGS() : firstTime(true), enableThreshold(true), threshold(15), showOutput(true) -{ - std::cout << "FrameDifferenceBGS()" << std::endl; -} - -FrameDifferenceBGS::~FrameDifferenceBGS() -{ - std::cout << "~FrameDifferenceBGS()" << std::endl; -} - -void FrameDifferenceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - - if(img_input_prev.empty()) - { - img_input.copyTo(img_input_prev); - return; - } - - cv::absdiff(img_input_prev, img_input, img_foreground); - - if(img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - if(enableThreshold) - cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - - if(showOutput) - cv::imshow("Frame Difference", img_foreground); - - img_foreground.copyTo(img_output); - - img_input.copyTo(img_input_prev); - - firstTime = false; -} - -void FrameDifferenceBGS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/FrameDifferenceBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "enableThreshold", enableThreshold); - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void FrameDifferenceBGS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/FrameDifferenceBGS.xml", 0, CV_STORAGE_READ); - - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} \ No newline at end of file diff --git a/package_bgs/tb/FuzzyChoquetIntegral.cpp b/package_bgs/FuzzyChoquetIntegral.cpp similarity index 62% rename from package_bgs/tb/FuzzyChoquetIntegral.cpp rename to package_bgs/FuzzyChoquetIntegral.cpp index c97e174..3d24126 100644 --- a/package_bgs/tb/FuzzyChoquetIntegral.cpp +++ b/package_bgs/FuzzyChoquetIntegral.cpp @@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "FuzzyChoquetIntegral.h" -#include <opencv2/legacy/compat.hpp> -FuzzyChoquetIntegral::FuzzyChoquetIntegral() : firstTime(true), frameNumber(0), showOutput(true), - framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), colorSpace(1), option(2), smooth(true), threshold(0.67) +using namespace bgslibrary::algorithms; + +FuzzyChoquetIntegral::FuzzyChoquetIntegral() : + frameNumber(0), framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), + colorSpace(1), option(2), smooth(true), threshold(0.67) { std::cout << "FuzzyChoquetIntegral()" << std::endl; + setup("./config/FuzzyChoquetIntegral.xml"); } FuzzyChoquetIntegral::~FuzzyChoquetIntegral() @@ -30,48 +33,52 @@ FuzzyChoquetIntegral::~FuzzyChoquetIntegral() void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); cv::Mat img_input_f3(img_input.size(), CV_32F); - img_input.convertTo(img_input_f3, CV_32F, 1./255.); - - loadConfig(); + img_input.convertTo(img_input_f3, CV_32F, 1. / 255.); - if(firstTime) + if (firstTime) { std::cout << "FuzzyChoquetIntegral parameters:" << std::endl; - + std::string colorSpaceName = ""; - switch(colorSpace) + switch (colorSpace) { - case 1: colorSpaceName = "RGB"; break; - case 2: colorSpaceName = "OHTA"; break; - case 3: colorSpaceName = "HSV"; break; - case 4: colorSpaceName = "YCrCb"; break; + case 1: colorSpaceName = "RGB"; break; + case 2: colorSpaceName = "OHTA"; break; + case 3: colorSpaceName = "HSV"; break; + case 4: colorSpaceName = "YCrCb"; break; } std::cout << "Color space: " << colorSpaceName << std::endl; - if(option == 1) + if (option == 1) std::cout << "Fuzzing by 3 color components" << std::endl; - if(option == 2) + if (option == 2) std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl; - - saveConfig(); } - if(frameNumber <= framesToLearn) + if (frameNumber <= framesToLearn) { - if(frameNumber == 0) + if (frameNumber == 0) std::cout << "FuzzyChoquetIntegral initializing background model by adaptive learning..." << std::endl; - if(img_background_f3.empty()) + if (img_background_f3.empty()) img_input_f3.copyTo(img_background_f3); else - img_background_f3 = alphaLearn*img_input_f3 + (1-alphaLearn)*img_background_f3; + img_background_f3 = alphaLearn*img_input_f3 + (1 - alphaLearn)*img_background_f3; + + double minVal = 0., maxVal = 1.; + img_background_f3.convertTo(img_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_background.copyTo(img_bgmodel); + + img_foreground = cv::Mat::zeros(img_input.size(), img_input.type()); + img_foreground.copyTo(img_output); - if(showOutput) - cv::imshow("CI BG Model", img_background_f3); +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("CI BG Model", img_background); +#endif } else { @@ -87,72 +94,74 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output IplImage* background_f1 = new IplImage(img_background_f1); IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); - cvFillImage(lbp_input_f1, 0.0); + cvSetZero(lbp_input_f1); fu.LBP(input_f1, lbp_input_f1); - IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F , 1); - cvFillImage(lbp_background_f1, 0.0); + IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F, 1); + cvSetZero(lbp_background_f1); fu.LBP(background_f1, lbp_background_f1); IplImage* sim_texture_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); fu.SimilarityDegreesImage(lbp_input_f1, lbp_background_f1, sim_texture_f1, 1, colorSpace); IplImage* sim_color_f3 = cvCreateImage(cvSize(input_f3->width, input_f3->height), IPL_DEPTH_32F, 3); - fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace); + fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace); - float* measureG = (float*) malloc(3*(sizeof(float))); + float* measureG = (float*)malloc(3 * (sizeof(float))); IplImage* integral_choquet_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); // 3 color components - if(option == 1) + if (option == 1) { fu.FuzzyMeasureG(0.4f, 0.3f, 0.3f, measureG); fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1); } // 2 color components + 1 texture component - if(option == 2) + if (option == 2) { fu.FuzzyMeasureG(0.6f, 0.3f, 0.1f, measureG); fu.getFuzzyIntegralChoquet(sim_texture_f1, sim_color_f3, option, measureG, integral_choquet_f1); } free(measureG); - cv::Mat img_integral_choquet_f1(integral_choquet_f1); + cv::Mat img_integral_choquet_f1 = cv::cvarrToMat(integral_choquet_f1); - if(smooth) + if (smooth) cv::medianBlur(img_integral_choquet_f1, img_integral_choquet_f1, 3); cv::Mat img_foreground_f1(img_input.size(), CV_32F); cv::threshold(img_integral_choquet_f1, img_foreground_f1, threshold, 255, cv::THRESH_BINARY_INV); - cv::Mat img_foreground_u1(img_input.size(), CV_8U); + //cv::Mat img_foreground_u1(img_input.size(), CV_8U); double minVal = 0., maxVal = 1.; - img_foreground_f1.convertTo(img_foreground_u1, CV_8U, 255.0/(maxVal - minVal), -minVal); - img_foreground_u1.copyTo(img_output); + img_foreground_f1.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_foreground.copyTo(img_output); - cv::Mat img_background_u3(img_input.size(), CV_8U); + //cv::Mat img_background_u3(img_input.size(), CV_8U); //double minVal = 0., maxVal = 1.; - img_background_f3.convertTo(img_background_u3, CV_8U, 255.0/(maxVal - minVal), -minVal); - img_background_u3.copyTo(img_bgmodel); + img_background_f3.convertTo(img_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_background.copyTo(img_bgmodel); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cvShowImage("CI LBP Input", lbp_input_f1); cvShowImage("CI LBP Background", lbp_background_f1); cvShowImage("CI Prob FG Mask", integral_choquet_f1); - cv::imshow("CI BG Model", img_background_f3); - cv::imshow("CI FG Mask", img_foreground_u1); + cv::imshow("CI BG Model", img_background); + cv::imshow("CI FG Mask", img_foreground); } +#endif - if(frameNumber == (framesToLearn + 1)) + if (frameNumber == (framesToLearn + 1)) std::cout << "FuzzyChoquetIntegral updating background model by adaptive-selective learning..." << std::endl; IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3); - cvFillImage(updated_background_f3, 0.0); + cvSetZero(updated_background_f3); fu.AdaptativeSelectiveBackgroundModelUpdate(input_f3, background_f3, updated_background_f3, integral_choquet_f1, threshold, alphaUpdate); - cv::Mat img_updated_background_f3(updated_background_f3); + cv::Mat img_updated_background_f3 = cv::cvarrToMat(updated_background_f3); img_updated_background_f3.copyTo(img_background_f3); cvReleaseImage(&lbp_input_f1); @@ -161,7 +170,7 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output cvReleaseImage(&sim_color_f3); cvReleaseImage(&integral_choquet_f1); cvReleaseImage(&updated_background_f3); - + delete background_f1; delete background_f3; delete input_f1; @@ -174,8 +183,8 @@ void FuzzyChoquetIntegral::process(const cv::Mat &img_input, cv::Mat &img_output void FuzzyChoquetIntegral::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/FuzzyChoquetIntegral.xml", 0, CV_STORAGE_WRITE); - + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + cvWriteInt(fs, "showOutput", showOutput); cvWriteInt(fs, "framesToLearn", framesToLearn); cvWriteReal(fs, "alphaLearn", alphaLearn); @@ -190,16 +199,16 @@ void FuzzyChoquetIntegral::saveConfig() void FuzzyChoquetIntegral::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/FuzzyChoquetIntegral.xml", 0, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10); - alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.1); - alphaUpdate = cvReadRealByName(fs, 0, "alphaUpdate", 0.01); - colorSpace = cvReadIntByName(fs, 0, "colorSpace", 1); - option = cvReadIntByName(fs, 0, "option", 2); - smooth = cvReadIntByName(fs, 0, "smooth", true); - threshold = cvReadRealByName(fs, 0, "threshold", 0.67); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); + alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.1); + alphaUpdate = cvReadRealByName(fs, nullptr, "alphaUpdate", 0.01); + colorSpace = cvReadIntByName(fs, nullptr, "colorSpace", 1); + option = cvReadIntByName(fs, nullptr, "option", 2); + smooth = cvReadIntByName(fs, nullptr, "smooth", true); + threshold = cvReadRealByName(fs, nullptr, "threshold", 0.67); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/FuzzyChoquetIntegral.h b/package_bgs/FuzzyChoquetIntegral.h new file mode 100644 index 0000000..25681b0 --- /dev/null +++ b/package_bgs/FuzzyChoquetIntegral.h @@ -0,0 +1,53 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "T2F/FuzzyUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + class FuzzyChoquetIntegral : public IBGS + { + private: + long frameNumber; + + int framesToLearn; + double alphaLearn; + double alphaUpdate; + int colorSpace; + int option; + bool smooth; + double threshold; + + FuzzyUtils fu; + cv::Mat img_background_f3; + + public: + FuzzyChoquetIntegral(); + ~FuzzyChoquetIntegral(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/tb/FuzzySugenoIntegral.cpp b/package_bgs/FuzzySugenoIntegral.cpp similarity index 62% rename from package_bgs/tb/FuzzySugenoIntegral.cpp rename to package_bgs/FuzzySugenoIntegral.cpp index 859f14e..e62fa02 100644 --- a/package_bgs/tb/FuzzySugenoIntegral.cpp +++ b/package_bgs/FuzzySugenoIntegral.cpp @@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "FuzzySugenoIntegral.h" -#include <opencv2/legacy/compat.hpp> -FuzzySugenoIntegral::FuzzySugenoIntegral() : firstTime(true), frameNumber(0), showOutput(true), - framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), colorSpace(1), option(2), smooth(true), threshold(0.67) +using namespace bgslibrary::algorithms; + +FuzzySugenoIntegral::FuzzySugenoIntegral() : + frameNumber(0), framesToLearn(10), alphaLearn(0.1), alphaUpdate(0.01), + colorSpace(1), option(2), smooth(true), threshold(0.67) { std::cout << "FuzzySugenoIntegral()" << std::endl; + setup("./config/FuzzySugenoIntegral.xml"); } FuzzySugenoIntegral::~FuzzySugenoIntegral() @@ -30,48 +33,52 @@ FuzzySugenoIntegral::~FuzzySugenoIntegral() void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); cv::Mat img_input_f3(img_input.size(), CV_32F); - img_input.convertTo(img_input_f3, CV_32F, 1./255.); - - loadConfig(); + img_input.convertTo(img_input_f3, CV_32F, 1. / 255.); - if(firstTime) + if (firstTime) { std::cout << "FuzzySugenoIntegral parameters:" << std::endl; - + std::string colorSpaceName = ""; - switch(colorSpace) + switch (colorSpace) { - case 1: colorSpaceName = "RGB"; break; - case 2: colorSpaceName = "OHTA"; break; - case 3: colorSpaceName = "HSV"; break; - case 4: colorSpaceName = "YCrCb"; break; + case 1: colorSpaceName = "RGB"; break; + case 2: colorSpaceName = "OHTA"; break; + case 3: colorSpaceName = "HSV"; break; + case 4: colorSpaceName = "YCrCb"; break; } std::cout << "Color space: " << colorSpaceName << std::endl; - if(option == 1) + if (option == 1) std::cout << "Fuzzing by 3 color components" << std::endl; - if(option == 2) + if (option == 2) std::cout << "Fuzzing by 2 color components + 1 texture component" << std::endl; - - saveConfig(); } - if(frameNumber <= framesToLearn) + if (frameNumber <= framesToLearn) { - if(frameNumber == 0) + if (frameNumber == 0) std::cout << "FuzzySugenoIntegral initializing background model by adaptive learning..." << std::endl; - if(img_background_f3.empty()) + if (img_background_f3.empty()) img_input_f3.copyTo(img_background_f3); else - img_background_f3 = alphaLearn*img_input_f3 + (1-alphaLearn)*img_background_f3; + img_background_f3 = alphaLearn*img_input_f3 + (1 - alphaLearn)*img_background_f3; + + double minVal = 0., maxVal = 1.; + img_background_f3.convertTo(img_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_background.copyTo(img_bgmodel); + + img_foreground = cv::Mat::zeros(img_input.size(), img_input.type()); + img_foreground.copyTo(img_output); - if(showOutput) - cv::imshow("SI BG Model", img_background_f3); +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("SI BG Model", img_background); +#endif } else { @@ -87,72 +94,74 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, IplImage* background_f1 = new IplImage(img_background_f1); IplImage* lbp_input_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); - cvFillImage(lbp_input_f1, 0.0); + cvSetZero(lbp_input_f1); fu.LBP(input_f1, lbp_input_f1); - IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F , 1); - cvFillImage(lbp_background_f1, 0.0); + IplImage* lbp_background_f1 = cvCreateImage(cvSize(background_f1->width, background_f1->height), IPL_DEPTH_32F, 1); + cvSetZero(lbp_background_f1); fu.LBP(background_f1, lbp_background_f1); IplImage* sim_texture_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); fu.SimilarityDegreesImage(lbp_input_f1, lbp_background_f1, sim_texture_f1, 1, colorSpace); IplImage* sim_color_f3 = cvCreateImage(cvSize(input_f3->width, input_f3->height), IPL_DEPTH_32F, 3); - fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace); + fu.SimilarityDegreesImage(input_f3, background_f3, sim_color_f3, 3, colorSpace); - float* measureG = (float*) malloc(3*(sizeof(float))); + float* measureG = (float*)malloc(3 * (sizeof(float))); IplImage* integral_sugeno_f1 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 1); // 3 color components - if(option == 1) + if (option == 1) { fu.FuzzyMeasureG(0.4f, 0.3f, 0.3f, measureG); fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1); } // 2 color components + 1 texture component - if(option == 2) + if (option == 2) { fu.FuzzyMeasureG(0.6f, 0.3f, 0.1f, measureG); fu.getFuzzyIntegralSugeno(sim_texture_f1, sim_color_f3, option, measureG, integral_sugeno_f1); } free(measureG); - cv::Mat img_integral_sugeno_f1(integral_sugeno_f1); + cv::Mat img_integral_sugeno_f1 = cv::cvarrToMat(integral_sugeno_f1); - if(smooth) + if (smooth) cv::medianBlur(img_integral_sugeno_f1, img_integral_sugeno_f1, 3); cv::Mat img_foreground_f1(img_input.size(), CV_32F); cv::threshold(img_integral_sugeno_f1, img_foreground_f1, threshold, 255, cv::THRESH_BINARY_INV); - cv::Mat img_foreground_u1(img_input.size(), CV_8U); + //cv::Mat img_foreground_u1(img_input.size(), CV_8U); double minVal = 0., maxVal = 1.; - img_foreground_f1.convertTo(img_foreground_u1, CV_8U, 255.0/(maxVal - minVal), -minVal); - img_foreground_u1.copyTo(img_output); - - cv::Mat img_background_u3(img_input.size(), CV_8U); + img_foreground_f1.convertTo(img_foreground, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_foreground.copyTo(img_output); + + //cv::Mat img_background_u3(img_input.size(), CV_8U); //double minVal = 0., maxVal = 1.; - img_background_f3.convertTo(img_background_u3, CV_8U, 255.0/(maxVal - minVal), -minVal); - img_background_u3.copyTo(img_bgmodel); + img_background_f3.convertTo(img_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); + img_background.copyTo(img_bgmodel); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cvShowImage("SI LBP Input", lbp_input_f1); cvShowImage("SI LBP Background", lbp_background_f1); cvShowImage("SI Prob FG Mask", integral_sugeno_f1); - cv::imshow("SI BG Model", img_background_f3); - cv::imshow("SI FG Mask", img_foreground_u1); + cv::imshow("SI BG Model", img_background); + cv::imshow("SI FG Mask", img_foreground); } +#endif - if(frameNumber == (framesToLearn + 1)) + if (frameNumber == (framesToLearn + 1)) std::cout << "FuzzySugenoIntegral updating background model by adaptive-selective learning..." << std::endl; IplImage* updated_background_f3 = cvCreateImage(cvSize(input_f1->width, input_f1->height), IPL_DEPTH_32F, 3); - cvFillImage(updated_background_f3, 0.0); + cvSetZero(updated_background_f3); fu.AdaptativeSelectiveBackgroundModelUpdate(input_f3, background_f3, updated_background_f3, integral_sugeno_f1, threshold, alphaUpdate); - cv::Mat img_updated_background_f3(updated_background_f3); + cv::Mat img_updated_background_f3 = cv::cvarrToMat(updated_background_f3); img_updated_background_f3.copyTo(img_background_f3); cvReleaseImage(&lbp_input_f1); @@ -161,7 +170,7 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, cvReleaseImage(&sim_color_f3); cvReleaseImage(&integral_sugeno_f1); cvReleaseImage(&updated_background_f3); - + delete background_f1; delete background_f3; delete input_f1; @@ -174,8 +183,8 @@ void FuzzySugenoIntegral::process(const cv::Mat &img_input, cv::Mat &img_output, void FuzzySugenoIntegral::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/FuzzySugenoIntegral.xml", 0, CV_STORAGE_WRITE); - + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + cvWriteInt(fs, "showOutput", showOutput); cvWriteInt(fs, "framesToLearn", framesToLearn); cvWriteReal(fs, "alphaLearn", alphaLearn); @@ -184,22 +193,22 @@ void FuzzySugenoIntegral::saveConfig() cvWriteInt(fs, "option", option); cvWriteInt(fs, "smooth", smooth); cvWriteReal(fs, "threshold", threshold); - + cvReleaseFileStorage(&fs); } void FuzzySugenoIntegral::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/FuzzySugenoIntegral.xml", 0, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10); - alphaLearn = cvReadRealByName(fs, 0, "alphaLearn", 0.1); - alphaUpdate = cvReadRealByName(fs, 0, "alphaUpdate", 0.01); - colorSpace = cvReadIntByName(fs, 0, "colorSpace", 1); - option = cvReadIntByName(fs, 0, "option", 2); - smooth = cvReadIntByName(fs, 0, "smooth", true); - threshold = cvReadRealByName(fs, 0, "threshold", 0.67); - + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); + alphaLearn = cvReadRealByName(fs, nullptr, "alphaLearn", 0.1); + alphaUpdate = cvReadRealByName(fs, nullptr, "alphaUpdate", 0.01); + colorSpace = cvReadIntByName(fs, nullptr, "colorSpace", 1); + option = cvReadIntByName(fs, nullptr, "option", 2); + smooth = cvReadIntByName(fs, nullptr, "smooth", true); + threshold = cvReadRealByName(fs, nullptr, "threshold", 0.67); + cvReleaseFileStorage(&fs); } diff --git a/package_bgs/FuzzySugenoIntegral.h b/package_bgs/FuzzySugenoIntegral.h new file mode 100644 index 0000000..70bde15 --- /dev/null +++ b/package_bgs/FuzzySugenoIntegral.h @@ -0,0 +1,53 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "T2F/FuzzyUtils.h" + +namespace bgslibrary +{ + namespace algorithms + { + class FuzzySugenoIntegral : public IBGS + { + private: + long long frameNumber; + + int framesToLearn; + double alphaLearn; + double alphaUpdate; + int colorSpace; + int option; + bool smooth; + double threshold; + + FuzzyUtils fu; + cv::Mat img_background_f3; + + public: + FuzzySugenoIntegral(); + ~FuzzySugenoIntegral(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/GMG.cpp b/package_bgs/GMG.cpp index 675b23c..19bd8ab 100644 --- a/package_bgs/GMG.cpp +++ b/package_bgs/GMG.cpp @@ -16,9 +16,14 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "GMG.h" -GMG::GMG() : firstTime(true), initializationFrames(20), decisionThreshold(0.7), showOutput(true) +#if CV_MAJOR_VERSION == 2 + +using namespace bgslibrary::algorithms; + +GMG::GMG() : initializationFrames(20), decisionThreshold(0.7) { std::cout << "GMG()" << std::endl; + setup("./config/GMG.xml"); cv::initModule_video(); cv::setUseOptimized(true); @@ -34,41 +39,33 @@ GMG::~GMG() void GMG::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - - if(firstTime) + if (firstTime) { fgbg->set("initializationFrames", initializationFrames); fgbg->set("decisionThreshold", decisionThreshold); - - saveConfig(); } - - if(fgbg.empty()) + + if (fgbg.empty()) { std::cerr << "Failed to create BackgroundSubtractor.GMG Algorithm." << std::endl; return; } (*fgbg)(img_input, img_foreground); - - cv::Mat img_background; (*fgbg).getBackgroundImage(img_background); img_input.copyTo(img_segmentation); cv::add(img_input, cv::Scalar(100, 100, 0), img_segmentation, img_foreground); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) { - if (!img_foreground.empty()) - cv::imshow("GMG FG (Godbehere-Matsukawa-Goldberg)", img_foreground); - - if (!img_background.empty()) - cv::imshow("GMG BG (Godbehere-Matsukawa-Goldberg)", img_background); + cv::imshow("GMG FG (Godbehere-Matsukawa-Goldberg)", img_foreground); + cv::imshow("GMG BG (Godbehere-Matsukawa-Goldberg)", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -78,7 +75,7 @@ void GMG::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bg void GMG::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/GMG.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "initializationFrames", initializationFrames); cvWriteReal(fs, "decisionThreshold", decisionThreshold); @@ -89,11 +86,13 @@ void GMG::saveConfig() void GMG::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/GMG.xml", 0, CV_STORAGE_READ); - - initializationFrames = cvReadIntByName(fs, 0, "initializationFrames", 20); - decisionThreshold = cvReadRealByName(fs, 0, "decisionThreshold", 0.7); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + initializationFrames = cvReadIntByName(fs, nullptr, "initializationFrames", 20); + decisionThreshold = cvReadRealByName(fs, nullptr, "decisionThreshold", 0.7); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + cvReleaseFileStorage(&fs); } + +#endif diff --git a/package_bgs/GMG.h b/package_bgs/GMG.h index 9da28ad..1b4af30 100644 --- a/package_bgs/GMG.h +++ b/package_bgs/GMG.h @@ -16,30 +16,34 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION == 2 #include "IBGS.h" -class GMG : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Ptr<cv::BackgroundSubtractorGMG> fgbg; - int initializationFrames; - double decisionThreshold; - cv::Mat img_foreground; - cv::Mat img_segmentation; - bool showOutput; - -public: - GMG(); - ~GMG(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class GMG : public IBGS + { + private: + cv::Ptr<cv::BackgroundSubtractorGMG> fgbg; + int initializationFrames; + double decisionThreshold; + cv::Mat img_segmentation; + + public: + GMG(); + ~GMG(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} + +#endif diff --git a/package_bgs/IBGS.h b/package_bgs/IBGS.h index 073ce18..718bf51 100644 --- a/package_bgs/IBGS.h +++ b/package_bgs/IBGS.h @@ -16,18 +16,59 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once +#include <iostream> +#include <fstream> #include <opencv2/opencv.hpp> -class IBGS +namespace bgslibrary { -public: - virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground, cv::Mat &img_background) = 0; - /*virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground){ - process(img_input, img_foreground, cv::Mat()); - }*/ - virtual ~IBGS(){} + namespace algorithms + { + class IBGS + { + public: + void setShowOutput(const bool _showOutput) { + showOutput = _showOutput; + } + cv::Mat apply(const cv::Mat &img_input) { + setShowOutput(false); + cv::Mat _img_foreground; + cv::Mat _img_background; + process(img_input, _img_foreground, _img_background); + _img_background.copyTo(img_background); + return _img_foreground; + } + cv::Mat getBackgroundModel() { + return img_background; + } + virtual void process(const cv::Mat &img_input, cv::Mat &img_foreground, cv::Mat &img_background) = 0; + virtual ~IBGS() {} -private: - virtual void saveConfig() = 0; - virtual void loadConfig() = 0; -}; + protected: + bool firstTime = true; + bool showOutput = true; + cv::Mat img_background; + cv::Mat img_foreground; + std::string config_xml; + void setup(const std::string _config_xml) { + config_xml = _config_xml; + if (!config_xml.empty()) { + if (!std::ifstream(config_xml)) + saveConfig(); + loadConfig(); + } + } + void init(const cv::Mat &img_input, cv::Mat &img_outfg, cv::Mat &img_outbg) { + assert(img_input.empty() == false); + //img_outfg = cv::Mat::zeros(img_input.size(), img_input.type()); + //img_outbg = cv::Mat::zeros(img_input.size(), img_input.type()); + img_outfg = cv::Mat::zeros(img_input.size(), CV_8UC1); + img_outbg = cv::Mat::zeros(img_input.size(), CV_8UC3); + } + + private: + virtual void saveConfig() = 0; + virtual void loadConfig() = 0; + }; + } +} diff --git a/package_bgs/db/imbs.cpp b/package_bgs/IMBS/IMBS.cpp similarity index 74% rename from package_bgs/db/imbs.cpp rename to package_bgs/IMBS/IMBS.cpp index f5fc0d0..b1e177b 100644 --- a/package_bgs/db/imbs.cpp +++ b/package_bgs/IMBS/IMBS.cpp @@ -1,5 +1,21 @@ /* -* IMBS Background Subtraction Library +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* +* IMBS Background Subtraction Library * * This file imbs.hpp contains the C++ OpenCV based implementation for * IMBS algorithm described in @@ -8,8 +24,8 @@ * In Proc. of the Third Int. Conf. on Computational Modeling of Objects * Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012. * Please, cite the above paper if you use IMBS. -* -* This software is provided without any warranty about its usability. +* +* This software is provided without any warranty about its usability. * It is for educational purposes and should be regarded as such. * * Written by Domenico D. Bloisi @@ -19,7 +35,7 @@ * */ -#include "imbs.hpp" +#include "IMBS.hpp" using namespace std; using namespace cv; @@ -29,15 +45,15 @@ BackgroundSubtractorIMBS::BackgroundSubtractorIMBS() fps = 0.; fgThreshold = 15; associationThreshold = 5; - samplingPeriod = 250.;//500.ms + samplingPeriod = 250;//500.ms minBinHeight = 2; numSamples = 10; //30 alpha = 0.65f; beta = 1.15f; - tau_s = 60.; - tau_h = 40.; + tau_s = 60; + tau_h = 40; minArea = 30.; - persistencePeriod = samplingPeriod*numSamples/3.;//ms + persistencePeriod = samplingPeriod*numSamples / 3.;//ms initial_tick_count = (double)getTickCount(); @@ -63,7 +79,7 @@ BackgroundSubtractorIMBS::BackgroundSubtractorIMBS( this->fps = fps; this->fgThreshold = fgThreshold; this->persistencePeriod = persistencePeriod; - if(minBinHeight <= 1){ + if (minBinHeight <= 1) { this->minBinHeight = 1; } else { @@ -79,7 +95,7 @@ BackgroundSubtractorIMBS::BackgroundSubtractorIMBS( this->tau_h = tau_h; this->minArea = minArea; - if(fps == 0.) + if (fps == 0.) initial_tick_count = (double)getTickCount(); else initial_tick_count = 0; @@ -106,7 +122,7 @@ void BackgroundSubtractorIMBS::initialize(Size frameSize, int frameType) this->numPixels = frameSize.width*frameSize.height; persistenceMap = new unsigned int[numPixels]; - for(unsigned int i = 0; i < numPixels; i++) { + for (unsigned int i = 0; i < numPixels; i++) { persistenceMap[i] = 0; } @@ -134,20 +150,20 @@ void BackgroundSubtractorIMBS::initialize(Size frameSize, int frameType) //initial message to be shown until the first fg mask is computed initialMsgGray = Mat::zeros(frameSize, CV_8UC1); - putText(initialMsgGray, "Creating", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); - putText(initialMsgGray, "initial", Point(10,40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); - putText(initialMsgGray, "background...", Point(10,60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgGray, "Creating", Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgGray, "initial", Point(10, 40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgGray, "background...", Point(10, 60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); initialMsgRGB = Mat::zeros(frameSize, CV_8UC3); - putText(initialMsgRGB, "Creating", Point(10,20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); - putText(initialMsgRGB, "initial", Point(10,40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); - putText(initialMsgRGB, "background...", Point(10,60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgRGB, "Creating", Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgRGB, "initial", Point(10, 40), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); + putText(initialMsgRGB, "background...", Point(10, 60), FONT_HERSHEY_SIMPLEX, 0.4, CV_RGB(255, 255, 255)); - if(minBinHeight <= 1){ + if (minBinHeight <= 1) { minBinHeight = 1; } - for(unsigned int p = 0; p < numPixels; ++p) + for (unsigned int p = 0; p < numPixels; ++p) { bgBins[p].binValues = new Vec3b[numSamples]; bgBins[p].binHeights = new uchar[numSamples]; @@ -169,7 +185,7 @@ void BackgroundSubtractorIMBS::apply(InputArray _frame, OutputArray _fgmask, dou CV_Assert(frame.channels() == 3); bool needToInitialize = nframes == 0 || frame.type() != frameType; - if( needToInitialize ) { + if (needToInitialize) { initialize(frame.size(), frame.type()); } @@ -179,29 +195,29 @@ void BackgroundSubtractorIMBS::apply(InputArray _frame, OutputArray _fgmask, dou //get current time prev_timestamp = timestamp; - if(fps == 0.) { + if (fps == 0.) { timestamp = getTimestamp();//ms } else { - timestamp += 1000./fps;//ms + timestamp += 1000. / fps;//ms } //check for global changes - if(sudden_change) { + if (sudden_change) { changeBg(); } //wait for the first model to be generated - if(bgModel[0].isValid[0]) { - getFg(); + if (bgModel[0].isValid[0]) { + getFg(); hsvSuppression(); filterFg(); - } + } //update the bg model updateBg(); //show an initial message if the first bg is not yet ready - if(!bgModel[0].isValid[0]) { + if (!bgModel[0].isValid[0]) { initialMsgGray.copyTo(fgmask); initialMsgRGB.copyTo(bgImage); } @@ -209,23 +225,23 @@ void BackgroundSubtractorIMBS::apply(InputArray _frame, OutputArray _fgmask, dou } void BackgroundSubtractorIMBS::updateBg() { - if(bg_reset) { - if(bg_frame_counter > numSamples - 1) { + if (bg_reset) { + if (bg_frame_counter > numSamples - 1) { bg_frame_counter = numSamples - 1; } } - if(prev_bg_frame_time > timestamp) { + if (prev_bg_frame_time > timestamp) { prev_bg_frame_time = timestamp; } - if(bg_frame_counter == numSamples - 1) { + if (bg_frame_counter == numSamples - 1) { createBg(bg_frame_counter); bg_frame_counter = 0; } else { //bg_frame_counter < (numSamples - 1) - if((timestamp - prev_bg_frame_time) >= samplingPeriod) + if ((timestamp - prev_bg_frame_time) >= samplingPeriod) { //get a new sample for creating the bg model prev_bg_frame_time = timestamp; @@ -237,7 +253,7 @@ void BackgroundSubtractorIMBS::updateBg() { } double BackgroundSubtractorIMBS::getTimestamp() { - return ((double)getTickCount() - initial_tick_count)*1000./getTickFrequency(); + return ((double)getTickCount() - initial_tick_count)*1000. / getTickFrequency(); } void BackgroundSubtractorIMBS::hsvSuppression() { @@ -251,35 +267,35 @@ void BackgroundSubtractorIMBS::hsvSuppression() { vector<Mat> imHSV; cv::split(convertImageRGBtoHSV(frame), imHSV); - for(unsigned int p = 0; p < numPixels; ++p) { - if(fgmask.data[p]) { + for (unsigned int p = 0; p < numPixels; ++p) { + if (fgmask.data[p]) { h_i = imHSV[0].data[p]; s_i = imHSV[1].data[p]; v_i = imHSV[2].data[p]; - for(unsigned int n = 0; n < maxBgBins; ++n) { - if(!bgModel[p].isValid[n]) { + for (unsigned int n = 0; n < maxBgBins; ++n) { + if (!bgModel[p].isValid[n]) { break; } - if(bgModel[p].isFg[n]) { + if (bgModel[p].isFg[n]) { continue; } - bgrPixel.at<cv::Vec3b>(0,0) = bgModel[p].values[n]; + bgrPixel.at<cv::Vec3b>(0, 0) = bgModel[p].values[n]; cv::Mat hsvPixel = convertImageRGBtoHSV(bgrPixel); - h_b = hsvPixel.at<cv::Vec3b>(0,0)[0]; - s_b = hsvPixel.at<cv::Vec3b>(0,0)[1]; - v_b = hsvPixel.at<cv::Vec3b>(0,0)[2]; + h_b = hsvPixel.at<cv::Vec3b>(0, 0)[0]; + s_b = hsvPixel.at<cv::Vec3b>(0, 0)[1]; + v_b = hsvPixel.at<cv::Vec3b>(0, 0)[2]; v_ratio = (float)v_i / (float)v_b; s_diff = std::abs(s_i - s_b); - h_diff = std::min( std::abs(h_i - h_b), 255 - std::abs(h_i - h_b)); + h_diff = std::min(std::abs(h_i - h_b), 255 - std::abs(h_i - h_b)); - if( h_diff <= tau_h && + if (h_diff <= tau_h && s_diff <= tau_s && v_ratio >= alpha && v_ratio < beta) @@ -293,7 +309,7 @@ void BackgroundSubtractorIMBS::hsvSuppression() { } void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { - if(!bgSample.data) { + if (!bgSample.data) { //cerr << "createBg -- an error occurred: " << // " unable to retrieve frame no. " << bg_sample_number << endl; @@ -305,18 +321,18 @@ void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { //split bgSample in channels cv::split(bgSample, bgSampleBGR); //create a statistical model for each pixel (a set of bins of variable size) - for(unsigned int p = 0; p < numPixels; ++p) { + for (unsigned int p = 0; p < numPixels; ++p) { //create an initial bin for each pixel from the first sample (bg_sample_number = 0) - if(bg_sample_number == 0) { - for(int k = 0; k < 3; ++k) { + if (bg_sample_number == 0) { + for (int k = 0; k < 3; ++k) { bgBins[p].binValues[0][k] = bgSampleBGR[k].data[p]; } bgBins[p].binHeights[0] = 1; - for(unsigned int s = 1; s < numSamples; ++s) { + for (unsigned int s = 1; s < numSamples; ++s) { bgBins[p].binHeights[s] = 0; } //if the sample pixel is from foreground keep track of that situation - if(fgmask.data[p] == FOREGROUND_LABEL) { + if (fgmask.data[p] == FOREGROUND_LABEL) { bgBins[p].isFg[0] = true; } else { @@ -324,32 +340,32 @@ void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { } }//if(bg_sample_number == 0) else { //bg_sample_number > 0 - for(int k = 0; k < 3; ++k) { + for (int k = 0; k < 3; ++k) { currentPixel[k] = bgSampleBGR[k].data[p]; } int den = 0; - for(unsigned int s = 0; s < bg_sample_number; ++s) { + for (unsigned int s = 0; s < bg_sample_number; ++s) { //try to associate the current pixel values to an existing bin - if( std::abs(currentPixel[2] - bgBins[p].binValues[s][2]) <= associationThreshold && + if (std::abs(currentPixel[2] - bgBins[p].binValues[s][2]) <= associationThreshold && std::abs(currentPixel[1] - bgBins[p].binValues[s][1]) <= associationThreshold && - std::abs(currentPixel[0] - bgBins[p].binValues[s][0]) <= associationThreshold ) + std::abs(currentPixel[0] - bgBins[p].binValues[s][0]) <= associationThreshold) { den = (bgBins[p].binHeights[s] + 1); - for(int k = 0; k < 3; ++k) { + for (int k = 0; k < 3; ++k) { bgBins[p].binValues[s][k] = (bgBins[p].binValues[s][k] * bgBins[p].binHeights[s] + currentPixel[k]) / den; } bgBins[p].binHeights[s]++; //increment the height of the bin - if(fgmask.data[p] == FOREGROUND_LABEL) { + if (fgmask.data[p] == FOREGROUND_LABEL) { bgBins[p].isFg[s] = true; } break; } //if the association is not possible, create a new bin - else if(bgBins[p].binHeights[s] == 0) { + else if (bgBins[p].binHeights[s] == 0) { bgBins[p].binValues[s] = currentPixel; bgBins[p].binHeights[s]++; - if(fgmask.data[p] == FOREGROUND_LABEL) { + if (fgmask.data[p] == FOREGROUND_LABEL) { bgBins[p].isFg[s] = true; } else { @@ -362,44 +378,44 @@ void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { //if all samples have been processed //it is time to compute the fg mask - if(bg_sample_number == (numSamples - 1)) { + if (bg_sample_number == (numSamples - 1)) { unsigned int index = 0; int max_height = -1; - for(unsigned int s = 0; s < numSamples; ++s){ - if(bgBins[p].binHeights[s] == 0) { + for (unsigned int s = 0; s < numSamples; ++s) { + if (bgBins[p].binHeights[s] == 0) { bgModel[p].isValid[index] = false; break; } - if(index == maxBgBins) { + if (index == maxBgBins) { break; } - else if(bgBins[p].binHeights[s] >= minBinHeight) { - if(fgmask.data[p] == PERSISTENCE_LABEL) { - for(unsigned int n = 0; n < maxBgBins; n++) { - if(!bgModel[p].isValid[n]) { + else if (bgBins[p].binHeights[s] >= minBinHeight) { + if (fgmask.data[p] == PERSISTENCE_LABEL) { + for (unsigned int n = 0; n < maxBgBins; n++) { + if (!bgModel[p].isValid[n]) { break; } unsigned int d = std::max((int)std::abs(bgModel[p].values[n][0] - bgBins[p].binValues[s][0]), - std::abs(bgModel[p].values[n][1] - bgBins[p].binValues[s][1]) ); - d = std::max((int)d, std::abs(bgModel[p].values[n][2] - bgBins[p].binValues[s][2]) ); - if(d < fgThreshold){ + std::abs(bgModel[p].values[n][1] - bgBins[p].binValues[s][1])); + d = std::max((int)d, std::abs(bgModel[p].values[n][2] - bgBins[p].binValues[s][2])); + if (d < fgThreshold) { bgModel[p].isFg[n] = false; bgBins[p].isFg[s] = false; } } } - if(bgBins[p].binHeights[s] > max_height) { + if (bgBins[p].binHeights[s] > max_height) { max_height = bgBins[p].binHeights[s]; - for(int k = 0; k < 3; ++k) { + for (int k = 0; k < 3; ++k) { bgModel[p].values[index][k] = bgModel[p].values[0][k]; } bgModel[p].isValid[index] = true; bgModel[p].isFg[index] = bgModel[p].isFg[0]; bgModel[p].counter[index] = bgModel[p].counter[0]; - for(int k = 0; k < 3; ++k) { + for (int k = 0; k < 3; ++k) { bgModel[p].values[0][k] = bgBins[p].binValues[s][k]; } bgModel[p].isValid[0] = true; @@ -407,7 +423,7 @@ void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { bgModel[p].counter[0] = bgBins[p].binHeights[s]; } else { - for(int k = 0; k < 3; ++k) { + for (int k = 0; k < 3; ++k) { bgModel[p].values[index][k] = bgBins[p].binValues[s][k]; } bgModel[p].isValid[index] = true; @@ -421,25 +437,25 @@ void BackgroundSubtractorIMBS::createBg(unsigned int bg_sample_number) { }//else --> if(frame_number == 0) }//numPixels - if(bg_sample_number == (numSamples - 1)) { - //std::cout << "new bg created" << std::endl; + if (bg_sample_number == (numSamples - 1)) { + //std::cout << "new bg created" << std::endl; persistenceImage = Scalar(0); bg_reset = false; - if(sudden_change) { + if (sudden_change) { numSamples *= 3.; samplingPeriod *= 2.; sudden_change = false; } - for(unsigned int i = 0; i < numPixels; i++) { + for (unsigned int i = 0; i < numPixels; i++) { persistenceMap[i] = 0; } unsigned int p = 0; - for(int i = 0; i < bgImage.rows; ++i) { - for(int j = 0; j < bgImage.cols; ++j, ++p) { - bgImage.at<cv::Vec3b>(i,j) = bgModel[p].values[0]; + for (int i = 0; i < bgImage.rows; ++i) { + for (int j = 0; j < bgImage.cols; ++j, ++p) { + bgImage.at<cv::Vec3b>(i, j) = bgModel[p].values[0]; } } } @@ -452,13 +468,13 @@ void BackgroundSubtractorIMBS::getFg() { bool isFg = true; bool conditionalUpdated = false; unsigned int d = 0; - for(unsigned int p = 0; p < numPixels; ++p) { + for (unsigned int p = 0; p < numPixels; ++p) { isFg = true; conditionalUpdated = false; d = 0; - for(unsigned int n = 0; n < maxBgBins; ++n) { - if(!bgModel[p].isValid[n]) { - if(n == 0) { + for (unsigned int n = 0; n < maxBgBins; ++n) { + if (!bgModel[p].isValid[n]) { + if (n == 0) { isFg = false; } break; @@ -466,13 +482,13 @@ void BackgroundSubtractorIMBS::getFg() { else { //the model is valid d = std::max( (int)std::abs(bgModel[p].values[n][0] - frameBGR[0].data[p]), - std::abs(bgModel[p].values[n][1] - frameBGR[1].data[p]) ); + std::abs(bgModel[p].values[n][1] - frameBGR[1].data[p])); d = std::max( - (int)d, std::abs(bgModel[p].values[n][2] - frameBGR[2].data[p]) ); - if(d < fgThreshold){ + (int)d, std::abs(bgModel[p].values[n][2] - frameBGR[2].data[p])); + if (d < fgThreshold) { //check if it is a potential background pixel //from stationary object - if(bgModel[p].isFg[n]) { + if (bgModel[p].isFg[n]) { conditionalUpdated = true; break; } @@ -483,13 +499,13 @@ void BackgroundSubtractorIMBS::getFg() { } } } - if(isFg) { - if(conditionalUpdated) { + if (isFg) { + if (conditionalUpdated) { fgmask.data[p] = PERSISTENCE_LABEL; persistenceMap[p] += (timestamp - prev_timestamp); - if(persistenceMap[p] > persistencePeriod) { - for(unsigned int n = 0; n < maxBgBins; ++n) { - if(!bgModel[p].isValid[n]) { + if (persistenceMap[p] > persistencePeriod) { + for (unsigned int n = 0; n < maxBgBins; ++n) { + if (!bgModel[p].isValid[n]) { break; } bgModel[p].isFg[n] = false; @@ -521,13 +537,13 @@ void BackgroundSubtractorIMBS::areaThresholding() if (area < minArea || area >= maxArea) continue; else { - drawContours( tmpBinaryImage, contours, contourIdx, Scalar(255), CV_FILLED ); + drawContours(tmpBinaryImage, contours, contourIdx, Scalar(255), CV_FILLED); } - } - for(int i = 0; i < fgfiltered.rows; ++i) { - for(int j = 0; j < fgfiltered.cols; ++j) { - if(!tmpBinaryImage.at<uchar>(i,j)) { - fgfiltered.at<uchar>(i,j) = 0; + } + for (int i = 0; i < fgfiltered.rows; ++i) { + for (int j = 0; j < fgfiltered.cols; ++j) { + if (!tmpBinaryImage.at<uchar>(i, j)) { + fgfiltered.at<uchar>(i, j) = 0; } } } @@ -560,9 +576,9 @@ Mat BackgroundSubtractorIMBS::convertImageRGBtoHSV(const Mat& imageRGB) for (int x = 0; x < w; ++x) { // Get the RGB pixel components. NOTE that OpenCV stores RGB pixels in B,G,R order. //uchar *pRGB = (uchar*)(imRGB + y*rowSizeRGB + x*3); - int bB = imageRGB.at<Vec3b>(y,x)[0]; //*(uchar*)(pRGB+0); // Blue component - int bG = imageRGB.at<Vec3b>(y,x)[1]; //*(uchar*)(pRGB+1); // Green component - int bR = imageRGB.at<Vec3b>(y,x)[2]; //*(uchar*)(pRGB+2); // Red component + int bB = imageRGB.at<Vec3b>(y, x)[0]; //*(uchar*)(pRGB+0); // Blue component + int bG = imageRGB.at<Vec3b>(y, x)[1]; //*(uchar*)(pRGB+1); // Green component + int bR = imageRGB.at<Vec3b>(y, x)[2]; //*(uchar*)(pRGB+2); // Red component // Convert from 8-bit integers to floats. fR = bR * BYTE_TO_FLOAT; @@ -619,10 +635,10 @@ Mat BackgroundSubtractorIMBS::convertImageRGBtoHSV(const Mat& imageRGB) fH = (fG - fB) * ANGLE_TO_UNIT; } else if (iMax == bG) { // between cyan and yellow. - fH = (2.0f/6.0f) + ( fB - fR ) * ANGLE_TO_UNIT; + fH = (2.0f / 6.0f) + (fB - fR) * ANGLE_TO_UNIT; } else { // between magenta and cyan. - fH = (4.0f/6.0f) + ( fR - fG ) * ANGLE_TO_UNIT; + fH = (4.0f / 6.0f) + (fR - fG) * ANGLE_TO_UNIT; } // Wrap outlier Hues around the circle. if (fH < 0.0f) @@ -666,14 +682,14 @@ Mat BackgroundSubtractorIMBS::convertImageRGBtoHSV(const Mat& imageRGB) void BackgroundSubtractorIMBS::getBackgroundImage(OutputArray backgroundImage) const { - bgImage.copyTo(backgroundImage); + bgImage.copyTo(backgroundImage); } void BackgroundSubtractorIMBS::filterFg() { unsigned int cnt = 0; - for(unsigned int p = 0; p < numPixels; ++p) { - if(fgmask.data[p] == (uchar)255) { + for (unsigned int p = 0; p < numPixels; ++p) { + if (fgmask.data[p] == (uchar)255) { fgfiltered.data[p] = 255; cnt++; } @@ -682,23 +698,23 @@ void BackgroundSubtractorIMBS::filterFg() { } } - if(cnt > numPixels*0.5) { + if (cnt > numPixels*0.5) { sudden_change = true; } - if(morphologicalFiltering) { - cv::Mat element3(3,3,CV_8U,cv::Scalar(1)); + if (morphologicalFiltering) { + cv::Mat element3(3, 3, CV_8U, cv::Scalar(1)); cv::morphologyEx(fgfiltered, fgfiltered, cv::MORPH_OPEN, element3); cv::morphologyEx(fgfiltered, fgfiltered, cv::MORPH_CLOSE, element3); } areaThresholding(); - for(unsigned int p = 0; p < numPixels; ++p) { - if(fgmask.data[p] == PERSISTENCE_LABEL) { + for (unsigned int p = 0; p < numPixels; ++p) { + if (fgmask.data[p] == PERSISTENCE_LABEL) { fgfiltered.data[p] = PERSISTENCE_LABEL; } - else if(fgmask.data[p] == SHADOW_LABEL) { + else if (fgmask.data[p] == SHADOW_LABEL) { fgfiltered.data[p] = SHADOW_LABEL; } } @@ -715,7 +731,7 @@ void BackgroundSubtractorIMBS::changeBg() { //bg_reset = true; //cout << "qua" << endl; - if(!bg_reset) { + if (!bg_reset) { numSamples /= 3.; samplingPeriod /= 2.; bg_frame_counter = 0; @@ -724,19 +740,19 @@ void BackgroundSubtractorIMBS::changeBg() { } void BackgroundSubtractorIMBS::getBgModel(BgModel bgModel_copy[], int size) { - if(size != numPixels) { + if (size != numPixels) { return; } - for(unsigned int i = 0; i < numPixels; ++i){ + for (unsigned int i = 0; i < numPixels; ++i) { bgModel_copy[i].values = new Vec3b[maxBgBins]; bgModel_copy[i].isValid = new bool[maxBgBins]; bgModel_copy[i].isValid[0] = false; bgModel_copy[i].isFg = new bool[maxBgBins]; bgModel_copy[i].counter = new uchar[maxBgBins]; } - for(unsigned int p = 0; p < numPixels; ++p) { - for(unsigned int n = 0; n < maxBgBins; ++n) { - if(!bgModel[p].isValid[n]) { + for (unsigned int p = 0; p < numPixels; ++p) { + for (unsigned int n = 0; n < maxBgBins; ++n) { + if (!bgModel[p].isValid[n]) { break; } bgModel_copy[p].values[n] = bgModel[p].values[n]; diff --git a/package_bgs/db/imbs.hpp b/package_bgs/IMBS/IMBS.hpp similarity index 77% rename from package_bgs/db/imbs.hpp rename to package_bgs/IMBS/IMBS.hpp index fd7faf1..383e0ae 100644 --- a/package_bgs/db/imbs.hpp +++ b/package_bgs/IMBS/IMBS.hpp @@ -1,5 +1,21 @@ /* -* IMBS Background Subtraction Library +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* +* IMBS Background Subtraction Library * * This file imbs.hpp contains the C++ OpenCV based implementation for * IMBS algorithm described in @@ -8,8 +24,8 @@ * In Proc. of the Third Int. Conf. on Computational Modeling of Objects * Presented in Images: Fundamentals, Methods and Applications, pp. 39-44, 2012. * Please, cite the above paper if you use IMBS. -* -* This software is provided without any warranty about its usability. +* +* This software is provided without any warranty about its usability. * It is for educational purposes and should be regarded as such. * * Written by Domenico D. Bloisi @@ -18,9 +34,7 @@ * domenico.bloisi@gmail.com * */ - -#ifndef __IMBS_HPP__ -#define __IMBS_HPP__ +#pragma once //OPENCV #include <opencv2/core/core.hpp> @@ -41,23 +55,23 @@ public: BackgroundSubtractorIMBS(); //! the full constructor BackgroundSubtractorIMBS(double fps, - unsigned int fgThreshold=15, - unsigned int associationThreshold=5, - double samplingPeriod=500., - unsigned int minBinHeight=2, - unsigned int numSamples=30, - double alpha=0.65, - double beta=1.15, - double tau_s=60., - double tau_h=40., - double minArea=30., - double persistencePeriod=10000., - bool morphologicalFiltering=false - ); + unsigned int fgThreshold = 15, + unsigned int associationThreshold = 5, + double samplingPeriod = 500., + unsigned int minBinHeight = 2, + unsigned int numSamples = 30, + double alpha = 0.65, + double beta = 1.15, + double tau_s = 60., + double tau_h = 40., + double minArea = 30., + double persistencePeriod = 10000., + bool morphologicalFiltering = false + ); //! the destructor ~BackgroundSubtractorIMBS(); //! the update operator - void apply(InputArray image, OutputArray fgmask, double learningRate=-1.); + void apply(InputArray image, OutputArray fgmask, double learningRate = -1.); //! computes a background image which shows only the highest bin for each pixel void getBackgroundImage(OutputArray backgroundImage) const; @@ -73,7 +87,7 @@ private: //method for computing the foreground mask void getFg(); //method for suppressing shadows and highlights - void hsvSuppression(); + void hsvSuppression(); //method for refining foreground mask void filterFg(); //method for filtering out blobs smaller than a given area @@ -82,7 +96,7 @@ private: double getTimestamp(); //method for converting from RGB to HSV Mat convertImageRGBtoHSV(const Mat& imageRGB); - //method for changing the bg in case of sudden changes + //method for changing the bg in case of sudden changes void changeBg(); //current input RGB frame @@ -112,7 +126,7 @@ private: //previous time stamp in milliseconds (ms) double prev_timestamp; double initial_tick_count; - //initial message to be shown until the first bg model is ready + //initial message to be shown until the first bg model is ready Mat initialMsgGray; Mat initialMsgRGB; @@ -174,5 +188,3 @@ public: } void getBgModel(BgModel bgModel_copy[], int size); }; - -#endif //__IMBS_HPP__ diff --git a/package_bgs/IndependentMultimodal.cpp b/package_bgs/IndependentMultimodal.cpp new file mode 100644 index 0000000..7b4de4c --- /dev/null +++ b/package_bgs/IndependentMultimodal.cpp @@ -0,0 +1,74 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "IndependentMultimodal.h" + +using namespace bgslibrary::algorithms; + +IndependentMultimodal::IndependentMultimodal() : fps(10) +{ + std::cout << "IndependentMultimodal()" << std::endl; + pIMBS = new BackgroundSubtractorIMBS(fps); + setup("./config/IndependentMultimodal.xml"); +} + +IndependentMultimodal::~IndependentMultimodal() +{ + std::cout << "~IndependentMultimodal()" << std::endl; + delete pIMBS; +} + +void IndependentMultimodal::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + //get the fgmask and update the background model + pIMBS->apply(img_input, img_foreground); + + //get background image + pIMBS->getBackgroundImage(img_background); + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + cv::imshow("IMBS FG", img_foreground); + cv::imshow("IMBS BG", img_background); + } +#endif + + firstTime = false; +} + +void IndependentMultimodal::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void IndependentMultimodal::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/StaticFrameDifferenceBGS.h b/package_bgs/IndependentMultimodal.h similarity index 60% rename from package_bgs/StaticFrameDifferenceBGS.h rename to package_bgs/IndependentMultimodal.h index 55f7bf1..4e2e3a3 100644 --- a/package_bgs/StaticFrameDifferenceBGS.h +++ b/package_bgs/IndependentMultimodal.h @@ -16,30 +16,28 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - #include "IBGS.h" +#include "IMBS/IMBS.hpp" -class StaticFrameDifferenceBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Mat img_background; - cv::Mat img_foreground; - bool enableThreshold; - int threshold; - bool showOutput; - -public: - StaticFrameDifferenceBGS(); - ~StaticFrameDifferenceBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class IndependentMultimodal : public IBGS + { + private: + BackgroundSubtractorIMBS* pIMBS; + int fps; + + public: + IndependentMultimodal(); + ~IndependentMultimodal(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/ae/KDE.cpp b/package_bgs/KDE.cpp similarity index 56% rename from package_bgs/ae/KDE.cpp rename to package_bgs/KDE.cpp index 2cbbd8c..28564a0 100644 --- a/package_bgs/ae/KDE.cpp +++ b/package_bgs/KDE.cpp @@ -16,11 +16,15 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "KDE.h" -KDE::KDE() : SequenceLength(50), TimeWindowSize(100), SDEstimationFlag(1), lUseColorRatiosFlag(1), - th(10e-8), alpha(0.3), framesToLearn(10), frameNumber(0), firstTime(true), showOutput(true) +using namespace bgslibrary::algorithms; + +KDE::KDE() : + SequenceLength(50), TimeWindowSize(100), SDEstimationFlag(1), lUseColorRatiosFlag(1), + th(10e-8), alpha(0.3), framesToLearn(10), frameNumber(0) { p = new NPBGSubtractor; std::cout << "KDE()" << std::endl; + setup("./config/KDE.xml"); } KDE::~KDE() @@ -32,72 +36,73 @@ KDE::~KDE() void KDE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); + init(img_input, img_output, img_bgmodel); - if(firstTime) + if (firstTime) { rows = img_input.size().height; cols = img_input.size().width; color_channels = img_input.channels(); // SequenceLength: number of samples for each pixel. - // TimeWindowSize: Time window for sampling. for example in the call above, the bg will sample 50 points out of 100 frames. + // TimeWindowSize: Time window for sampling. for example in the call above, the bg will sample 50 points out of 100 frames. // this rate will affect how fast the model adapt. // SDEstimationFlag: True means to estimate suitable kernel bandwidth to each pixel, False uses a default value. // lUseColorRatiosFlag: True means use normalized RGB for color (recommended.) - p->Intialize(rows,cols,color_channels,SequenceLength,TimeWindowSize,SDEstimationFlag,lUseColorRatiosFlag); + p->Intialize(rows, cols, color_channels, SequenceLength, TimeWindowSize, SDEstimationFlag, lUseColorRatiosFlag); // th: 0-1 is the probability threshold for a pixel to be a foregroud. typically make it small as 10e-8. the smaller the value the less false positive and more false negative. // alpha: 0-1, for color. typically set to 0.3. this affect shadow suppression. - p->SetThresholds(th,alpha); + p->SetThresholds(th, alpha); FGImage = new unsigned char[rows*cols]; //FilteredFGImage = new unsigned char[rows*cols]; FilteredFGImage = 0; DisplayBuffers = 0; - img_foreground = cv::Mat::zeros(rows,cols,CV_8UC1); + img_foreground = cv::Mat::zeros(img_input.size(), CV_8UC1); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); frameNumber = 0; - saveConfig(); firstTime = false; } // Stores the first N frames to build the background model - if(frameNumber < framesToLearn) + if (frameNumber < framesToLearn) { p->AddFrame(img_input.data); frameNumber++; - return; } - - // Build the background model with first 10 frames - if(frameNumber == framesToLearn) + else { - p->Estimation(); - frameNumber++; - } + // Build the background model with first 10 frames + if (frameNumber == framesToLearn) + { + p->Estimation(); + frameNumber++; + } + + // Now, we can subtract the background + ((NPBGSubtractor*)p)->NBBGSubtraction(img_input.data, FGImage, FilteredFGImage, DisplayBuffers); - // Now, we can subtract the background - ((NPBGSubtractor *)p)->NBBGSubtraction(img_input.data,FGImage,FilteredFGImage,DisplayBuffers); - - // At each frame also you can call the update function to adapt the bg - // here you pass a mask where pixels with true value will be masked out of the update. - ((NPBGSubtractor *)p)->Update(FGImage); + // At each frame also you can call the update function to adapt the bg + // here you pass a mask where pixels with true value will be masked out of the update. + ((NPBGSubtractor*)p)->Update(FGImage); - img_foreground.data = FGImage; + img_foreground.data = FGImage; + } - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) cv::imshow("KDE", img_foreground); +#endif img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); } void KDE::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/KDE.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "framesToLearn", framesToLearn); cvWriteInt(fs, "SequenceLength", SequenceLength); @@ -113,16 +118,16 @@ void KDE::saveConfig() void KDE::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/KDE.xml", 0, CV_STORAGE_READ); - - framesToLearn = cvReadIntByName(fs, 0, "framesToLearn", 10); - SequenceLength = cvReadIntByName(fs, 0, "SequenceLength", 50); - TimeWindowSize = cvReadIntByName(fs, 0, "TimeWindowSize", 100); - SDEstimationFlag = cvReadIntByName(fs, 0, "SDEstimationFlag", 1); - lUseColorRatiosFlag = cvReadIntByName(fs, 0, "lUseColorRatiosFlag", 1); - th = cvReadRealByName(fs, 0, "th", 10e-8); - alpha = cvReadRealByName(fs, 0, "alpha", 0.3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + framesToLearn = cvReadIntByName(fs, nullptr, "framesToLearn", 10); + SequenceLength = cvReadIntByName(fs, nullptr, "SequenceLength", 50); + TimeWindowSize = cvReadIntByName(fs, nullptr, "TimeWindowSize", 100); + SDEstimationFlag = cvReadIntByName(fs, nullptr, "SDEstimationFlag", 1); + lUseColorRatiosFlag = cvReadIntByName(fs, nullptr, "lUseColorRatiosFlag", 1); + th = cvReadRealByName(fs, nullptr, "th", 10e-8); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/KDE.h b/package_bgs/KDE.h new file mode 100644 index 0000000..e77996f --- /dev/null +++ b/package_bgs/KDE.h @@ -0,0 +1,57 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "KDE/NPBGSubtractor.h" + +namespace bgslibrary +{ + namespace algorithms + { + class KDE : public IBGS + { + private: + NPBGSubtractor *p; + int rows; + int cols; + int color_channels; + int SequenceLength; + int TimeWindowSize; + int SDEstimationFlag; + int lUseColorRatiosFlag; + double th; + double alpha; + int framesToLearn; + int frameNumber; + + unsigned char *FGImage; + unsigned char *FilteredFGImage; + unsigned char **DisplayBuffers; + + public: + KDE(); + ~KDE(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/ae/KernelTable.cpp b/package_bgs/KDE/KernelTable.cpp similarity index 75% rename from package_bgs/ae/KernelTable.cpp rename to package_bgs/KDE/KernelTable.cpp index 9e20d7c..bd9c368 100644 --- a/package_bgs/ae/KernelTable.cpp +++ b/package_bgs/KDE/KernelTable.cpp @@ -26,21 +26,21 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * copyright notice must be included. For any other uses of this software, * in original or modified form, including but not limited to distribution * in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. * Other than these cases, no part of this software may be used or * distributed without written permission of the author. * -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * Ahmed Elgammal -* +* * University of Maryland at College Park * UMIACS -* A.V. Williams Bldg. +* A.V. Williams Bldg. * CollegePark, MD 20742 * E-mail: elgammal@umiacs.umd.edu * @@ -67,8 +67,8 @@ KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmam { std::cout << "KernelLUTable()" << std::endl; - double C1,C2,v,segma,sum; - int bin,b; + double C1, C2, v, segma, sum; + int bin, b; minsegma = Segmamin; maxsegma = Segmamax; @@ -78,27 +78,27 @@ KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmam // Generate the Kernel // allocate memory for the Kernal Table - kerneltable = new double[segmabins*(2*KernelHalfWidth+1)]; + kerneltable = new double[segmabins*(2 * KernelHalfWidth + 1)]; kernelsums = new double[segmabins]; double segmastep = (maxsegma - minsegma) / segmabins; double y; - for(segma = minsegma, bin = 0; bin < segmabins; segma += segmastep, bin++) + for (segma = minsegma, bin = 0; bin < segmabins; segma += segmastep, bin++) { - C1 = 1/(sqrt(2*PI)*segma); - C2 = -1/(2*segma*segma); + C1 = 1 / (sqrt(2 * PI)*segma); + C2 = -1 / (2 * segma*segma); - b = (2*KernelHalfWidth+1)*bin; + b = (2 * KernelHalfWidth + 1)*bin; sum = 0; - - for(int x = 0; x <= KernelHalfWidth; x++) + + for (int x = 0; x <= KernelHalfWidth; x++) { - y = x/1.0; + y = x / 1.0; v = C1*exp(C2*y*y); - kerneltable[b+KernelHalfWidth+x]=v; - kerneltable[b+KernelHalfWidth-x]=v; - sum += 2*v; + kerneltable[b + KernelHalfWidth + x] = v; + kerneltable[b + KernelHalfWidth - x] = v; + sum += 2 * v; } sum -= C1; @@ -106,11 +106,11 @@ KernelLUTable::KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmam kernelsums[bin] = sum; // Normailization - for(int x = 0; x <= KernelHalfWidth; x++) + for (int x = 0; x <= KernelHalfWidth; x++) { - v = kerneltable[b+KernelHalfWidth+x] / sum; - kerneltable[b+KernelHalfWidth+x]=v; - kerneltable[b+KernelHalfWidth-x]=v; + v = kerneltable[b + KernelHalfWidth + x] / sum; + kerneltable[b + KernelHalfWidth + x] = v; + kerneltable[b + KernelHalfWidth - x] = v; } } } diff --git a/package_bgs/ae/KernelTable.h b/package_bgs/KDE/KernelTable.h similarity index 86% rename from package_bgs/ae/KernelTable.h rename to package_bgs/KDE/KernelTable.h index bc37cc4..63a20dc 100644 --- a/package_bgs/ae/KernelTable.h +++ b/package_bgs/KDE/KernelTable.h @@ -26,28 +26,26 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * copyright notice must be included. For any other uses of this software, * in original or modified form, including but not limited to distribution * in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. * Other than these cases, no part of this software may be used or * distributed without written permission of the author. * -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * Ahmed Elgammal -* +* * University of Maryland at College Park * UMIACS -* A.V. Williams Bldg. +* A.V. Williams Bldg. * CollegePark, MD 20742 * E-mail: elgammal@umiacs.umd.edu * **/ - -#ifndef __KERNEL_TABLE__ -#define __KERNEL_TABLE__ +#pragma once #include <iostream> @@ -65,7 +63,5 @@ public: KernelLUTable(); ~KernelLUTable(); - KernelLUTable(int KernelHalfWidth,double Segmamin,double Segmamax,int Segmabins); + KernelLUTable(int KernelHalfWidth, double Segmamin, double Segmamax, int Segmabins); }; - -#endif diff --git a/package_bgs/KDE/NPBGSubtractor.cpp b/package_bgs/KDE/NPBGSubtractor.cpp new file mode 100644 index 0000000..5f004b9 --- /dev/null +++ b/package_bgs/KDE/NPBGSubtractor.cpp @@ -0,0 +1,1160 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* +* +* Copyright 2001 by Ahmed Elgammal All rights reserved. +* +* Permission to use, copy, or modify this software and its documentation +* for educational and research purposes only and without fee is hereby +* granted, provided that this copyright notice and the original authors's +* name appear on all copies and supporting documentation. If individual +* files are separated from this distribution directory structure, this +* copyright notice must be included. For any other uses of this software, +* in original or modified form, including but not limited to distribution +* in whole or in part, specific prior permission must be obtained from +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. +* Other than these cases, no part of this software may be used or +* distributed without written permission of the author. +* +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided +* "as is" without express or implied warranty. +* +* Ahmed Elgammal +* +* University of Maryland at College Park +* UMIACS +* A.V. Williams Bldg. +* CollegePark, MD 20742 +* E-mail: elgammal@umiacs.umd.edu +* +**/ + +// NPBGSubtractor.cpp: implementation of the NPBGSubtractor class. +// +////////////////////////////////////////////////////////////////////// + +#include "NPBGSubtractor.h" +#include <assert.h> +#include <math.h> +#include <string.h> + +//#ifdef _DEBUG +//#undef THIS_FILE +//static char THIS_FILE[]=__FILE__; +//#define new DEBUG_NEW +//#endif + +void BGR2SnGnRn(unsigned char * in_image, + unsigned char * out_image, + unsigned int rows, + unsigned int cols) +{ + unsigned int i; + unsigned int r2, r3; + unsigned int r, g, b; + double s; + + for (i = 0; i < rows*cols * 3; i += 3) + { + b = in_image[i]; + g = in_image[i + 1]; + r = in_image[i + 2]; + + // calculate color ratios + s = (double)255 / (double)(b + g + r + 30); + + r2 = (unsigned int)((g + 10) * s); + r3 = (unsigned int)((r + 10) * s); + + out_image[i] = (unsigned char)(((unsigned int)b + g + r) / 3); + out_image[i + 1] = (unsigned char)(r2 > 255 ? 255 : r2); + out_image[i + 2] = (unsigned char)(r3 > 255 ? 255 : r3); + } +} + +void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist) +{ + unsigned int j; + int bin, diff; + + unsigned int imagesize = pHist->imagesize; + unsigned char histbins = pHist->histbins; + unsigned char *pAbsDiffHist = pHist->Hist; + + int histbins_1 = histbins - 1; + + for (j = 0; j < imagesize; j++) + { + diff = (int)image1[j] - (int)image2[j]; + diff = abs(diff); + // update histogram + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[j*histbins + bin]++; + } +} + +void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist) +{ + unsigned char * Hist = pAbsDiffHist->Hist; + unsigned char * MedianBins = pAbsDiffHist->MedianBins; + unsigned char * AccSum = pAbsDiffHist->AccSum; + unsigned char histsum = pAbsDiffHist->histsum; + unsigned char histbins = pAbsDiffHist->histbins; + unsigned int imagesize = pAbsDiffHist->imagesize; + + int sum; + int bin; + unsigned int histindex; + unsigned char medianCount = histsum / 2; + unsigned int j; + + // find medians + for (j = 0; j < imagesize; j++) + { + // find the median + bin = 0; + sum = 0; + + histindex = j*histbins; + + while (sum < medianCount) + { + sum += Hist[histindex + bin]; + bin++; + } + + bin--; + + MedianBins[j] = bin; + AccSum[j] = sum; + } +} + +DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence, + unsigned int rows, + unsigned int cols, + unsigned int color_channels, + unsigned int SequenceLength, + unsigned int histbins) +{ + + unsigned int imagesize = rows*cols*color_channels; + unsigned int i; + + DynamicMedianHistogram Hist; + + unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins]; + unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels]; + unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels]; + unsigned char *pAccSum = new unsigned char[rows*cols*color_channels]; + + memset(pAbsDiffHist, 0, rows*cols*color_channels*histbins); + + Hist.Hist = pAbsDiffHist; + Hist.MedianBins = pMedianBins; + Hist.MedianFreq = pMedianFreq; + Hist.AccSum = pAccSum; + Hist.histbins = histbins; + Hist.imagesize = rows*cols*color_channels; + Hist.histsum = SequenceLength - 1; + + unsigned char *image1, *image2; + for (i = 1; i < SequenceLength; i++) + { + // find diff between frame i,i-1; + image1 = pSequence + (i - 1)*imagesize; + image2 = pSequence + (i)*imagesize; + + UpdateDiffHist(image1, image2, &Hist); + } + + FindHistMedians(&Hist); + + return Hist; +} + +void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist, + unsigned char * pSDs, + unsigned int imagesize, + double MinSD, + double MaxSD, + unsigned int kernelbins) +{ + double v; + double kernelbinfactor = (kernelbins - 1) / (MaxSD - MinSD); + int medianCount; + int sum; + int bin; + unsigned int histindex; + unsigned int j; + unsigned int x1, x2; + + unsigned char *Hist = pAbsDiffHist->Hist; + unsigned char *MedianBins = pAbsDiffHist->MedianBins; + unsigned char *AccSum = pAbsDiffHist->AccSum; + unsigned char histsum = pAbsDiffHist->histsum; + unsigned char histbins = pAbsDiffHist->histbins; + + medianCount = (histsum) / 2; + + for (j = 0; j < imagesize; j++) + { + histindex = j*histbins; + + bin = MedianBins[j]; + sum = AccSum[j]; + + x1 = sum - Hist[histindex + bin]; + x2 = sum; + + // interpolate to get the median + // x1 < 50 % < x2 + + v = 1.04 * ((double)bin - (double)(x2 - medianCount) / (double)(x2 - x1)); + v = (v <= MinSD ? MinSD : v); + + // convert sd to kernel table bin + + bin = (int)(v >= MaxSD ? kernelbins - 1 : floor((v - MinSD)*kernelbinfactor + .5)); + + assert(bin >= 0 && bin < kernelbins); + + pSDs[j] = bin; + } +} + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +NPBGSubtractor::NPBGSubtractor() {} + +NPBGSubtractor::~NPBGSubtractor() +{ + delete AbsDiffHist.Hist; + delete AbsDiffHist.MedianBins; + delete AbsDiffHist.MedianFreq; + delete AbsDiffHist.AccSum; + delete KernelTable; + delete BGModel->SDbinsImage; + delete BGModel; + delete Pimage1; + delete Pimage2; + delete tempFrame; + delete imageindex->List; + delete imageindex; +} + +int NPBGSubtractor::Intialize(unsigned int prows, + unsigned int pcols, + unsigned int pcolor_channels, + unsigned int SequenceLength, + unsigned int pTimeWindowSize, + unsigned char pSDEstimationFlag, + unsigned char pUseColorRatiosFlag) +{ + + rows = prows; + cols = pcols; + color_channels = pcolor_channels; + imagesize = rows*cols*color_channels; + SdEstimateFlag = pSDEstimationFlag; + UseColorRatiosFlag = pUseColorRatiosFlag; + //SampleSize = SequenceLength; + + AdaptBGFlag = FALSE; + // + SubsetFlag = TRUE; + + UpdateSDRate = 0; + + BGModel = new NPBGmodel(rows, cols, color_channels, SequenceLength, pTimeWindowSize, 500); + + Pimage1 = new double[rows*cols]; + Pimage2 = new double[rows*cols]; + + tempFrame = new unsigned char[rows*cols * 3]; + + imageindex = new ImageIndex; + imageindex->List = new unsigned int[rows*cols]; + + // error checking + if (BGModel == NULL) + return 0; + + return 1; +} + +void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer) +{ + if (UseColorRatiosFlag && color_channels == 3) + BGR2SnGnRn(ImageBuffer, ImageBuffer, rows, cols); + + BGModel->AddFrame(ImageBuffer); +} + +void NPBGSubtractor::Estimation() +{ + int SampleSize = BGModel->SampleSize; + + memset(BGModel->TemporalMask, 0, rows*cols*BGModel->TemporalBufferLength); + + //BGModel->AccMask= new unsigned int [rows*cols]; + memset(BGModel->AccMask, 0, rows*cols * sizeof(unsigned int)); + + unsigned char *pSDs = new unsigned char[rows*cols*color_channels]; + + //DynamicMedianHistogram AbsDiffHist; + + int Abshistbins = 20; + + TimeIndex = 0; + + // estimate standard deviations + + if (SdEstimateFlag) + { + AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence, rows, cols, color_channels, SampleSize, Abshistbins); + EstimateSDsFromAbsDiffHist(&AbsDiffHist, pSDs, imagesize, SEGMAMIN, SEGMAMAX, SEGMABINS); + } + else + { + unsigned int bin; + bin = (unsigned int)floor(((DEFAULTSEGMA - SEGMAMIN)*SEGMABINS) / (SEGMAMAX - SEGMAMIN)); + memset(pSDs, bin, rows*cols*color_channels * sizeof(unsigned char)); + } + + BGModel->SDbinsImage = pSDs; + + // Generate the Kernel + KernelTable = new KernelLUTable(KERNELHALFWIDTH, SEGMAMIN, SEGMAMAX, SEGMABINS); +} + +/*********************************************************************/ + +void BuildImageIndex(unsigned char * Image, + ImageIndex * imageIndex, + unsigned int rows, + unsigned int cols) +{ + unsigned int i, j; + unsigned int r, c; + unsigned int * image_list; + + j = cols + 1; + i = 0; + image_list = imageIndex->List; + + for (r = 1; r < rows - 1; r++) + { + for (c = 1; c < cols - 1; c++) + { + if (Image[j]) + image_list[i++] = j; + + j++; + } + j += 2; + } + + imageIndex->cnt = i; +} + +/*********************************************************************/ + +void HystExpandOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + double * Pimage, + double hyst_th, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) +{ + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k; + unsigned int idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + + for (i = 0; i < in_cnt; i++) + { + for (j = 0; j < 9; j++) + { + idx = in_list[i] + Nbr[j]; + + if (Pimage[idx] < hyst_th) + outImage[idx] = 255; + } + } + + // build index for out image + BuildImageIndex(outImage, outIndex, urows, ucols); +} + +/*********************************************************************/ + +void HystShrinkOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + double * Pimage, + double hyst_th, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) +{ + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k, idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + + for (i = 0; i < in_cnt; i++) + { + idx = in_list[i]; + j = 0; + + while (j < 9 && inImage[idx + Nbr[j]]) + j++; + + if (j >= 9 || Pimage[idx] <= hyst_th) + outImage[idx] = 255; + } + + BuildImageIndex(outImage, outIndex, rows, cols); +} + +/*********************************************************************/ + +void ExpandOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) +{ + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k; + unsigned int idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + + memset(outImage, 0, rows*cols); + + + out_list = outIndex->List; + k = 0; + for (i = 0; i < in_cnt; i++) + for (j = 0; j < 9; j++) { + idx = in_list[i] + Nbr[j]; + outImage[idx] = 255; + } + + + // build index for out image + + BuildImageIndex(outImage, outIndex, rows, cols); + +} + +/*********************************************************************/ + +void ShrinkOperatorIndexed(unsigned char * inImage, + ImageIndex * inIndex, + unsigned char * outImage, + ImageIndex * outIndex, + unsigned int urows, + unsigned int ucols) +{ + + unsigned int * in_list; + unsigned int in_cnt; + unsigned int * out_list; + + int rows, cols; + + int Nbr[9]; + unsigned int i, j; + unsigned int k, idx; + + rows = (int)urows; + cols = (int)ucols; + + in_cnt = inIndex->cnt; + in_list = inIndex->List; + + Nbr[0] = -cols - 1; + Nbr[1] = -cols; + Nbr[2] = -cols + 1; + Nbr[3] = -1; + Nbr[4] = 0; + Nbr[5] = 1; + Nbr[6] = cols - 1; + Nbr[7] = cols; + Nbr[8] = cols + 1; + + + memset(outImage, 0, rows*cols); + + out_list = outIndex->List; + k = 0; + for (i = 0; i < in_cnt; i++) { + idx = in_list[i]; + j = 0; + + while (j < 9 && inImage[idx + Nbr[j]]) { + j++; + } + + if (j >= 9) { + outImage[idx] = 255; + } + } + + BuildImageIndex(outImage, outIndex, rows, cols); +} + +/*********************************************************************/ + +void NoiseFilter_o(unsigned char * Image, + unsigned char * ResultIm, + int rows, + int cols, + unsigned char th) +{ + /* assuming input is 1 for on, 0 for off */ + + + int r, c; + unsigned char *p, *n, *nw, *ne, *e, *w, *s, *sw, *se; + unsigned int v; + unsigned int TH; + + unsigned char * ResultPtr; + + TH = 255 * th; + + memset(ResultIm, 0, rows*cols); + + p = Image + cols + 1; + ResultPtr = ResultIm + cols + 1; + + for (r = 1; r < rows - 1; r++) + { + for (c = 1; c < cols - 1; c++) + { + if (*p) + { + n = p - cols; + ne = n + 1; + nw = n - 1; + e = p + 1; + w = p - 1; + s = p + cols; + se = s + 1; + sw = s - 1; + + v = (unsigned int)*nw + *n + *ne + *w + *e + *sw + *s + *se; + + if (v >= TH) + *ResultPtr = 255; + else + *ResultPtr = 0; + } + p++; + ResultPtr++; + } + p += 2; + ResultPtr += 2; + } +} + +/*********************************************************************/ + +void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image, + unsigned char * Mask) +{ + unsigned int i, ic; + unsigned char * pSequence = BGModel->Sequence; + unsigned char * PixelQTop = BGModel->PixelQTop; + unsigned int Top = BGModel->Top; + unsigned int rate; + + int TemporalBufferTop = (int)BGModel->TemporalBufferTop; + unsigned char * pTemporalBuffer = BGModel->TemporalBuffer; + unsigned char * pTemporalMask = BGModel->TemporalMask; + int TemporalBufferLength = BGModel->TemporalBufferLength; + + unsigned int * AccMask = BGModel->AccMask; + unsigned int ResetMaskTh = BGModel->ResetMaskTh; + + unsigned char *pAbsDiffHist = AbsDiffHist.Hist; + unsigned char histbins = AbsDiffHist.histbins; + int histbins_1 = histbins - 1; + + int TimeWindowSize = BGModel->TimeWindowSize; + int SampleSize = BGModel->SampleSize; + + int TemporalBufferNext; + + unsigned int imagebuffersize = rows*cols*color_channels; + unsigned int imagespatialsize = rows*cols; + + unsigned char mask; + + unsigned int histindex; + unsigned char diff; + unsigned char bin; + + static int TBCount = 0; + + unsigned char * pTBbase1, *pTBbase2; + unsigned char * pModelbase1, *pModelbase2; + + rate = TimeWindowSize / SampleSize; + rate = (rate > 2) ? rate : 2; + + + TemporalBufferNext = (TemporalBufferTop + 1) + % TemporalBufferLength; + + // pointers to Masks : Top and Next + unsigned char * pTMaskTop = pTemporalMask + TemporalBufferTop*imagespatialsize; + unsigned char * pTMaskNext = pTemporalMask + TemporalBufferNext*imagespatialsize; + + // pointers to TB frames: Top and Next + unsigned char * pTBTop = pTemporalBuffer + TemporalBufferTop*imagebuffersize; + unsigned char * pTBNext = pTemporalBuffer + TemporalBufferNext*imagebuffersize; + + if (((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength) + { + for (i = 0, ic = 0; i < imagespatialsize; i++, ic += color_channels) + { + mask = *(pTMaskTop + i) || *(pTMaskNext + i); + + if (!mask) + { + // pointer to TB pixels to be added to the model + pTBbase1 = pTBTop + ic; + pTBbase2 = pTBNext + ic; + + // pointers to Model pixels to be replaced + pModelbase1 = pSequence + PixelQTop[i] * imagebuffersize + ic; + pModelbase2 = pSequence + ((PixelQTop[i] + 1) % SampleSize)*imagebuffersize + ic; + + // update Deviation Histogram + if (SdEstimateFlag) + { + if (color_channels == 1) + { + histindex = i*histbins; + + // add new pair from temporal buffer + diff = (unsigned char)abs((int)*pTBbase1 - (int)*pTBbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + + // remove old pair from the model + diff = (unsigned char)abs((int)*pModelbase1 - (int)*pModelbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + } + else + { + // color + + // add new pair from temporal buffer + histindex = ic*histbins; + diff = abs(*pTBbase1 - + *pTBbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + histindex += histbins; + diff = abs(*(pTBbase1 + 1) - + *(pTBbase2 + 1)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + histindex += histbins; + diff = abs(*(pTBbase1 + 2) - + *(pTBbase2 + 2)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]++; + + // remove old pair from the model + histindex = ic*histbins; + + diff = abs(*pModelbase1 - + *pModelbase2); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + + histindex += histbins; + diff = abs(*(pModelbase1 + 1) - + *(pModelbase2 + 1)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + + histindex += histbins; + diff = abs(*(pModelbase1 + 2) - + *(pModelbase2 + 2)); + bin = (diff < histbins ? diff : histbins_1); + pAbsDiffHist[histindex + bin]--; + } + } + + // add new pair into the model + memcpy(pModelbase1, pTBbase1, color_channels * sizeof(unsigned char)); + + memcpy(pModelbase2, pTBbase2, color_channels * sizeof(unsigned char)); + + PixelQTop[i] = (PixelQTop[i] + 2) % SampleSize; + } + } + } // end if (sampling event) + + // update temporal buffer + // add new frame to Temporal buffer. + memcpy(pTBTop, image, imagebuffersize); + + // update AccMask + // update new Mask with information in AccMask + + for (i = 0; i < rows*cols; i++) + { + if (Mask[i]) + AccMask[i]++; + else + AccMask[i] = 0; + + if (AccMask[i] > ResetMaskTh) + Mask[i] = 0; + } + + // add new mask + memcpy(pTMaskTop, Mask, imagespatialsize); + + // advance Temporal buffer pointer + TemporalBufferTop = (TemporalBufferTop + 1) % TemporalBufferLength; + + BGModel->TemporalBufferTop = TemporalBufferTop; + + TBCount++; + + // estimate SDs + + if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0)) + { + double MaxSD = KernelTable->maxsegma; + double MinSD = KernelTable->minsegma; + int KernelBins = KernelTable->segmabins; + + unsigned char * pSDs = BGModel->SDbinsImage; + + FindHistMedians(&(AbsDiffHist)); + EstimateSDsFromAbsDiffHist(&(AbsDiffHist), pSDs, imagebuffersize, MinSD, MaxSD, KernelBins); + } + + TimeIndex++; +} + +/*********************************************************************/ + +void DisplayPropabilityImageWithThresholding(double * Pimage, + unsigned char * DisplayImage, + double Threshold, + unsigned int rows, + unsigned int cols) +{ + double p; + + for (unsigned int i = 0; i < rows*cols; i++) + { + p = Pimage[i]; + + DisplayImage[i] = (p > Threshold) ? 0 : 255; + } +} + +/*********************************************************************/ + +void NPBGSubtractor::NPBGSubtraction_Subset_Kernel( + unsigned char * image, + unsigned char * FGImage, + unsigned char * FilteredFGImage) +{ + unsigned int i, j; + unsigned char *pSequence = BGModel->Sequence; + + unsigned int SampleSize = BGModel->SampleSize; + + double *kerneltable = KernelTable->kerneltable; + int KernelHalfWidth = KernelTable->tablehalfwidth; + double *KernelSum = KernelTable->kernelsums; + double KernelMaxSigma = KernelTable->maxsegma; + double KernelMinSigma = KernelTable->minsegma; + int KernelBins = KernelTable->segmabins; + unsigned char * SDbins = BGModel->SDbinsImage; + + unsigned char * SaturationImage = FilteredFGImage; + + // default sigmas .. to be removed. + double sigma1; + double sigma2; + double sigma3; + + sigma1 = 2.25; + sigma2 = 2.25; + sigma3 = 2.25; + + double p; + double th; + + double alpha; + + alpha = AlphaValue; + + /* intialize FG image */ + + memset(FGImage, 0, rows*cols); + + //Threshold=1; + th = Threshold * SampleSize; + + double sum = 0, kernel1, kernel2, kernel3; + int k, g; + + + if (color_channels == 1) + { + // gray scale + + int kernelbase; + + for (i = 0; i < rows*cols; i++) + { + kernelbase = SDbins[i] * (2 * KernelHalfWidth + 1); + sum = 0; + j = 0; + + while (j < SampleSize && sum < th) + { + g = pSequence[j*imagesize + i]; + k = g - image[i] + KernelHalfWidth; + sum += kerneltable[kernelbase + k]; + j++; + } + + p = sum / j; + Pimage1[i] = p; + } + } + else if (UseColorRatiosFlag && SubsetFlag) + { + // color ratios + + unsigned int ig; + int base; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + double beta = 3.0; // minimum bound on the range. + double betau = 100.0; + + double beta_over_alpha = beta / alpha; + double betau_over_alpha = betau / alpha; + + + double brightness_lowerbound = 1 - alpha; + double brightness_upperbound = 1 + alpha; + int x1, x2; + unsigned int SubsampleCount; + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + kernelbase1 = SDbins[i] * kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + SubsampleCount = 0; + + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + + if (g < beta_over_alpha) + { + x1 = (int)(g - beta); + x2 = (int)(g + beta); + } + else if (g > betau_over_alpha) + { + x1 = (int)(g - betau); + x2 = (int)(g + betau); + } + else + { + x1 = (int)(g*brightness_lowerbound + 0.5); + x2 = (int)(g*brightness_upperbound + 0.5); + } + + if (x1 < image[i] && image[i] < x2) + { + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel2*kernel3; + + SubsampleCount++; + } + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + else if (UseColorRatiosFlag && !SubsetFlag) + { + // color ratios + + unsigned int ig; + int base; + int bin; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + int gmin, gmax; + double gfactor; + + gmax = 200; + gmin = 10; + + gfactor = (KernelMaxSigma - KernelMinSigma) / (double)(gmax - gmin); + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + + bin = (int)floor(((alpha * 16 - KernelMinSigma)*KernelBins) / (KernelMaxSigma - KernelMinSigma)); + + kernelbase1 = bin*kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + + if (g < gmin) + bin = 0; + else if (g > gmax) + bin = KernelBins - 1; + else + bin = (int)((g - gmin) * gfactor + 0.5); + + kernelbase1 = bin*kerneltablewidth; + + k = (g - image[i]) + KernelHalfWidth; + kernel1 = kerneltable[kernelbase1 + k]; + + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel1*kernel2*kernel3; + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + else // RGB color + { + unsigned int ig; + int base; + + int kernelbase1; + int kernelbase2; + int kernelbase3; + unsigned int kerneltablewidth = 2 * KernelHalfWidth + 1; + + for (i = 0, ig = 0; i < imagesize; i += 3, ig++) + { + // used extimated kernel width to access the right kernel + kernelbase1 = SDbins[i] * kerneltablewidth; + kernelbase2 = SDbins[i + 1] * kerneltablewidth; + kernelbase3 = SDbins[i + 2] * kerneltablewidth; + + sum = 0; + j = 0; + while (j < SampleSize && sum < th) + { + base = j*imagesize + i; + g = pSequence[base]; + k = (g - image[i]) + KernelHalfWidth; + kernel1 = kerneltable[kernelbase1 + k]; + + g = pSequence[base + 1]; + k = (g - image[i + 1]) + KernelHalfWidth; + kernel2 = kerneltable[kernelbase2 + k]; + + g = pSequence[base + 2]; + k = (g - image[i + 2]) + KernelHalfWidth; + kernel3 = kerneltable[kernelbase3 + k]; + + sum += kernel1*kernel2*kernel3; + j++; + } + + p = sum / j; + Pimage1[ig] = p; + } + } + + DisplayPropabilityImageWithThresholding(Pimage1, FGImage, Threshold, rows, cols); +} + +/*********************************************************************/ + +void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame, + unsigned char * FGImage, + unsigned char * FilteredFGImage, + unsigned char ** DisplayBuffers) +{ + if (UseColorRatiosFlag) + BGR2SnGnRn(Frame, tempFrame, rows, cols); + else + memcpy(tempFrame, Frame, rows*cols*color_channels); + + NPBGSubtraction_Subset_Kernel(tempFrame, FGImage, FilteredFGImage); + /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4); + BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols); + + ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols); + ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols); + + memset(DisplayBuffers[3],0,rows*cols);*/ +} + +void NPBGSubtractor::Update(unsigned char * FGMask) +{ + if (UpdateBGFlag) + SequenceBGUpdate_Pairs(tempFrame, FGMask); +} diff --git a/package_bgs/ae/NPBGSubtractor.h b/package_bgs/KDE/NPBGSubtractor.h similarity index 87% rename from package_bgs/ae/NPBGSubtractor.h rename to package_bgs/KDE/NPBGSubtractor.h index e7f3795..ce4bffc 100644 --- a/package_bgs/ae/NPBGSubtractor.h +++ b/package_bgs/KDE/NPBGSubtractor.h @@ -26,21 +26,21 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * copyright notice must be included. For any other uses of this software, * in original or modified form, including but not limited to distribution * in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. * Other than these cases, no part of this software may be used or * distributed without written permission of the author. * -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * Ahmed Elgammal -* +* * University of Maryland at College Park * UMIACS -* A.V. Williams Bldg. +* A.V. Williams Bldg. * CollegePark, MD 20742 * E-mail: elgammal@umiacs.umd.edu * @@ -49,13 +49,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // NPBGSubtractor.h: interface for the NPBGSubtractor class. // ////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_) -#define AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_ - -#if _MSC_VER > 1000 #pragma once -#endif // _MSC_VER > 1000 #include "NPBGmodel.h" #include "KernelTable.h" @@ -87,7 +81,7 @@ typedef struct unsigned int *List; } ImageIndex; -class NPBGSubtractor +class NPBGSubtractor { private: unsigned int rows; @@ -146,9 +140,7 @@ public: AlphaValue = alpha; }; - void SetUpdateFlag(unsigned int bgflag){ + void SetUpdateFlag(unsigned int bgflag) { UpdateBGFlag = bgflag; }; }; - -#endif // !defined(AFX_NPBGSUBTRACTOR_H__84B0F51E_6E65_41E4_AC01_723B406363C4__INCLUDED_) diff --git a/package_bgs/ae/NPBGmodel.cpp b/package_bgs/KDE/NPBGmodel.cpp similarity index 78% rename from package_bgs/ae/NPBGmodel.cpp rename to package_bgs/KDE/NPBGmodel.cpp index 2c8b074..a79a7b4 100644 --- a/package_bgs/ae/NPBGmodel.cpp +++ b/package_bgs/KDE/NPBGmodel.cpp @@ -26,21 +26,21 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * copyright notice must be included. For any other uses of this software, * in original or modified form, including but not limited to distribution * in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. * Other than these cases, no part of this software may be used or * distributed without written permission of the author. * -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * Ahmed Elgammal -* +* * University of Maryland at College Park * UMIACS -* A.V. Williams Bldg. +* A.V. Williams Bldg. * CollegePark, MD 20742 * E-mail: elgammal@umiacs.umd.edu * @@ -55,7 +55,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #ifdef _DEBUG #undef THIS_FILE -static char THIS_FILE[]=__FILE__; +static char THIS_FILE[] = __FILE__; //#define new DEBUG_NEW #endif @@ -80,11 +80,11 @@ NPBGmodel::~NPBGmodel() } NPBGmodel::NPBGmodel(unsigned int Rows, - unsigned int Cols, - unsigned int ColorChannels, - unsigned int Length, - unsigned int pTimeWindowSize, - unsigned int bg_suppression_time) + unsigned int Cols, + unsigned int ColorChannels, + unsigned int Length, + unsigned int pTimeWindowSize, + unsigned int bg_suppression_time) { std::cout << "NPBGmodel()" << std::endl; @@ -98,14 +98,14 @@ NPBGmodel::NPBGmodel(unsigned int Rows, TimeWindowSize = pTimeWindowSize; - Sequence = new unsigned char[imagesize*Length]; + Sequence = new unsigned char[imagesize*Length]; Top = 0; - memset(Sequence,0,imagesize*Length); + memset(Sequence, 0, imagesize*Length); PixelQTop = new unsigned char[rows*cols]; // temporalBuffer - TemporalBufferLength = (TimeWindowSize/Length > 2 ? TimeWindowSize/Length:2); + TemporalBufferLength = (TimeWindowSize / Length > 2 ? TimeWindowSize / Length : 2); TemporalBuffer = new unsigned char[imagesize*TemporalBufferLength]; TemporalMask = new unsigned char[rows*cols*TemporalBufferLength]; @@ -116,12 +116,12 @@ NPBGmodel::NPBGmodel(unsigned int Rows, ResetMaskTh = bg_suppression_time; } -void NPBGmodel::AddFrame(unsigned char *ImageBuffer) +void NPBGmodel::AddFrame(unsigned char *ImageBuffer) { - memcpy(Sequence+Top*imagesize,ImageBuffer,imagesize); - Top = (Top + 1) % SampleSize; + memcpy(Sequence + Top*imagesize, ImageBuffer, imagesize); + Top = (Top + 1) % SampleSize; - memset(PixelQTop, (unsigned char) Top, rows*cols); + memset(PixelQTop, (unsigned char)Top, rows*cols); - memcpy(TemporalBuffer,ImageBuffer,imagesize); + memcpy(TemporalBuffer, ImageBuffer, imagesize); } diff --git a/package_bgs/ae/NPBGmodel.h b/package_bgs/KDE/NPBGmodel.h similarity index 84% rename from package_bgs/ae/NPBGmodel.h rename to package_bgs/KDE/NPBGmodel.h index 9e28510..ba4a927 100644 --- a/package_bgs/ae/NPBGmodel.h +++ b/package_bgs/KDE/NPBGmodel.h @@ -26,21 +26,21 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * copyright notice must be included. For any other uses of this software, * in original or modified form, including but not limited to distribution * in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. +* Author or UMIACS. These programs shall not be used, rewritten, or +* adapted as the basis of a commercial software or hardware product +* without first obtaining appropriate licenses from Author. * Other than these cases, no part of this software may be used or * distributed without written permission of the author. * -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided +* Neither the author nor UMIACS make any representations about the +* suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * Ahmed Elgammal -* +* * University of Maryland at College Park * UMIACS -* A.V. Williams Bldg. +* A.V. Williams Bldg. * CollegePark, MD 20742 * E-mail: elgammal@umiacs.umd.edu * @@ -49,24 +49,18 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // NPBGmodel.h: interface for the NPBGmodel class. // ////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_) -#define AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_ - -#if _MSC_VER > 1000 #pragma once -#endif // _MSC_VER > 1000 #include <iostream> -class NPBGmodel +class NPBGmodel { private: unsigned char *Sequence; unsigned int SampleSize; unsigned int TimeWindowSize; - unsigned int rows,cols,color_channels; + unsigned int rows, cols, color_channels; unsigned int imagesize; unsigned int Top; @@ -74,7 +68,7 @@ private: //unsigned int *PixelUpdateCounter; - unsigned char *SDbinsImage; + unsigned char *SDbinsImage; unsigned char *TemporalBuffer; unsigned char TemporalBufferLength; @@ -107,5 +101,3 @@ public: friend class NPBGSubtractor; }; - -#endif // !defined(AFX_NPBGMODEL_H__CCAF05D4_D06E_44C2_95D8_979E2249953A__INCLUDED_) diff --git a/package_bgs/KNN.cpp b/package_bgs/KNN.cpp new file mode 100644 index 0000000..d2e1412 --- /dev/null +++ b/package_bgs/KNN.cpp @@ -0,0 +1,111 @@ +/* + This file is part of BGSLibrary. + + BGSLibrary is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + BGSLibrary is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. + */ +#include "KNN.h" + +#if CV_MAJOR_VERSION == 3 + +using namespace bgslibrary::algorithms; + +KNN::KNN() : + history(500), nSamples(7), dist2Threshold(20.0f * 20.0f), knnSamples(0), + doShadowDetection(true), shadowValue(127), shadowThreshold(0.5f) +{ + std::cout << "KNN()" << std::endl; + setup("./config/KNN.xml"); +} + +KNN::~KNN() +{ + std::cout << "~KNN()" << std::endl; +} + +void KNN::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + //------------------------------------------------------------------ + // BackgroundSubtractorKNN + // http://docs.opencv.org/trunk/modules/video/doc/motion_analysis_and_object_tracking.html#backgroundsubtractorknn + // + // The class implements the K nearest neigbours algorithm from: + // "Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction" + // Z.Zivkovic, F. van der Heijden + // Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006 + // http: //www.zoranz.net/Publications/zivkovicPRL2006.pdf + // + // Fast for small foreground object. Results on the benchmark data is at http://www.changedetection.net. + //------------------------------------------------------------------ + + int prevNSamples = nSamples; + if (firstTime) + knn = cv::createBackgroundSubtractorKNN(history, dist2Threshold, doShadowDetection); + + knn->setNSamples(nSamples); + knn->setkNNSamples(knnSamples); + knn->setShadowValue(shadowValue); + knn->setShadowThreshold(shadowThreshold); + + knn->apply(img_input, img_foreground, prevNSamples != nSamples ? 0.f : 1.f); + knn->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + cv::imshow("KNN FG", img_foreground); + cv::imshow("KNN BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void KNN::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "history", history); + cvWriteInt(fs, "nSamples", nSamples); + cvWriteReal(fs, "dist2Threshold", dist2Threshold); + cvWriteInt(fs, "knnSamples", knnSamples); + cvWriteInt(fs, "doShadowDetection", doShadowDetection); + cvWriteInt(fs, "shadowValue", shadowValue); + cvWriteReal(fs, "shadowThreshold", shadowThreshold); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void KNN::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + history = cvReadIntByName(fs, nullptr, "history", 500); + nSamples = cvReadIntByName(fs, nullptr, "nSamples", 7); + dist2Threshold = cvReadRealByName(fs, nullptr, "dist2Threshold", 20.0f * 20.0f); + knnSamples = cvReadIntByName(fs, nullptr, "knnSamples", 0); + doShadowDetection = cvReadIntByName(fs, nullptr, "doShadowDetection", 1); + shadowValue = cvReadIntByName(fs, nullptr, "shadowValue", 127); + shadowThreshold = cvReadRealByName(fs, nullptr, "shadowThreshold", 0.5f); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} + +#endif diff --git a/package_bgs/KNN.h b/package_bgs/KNN.h new file mode 100644 index 0000000..87f20b2 --- /dev/null +++ b/package_bgs/KNN.h @@ -0,0 +1,57 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION == 3 + +#include <iostream> +#include <opencv2/opencv.hpp> +#include <opencv2/video/background_segm.hpp> + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class KNN : public IBGS + { + private: + cv::Ptr<cv::BackgroundSubtractorKNN> knn; + int history; + int nSamples; + float dist2Threshold; + int knnSamples; + bool doShadowDetection; + int shadowValue; + float shadowThreshold; + + public: + KNN(); + ~KNN(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} + +#endif diff --git a/package_bgs/lb/LBAdaptiveSOM.cpp b/package_bgs/LBAdaptiveSOM.cpp similarity index 61% rename from package_bgs/lb/LBAdaptiveSOM.cpp rename to package_bgs/LBAdaptiveSOM.cpp index ce06433..188e11d 100644 --- a/package_bgs/lb/LBAdaptiveSOM.cpp +++ b/package_bgs/LBAdaptiveSOM.cpp @@ -16,10 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "LBAdaptiveSOM.h" -LBAdaptiveSOM::LBAdaptiveSOM() : firstTime(true), showOutput(true), +using namespace bgslibrary::algorithms; + +LBAdaptiveSOM::LBAdaptiveSOM() : sensitivity(75), trainingSensitivity(245), learningRate(62), trainingLearningRate(255), trainingSteps(55) { std::cout << "LBAdaptiveSOM()" << std::endl; + setup("./config/LBAdaptiveSOM.xml"); } LBAdaptiveSOM::~LBAdaptiveSOM() @@ -30,64 +33,55 @@ LBAdaptiveSOM::~LBAdaptiveSOM() void LBAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - IplImage *frame = new IplImage(img_input); - - if(firstTime) - { - saveConfig(); + if (firstTime) + { int w = cvGetSize(frame).width; int h = cvGetSize(frame).height; - m_pBGModel = new BGModelSom(w,h); + m_pBGModel = new BGModelSom(w, h); m_pBGModel->InitModel(frame); } - - m_pBGModel->setBGModelParameter(0,sensitivity); - m_pBGModel->setBGModelParameter(1,trainingSensitivity); - m_pBGModel->setBGModelParameter(2,learningRate); - m_pBGModel->setBGModelParameter(3,trainingLearningRate); - m_pBGModel->setBGModelParameter(5,trainingSteps); + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, trainingSensitivity); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, trainingLearningRate); + m_pBGModel->setBGModelParameter(5, trainingSteps); m_pBGModel->UpdateModel(frame); - img_foreground = cv::Mat(m_pBGModel->GetFG()); - img_background = cv::Mat(m_pBGModel->GetBG()); - - if(showOutput) + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("SOM Mask", img_foreground); cv::imshow("SOM Model", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); - + delete frame; - + firstTime = false; } -//void LBAdaptiveSOM::finish(void) -//{ -// delete m_pBGModel; -//} - void LBAdaptiveSOM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBAdaptiveSOM.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "sensitivity", sensitivity); cvWriteInt(fs, "trainingSensitivity", trainingSensitivity); cvWriteInt(fs, "learningRate", learningRate); cvWriteInt(fs, "trainingLearningRate", trainingLearningRate); cvWriteInt(fs, "trainingSteps", trainingSteps); - cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); @@ -95,15 +89,14 @@ void LBAdaptiveSOM::saveConfig() void LBAdaptiveSOM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBAdaptiveSOM.xml", 0, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, 0, "sensitivity", 75); - trainingSensitivity = cvReadIntByName(fs, 0, "trainingSensitivity", 245); - learningRate = cvReadIntByName(fs, 0, "learningRate", 62); - trainingLearningRate = cvReadIntByName(fs, 0, "trainingLearningRate", 255); - trainingSteps = cvReadIntByName(fs, 0, "trainingSteps", 55); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 75); + trainingSensitivity = cvReadIntByName(fs, nullptr, "trainingSensitivity", 245); + learningRate = cvReadIntByName(fs, nullptr, "learningRate", 62); + trainingLearningRate = cvReadIntByName(fs, nullptr, "trainingLearningRate", 255); + trainingSteps = cvReadIntByName(fs, nullptr, "trainingSteps", 55); showOutput = cvReadIntByName(fs, 0, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/lb/LBAdaptiveSOM.h b/package_bgs/LBAdaptiveSOM.h similarity index 55% rename from package_bgs/lb/LBAdaptiveSOM.h rename to package_bgs/LBAdaptiveSOM.h index beaf77b..7671ae1 100644 --- a/package_bgs/lb/LBAdaptiveSOM.h +++ b/package_bgs/LBAdaptiveSOM.h @@ -16,41 +16,35 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "BGModelSom.h" - -#include "../IBGS.h" +#include "lb/BGModelSom.h" +#include "IBGS.h" using namespace lb_library; using namespace lb_library::AdaptiveSOM; -class LBAdaptiveSOM : public IBGS +namespace bgslibrary { -private: - bool firstTime; - bool showOutput; - - BGModel* m_pBGModel; - int sensitivity; - int trainingSensitivity; - int learningRate; - int trainingLearningRate; - int trainingSteps; - - cv::Mat img_foreground; - cv::Mat img_background; - -public: - LBAdaptiveSOM(); - ~LBAdaptiveSOM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - //void finish(void); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class LBAdaptiveSOM : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int trainingSensitivity; + int learningRate; + int trainingLearningRate; + int trainingSteps; + + public: + LBAdaptiveSOM(); + ~LBAdaptiveSOM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/lb/LBFuzzyAdaptiveSOM.cpp b/package_bgs/LBFuzzyAdaptiveSOM.cpp similarity index 59% rename from package_bgs/lb/LBFuzzyAdaptiveSOM.cpp rename to package_bgs/LBFuzzyAdaptiveSOM.cpp index 4ef8560..73df1d7 100644 --- a/package_bgs/lb/LBFuzzyAdaptiveSOM.cpp +++ b/package_bgs/LBFuzzyAdaptiveSOM.cpp @@ -16,10 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "LBFuzzyAdaptiveSOM.h" -LBFuzzyAdaptiveSOM::LBFuzzyAdaptiveSOM() : firstTime(true), showOutput(true), +using namespace bgslibrary::algorithms; + +LBFuzzyAdaptiveSOM::LBFuzzyAdaptiveSOM() : sensitivity(90), trainingSensitivity(240), learningRate(38), trainingLearningRate(255), trainingSteps(81) { std::cout << "LBFuzzyAdaptiveSOM()" << std::endl; + setup("./config/LBFuzzyAdaptiveSOM.xml"); } LBFuzzyAdaptiveSOM::~LBFuzzyAdaptiveSOM() @@ -30,64 +33,55 @@ LBFuzzyAdaptiveSOM::~LBFuzzyAdaptiveSOM() void LBFuzzyAdaptiveSOM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - IplImage *frame = new IplImage(img_input); - - if(firstTime) - { - saveConfig(); + if (firstTime) + { int w = cvGetSize(frame).width; int h = cvGetSize(frame).height; - m_pBGModel = new BGModelFuzzySom(w,h); + m_pBGModel = new BGModelFuzzySom(w, h); m_pBGModel->InitModel(frame); } - - m_pBGModel->setBGModelParameter(0,sensitivity); - m_pBGModel->setBGModelParameter(1,trainingSensitivity); - m_pBGModel->setBGModelParameter(2,learningRate); - m_pBGModel->setBGModelParameter(3,trainingLearningRate); - m_pBGModel->setBGModelParameter(5,trainingSteps); + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, trainingSensitivity); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, trainingLearningRate); + m_pBGModel->setBGModelParameter(5, trainingSteps); m_pBGModel->UpdateModel(frame); - img_foreground = cv::Mat(m_pBGModel->GetFG()); - img_background = cv::Mat(m_pBGModel->GetBG()); - - if(showOutput) + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("FSOM Mask", img_foreground); cv::imshow("FSOM Model", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); - + delete frame; - + firstTime = false; } -//void LBFuzzyAdaptiveSOM::finish(void) -//{ -// //delete m_pBGModel; -//} - void LBFuzzyAdaptiveSOM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyAdaptiveSOM.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "sensitivity", sensitivity); cvWriteInt(fs, "trainingSensitivity", trainingSensitivity); cvWriteInt(fs, "learningRate", learningRate); cvWriteInt(fs, "trainingLearningRate", trainingLearningRate); cvWriteInt(fs, "trainingSteps", trainingSteps); - cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); @@ -95,15 +89,14 @@ void LBFuzzyAdaptiveSOM::saveConfig() void LBFuzzyAdaptiveSOM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyAdaptiveSOM.xml", 0, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, 0, "sensitivity", 90); - trainingSensitivity = cvReadIntByName(fs, 0, "trainingSensitivity", 240); - learningRate = cvReadIntByName(fs, 0, "learningRate", 38); - trainingLearningRate = cvReadIntByName(fs, 0, "trainingLearningRate", 255); - trainingSteps = cvReadIntByName(fs, 0, "trainingSteps", 81); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 90); + trainingSensitivity = cvReadIntByName(fs, nullptr, "trainingSensitivity", 240); + learningRate = cvReadIntByName(fs, nullptr, "learningRate", 38); + trainingLearningRate = cvReadIntByName(fs, nullptr, "trainingLearningRate", 255); + trainingSteps = cvReadIntByName(fs, nullptr, "trainingSteps", 81); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/lb/LBFuzzyAdaptiveSOM.h b/package_bgs/LBFuzzyAdaptiveSOM.h similarity index 55% rename from package_bgs/lb/LBFuzzyAdaptiveSOM.h rename to package_bgs/LBFuzzyAdaptiveSOM.h index 9c11d75..6a4a85c 100644 --- a/package_bgs/lb/LBFuzzyAdaptiveSOM.h +++ b/package_bgs/LBFuzzyAdaptiveSOM.h @@ -16,41 +16,35 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "BGModelFuzzySom.h" - -#include "../IBGS.h" +#include "IBGS.h" +#include "lb/BGModelFuzzySom.h" using namespace lb_library; using namespace lb_library::FuzzyAdaptiveSOM; -class LBFuzzyAdaptiveSOM : public IBGS +namespace bgslibrary { -private: - bool firstTime; - bool showOutput; - - BGModel* m_pBGModel; - int sensitivity; - int trainingSensitivity; - int learningRate; - int trainingLearningRate; - int trainingSteps; - - cv::Mat img_foreground; - cv::Mat img_background; - -public: - LBFuzzyAdaptiveSOM(); - ~LBFuzzyAdaptiveSOM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - //void finish(void); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class LBFuzzyAdaptiveSOM : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int trainingSensitivity; + int learningRate; + int trainingLearningRate; + int trainingSteps; + + public: + LBFuzzyAdaptiveSOM(); + ~LBFuzzyAdaptiveSOM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/lb/LBFuzzyGaussian.cpp b/package_bgs/LBFuzzyGaussian.cpp similarity index 59% rename from package_bgs/lb/LBFuzzyGaussian.cpp rename to package_bgs/LBFuzzyGaussian.cpp index dc257bf..b161026 100644 --- a/package_bgs/lb/LBFuzzyGaussian.cpp +++ b/package_bgs/LBFuzzyGaussian.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "LBFuzzyGaussian.h" -LBFuzzyGaussian::LBFuzzyGaussian() : firstTime(true), showOutput(true), sensitivity(72), bgThreshold(162), learningRate(49), noiseVariance(195) +using namespace bgslibrary::algorithms; + +LBFuzzyGaussian::LBFuzzyGaussian() : + sensitivity(72), bgThreshold(162), learningRate(49), noiseVariance(195) { std::cout << "LBFuzzyGaussian()" << std::endl; + setup("./config/LBFuzzyGaussian.xml"); } LBFuzzyGaussian::~LBFuzzyGaussian() @@ -29,62 +33,53 @@ LBFuzzyGaussian::~LBFuzzyGaussian() void LBFuzzyGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - IplImage *frame = new IplImage(img_input); - - if(firstTime) - { - saveConfig(); + if (firstTime) + { int w = cvGetSize(frame).width; int h = cvGetSize(frame).height; - m_pBGModel = new BGModelFuzzyGauss(w,h); + m_pBGModel = new BGModelFuzzyGauss(w, h); m_pBGModel->InitModel(frame); } - - m_pBGModel->setBGModelParameter(0,sensitivity); - m_pBGModel->setBGModelParameter(1,bgThreshold); - m_pBGModel->setBGModelParameter(2,learningRate); - m_pBGModel->setBGModelParameter(3,noiseVariance); + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, bgThreshold); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, noiseVariance); m_pBGModel->UpdateModel(frame); - img_foreground = cv::Mat(m_pBGModel->GetFG()); - img_background = cv::Mat(m_pBGModel->GetBG()); - - if(showOutput) + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("FG Mask", img_foreground); cv::imshow("FG Model", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); - + delete frame; - + firstTime = false; } -//void LBFuzzyGaussian::finish(void) -//{ -// delete m_pBGModel; -//} - void LBFuzzyGaussian::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyGaussian.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "sensitivity", sensitivity); cvWriteInt(fs, "bgThreshold", bgThreshold); cvWriteInt(fs, "learningRate", learningRate); cvWriteInt(fs, "noiseVariance", noiseVariance); - cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); @@ -92,14 +87,13 @@ void LBFuzzyGaussian::saveConfig() void LBFuzzyGaussian::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBFuzzyGaussian.xml", 0, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, 0, "sensitivity", 72); - bgThreshold = cvReadIntByName(fs, 0, "bgThreshold", 162); - learningRate = cvReadIntByName(fs, 0, "learningRate", 49); - noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 195); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 72); + bgThreshold = cvReadIntByName(fs, nullptr, "bgThreshold", 162); + learningRate = cvReadIntByName(fs, nullptr, "learningRate", 49); + noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 195); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/lb/LBFuzzyGaussian.h b/package_bgs/LBFuzzyGaussian.h similarity index 56% rename from package_bgs/lb/LBFuzzyGaussian.h rename to package_bgs/LBFuzzyGaussian.h index f76156e..53c2667 100644 --- a/package_bgs/lb/LBFuzzyGaussian.h +++ b/package_bgs/LBFuzzyGaussian.h @@ -16,40 +16,34 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "BGModelFuzzyGauss.h" - -#include "../IBGS.h" +#include "IBGS.h" +#include "lb/BGModelFuzzyGauss.h" using namespace lb_library; using namespace lb_library::FuzzyGaussian; -class LBFuzzyGaussian : public IBGS +namespace bgslibrary { -private: - bool firstTime; - bool showOutput; - - BGModel* m_pBGModel; - int sensitivity; - int bgThreshold; - int learningRate; - int noiseVariance; - - cv::Mat img_foreground; - cv::Mat img_background; - -public: - LBFuzzyGaussian(); - ~LBFuzzyGaussian(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - //void finish(void); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class LBFuzzyGaussian : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int bgThreshold; + int learningRate; + int noiseVariance; + + public: + LBFuzzyGaussian(); + ~LBFuzzyGaussian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/lb/LBMixtureOfGaussians.cpp b/package_bgs/LBMixtureOfGaussians.cpp similarity index 59% rename from package_bgs/lb/LBMixtureOfGaussians.cpp rename to package_bgs/LBMixtureOfGaussians.cpp index 8d235c5..6cd9c91 100644 --- a/package_bgs/lb/LBMixtureOfGaussians.cpp +++ b/package_bgs/LBMixtureOfGaussians.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "LBMixtureOfGaussians.h" -LBMixtureOfGaussians::LBMixtureOfGaussians() : firstTime(true), showOutput(true), sensitivity(81), bgThreshold(83), learningRate(59), noiseVariance(206) +using namespace bgslibrary::algorithms; + +LBMixtureOfGaussians::LBMixtureOfGaussians() : + sensitivity(81), bgThreshold(83), learningRate(59), noiseVariance(206) { std::cout << "LBMixtureOfGaussians()" << std::endl; + setup("./config/LBMixtureOfGaussians.xml"); } LBMixtureOfGaussians::~LBMixtureOfGaussians() @@ -29,62 +33,53 @@ LBMixtureOfGaussians::~LBMixtureOfGaussians() void LBMixtureOfGaussians::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - IplImage *frame = new IplImage(img_input); - - if(firstTime) - { - saveConfig(); + if (firstTime) + { int w = cvGetSize(frame).width; int h = cvGetSize(frame).height; - m_pBGModel = new BGModelMog(w,h); + m_pBGModel = new BGModelMog(w, h); m_pBGModel->InitModel(frame); } - - m_pBGModel->setBGModelParameter(0,sensitivity); - m_pBGModel->setBGModelParameter(1,bgThreshold); - m_pBGModel->setBGModelParameter(2,learningRate); - m_pBGModel->setBGModelParameter(3,noiseVariance); + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, bgThreshold); + m_pBGModel->setBGModelParameter(2, learningRate); + m_pBGModel->setBGModelParameter(3, noiseVariance); m_pBGModel->UpdateModel(frame); - img_foreground = cv::Mat(m_pBGModel->GetFG()); - img_background = cv::Mat(m_pBGModel->GetBG()); - - if(showOutput) + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("MOG Mask", img_foreground); cv::imshow("MOG Model", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); - + delete frame; - + firstTime = false; } -//void LBMixtureOfGaussians::finish(void) -//{ -// delete m_pBGModel; -//} - void LBMixtureOfGaussians::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBMixtureOfGaussians.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "sensitivity", sensitivity); cvWriteInt(fs, "bgThreshold", bgThreshold); cvWriteInt(fs, "learningRate", learningRate); cvWriteInt(fs, "noiseVariance", noiseVariance); - cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); @@ -92,14 +87,13 @@ void LBMixtureOfGaussians::saveConfig() void LBMixtureOfGaussians::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBMixtureOfGaussians.xml", 0, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, 0, "sensitivity", 81); - bgThreshold = cvReadIntByName(fs, 0, "bgThreshold", 83); - learningRate = cvReadIntByName(fs, 0, "learningRate", 59); - noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 206); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 81); + bgThreshold = cvReadIntByName(fs, nullptr, "bgThreshold", 83); + learningRate = cvReadIntByName(fs, nullptr, "learningRate", 59); + noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 206); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/lb/LBMixtureOfGaussians.h b/package_bgs/LBMixtureOfGaussians.h similarity index 56% rename from package_bgs/lb/LBMixtureOfGaussians.h rename to package_bgs/LBMixtureOfGaussians.h index 3b1a96d..8d4cb56 100644 --- a/package_bgs/lb/LBMixtureOfGaussians.h +++ b/package_bgs/LBMixtureOfGaussians.h @@ -16,40 +16,35 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "BGModelMog.h" - -#include "../IBGS.h" +#include "IBGS.h" +#include "lb/BGModelMog.h" using namespace lb_library; using namespace lb_library::MixtureOfGaussians; -class LBMixtureOfGaussians : public IBGS +namespace bgslibrary { -private: - bool firstTime; - bool showOutput; - - BGModel* m_pBGModel; - int sensitivity; - int bgThreshold; - int learningRate; - int noiseVariance; - - cv::Mat img_foreground; - cv::Mat img_background; - -public: - LBMixtureOfGaussians(); - ~LBMixtureOfGaussians(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - //void finish(void); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class LBMixtureOfGaussians : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int bgThreshold; + int learningRate; + int noiseVariance; + + public: + LBMixtureOfGaussians(); + ~LBMixtureOfGaussians(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} + diff --git a/package_bgs/ck/LbpMrf.cpp b/package_bgs/LBP_MRF.cpp similarity index 57% rename from package_bgs/ck/LbpMrf.cpp rename to package_bgs/LBP_MRF.cpp index f3d068c..b9e6bbe 100644 --- a/package_bgs/ck/LbpMrf.cpp +++ b/package_bgs/LBP_MRF.cpp @@ -18,35 +18,29 @@ Csaba, Kertész: Texture-Based Foreground Detection, International Journal of Si Image Processing and Pattern Recognition (IJSIP), Vol. 4, No. 4, 2011. */ -#include "LbpMrf.h" +#include "LBP_MRF.h" -#include "MotionDetection.hpp" +using namespace bgslibrary::algorithms; -LbpMrf::LbpMrf() : firstTime(true), Detector(NULL), showOutput(true) +LBP_MRF::LBP_MRF() : + Detector(nullptr) { - std::cout << "LbpMrf()" << std::endl; + std::cout << "LBP_MRF()" << std::endl; + setup("./config/LBP_MRF.xml"); Detector = new MotionDetection(); Detector->SetMode(MotionDetection::md_LBPHistograms); } -LbpMrf::~LbpMrf() +LBP_MRF::~LBP_MRF() { - std::cout << "~LbpMrf()" << std::endl; + std::cout << "~LBP_MRF()" << std::endl; delete Detector; - Detector = NULL; + Detector = nullptr; } -void LbpMrf::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void LBP_MRF::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - { - saveConfig(); - } + init(img_input, img_output, img_bgmodel); IplImage TempImage(img_input); MEImage InputImage(img_input.cols, img_input.rows, img_input.channels()); @@ -56,32 +50,35 @@ void LbpMrf::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img Detector->DetectMotions(InputImage); Detector->GetMotionsMask(OutputImage); - img_output = (IplImage*)OutputImage.GetIplImage(); - bitwise_not(img_output, img_bgmodel); + img_foreground = cv::cvarrToMat((IplImage*)OutputImage.GetIplImage()); + //bitwise_not(img_foreground, img_background); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("LBP-MRF FG", img_foreground); +#endif - if(showOutput) - { - cv::imshow("LBP-MRF FG", img_output); - cv::imshow("LBP-MRF BG", img_bgmodel); - } + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); firstTime = false; } -void LbpMrf::saveConfig() +void LBP_MRF::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LbpMrf.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); } -void LbpMrf::loadConfig() +void LBP_MRF::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LbpMrf.xml", 0, CV_STORAGE_READ); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/WeightedMovingMeanBGS.h b/package_bgs/LBP_MRF.h similarity index 58% rename from package_bgs/WeightedMovingMeanBGS.h rename to package_bgs/LBP_MRF.h index 6f72306..a6e5c05 100644 --- a/package_bgs/WeightedMovingMeanBGS.h +++ b/package_bgs/LBP_MRF.h @@ -16,32 +16,28 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - #include "IBGS.h" +#include "LBP_MRF/MotionDetection.hpp" -class WeightedMovingMeanBGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::Mat img_input_prev_1; - cv::Mat img_input_prev_2; - bool enableWeight; - bool enableThreshold; - int threshold; - bool showOutput; - bool showBackground; - -public: - WeightedMovingMeanBGS(); - ~WeightedMovingMeanBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class LBP_MRF : public IBGS + { + private: + MotionDetection* Detector; + cv::Mat img_segmentation; + + public: + LBP_MRF(); + ~LBP_MRF(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/LBP_MRF/MEDefs.cpp b/package_bgs/LBP_MRF/MEDefs.cpp new file mode 100644 index 0000000..95b8033 --- /dev/null +++ b/package_bgs/LBP_MRF/MEDefs.cpp @@ -0,0 +1,57 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + * This file is part of the AiBO+ project + * + * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) + * + * AiBO+ is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * AiBO+ is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#include "MEDefs.hpp" + +#include <math.h> + +float MERound(float number) +{ + double FracPart = 0.0; + double IntPart = 0.0; + float Ret = 0.0; + + FracPart = modf((double)number, &IntPart); + if (number >= 0) + { + Ret = (float)(FracPart >= 0.5 ? IntPart + 1 : IntPart); + } + else { + Ret = (float)(FracPart <= -0.5 ? IntPart - 1 : IntPart); + } + return Ret; +} diff --git a/package_bgs/ck/MEDefs.hpp b/package_bgs/LBP_MRF/MEDefs.hpp similarity index 73% rename from package_bgs/ck/MEDefs.hpp rename to package_bgs/LBP_MRF/MEDefs.hpp index d5bc246..a886ee9 100644 --- a/package_bgs/ck/MEDefs.hpp +++ b/package_bgs/LBP_MRF/MEDefs.hpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -18,16 +34,9 @@ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ +#pragma once -#ifndef MEDefs_hpp -#define MEDefs_hpp - -/** - * @addtogroup mindeye - * @{ - */ - -/// Pi value + /// Pi value #ifndef ME_PI_VALUE #define ME_PI_VALUE 3.14159265 #endif @@ -79,5 +88,3 @@ const T& MEBound(const T& min, const T& val, const T& max) float MERound(float number); /** @} */ - -#endif diff --git a/package_bgs/ck/MEHistogram.cpp b/package_bgs/LBP_MRF/MEHistogram.cpp similarity index 54% rename from package_bgs/ck/MEHistogram.cpp rename to package_bgs/LBP_MRF/MEHistogram.cpp index 09a9672..17c77fd 100644 --- a/package_bgs/ck/MEHistogram.cpp +++ b/package_bgs/LBP_MRF/MEHistogram.cpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -45,7 +61,7 @@ MEHistogram::~MEHistogram() void MEHistogram::Clear() { - memset(&HistogramData, 0, 256*sizeof(int)); + memset(&HistogramData, 0, 256 * sizeof(int)); } @@ -77,11 +93,11 @@ void MEHistogram::Calculate(MEImage& image, int channel, HistogramType mode) unsigned char *ImageData = image.GetImageData(); int rowStart = 0; - for (int i = image.GetHeight()-1; i >= 0; i--) + for (int i = image.GetHeight() - 1; i >= 0; i--) { - for (int i1 = (image.GetWidth()-1)*image.GetLayers()+Channel-1; i1 >= Channel-1; i1 -= image.GetLayers()) + for (int i1 = (image.GetWidth() - 1)*image.GetLayers() + Channel - 1; i1 >= Channel - 1; i1 -= image.GetLayers()) { - HistogramData[ImageData[rowStart+i1]]++; + HistogramData[ImageData[rowStart + i1]]++; } rowStart += image.GetRowWidth(); } @@ -99,11 +115,11 @@ void MEHistogram::Calculate(MEImage& image, HistogramType mode) int RowStart = 0; int RowWidth = image.GetRowWidth(); - for (int i = image.GetHeight()-1; i >= 0; i--) + for (int i = image.GetHeight() - 1; i >= 0; i--) { - for (int i1 = image.GetWidth()*image.GetLayers()-1; i1 >= 0; i1--) + for (int i1 = image.GetWidth()*image.GetLayers() - 1; i1 >= 0; i1--) { - HistogramData[ImageData[RowStart+i1]]++; + HistogramData[ImageData[RowStart + i1]]++; } RowStart += RowWidth; } @@ -126,16 +142,16 @@ void MEHistogram::Calculate(MEImage& image, int channel, int x0, int y0, int x1, // Compute the correct region coordinates and check them X0 = X0 < 0 ? 0 : X0; Y0 = Y0 < 0 ? 0 : Y0; - X1 = X1 > image.GetWidth()-1 ? image.GetWidth()-1 : X1; - Y1 = Y1 > image.GetHeight()-1 ? image.GetHeight()-1 : Y1; + X1 = X1 > image.GetWidth() - 1 ? image.GetWidth() - 1 : X1; + Y1 = Y1 > image.GetHeight() - 1 ? image.GetHeight() - 1 : Y1; RowStart = Y0*image.GetRowWidth(); for (int i = Y1; i >= Y0; --i) { - for (int i1 = X1*image.GetLayers()+Channel-1; i1 >= X0*image.GetLayers()+Channel-1; - i1 -= image.GetLayers()) + for (int i1 = X1*image.GetLayers() + Channel - 1; i1 >= X0*image.GetLayers() + Channel - 1; + i1 -= image.GetLayers()) { - HistogramData[ImageData[RowStart+i1]]++; + HistogramData[ImageData[RowStart + i1]]++; } RowStart += RowWidth; } @@ -242,70 +258,70 @@ bool MEHistogram::Stretch(StretchType mode) switch (mode) { - case s_OwnMode: - Percent = 20; + case s_OwnMode: + Percent = 20; + MinIndex = GetLowestLimitIndex(Percent); + MaxIndex = GetHighestLimitIndex(Percent); + + while ((abs(MaxIndex - MinIndex) < 52) && (Percent > 1)) + { + Percent = Percent / 2; MinIndex = GetLowestLimitIndex(Percent); MaxIndex = GetHighestLimitIndex(Percent); - while ((abs(MaxIndex-MinIndex) < 52) && (Percent > 1)) + // The calculation gives wrong answer back + if (MinIndex == 0 && MaxIndex == 255) { - Percent = Percent / 2; - MinIndex = GetLowestLimitIndex(Percent); - MaxIndex = GetHighestLimitIndex(Percent); - - // The calculation gives wrong answer back - if (MinIndex == 0 && MaxIndex == 255) - { - MinIndex = 128; - MaxIndex = 128; - Ret = false; - } + MinIndex = 128; + MaxIndex = 128; + Ret = false; } - break; + } + break; - case s_GimpMode: - Count = GetPowerAmount(0, 255); - NewCount = 0; + case s_GimpMode: + Count = GetPowerAmount(0, 255); + NewCount = 0; - for (int i = 0; i < 255; i++) - { - double Value = 0.0; - double NextValue = 0.0; + for (int i = 0; i < 255; i++) + { + double Value = 0.0; + double NextValue = 0.0; - Value = HistogramData[i]; - NextValue = HistogramData[i+1]; - NewCount += Value; - Percentage = NewCount / Count; - NextPercentage = (NewCount+NextValue) / Count; + Value = HistogramData[i]; + NextValue = HistogramData[i + 1]; + NewCount += Value; + Percentage = NewCount / Count; + NextPercentage = (NewCount + NextValue) / Count; - if (fabs(Percentage-0.006) < fabs(NextPercentage-0.006)) - { - MinIndex = i+1; - break; - } - } - NewCount = 0.0; - for (int i = 255; i > 0; i--) + if (fabs(Percentage - 0.006) < fabs(NextPercentage - 0.006)) { - double Value = 0.0; - double NextValue = 0.0; + MinIndex = i + 1; + break; + } + } + NewCount = 0.0; + for (int i = 255; i > 0; i--) + { + double Value = 0.0; + double NextValue = 0.0; - Value = HistogramData[i]; - NextValue = HistogramData[i-1]; - NewCount += Value; - Percentage = NewCount / Count; - NextPercentage = (NewCount+NextValue) / Count; + Value = HistogramData[i]; + NextValue = HistogramData[i - 1]; + NewCount += Value; + Percentage = NewCount / Count; + NextPercentage = (NewCount + NextValue) / Count; - if (fabs(Percentage-0.006) < fabs(NextPercentage-0.006)) - { - MaxIndex = i-1; - break; - } + if (fabs(Percentage - 0.006) < fabs(NextPercentage - 0.006)) + { + MaxIndex = i - 1; + break; } - break; + } + break; - default: - break; + default: + break; } if (MaxIndex <= MinIndex) @@ -314,8 +330,8 @@ bool MEHistogram::Stretch(StretchType mode) MaxIndex = 255; Ret = false; } - if (MaxIndex-MinIndex <= 10 || - (MaxIndex-MinIndex <= 20 && (float)GetPowerAmount(MinIndex, MaxIndex) / GetPowerAmount(0, 255) < 0.20)) + if (MaxIndex - MinIndex <= 10 || + (MaxIndex - MinIndex <= 20 && (float)GetPowerAmount(MinIndex, MaxIndex) / GetPowerAmount(0, 255) < 0.20)) { MinIndex = 0; MaxIndex = 255; @@ -327,7 +343,7 @@ bool MEHistogram::Stretch(StretchType mode) for (int i = 0; i < 256; ++i) { - TransformedHistogram[i] = (unsigned char)MEBound(0, 255*(i-MinIndex) / (MaxIndex-MinIndex), 255); + TransformedHistogram[i] = (unsigned char)MEBound(0, 255 * (i - MinIndex) / (MaxIndex - MinIndex), 255); } for (int i = 0; i < 256; ++i) { @@ -371,7 +387,7 @@ void MEHistogramTransform::HistogramStretch(MEImage& image, TransformType time_m for (int l = 1; l < image.GetLayers(); l++) { - RedChannel.Calculate(image, l+1, MEHistogram::h_Add); + RedChannel.Calculate(image, l + 1, MEHistogram::h_Add); } RedChannel.Stretch(StretchMode); if (time_mode == t_Discrete && !DiscreteStretchingDone) @@ -383,45 +399,46 @@ void MEHistogramTransform::HistogramStretch(MEImage& image, TransformType time_m int RowStart = 0; int RowWidth = image.GetRowWidth(); - for (int i = image.GetHeight()-1; i >= 0; i--) + for (int i = image.GetHeight() - 1; i >= 0; i--) { - for (int i1 = image.GetWidth()*image.GetLayers()-1; i1 >= 0; i1--) + for (int i1 = image.GetWidth()*image.GetLayers() - 1; i1 >= 0; i1--) { - ImageData[RowStart+i1] = RedChannel.HistogramData[ImageData[RowStart+i1]]; + ImageData[RowStart + i1] = RedChannel.HistogramData[ImageData[RowStart + i1]]; } RowStart += RowWidth; } - } else - if (ChannelMode == p_SeparateChannels) - { - if (time_mode == t_Continuous || (time_mode == t_Discrete && !DiscreteStretchingDone)) + } + else + if (ChannelMode == p_SeparateChannels) { - RedChannel.Calculate(image, 1, MEHistogram::h_Overwrite); - GreenChannel.Calculate(image, 2, MEHistogram::h_Overwrite); - BlueChannel.Calculate(image, 3, MEHistogram::h_Overwrite); - RedChannel.Stretch(StretchMode); - GreenChannel.Stretch(StretchMode); - BlueChannel.Stretch(StretchMode); - if (time_mode == t_Discrete && !DiscreteStretchingDone) + if (time_mode == t_Continuous || (time_mode == t_Discrete && !DiscreteStretchingDone)) { - DiscreteStretchingDone = true; + RedChannel.Calculate(image, 1, MEHistogram::h_Overwrite); + GreenChannel.Calculate(image, 2, MEHistogram::h_Overwrite); + BlueChannel.Calculate(image, 3, MEHistogram::h_Overwrite); + RedChannel.Stretch(StretchMode); + GreenChannel.Stretch(StretchMode); + BlueChannel.Stretch(StretchMode); + if (time_mode == t_Discrete && !DiscreteStretchingDone) + { + DiscreteStretchingDone = true; + } } - } - unsigned char *ImageData = image.GetImageData(); - int RowStart = 0; - int RowWidth = image.GetRowWidth(); + unsigned char *ImageData = image.GetImageData(); + int RowStart = 0; + int RowWidth = image.GetRowWidth(); - for (int i = image.GetHeight()-1; i >= 0; i--) - { - for (int i1 = image.GetWidth()*image.GetLayers()-3; i1 >= 0; i1 -= 3) + for (int i = image.GetHeight() - 1; i >= 0; i--) { - ImageData[RowStart+i1] = RedChannel.HistogramData[ImageData[RowStart+i1]]; - ImageData[RowStart+i1+1] = GreenChannel.HistogramData[ImageData[RowStart+i1+1]]; - ImageData[RowStart+i1+2] = BlueChannel.HistogramData[ImageData[RowStart+i1+2]]; + for (int i1 = image.GetWidth()*image.GetLayers() - 3; i1 >= 0; i1 -= 3) + { + ImageData[RowStart + i1] = RedChannel.HistogramData[ImageData[RowStart + i1]]; + ImageData[RowStart + i1 + 1] = GreenChannel.HistogramData[ImageData[RowStart + i1 + 1]]; + ImageData[RowStart + i1 + 2] = BlueChannel.HistogramData[ImageData[RowStart + i1 + 2]]; + } + RowStart += RowWidth; } - RowStart += RowWidth; } - } } @@ -433,72 +450,72 @@ void MEHistogramTransform::HistogramEqualize(MEImage& image) switch (image.GetLayers()) { - case 1: - // Grayscale image - cvDest8bitImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); - cvEqualizeHist((IplImage*)image.GetIplImage(), cvDest8bitImg); - image.SetIplImage((void*)cvDest8bitImg); - cvReleaseImage(&cvDest8bitImg); - break; - - case 3: - // RGB image - cvDestImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 3); - IplImage *cvR, *cvG, *cvB; - - cvR = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); - cvG = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); - cvB = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); - - cvSplit((IplImage*)image.GetIplImage(), cvR, cvG, cvB, NULL); - cvEqualizeHist(cvR, cvR); - cvEqualizeHist(cvG, cvG); - cvEqualizeHist(cvB, cvB); - cvMerge(cvR, cvG, cvB, NULL, cvDestImg); - - image.SetIplImage((void*)cvDestImg); - cvReleaseImage(&cvR); - cvReleaseImage(&cvG); - cvReleaseImage(&cvB); - cvReleaseImage(&cvDestImg); - break; - - default: - break; + case 1: + // Grayscale image + cvDest8bitImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); + cvEqualizeHist((IplImage*)image.GetIplImage(), cvDest8bitImg); + image.SetIplImage((void*)cvDest8bitImg); + cvReleaseImage(&cvDest8bitImg); + break; + + case 3: + // RGB image + cvDestImg = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 3); + IplImage *cvR, *cvG, *cvB; + + cvR = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); + cvG = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); + cvB = cvCreateImage(cvSize(image.GetWidth(), image.GetHeight()), 8, 1); + + cvSplit((IplImage*)image.GetIplImage(), cvR, cvG, cvB, NULL); + cvEqualizeHist(cvR, cvR); + cvEqualizeHist(cvG, cvG); + cvEqualizeHist(cvB, cvB); + cvMerge(cvR, cvG, cvB, NULL, cvDestImg); + + image.SetIplImage((void*)cvDestImg); + cvReleaseImage(&cvR); + cvReleaseImage(&cvG); + cvReleaseImage(&cvB); + cvReleaseImage(&cvDestImg); + break; + + default: + break; } } void MEHistogramTransform::SetStretchProcessingMode(ProcessingType new_channel_mode, - MEHistogram::StretchType new_stretch_mode) + MEHistogram::StretchType new_stretch_mode) { DiscreteStretchingDone = false; - switch(new_channel_mode) + switch (new_channel_mode) { - case p_SeparateChannels: - ChannelMode = new_channel_mode; - break; + case p_SeparateChannels: + ChannelMode = new_channel_mode; + break; - case p_Average: - ChannelMode = new_channel_mode; - break; + case p_Average: + ChannelMode = new_channel_mode; + break; - default: - break; + default: + break; } - switch(new_stretch_mode) + switch (new_stretch_mode) { - case MEHistogram::s_OwnMode: - StretchMode = new_stretch_mode; - break; + case MEHistogram::s_OwnMode: + StretchMode = new_stretch_mode; + break; - case MEHistogram::s_GimpMode: - StretchMode = new_stretch_mode; - break; + case MEHistogram::s_GimpMode: + StretchMode = new_stretch_mode; + break; - default: - break; + default: + break; } } diff --git a/package_bgs/ck/MEHistogram.hpp b/package_bgs/LBP_MRF/MEHistogram.hpp similarity index 93% rename from package_bgs/ck/MEHistogram.hpp rename to package_bgs/LBP_MRF/MEHistogram.hpp index 5b2b47f..0b2fb0d 100644 --- a/package_bgs/ck/MEHistogram.hpp +++ b/package_bgs/LBP_MRF/MEHistogram.hpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -18,14 +34,12 @@ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ +#pragma once -#ifndef MEHistogram_hpp -#define MEHistogram_hpp - -/** - * @addtogroup mindeye - * @{ - */ + /** + * @addtogroup mindeye + * @{ + */ class MEImage; @@ -344,5 +358,3 @@ private: }; /** @} */ - -#endif diff --git a/package_bgs/ck/MEImage.cpp b/package_bgs/LBP_MRF/MEImage.cpp similarity index 50% rename from package_bgs/ck/MEImage.cpp rename to package_bgs/LBP_MRF/MEImage.cpp index 7373834..b01d494 100644 --- a/package_bgs/ck/MEImage.cpp +++ b/package_bgs/LBP_MRF/MEImage.cpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -30,17 +46,17 @@ cvReleaseImage((IplImage**)&image_ptr); \ image_ptr = NULL; -// RGB to YUV transform + // RGB to YUV transform const float RGBtoYUVMatrix[3][3] = - {{ 0.299, 0.587, 0.114 }, - { -0.147, -0.289, 0.436 }, - { 0.615, -0.515, -0.100 }}; +{ { 0.299, 0.587, 0.114 }, + { -0.147, -0.289, 0.436 }, + { 0.615, -0.515, -0.100 } }; // RGB to YIQ transform const float RGBtoYIQMatrix[3][3] = - {{ 0.299, 0.587, 0.114 }, - { 0.596, -0.274, -0.322 }, - { 0.212, -0.523, 0.311 }}; +{ { 0.299, 0.587, 0.114 }, + { 0.596, -0.274, -0.322 }, + { 0.212, -0.523, 0.311 } }; MEImage::MEImage(int width, int height, int layers) : cvImg(NULL) { @@ -74,15 +90,15 @@ void MEImage::GetLayer(MEImage& new_layer, int layer_number) const int LayerNumber = layer_number; if ((new_layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width) || - (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) || - (new_layer.GetLayers() != 1)) + (new_layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) || + (new_layer.GetLayers() != 1)) { new_layer.Realloc(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height, 1); } if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) { printf("The given layer number is too large (%d > %d)\n", - LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; } @@ -103,17 +119,17 @@ void MEImage::SetLayer(MEImage& layer, int layer_number) int LayerNumber = layer_number; if (layer.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) + layer.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) { printf("The dimensions of the layer and " - "destination image is different (%dx%d <> %dx%d)\n", - layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height); + "destination image is different (%dx%d <> %dx%d)\n", + layer.GetWidth(), layer.GetHeight(), ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height); return; } if (ME_CAST_TO_IPLIMAGE(cvImg)->nChannels < LayerNumber) { printf("The given layer number is too large (%d > %d)\n", - LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + LayerNumber, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); LayerNumber = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; } if (LayerNumber <= 0) @@ -124,7 +140,7 @@ void MEImage::SetLayer(MEImage& layer, int layer_number) if (layer.GetLayers() != 1) { printf("The layer image has not one color channel (1 != %d)\n", - layer.GetLayers()); + layer.GetLayers()); return; } cvSetImageCOI(ME_CAST_TO_IPLIMAGE(cvImg), LayerNumber); @@ -223,7 +239,7 @@ void MEImage::SetData(unsigned char* image_data, int width, int height, int chan { _Init(width, height, channels); - for (int y = height-1; y >= 0; --y) + for (int y = height - 1; y >= 0; --y) { int Start = GetRowWidth()*y; int Start2 = width*channels*y; @@ -235,7 +251,7 @@ void MEImage::SetData(unsigned char* image_data, int width, int height, int chan float MEImage::GetRatio() const { - return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height/(float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0; + return ME_CAST_TO_IPLIMAGE(cvImg) ? (float)ME_CAST_TO_IPLIMAGE(cvImg)->height / (float)ME_CAST_TO_IPLIMAGE(cvImg)->width : 0.0; } @@ -289,7 +305,7 @@ void MEImage::ResizeScaleY(int new_height) printf("Invalid new height: %d < 1\n", new_height); return; } - Resize((int)((float)new_height*1/GetRatio()), new_height); + Resize((int)((float)new_height * 1 / GetRatio()), new_height); } @@ -322,19 +338,19 @@ void MEImage::Crop(int x1, int y1, int x2, int y2) NewY2 = (NewY2 < 0) ? 0 : NewY2; NewY2 = (NewY2 > ME_CAST_TO_IPLIMAGE(cvImg)->height) ? ME_CAST_TO_IPLIMAGE(cvImg)->height : NewY2; - if ((NewX2-NewX1) <= 0) + if ((NewX2 - NewX1) <= 0) { - printf("Invalid new width: %d <= 0\n", NewX2-NewX1); + printf("Invalid new width: %d <= 0\n", NewX2 - NewX1); return; } - if ((NewY2-NewY1) <= 0) + if ((NewY2 - NewY1) <= 0) { - printf("Invalid new height: %d <= 0\n", NewY2-NewY1); + printf("Invalid new height: %d <= 0\n", NewY2 - NewY1); return; } - IplImage* TempImg = cvCreateImage(cvSize(NewX2-NewX1, NewY2-NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + IplImage* TempImg = cvCreateImage(cvSize(NewX2 - NewX1, NewY2 - NewY1), 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2-NewX1, NewY2-NewY1)); + cvSetImageROI(ME_CAST_TO_IPLIMAGE(cvImg), cvRect(NewX1, NewY1, NewX2 - NewX1, NewY2 - NewY1)); cvCopy(ME_CAST_TO_IPLIMAGE(cvImg), TempImg); ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; @@ -367,13 +383,13 @@ void MEImage::CopyImageInside(int x, int y, MEImage& source_image) NewY = 0; if (NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height) NewY = ME_CAST_TO_IPLIMAGE(cvImg)->height; - if (NewX+PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width) - PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width-NewX; - if (NewY+PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height) - PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height-NewY; + if (NewX + PasteLengthX > ME_CAST_TO_IPLIMAGE(cvImg)->width) + PasteLengthX = ME_CAST_TO_IPLIMAGE(cvImg)->width - NewX; + if (NewY + PasteLengthY > ME_CAST_TO_IPLIMAGE(cvImg)->height) + PasteLengthY = ME_CAST_TO_IPLIMAGE(cvImg)->height - NewY; if (PasteLengthX != source_image.GetWidth() || - PasteLengthY != source_image.GetHeight()) + PasteLengthY != source_image.GetHeight()) { source_image.Resize(PasteLengthX, PasteLengthY); } @@ -386,8 +402,8 @@ void MEImage::CopyImageInside(int x, int y, MEImage& source_image) void MEImage::Erode(int iterations) { IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->height), + 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); cvErode(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); ME_RELEASE_IPLIMAGE(cvImg); @@ -398,8 +414,8 @@ void MEImage::Erode(int iterations) void MEImage::Dilate(int iterations) { IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->height), + 8, ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); cvDilate(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, NULL, iterations); ME_RELEASE_IPLIMAGE(cvImg); @@ -416,22 +432,22 @@ void MEImage::Smooth() void MEImage::SmoothAdvanced(SmoothType filtermode, int filtersize) { IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); switch (filtermode) { - case s_Blur: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0); - break; - case s_Median: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); - break; - case s_Gaussian: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0); - break; - default: - cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); - break; + case s_Blur: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_BLUR, filtersize, filtersize, 0); + break; + case s_Median: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); + break; + case s_Gaussian: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_GAUSSIAN, filtersize, filtersize, 0); + break; + default: + cvSmooth(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_MEDIAN, filtersize, 0, 0); + break; } ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; @@ -446,7 +462,7 @@ void MEImage::Canny() } IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); cvCanny(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 800, 1100, 5); ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; @@ -460,8 +476,8 @@ void MEImage::Laplace() ConvertToGrayscale(g_OpenCV); } IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), - IPL_DEPTH_16S, 1); + ME_CAST_TO_IPLIMAGE(cvImg)->height), + IPL_DEPTH_16S, 1); cvLaplace(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 3); cvConvertScale(TempImg, ME_CAST_TO_IPLIMAGE(cvImg), 1, 0); ME_RELEASE_IPLIMAGE(cvImg); @@ -482,7 +498,7 @@ void MEImage::Quantize(int levels) } unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) { ImageData[i] = ImageData[i] / (256 / levels)*(256 / levels); } @@ -503,7 +519,7 @@ void MEImage::Threshold(int threshold_limit) } unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) { if (ImageData[i] < threshold_limit) { @@ -520,9 +536,9 @@ void MEImage::AdaptiveThreshold() ConvertToGrayscale(g_OpenCV); } IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); cvAdaptiveThreshold(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, 25, - CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7); + CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, -7); ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; } @@ -531,7 +547,7 @@ void MEImage::AdaptiveThreshold() void MEImage::ThresholdByMask(MEImage& mask_image) { if (mask_image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) + mask_image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height) { printf("Image properties are different\n"); return; @@ -543,7 +559,7 @@ void MEImage::ThresholdByMask(MEImage& mask_image) unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; unsigned char* MaskImageData = mask_image.GetImageData(); - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; --i) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; --i) { if (MaskImageData[i] == 0) { @@ -567,123 +583,123 @@ void MEImage::ColorSpace(ColorSpaceConvertType mode) } switch (mode) { - case csc_RGBtoXYZCIED65: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_XYZCIED65toRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoHSV: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_HSVtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, - ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoHLS: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_HLStoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoCIELab: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_CIELabtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoCIELuv: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_CIELuvtoRGB: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; - - case csc_RGBtoYUV: - ComputeColorSpace(csc_RGBtoYUV); - break; - - case csc_RGBtoYIQ: - ComputeColorSpace(csc_RGBtoYIQ); - break; - - case csc_RGBtorgI: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + case csc_RGBtoXYZCIED65: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2XYZ); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_XYZCIED65toRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_XYZ2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoHSV: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HSV); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_HSVtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, + ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HSV2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoHLS: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2HLS); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_HLStoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_HLS2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoCIELab: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Lab); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_CIELabtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Lab2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoCIELuv: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2Luv); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_CIELuvtoRGB: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_Luv2RGB); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; + + case csc_RGBtoYUV: + ComputeColorSpace(csc_RGBtoYUV); + break; + + case csc_RGBtoYIQ: + ComputeColorSpace(csc_RGBtoYIQ); + break; + + case csc_RGBtorgI: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; + RowStart = 0; + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) * 3; x >= 0; x -= 3) { - for (int x = (ME_CAST_TO_IPLIMAGE(cvImg)->width-1)*3; x >= 0; x -= 3) - { - int r = 0; - int g = 0; - int I = 0; - - I = (int)ImageData[RowStart+x]+(int)ImageData[RowStart+x+1]+(int)ImageData[RowStart+x+2]; - r = (int)((float)ImageData[RowStart+x] / I*255); - g = (int)((float)ImageData[RowStart+x+1] / I*255); - ImageData[RowStart+x] = (unsigned char)r; - ImageData[RowStart+x+1] = (unsigned char)g; - ImageData[RowStart+x+2] = (unsigned char)(I / 3); - } - RowStart += WidthStep; + int r = 0; + int g = 0; + int I = 0; + + I = (int)ImageData[RowStart + x] + (int)ImageData[RowStart + x + 1] + (int)ImageData[RowStart + x + 2]; + r = (int)((float)ImageData[RowStart + x] / I * 255); + g = (int)((float)ImageData[RowStart + x + 1] / I * 255); + ImageData[RowStart + x] = (unsigned char)r; + ImageData[RowStart + x + 1] = (unsigned char)g; + ImageData[RowStart + x + 2] = (unsigned char)(I / 3); } - break; + RowStart += WidthStep; + } + break; - default: - break; + default: + break; } } @@ -701,27 +717,27 @@ void MEImage::ConvertToGrayscale(GrayscaleType grayscale_mode) switch (grayscale_mode) { - case g_Average: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); - ImageData = (unsigned char*)TempImg->imageData; + case g_Average: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); + ImageData = (unsigned char*)TempImg->imageData; - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-3; i >= 0; i -= 3) - { - ImageData[i / 3] = (ImgData[i]+ImgData[i+1]+ImgData[i+2]) / 3; - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 3; i >= 0; i -= 3) + { + ImageData[i / 3] = (ImgData[i] + ImgData[i + 1] + ImgData[i + 2]) / 3; + } + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; - case g_OpenCV: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); - cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY); - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; + case g_OpenCV: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); + cvCvtColor(ME_CAST_TO_IPLIMAGE(cvImg), TempImg, CV_RGB2GRAY); + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; - default: - break; + default: + break; } } @@ -760,60 +776,60 @@ void MEImage::LBP(LBPType mode) IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, 1); unsigned char* TempImgData = (unsigned char*)TempImg->imageData; int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*2; + int WidthStep_2 = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2; cvSetZero(TempImg); switch (mode) { - case lbp_Normal: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height-2)-1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1; --i) - { - TempImgData[i] = - (ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1])+ - ((ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep])*2)+ - ((ImageData[i] <= ImageData[i-ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1])*4)+ - ((ImageData[i] <= ImageData[i-1])*8)+ - ((ImageData[i] <= ImageData[i+1])*16)+ - ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1])*32)+ - ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep])*64)+ - ((ImageData[i] <= ImageData[i+ME_CAST_TO_IPLIMAGE(cvImg)->widthStep+1])*128); - } - break; + case lbp_Normal: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 2) - 1; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1; --i) + { + TempImgData[i] = + (ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) + + ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 2) + + ((ImageData[i] <= ImageData[i - ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 4) + + ((ImageData[i] <= ImageData[i - 1]) * 8) + + ((ImageData[i] <= ImageData[i + 1]) * 16) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1]) * 32) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep]) * 64) + + ((ImageData[i] <= ImageData[i + ME_CAST_TO_IPLIMAGE(cvImg)->widthStep + 1]) * 128); + } + break; - case lbp_Special: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height-3)-2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*2+2; --i) - { - int CenterPixel = (ImageData[i+1]+ImageData[i-1]+ - ImageData[i-WidthStep]+ImageData[i+WidthStep]) / 4; - TempImgData[i] = ((CenterPixel <= (ImageData[i-(WidthStep_2)-2]+ - ImageData[i-(WidthStep_2)-1]+ - ImageData[i-WidthStep-2]+ - ImageData[i-WidthStep-1]) / 4))+ - ((CenterPixel <= (ImageData[i-WidthStep]+ - ImageData[i-(WidthStep_2)]) / 2)*2)+ - ((CenterPixel <= ((ImageData[i-(WidthStep_2)+2]+ - ImageData[i-(WidthStep_2)+1]+ - ImageData[i-WidthStep+2]+ - ImageData[i-WidthStep+1]) / 4))*4)+ - ((CenterPixel <= (ImageData[i-1]+ - ImageData[i-2]) / 2)*8)+ - ((CenterPixel <= (ImageData[i+1]+ - ImageData[i+2]) / 2)*16)+ - ((CenterPixel <= ((ImageData[i+(WidthStep_2)-2]+ - ImageData[i+(WidthStep_2)-1]+ - ImageData[i+WidthStep-2]+ - ImageData[i+WidthStep-1]) / 4))*32)+ - ((CenterPixel <= (ImageData[i+WidthStep]+ - ImageData[i-WidthStep_2]) / 2)*64)+ - ((CenterPixel <= ((ImageData[i+(WidthStep_2)+2]+ - ImageData[i+(WidthStep_2)+1]+ - ImageData[i+WidthStep+2]+ - ImageData[i+WidthStep+1]) / 4))*128); - } - break; + case lbp_Special: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*(ME_CAST_TO_IPLIMAGE(cvImg)->height - 3) - 2; i >= ME_CAST_TO_IPLIMAGE(cvImg)->widthStep * 2 + 2; --i) + { + int CenterPixel = (ImageData[i + 1] + ImageData[i - 1] + + ImageData[i - WidthStep] + ImageData[i + WidthStep]) / 4; + TempImgData[i] = ((CenterPixel <= (ImageData[i - (WidthStep_2)-2] + + ImageData[i - (WidthStep_2)-1] + + ImageData[i - WidthStep - 2] + + ImageData[i - WidthStep - 1]) / 4)) + + ((CenterPixel <= (ImageData[i - WidthStep] + + ImageData[i - (WidthStep_2)]) / 2) * 2) + + ((CenterPixel <= ((ImageData[i - (WidthStep_2)+2] + + ImageData[i - (WidthStep_2)+1] + + ImageData[i - WidthStep + 2] + + ImageData[i - WidthStep + 1]) / 4)) * 4) + + ((CenterPixel <= (ImageData[i - 1] + + ImageData[i - 2]) / 2) * 8) + + ((CenterPixel <= (ImageData[i + 1] + + ImageData[i + 2]) / 2) * 16) + + ((CenterPixel <= ((ImageData[i + (WidthStep_2)-2] + + ImageData[i + (WidthStep_2)-1] + + ImageData[i + WidthStep - 2] + + ImageData[i + WidthStep - 1]) / 4)) * 32) + + ((CenterPixel <= (ImageData[i + WidthStep] + + ImageData[i - WidthStep_2]) / 2) * 64) + + ((CenterPixel <= ((ImageData[i + (WidthStep_2)+2] + + ImageData[i + (WidthStep_2)+1] + + ImageData[i + WidthStep + 2] + + ImageData[i + WidthStep + 1]) / 4)) * 128); + } + break; - default: - break; + default: + break; } ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; @@ -824,12 +840,13 @@ void MEImage::Binarize(int threshold) { unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) { if (ImageData[i] >= threshold) { ImageData[i] = 255; - } else { + } + else { ImageData[i] = 0; } } @@ -839,8 +856,8 @@ void MEImage::Binarize(int threshold) void MEImage::Subtract(MEImage& source, SubtractModeType mode) { if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) { printf("Image properties are different.\n"); return; @@ -852,42 +869,42 @@ void MEImage::Subtract(MEImage& source, SubtractModeType mode) switch (mode) { - case sub_Normal: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - RowStart = 0; + case sub_Normal: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) - { - ImageData[RowStart+x] = - ImageData[RowStart+x]-DstData[RowStart+x] < 0 ? 0 : - ImageData[RowStart+x]-DstData[RowStart+x]; - } - RowStart += WidthStep; + ImageData[RowStart + x] = + ImageData[RowStart + x] - DstData[RowStart + x] < 0 ? 0 : + ImageData[RowStart + x] - DstData[RowStart + x]; } - break; + RowStart += WidthStep; + } + break; - case sub_Absolut: - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - RowStart = 0; + case sub_Absolut: + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + { + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) - { - ImageData[RowStart+x] = ImageData[RowStart+x]- - DstData[RowStart+x] < 0 ? -ImageData[RowStart+x]+ - DstData[RowStart+x] : ImageData[RowStart+x]-DstData[RowStart+x]; - } - RowStart += WidthStep; + ImageData[RowStart + x] = ImageData[RowStart + x] - + DstData[RowStart + x] < 0 ? -ImageData[RowStart + x] + + DstData[RowStart + x] : ImageData[RowStart + x] - DstData[RowStart + x]; } - break; + RowStart += WidthStep; + } + break; - default: - break; + default: + break; } } @@ -895,8 +912,8 @@ void MEImage::Subtract(MEImage& source, SubtractModeType mode) void MEImage::Multiple(MEImage& source, MultiplicationType mode) { if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) { printf("Image properties are different.\n"); return; @@ -910,57 +927,59 @@ void MEImage::Multiple(MEImage& source, MultiplicationType mode) switch (mode) { - case m_Normal: - Result = 0; - ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); + case m_Normal: + Result = 0; + ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + if ((ImageData[i] >= 128) && (DstData[i] >= 128)) { - if ((ImageData[i] >= 128) && (DstData[i] >= 128)) - { - Result = (float)ImageData[i]/128*(float)DstData[i]/128; + Result = (float)ImageData[i] / 128 * (float)DstData[i] / 128; - if (Result >= 1) - { - ImageData[i] = 255; - } else { - ImageData[i] = 0; - } - } else { + if (Result >= 1) + { + ImageData[i] = 255; + } + else { ImageData[i] = 0; } } - break; - - case m_Neighbourhood: - TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); - ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - DstData = source.GetImageData(); - ImageData3 = (unsigned char*)TempImg->imageData; - - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width-1; x >= 0; --x) - for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; l >= 0; --l) - { - if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+ - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] == 255) || - (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+ - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] == 255)) && - (NeighbourhoodCounter(x-2, y-2, n_5x5) > 3) && - (source.NeighbourhoodCounter(x-2, y-2, n_5x5) > 3)) + else { + ImageData[i] = 0; + } + } + break; + + case m_Neighbourhood: + TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ImageData2 = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; + DstData = source.GetImageData(); + ImageData3 = (unsigned char*)TempImg->imageData; + + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) + for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) { - ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+ - x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] = 255; + if (((DstData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255) || + (ImageData2[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] == 255)) && + (NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3) && + (source.NeighbourhoodCounter(x - 2, y - 2, n_5x5) > 3)) + { + ImageData3[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] = 255; + } } - } - ME_RELEASE_IPLIMAGE(cvImg); - cvImg = TempImg; - break; + ME_RELEASE_IPLIMAGE(cvImg); + cvImg = TempImg; + break; - default: - break; + default: + break; } } @@ -968,8 +987,8 @@ void MEImage::Multiple(MEImage& source, MultiplicationType mode) void MEImage::Addition(MEImage& source, AdditionType mode) { if (source.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + source.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + source.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) { printf("Image properties are different.\n"); return; @@ -979,25 +998,25 @@ void MEImage::Addition(MEImage& source, AdditionType mode) switch (mode) { - case a_Average: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i) - { - ImageData[i] = (ImageData[i]+DstData[i]) / 2; - } - break; + case a_Average: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + ImageData[i] = (ImageData[i] + DstData[i]) / 2; + } + break; - case a_Union: - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep-1; i >= 0; --i) + case a_Union: + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep - 1; i >= 0; --i) + { + if (DstData[i] > ImageData[i]) { - if (DstData[i] > ImageData[i]) - { - ImageData[i] = DstData[i]; - } + ImageData[i] = DstData[i]; } - break; + } + break; - default: - break; + default: + break; } } @@ -1005,42 +1024,44 @@ void MEImage::Addition(MEImage& source, AdditionType mode) void MEImage::EliminateSinglePixels() { IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; unsigned char* DstData = (unsigned char*)TempImg->imageData; int sum = 0; int xy = 0; int ywidth = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width-1; x >= 0; --x) - { - xy = y*ywidth+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; - - for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; l >= 0; --l) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width - 1; x >= 0; --x) { - if ((ImageData[xy+l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width-1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height-1)) + xy = y*ywidth + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; + + for (int l = ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; l >= 0; --l) { - sum = (ImageData[xy-ywidth-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+ - (ImageData[xy-ywidth+l] > 0)+ - (ImageData[xy-ywidth+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+ - (ImageData[xy-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+ - (ImageData[xy+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+ - (ImageData[xy+ywidth-ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0)+ - (ImageData[xy+ywidth+l] > 0)+ - (ImageData[xy+ywidth+ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l] > 0); - - if (sum > 3) + if ((ImageData[xy + l] > 0) && (x > 0) && (y > 0) && (x < ME_CAST_TO_IPLIMAGE(cvImg)->width - 1) && (y < ME_CAST_TO_IPLIMAGE(cvImg)->height - 1)) { - DstData[xy+l] = 255; - } else { - DstData[xy+l] = 0; + sum = (ImageData[xy - ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy - ywidth + l] > 0) + + (ImageData[xy - ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ywidth - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0) + + (ImageData[xy + ywidth + l] > 0) + + (ImageData[xy + ywidth + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l] > 0); + + if (sum > 3) + { + DstData[xy + l] = 255; + } + else { + DstData[xy + l] = 0; + } + } + else { + DstData[xy + l] = 0; } - } else { - DstData[xy+l] = 0; } } - } ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; } @@ -1049,8 +1070,8 @@ void MEImage::EliminateSinglePixels() float MEImage::DifferenceAreas(MEImage& reference, int difference) const { if (reference.GetWidth() != GetWidth() || - reference.GetHeight() != GetHeight() || - reference.GetLayers() != GetLayers()) + reference.GetHeight() != GetHeight() || + reference.GetLayers() != GetLayers()) { printf("Image dimensions or channels are different\n"); return -1.0; @@ -1062,16 +1083,16 @@ float MEImage::DifferenceAreas(MEImage& reference, int difference) const int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; int RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - if (abs(OrigImgData[RowStart+x]-RefImgData[RowStart+x]) > difference) + if (abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]) > difference) Pixels++; } RowStart += WidthStep; } - PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep)*100; + PixelDiff = (float)Pixels / (ME_CAST_TO_IPLIMAGE(cvImg)->height*ME_CAST_TO_IPLIMAGE(cvImg)->widthStep) * 100; return PixelDiff; } @@ -1079,8 +1100,8 @@ float MEImage::DifferenceAreas(MEImage& reference, int difference) const int MEImage::AverageDifference(MEImage& reference) const { if (reference.GetWidth() != GetWidth() || - reference.GetHeight() != GetHeight() || - reference.GetLayers() != GetLayers()) + reference.GetHeight() != GetHeight() || + reference.GetLayers() != GetLayers()) { printf("Image dimensions or channels are different\n"); return -1; @@ -1091,11 +1112,11 @@ int MEImage::AverageDifference(MEImage& reference) const int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; int RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - Difference += abs(OrigImgData[RowStart+x]-RefImgData[RowStart+x]); + Difference += abs(OrigImgData[RowStart + x] - RefImgData[RowStart + x]); } RowStart += WidthStep; } @@ -1107,8 +1128,8 @@ int MEImage::AverageDifference(MEImage& reference) const void MEImage::Minimum(MEImage& image) { if (image.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + image.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + image.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) { printf("Image properties are different\n"); return; @@ -1118,12 +1139,12 @@ void MEImage::Minimum(MEImage& image) int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; int RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - ImageData[RowStart+x] = ImageData[RowStart+x] > SecData[RowStart+x] ? - SecData[RowStart+x] : ImageData[RowStart+x]; + ImageData[RowStart + x] = ImageData[RowStart + x] > SecData[RowStart + x] ? + SecData[RowStart + x] : ImageData[RowStart + x]; } RowStart += WidthStep; } @@ -1137,11 +1158,11 @@ float MEImage::AverageBrightnessLevel() const int RowStart = 0; int BrightnessLevel = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - BrightnessLevel += (int)ImageData[RowStart+x]; + BrightnessLevel += (int)ImageData[RowStart + x]; } RowStart += WidthStep; } @@ -1160,8 +1181,8 @@ bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const bool Ret = true; if (reference.GetWidth() != ME_CAST_TO_IPLIMAGE(cvImg)->width || - reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || - reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) + reference.GetHeight() != ME_CAST_TO_IPLIMAGE(cvImg)->height || + reference.GetLayers() != ME_CAST_TO_IPLIMAGE(cvImg)->nChannels) { printf("Image properties are different\n"); return false; @@ -1171,11 +1192,11 @@ bool MEImage::Equal(const MEImage& reference, int maxabsdiff) const int WidthStep = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep; int RowStart = 0; - for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height-1; y >= 0; --y) + for (int y = ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; y >= 0; --y) { - for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels-1; x >= 0; --x) + for (int x = ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels - 1; x >= 0; --x) { - if (abs(ImageData[RowStart+x]-RefData[RowStart+x]) >= maxabsdiff) + if (abs(ImageData[RowStart + x] - RefData[RowStart + x]) >= maxabsdiff) { Ret = false; return Ret; @@ -1193,16 +1214,16 @@ unsigned char MEImage::GrayscalePixel(int x, int y) const int NewY = y; NewX = NewX < 0 ? 0 : NewX; - NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width-1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width-1 : NewX; + NewX = NewX > ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->width - 1 : NewX; NewY = NewY < 0 ? 0 : NewY; - NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height-1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height-1 : NewY; + NewY = NewY > ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 ? ME_CAST_TO_IPLIMAGE(cvImg)->height - 1 : NewY; float Sum = 0; unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; for (int l = 0; l < ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; l++) { - Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+l]; + Sum = Sum + (int)ImageData[NewY*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + NewX*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + l]; } Sum = Sum / ME_CAST_TO_IPLIMAGE(cvImg)->nChannels; return (unsigned char)(Sum); @@ -1210,7 +1231,7 @@ unsigned char MEImage::GrayscalePixel(int x, int y) const int MEImage::NeighbourhoodCounter(int startx, int starty, - NeighbourhoodType neighbourhood) const + NeighbourhoodType neighbourhood) const { int IterX = 0; int IterY = 0; @@ -1219,60 +1240,60 @@ int MEImage::NeighbourhoodCounter(int startx, int starty, // Determine the iteration numbers switch (neighbourhood) { - case n_2x2: - IterX = 2; - IterY = 2; - break; + case n_2x2: + IterX = 2; + IterY = 2; + break; - case n_3x3: - IterX = 3; - IterY = 3; - break; + case n_3x3: + IterX = 3; + IterY = 3; + break; - case n_3x2: - IterX = 2; - IterY = 3; - break; + case n_3x2: + IterX = 2; + IterY = 3; + break; - case n_5x5: - IterX = 5; - IterY = 5; - break; + case n_5x5: + IterX = 5; + IterY = 5; + break; - case n_7x7: - IterX = 7; - IterY = 7; - break; + case n_7x7: + IterX = 7; + IterY = 7; + break; - default: - IterX = 3; - IterY = 3; - break; + default: + IterX = 3; + IterY = 3; + break; } - int NewStartX = startx ; + int NewStartX = startx; int NewStartY = starty; NewStartX = startx < 0 ? 0 : startx; - NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width-IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width-IterX-1 : startx; + NewStartX = startx >= ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX ? ME_CAST_TO_IPLIMAGE(cvImg)->width - IterX - 1 : startx; NewStartY = starty < 0 ? 0 : starty; - NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height-IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height-IterY-1 : starty; + NewStartY = starty >= ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY ? ME_CAST_TO_IPLIMAGE(cvImg)->height - IterY - 1 : starty; int Value = 0; unsigned char* ImageData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; - for (int x = NewStartX; x < NewStartX+IterX; x++) - for (int y = NewStartY; y < NewStartY+IterY; y++) - { - Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels]+ - (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+1]+ - (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels+2]) / 3; - - if (Value == 255) + for (int x = NewStartX; x < NewStartX + IterX; x++) + for (int y = NewStartY; y < NewStartY + IterY; y++) { - Counter++; + Value = ((int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels] + + (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 1] + + (int)ImageData[y*ME_CAST_TO_IPLIMAGE(cvImg)->width*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + x*ME_CAST_TO_IPLIMAGE(cvImg)->nChannels + 2]) / 3; + + if (Value == 255) + { + Counter++; + } } - } return Counter; } @@ -1288,24 +1309,24 @@ void MEImage::GradientVector(bool smooth, int x, int y, int mask_size, int& resu } if (smooth) { - SmoothAdvanced(s_Gaussian, mask_size*3-(mask_size*3-1) % 2); + SmoothAdvanced(s_Gaussian, mask_size * 3 - (mask_size * 3 - 1) % 2); } - Results[0] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x,y-mask_size); - Results[1] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y-DiagonalMaskSize); - Results[2] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+mask_size,y); - Results[3] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y+DiagonalMaskSize); - Results[4] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x,y+mask_size); - Results[5] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x-DiagonalMaskSize,y+DiagonalMaskSize); - Results[6] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x-mask_size,y); - Results[7] = (int)GrayscalePixel(x,y)-(int)GrayscalePixel(x+DiagonalMaskSize,y-DiagonalMaskSize); + Results[0] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y - mask_size); + Results[1] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); + Results[2] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + mask_size, y); + Results[3] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y + DiagonalMaskSize); + Results[4] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x, y + mask_size); + Results[5] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - DiagonalMaskSize, y + DiagonalMaskSize); + Results[6] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x - mask_size, y); + Results[7] = (int)GrayscalePixel(x, y) - (int)GrayscalePixel(x + DiagonalMaskSize, y - DiagonalMaskSize); - result_x = (DiagonalMaskSize*Results[1]+mask_size*Results[2]+ - DiagonalMaskSize*Results[3]-DiagonalMaskSize*Results[5]- - mask_size*Results[6]+DiagonalMaskSize*Results[7]) / 256; - result_y = (-mask_size*Results[0]-DiagonalMaskSize*Results[1]+ - DiagonalMaskSize*Results[3]+mask_size*Results[4]+ - DiagonalMaskSize*Results[5]-DiagonalMaskSize*Results[7]) / 256; + result_x = (DiagonalMaskSize*Results[1] + mask_size*Results[2] + + DiagonalMaskSize*Results[3] - DiagonalMaskSize*Results[5] - + mask_size*Results[6] + DiagonalMaskSize*Results[7]) / 256; + result_y = (-mask_size*Results[0] - DiagonalMaskSize*Results[1] + + DiagonalMaskSize*Results[3] + mask_size*Results[4] + + DiagonalMaskSize*Results[5] - DiagonalMaskSize*Results[7]) / 256; } @@ -1327,28 +1348,28 @@ void MEImage::GradientVisualize(int vector_x, int vector_y) } int masksize = (ME_CAST_TO_IPLIMAGE(cvImg)->width < ME_CAST_TO_IPLIMAGE(cvImg)->height) ? - ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x+1) : - ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y+1); + ME_CAST_TO_IPLIMAGE(cvImg)->width / (vector_x + 1) : + ME_CAST_TO_IPLIMAGE(cvImg)->height / (vector_y + 1); - SmoothAdvanced(s_Gaussian, masksize*2-1); + SmoothAdvanced(s_Gaussian, masksize * 2 - 1); for (int i = 1; i < vector_x; i++) for (int i1 = 1; i1 < vector_y; i1++) - { - int Resultx = 0, Resulty = 0; - int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x))); - int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y))); + { + int Resultx = 0, Resulty = 0; + int x = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->width*i / (vector_x))); + int y = (int)(((float)ME_CAST_TO_IPLIMAGE(cvImg)->height*i1 / (vector_y))); - GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty); + GradientVector(false, x, y, (int)(0.707*masksize), Resultx, Resulty); - CvPoint Point1; - CvPoint Point2; + CvPoint Point1; + CvPoint Point2; - Point1.x = x-Resultx / 2; - Point1.y = y-Resulty / 2; - Point2.x = x+Resultx / 2; - Point2.y = y+Resulty / 2; - cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8); - } + Point1.x = x - Resultx / 2; + Point1.y = y - Resulty / 2; + Point2.x = x + Resultx / 2; + Point2.y = y + Resulty / 2; + cvLine(ME_CAST_TO_IPLIMAGE(cvImg), Point1, Point2, CV_RGB(255, 255, 255), 1, 8); + } } @@ -1400,16 +1421,16 @@ void MEImage::ComputeColorSpace(ColorSpaceConvertType mode) return; } IplImage* TempImg = cvCreateImage(cvSize(ME_CAST_TO_IPLIMAGE(cvImg)->width, ME_CAST_TO_IPLIMAGE(cvImg)->height), 8, - ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); + ME_CAST_TO_IPLIMAGE(cvImg)->nChannels); for (int i = 0; i < 3; i++) for (int i1 = 0; i1 < 3; i1++) - { - if (mode == csc_RGBtoYUV) - TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1]; - if (mode == csc_RGBtoYIQ) - TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1]; - } + { + if (mode == csc_RGBtoYUV) + TransformMatrix[i][i1] = RGBtoYUVMatrix[i][i1]; + if (mode == csc_RGBtoYIQ) + TransformMatrix[i][i1] = RGBtoYIQMatrix[i][i1]; + } float x = 0.0; float y = 0.0; float z = 0.0; @@ -1441,25 +1462,25 @@ void MEImage::ComputeColorSpace(ColorSpaceConvertType mode) unsigned char* SrcData = (unsigned char*)ME_CAST_TO_IPLIMAGE(cvImg)->imageData; unsigned char* DstData = (unsigned char*)TempImg->imageData; - for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height-1; i >= 0; i-=3) + for (int i = ME_CAST_TO_IPLIMAGE(cvImg)->widthStep*ME_CAST_TO_IPLIMAGE(cvImg)->height - 1; i >= 0; i -= 3) { - x = (float)SrcData[i]*TransformMatrix[0][0]+ - (float)SrcData[i+1]*TransformMatrix[0][1]+ - (float)SrcData[i+2]*TransformMatrix[0][2]; - y = (float)SrcData[i]*TransformMatrix[1][0]+ - (float)SrcData[i+1]*TransformMatrix[1][1]+ - (float)SrcData[i+2]*TransformMatrix[1][2]; - z = (float)SrcData[i]*TransformMatrix[2][0]+ - (float)SrcData[i+1]*TransformMatrix[2][1]+ - (float)SrcData[i+2]*TransformMatrix[2][2]; + x = (float)SrcData[i] * TransformMatrix[0][0] + + (float)SrcData[i + 1] * TransformMatrix[0][1] + + (float)SrcData[i + 2] * TransformMatrix[0][2]; + y = (float)SrcData[i] * TransformMatrix[1][0] + + (float)SrcData[i + 1] * TransformMatrix[1][1] + + (float)SrcData[i + 2] * TransformMatrix[1][2]; + z = (float)SrcData[i] * TransformMatrix[2][0] + + (float)SrcData[i + 1] * TransformMatrix[2][1] + + (float)SrcData[i + 2] * TransformMatrix[2][2]; - x = xmax-xmin != 0.0 ? 255.0 : (x-xmin) / (xmax-xmin)*255.0; - y = ymax-ymin != 0.0 ? 255.0 : (y-xmin) / (ymax-ymin)*255.0; - z = zmax-zmin != 0.0 ? 255.0 : (z-xmin) / (zmax-zmin)*255.0; + x = xmax - xmin != 0.0 ? 255.0 : (x - xmin) / (xmax - xmin)*255.0; + y = ymax - ymin != 0.0 ? 255.0 : (y - xmin) / (ymax - ymin)*255.0; + z = zmax - zmin != 0.0 ? 255.0 : (z - xmin) / (zmax - zmin)*255.0; DstData[i] = (unsigned char)MEBound(0, (int)x, 255); - DstData[i+1] = (unsigned char)MEBound(0, (int)y, 255); - DstData[i+2] = (unsigned char)MEBound(0, (int)z, 255); + DstData[i + 1] = (unsigned char)MEBound(0, (int)y, 255); + DstData[i + 2] = (unsigned char)MEBound(0, (int)z, 255); } ME_RELEASE_IPLIMAGE(cvImg); cvImg = TempImg; diff --git a/package_bgs/ck/MEImage.hpp b/package_bgs/LBP_MRF/MEImage.hpp similarity index 97% rename from package_bgs/ck/MEImage.hpp rename to package_bgs/LBP_MRF/MEImage.hpp index 41ada3b..3a52a77 100644 --- a/package_bgs/ck/MEImage.hpp +++ b/package_bgs/LBP_MRF/MEImage.hpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -18,19 +34,17 @@ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ +#pragma once -#ifndef MEImage_H -#define MEImage_H - -/** - * @addtogroup mindeye - * @{ - */ + /** + * @addtogroup mindeye + * @{ + */ -/** - * MEImage - * @brief Basic image functions - */ + /** + * MEImage + * @brief Basic image functions + */ class MEImage { public: @@ -995,5 +1009,3 @@ private: }; /** @} */ - -#endif diff --git a/package_bgs/ck/MotionDetection.cpp b/package_bgs/LBP_MRF/MotionDetection.cpp similarity index 91% rename from package_bgs/ck/MotionDetection.cpp rename to package_bgs/LBP_MRF/MotionDetection.cpp index 5ac096a..e591faa 100644 --- a/package_bgs/ck/MotionDetection.cpp +++ b/package_bgs/LBP_MRF/MotionDetection.cpp @@ -1,4 +1,20 @@ /* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* * This file is part of the AiBO+ project * * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) @@ -52,15 +68,15 @@ struct MEPixelDataType }; MotionDetection::MotionDetection(DetectorType mode) : -MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false), -HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special), -HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8), -HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL), -HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01), -HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0), -HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1), -HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1), -HUOFCamMovement(false) + MDMode(md_NotDefined), MDDataState(ps_Uninitialized), Frames(0), ReadyMask(false), + HUColorSpace(MEImage::csc_RGBtoCIELuv), HULBPMode(MEImage::lbp_Special), + HUHistogramsPerPixel(3), HUHistogramArea(5), HUHistogramBins(8), + HUImageWidth(-1), HUImageHeight(-1), HULBPPixelData(NULL), + HUPrThres(0.75), HUBackgrThres(0.95), HUHistLRate(0.01), HUWeightsLRate(0.01), + HUSamplePixels(-1), HUDesiredSamplePixels(-1), HUMinCutWeight(8.0), + HUOFDataState(ps_Uninitialized), HUOFPointsNumber(-1), + HUOFCamMovementX(0), MaxTrackedPoints(0), HUOFFrames(-1), + HUOFCamMovement(false) { HUOFPyramid = NULL; HUOFPrevPyramid = NULL; @@ -357,13 +373,13 @@ void MotionDetection::InitHUData(int imagewidth, int imageheight) for (int i = 0; i < HUImageWidth / 2; ++i) for (int i1 = 0; i1 < HUImageHeight; ++i1) { - HULBPPixelData[i][i1] = new MEPixelDataType; - HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel]; - HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel]; - HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel]; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins]; - HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins]; + HULBPPixelData[i][i1] = new MEPixelDataType; + HULBPPixelData[i][i1]->Weights = new float[HUHistogramsPerPixel]; + HULBPPixelData[i][i1]->BackgroundHistogram = new bool[HUHistogramsPerPixel]; + HULBPPixelData[i][i1]->Histograms = new float*[HUHistogramsPerPixel]; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + HULBPPixelData[i][i1]->Histograms[i2] = new float[HUHistogramBins]; + HULBPPixelData[i][i1]->PreviousHistogram = new float[HUHistogramBins]; } // Allocate auxiliary variables @@ -399,8 +415,8 @@ void MotionDetection::InitHUOFData(int imagewidth, int imageheight) HUOFPointsNumber = imagewidth*imageheight / 1000; HUOFPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); HUOFPrevPyramid = cvCreateImage(cvSize(imagewidth, imageheight), 8, 1); - HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber*sizeof(HUOFPoints[0][0])); - HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber*sizeof(HUOFPoints[1][0])); + HUOFPoints[0] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[0][0])); + HUOFPoints[1] = (CvPoint2D32f*)cvAlloc(HUOFPointsNumber * sizeof(HUOFPoints[1][0])); } } @@ -412,13 +428,13 @@ void MotionDetection::ReleaseHUData() for (int i = 0; i < HUImageWidth / 2; i++) for (int i1 = 0; i1 < HUImageHeight; i1++) { - delete[] HULBPPixelData[i][i1]->PreviousHistogram; - for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) - delete[] HULBPPixelData[i][i1]->Histograms[i2]; - delete[] HULBPPixelData[i][i1]->Histograms; - delete[] HULBPPixelData[i][i1]->BackgroundHistogram; - delete[] HULBPPixelData[i][i1]->Weights; - delete HULBPPixelData[i][i1]; + delete[] HULBPPixelData[i][i1]->PreviousHistogram; + for (int i2 = 0; i2 < HUHistogramsPerPixel; ++i2) + delete[] HULBPPixelData[i][i1]->Histograms[i2]; + delete[] HULBPPixelData[i][i1]->Histograms; + delete[] HULBPPixelData[i][i1]->BackgroundHistogram; + delete[] HULBPPixelData[i][i1]->Weights; + delete HULBPPixelData[i][i1]; } for (int i = 0; i < HUImageWidth / 2; i++) @@ -486,15 +502,15 @@ void MotionDetection::ClearHUData() for (int i = (HUImageWidth / 2) - 1; i >= 0; --i) for (int i1 = HUImageHeight - 1; i1 >= 0; --i1) { - for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2) - { - memset(HULBPPixelData[i][i1]->Histograms[i2], 0, - HUHistogramBins*sizeof(float)); - HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel; - HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true; - } - HULBPPixelData[i][i1]->BackgroundRate = 1.0; - HULBPPixelData[i][i1]->LifeCycle = 0; + for (int i2 = HUHistogramsPerPixel - 1; i2 >= 0; --i2) + { + memset(HULBPPixelData[i][i1]->Histograms[i2], 0, + HUHistogramBins * sizeof(float)); + HULBPPixelData[i][i1]->Weights[i2] = 1.0 / HUHistogramsPerPixel; + HULBPPixelData[i][i1]->BackgroundHistogram[i2] = true; + } + HULBPPixelData[i][i1]->BackgroundRate = 1.0; + HULBPPixelData[i][i1]->LifeCycle = 0; } MDDataState = ps_Initialized; } @@ -563,13 +579,13 @@ void MotionDetection::DetectMotionsHU(MEImage& image) else if (Frames > 1) { - PreviousImage = CurrentImage; - CurrentImage = image; - // Optical flow correction of the camera movements - if (MDMode == md_DLBPHistograms) - { - OpticalFlowCorrection(); - } + PreviousImage = CurrentImage; + CurrentImage = image; + // Optical flow correction of the camera movements + if (MDMode == md_DLBPHistograms) + { + OpticalFlowCorrection(); + } } newimage.ConvertToGrayscale(MEImage::g_OpenCV); @@ -915,17 +931,17 @@ void MotionDetection::UpdateHUPixelData(MEPixelDataType* PixelData, const float for (int i1 = HUHistogramsPerPixel - 1; i1 >= 2; --i1) for (int i = i1; i >= 1; --i) { - if (Weights[i][1] <= Weights[i - 1][1]) - { - float tmp = Weights[i][0]; - float tmp2 = Weights[i][1]; + if (Weights[i][1] <= Weights[i - 1][1]) + { + float tmp = Weights[i][0]; + float tmp2 = Weights[i][1]; - Weights[i][0] = Weights[i - 1][0]; - Weights[i][1] = Weights[i - 1][1]; + Weights[i][0] = Weights[i - 1][0]; + Weights[i][1] = Weights[i - 1][1]; - Weights[i - 1][0] = tmp; - Weights[i - 1][1] = tmp2; - } + Weights[i - 1][0] = tmp; + Weights[i - 1][1] = tmp2; + } } float Sum = 0; @@ -1056,7 +1072,7 @@ void MotionDetection::OpticalFlowCorrection() if ((Distances[i][2] > Distances[i - 1][2]) || ((Distances[i][2] == Distances[i - 1][2]) && (abs(Distances[i][0]) + abs(Distances[i][1]) < - abs(Distances[i - 1][0]) + abs(Distances[i - 1][1])))) + abs(Distances[i - 1][0]) + abs(Distances[i - 1][1])))) { int tmp = Distances[i][0]; int tmp2 = Distances[i][1]; @@ -1331,10 +1347,10 @@ void MotionDetection::GetMotionsMaskHU(MEImage& mask_image) MaskImgData[RowStart + x + (HUHistogramArea / 2)] = ((int)(x > 1 && HULBPPixelData[(x / 2) - 1][y]->BackgroundRate == 0.0) + (int)(x < mask_image.GetWidth() - HUHistogramArea - 1 && - HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) + - (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) + - (int)(y < mask_image.GetHeight() - HUHistogramArea && - HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1) + HULBPPixelData[(x / 2) + 1][y]->BackgroundRate == 0.0) + + (int)(y > 0 && HULBPPixelData[x / 2][y - 1]->BackgroundRate == 0.0) + + (int)(y < mask_image.GetHeight() - HUHistogramArea && + HULBPPixelData[x / 2][y + 1]->BackgroundRate == 0.0) > 1) ? 255 : 0; } } diff --git a/package_bgs/ck/MotionDetection.hpp b/package_bgs/LBP_MRF/MotionDetection.hpp similarity index 93% rename from package_bgs/ck/MotionDetection.hpp rename to package_bgs/LBP_MRF/MotionDetection.hpp index 6e11521..e58c93c 100644 --- a/package_bgs/ck/MotionDetection.hpp +++ b/package_bgs/LBP_MRF/MotionDetection.hpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* * This file is part of the AiBO+ project * @@ -18,14 +34,12 @@ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. * */ +#pragma once -#ifndef MotionDetection_hpp -#define MotionDetection_hpp - -/** - * @addtogroup mindeye - * @{ - */ + /** + * @addtogroup mindeye + * @{ + */ #include "MEDefs.hpp" #include "MEImage.hpp" @@ -181,7 +195,7 @@ public: */ void CalculateResults(MEImage& referenceimage, int& tnegatives, int& tpositives, - int& ttnegatives, int& ttpositives); + int& ttnegatives, int& ttpositives); private: @@ -397,5 +411,3 @@ private: }; /** @} */ - -#endif diff --git a/package_bgs/ck/block.h b/package_bgs/LBP_MRF/block.h similarity index 51% rename from package_bgs/ck/block.h rename to package_bgs/LBP_MRF/block.h index 98b1201..bd1ab67 100644 --- a/package_bgs/ck/block.h +++ b/package_bgs/LBP_MRF/block.h @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* block.h */ /* Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). @@ -16,8 +32,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - /* Template classes Block and DBlock Implement adding and deleting items of the same type in blocks. @@ -105,9 +119,7 @@ simultaneously at earlier moments. All memory is deallocated only when the destructor is called. */ - -#ifndef __BLOCK_H__ -#define __BLOCK_H__ +#pragma once #include <stdlib.h> #include <stdio.h> @@ -118,170 +130,168 @@ namespace ck { - template <class Type> class Block - { - public: - /* Constructor. Arguments are the block size and +template <class Type> class Block +{ +public: + /* Constructor. Arguments are the block size and (optionally) the pointer to the function which will be called if allocation failed; the message passed to this function is "Not enough memory!" */ - Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } + Block(int size, void(*err_function)(char *) = NULL) { first = last = NULL; block_size = size; error_function = err_function; } - /* Destructor. Deallocates all items added so far */ - ~Block() { while (first) { block *next = first->next; delete first; first = next; } } + /* Destructor. Deallocates all items added so far */ + ~Block() { while (first) { block *next = first->next; delete first; first = next; } } - /* Allocates 'num' consecutive items; returns pointer + /* Allocates 'num' consecutive items; returns pointer to the first item. 'num' cannot be greater than the block size since items must fit in one block */ - Type *New(int num = 1) - { - Type *t; + Type *New(int num = 1) + { + Type *t; - if (!last || last->current + num > last->last) + if (!last || last->current + num > last->last) + { + if (last && last->next) last = last->next; + else { - if (last && last->next) last = last->next; - else - { - block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)]; - if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); } - if (last) last->next = next; - else first = next; - last = next; - last->current = &(last->data[0]); - last->last = last->current + block_size; - last->next = NULL; - } + block *next = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(Type)]; + if (!next) { fprintf(stderr, "Not enough memory!"); exit(1); } + if (last) last->next = next; + else first = next; + last = next; + last->current = &(last->data[0]); + last->last = last->current + block_size; + last->next = NULL; } - - t = last->current; - last->current += num; - return t; } - /* Returns the first item (or NULL, if no items were added) */ - Type *ScanFirst() - { - scan_current_block = first; - if (!scan_current_block) return NULL; - scan_current_data = &(scan_current_block->data[0]); - return scan_current_data++; - } + t = last->current; + last->current += num; + return t; + } + + /* Returns the first item (or NULL, if no items were added) */ + Type *ScanFirst() + { + scan_current_block = first; + if (!scan_current_block) return NULL; + scan_current_data = &(scan_current_block->data[0]); + return scan_current_data++; + } - /* Returns the next item (or NULL, if all items have been read) + /* Returns the next item (or NULL, if all items have been read) Can be called only if previous ScanFirst() or ScanNext() call returned not NULL. */ - Type *ScanNext() + Type *ScanNext() + { + if (scan_current_data >= scan_current_block->current) { - if (scan_current_data >= scan_current_block->current) - { - scan_current_block = scan_current_block->next; - if (!scan_current_block) return NULL; - scan_current_data = &(scan_current_block->data[0]); - } - return scan_current_data++; + scan_current_block = scan_current_block->next; + if (!scan_current_block) return NULL; + scan_current_data = &(scan_current_block->data[0]); } + return scan_current_data++; + } - /* Marks all elements as empty */ - void Reset() + /* Marks all elements as empty */ + void Reset() + { + block *b; + if (!first) return; + for (b = first;; b = b->next) { - block *b; - if (!first) return; - for (b = first;; b = b->next) - { - b->current = &(b->data[0]); - if (b == last) break; - } - last = first; + b->current = &(b->data[0]); + if (b == last) break; } + last = first; + } - /***********************************************************************/ + /***********************************************************************/ - private: +private: - typedef struct block_st - { - Type *current, *last; - struct block_st *next; - Type data[1]; - } block; + typedef struct block_st + { + Type *current, *last; + struct block_st *next; + Type data[1]; + } block; - int block_size; - block *first; - block *last; + int block_size; + block *first; + block *last; - block *scan_current_block; - Type *scan_current_data; + block *scan_current_block; + Type *scan_current_data; - void(*error_function)(char *); - }; + void(*error_function)(char *); +}; - /***********************************************************************/ - /***********************************************************************/ - /***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ - template <class Type> class DBlock - { - public: - /* Constructor. Arguments are the block size and +template <class Type> class DBlock +{ +public: + /* Constructor. Arguments are the block size and (optionally) the pointer to the function which will be called if allocation failed; the message passed to this function is "Not enough memory!" */ - DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } - - /* Destructor. Deallocates all items added so far */ - ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } } - - /* Allocates one item */ - Type *New() - { - block_item *item; + DBlock(int size, void(*err_function)(char *) = NULL) { first = NULL; first_free = NULL; block_size = size; error_function = err_function; } - if (!first_free) - { - block *next = first; - first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)]; - if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); } - first_free = &(first->data[0]); - for (item = first_free; item < first_free + block_size - 1; item++) - item->next_free = item + 1; - item->next_free = NULL; - first->next = next; - } + /* Destructor. Deallocates all items added so far */ + ~DBlock() { while (first) { block *next = first->next; delete first; first = next; } } - item = first_free; - first_free = item->next_free; - return (Type *)item; - } + /* Allocates one item */ + Type *New() + { + block_item *item; - /* Deletes an item allocated previously */ - void Delete(Type *t) + if (!first_free) { - ((block_item *)t)->next_free = first_free; - first_free = (block_item *)t; + block *next = first; + first = (block *) new char[sizeof(block) + (block_size - 1)*sizeof(block_item)]; + if (!first) { fprintf(stderr, "Not enough memory!"); exit(1); } + first_free = &(first->data[0]); + for (item = first_free; item < first_free + block_size - 1; item++) + item->next_free = item + 1; + item->next_free = NULL; + first->next = next; } - /***********************************************************************/ + item = first_free; + first_free = item->next_free; + return (Type *)item; + } - private: + /* Deletes an item allocated previously */ + void Delete(Type *t) + { + ((block_item *)t)->next_free = first_free; + first_free = (block_item *)t; + } - typedef union block_item_st - { - Type t; - block_item_st *next_free; - } block_item; + /***********************************************************************/ - typedef struct block_st - { - struct block_st *next; - block_item data[1]; - } block; +private: - int block_size; - block *first; - block_item *first_free; + typedef union block_item_st + { + Type t; + block_item_st *next_free; + } block_item; - void(*error_function)(char *); - }; -} + typedef struct block_st + { + struct block_st *next; + block_item data[1]; + } block; + + int block_size; + block *first; + block_item *first_free; -#endif + void(*error_function)(char *); +}; +} diff --git a/package_bgs/ck/graph.cpp b/package_bgs/LBP_MRF/graph.cpp similarity index 78% rename from package_bgs/ck/graph.cpp rename to package_bgs/LBP_MRF/graph.cpp index daed395..9301250 100644 --- a/package_bgs/ck/graph.cpp +++ b/package_bgs/LBP_MRF/graph.cpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* graph.cpp */ /* Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). @@ -80,4 +96,4 @@ namespace ck flow += (cap_source < cap_sink) ? cap_source : cap_sink; ((node*)i)->tr_cap = cap_source - cap_sink; } -} \ No newline at end of file +} diff --git a/package_bgs/ck/graph.h b/package_bgs/LBP_MRF/graph.h similarity index 60% rename from package_bgs/ck/graph.h rename to package_bgs/LBP_MRF/graph.h index b6799e4..e7b83c7 100644 --- a/package_bgs/ck/graph.h +++ b/package_bgs/LBP_MRF/graph.h @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* graph.h */ /* This software library implements the maxflow algorithm @@ -16,41 +32,36 @@ If you use this software for research purposes, you should cite the aforementioned paper in any resulting publication. */ - -/* - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* - For description, example usage, discussion of graph representation - and memory usage see README.TXT. - */ - -#ifndef __GRAPH_H__ -#define __GRAPH_H__ + /* + Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + /* + For description, example usage, discussion of graph representation + and memory usage see README.TXT. + */ +#pragma once #include "block.h" -/* - Nodes, arcs and pointers to nodes are - added in blocks for memory and time efficiency. - Below are numbers of items in blocks - */ + /* + Nodes, arcs and pointers to nodes are + added in blocks for memory and time efficiency. + Below are numbers of items in blocks + */ #define NODE_BLOCK_SIZE 512 #define ARC_BLOCK_SIZE 1024 #define NODEPTR_BLOCK_SIZE 128 @@ -67,7 +78,7 @@ namespace ck } termtype; /* terminals */ /* Type of edge weights. - Can be changed to char, int, float, double, ... */ + Can be changed to char, int, float, double, ... */ typedef short captype; /* Type of total flow */ typedef int flowtype; @@ -77,9 +88,9 @@ namespace ck /* interface functions */ /* Constructor. Optional argument is the pointer to the - function which will be called if an error occurs; - an error message is passed to this function. If this - argument is omitted, exit(1) will be called. */ + function which will be called if an error occurs; + an error message is passed to this function. If this + argument is omitted, exit(1) will be called. */ Graph(void(*err_function)(char *) = NULL); /* Destructor */ @@ -89,21 +100,21 @@ namespace ck node_id add_node(); /* Adds a bidirectional edge between 'from' and 'to' - with the weights 'cap' and 'rev_cap' */ + with the weights 'cap' and 'rev_cap' */ void add_edge(node_id from, node_id to, captype cap, captype rev_cap); /* Sets the weights of the edges 'SOURCE->i' and 'i->SINK' - Can be called at most once for each node before any call to 'add_tweights'. - Weights can be negative */ + Can be called at most once for each node before any call to 'add_tweights'. + Weights can be negative */ void set_tweights(node_id i, captype cap_source, captype cap_sink); /* Adds new edges 'SOURCE->i' and 'i->SINK' with corresponding weights - Can be called multiple times for each node. - Weights can be negative */ + Can be called multiple times for each node. + Weights can be negative */ void add_tweights(node_id i, captype cap_source, captype cap_sink); /* After the maxflow is computed, this function returns to which - segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */ + segment the node 'i' belongs (Graph::SOURCE or Graph::SINK) */ termtype what_segment(node_id i); /* Computes the maxflow. Can be called only once. */ @@ -125,13 +136,13 @@ namespace ck arc_st *parent; /* node's parent */ node_st *next; /* pointer to the next active node - (or to itself if it is the last node in the list) */ + (or to itself if it is the last node in the list) */ int TS; /* timestamp showing when DIST was computed */ int DIST; /* distance to the terminal */ short is_sink; /* flag showing whether the node is in the source or in the sink tree */ captype tr_cap; /* if tr_cap > 0 then tr_cap is residual capacity of the arc SOURCE->node - otherwise -tr_cap is residual capacity of the arc node->SINK */ + otherwise -tr_cap is residual capacity of the arc node->SINK */ } node; /* arc structure */ @@ -156,8 +167,8 @@ namespace ck DBlock<nodeptr> *nodeptr_block; void(*error_function)(char *); /* this function is called if a error occurs, - with a corresponding error message - (or exit(1) is called if it's NULL) */ + with a corresponding error message + (or exit(1) is called if it's NULL) */ flowtype flow; /* total flow */ @@ -179,5 +190,3 @@ namespace ck void process_sink_orphan(node *i); }; } - -#endif diff --git a/package_bgs/ck/maxflow.cpp b/package_bgs/LBP_MRF/maxflow.cpp similarity index 67% rename from package_bgs/ck/maxflow.cpp rename to package_bgs/LBP_MRF/maxflow.cpp index 53d3705..6ddec50 100644 --- a/package_bgs/ck/maxflow.cpp +++ b/package_bgs/LBP_MRF/maxflow.cpp @@ -1,3 +1,19 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ /* maxflow.cpp */ /* Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). @@ -16,33 +32,31 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - #include <stdio.h> #include "graph.h" -/* - special constants for node->parent - */ + /* + special constants for node->parent + */ #define TERMINAL ( (arc *) 1 ) /* to terminal */ #define ORPHAN ( (arc *) 2 ) /* orphan */ #define INFINITE_D 1000000000 /* infinite distance to the terminal */ -/***********************************************************************/ + /***********************************************************************/ -/* - Functions for processing active list. - i->next points to the next node in the list - (or to i, if i is the last node in the list). - If i->next is NULL iff i is not in the list. - - There are two queues. Active nodes are added - to the end of the second queue and read from - the front of the first queue. If the first queue - is empty, it is replaced by the second queue - (and the second queue becomes empty). - */ + /* + Functions for processing active list. + i->next points to the next node in the list + (or to i, if i is the last node in the list). + If i->next is NULL iff i is not in the list. + + There are two queues. Active nodes are added + to the end of the second queue and read from + the front of the first queue. If the first queue + is empty, it is replaced by the second queue + (and the second queue becomes empty). + */ namespace ck { inline void Graph::set_active(node *i) @@ -58,10 +72,10 @@ namespace ck } /* - Returns the next active node. - If it is connected to the sink, it stays in the list, - otherwise it is removed from the list - */ + Returns the next active node. + If it is connected to the sink, it stays in the list, + otherwise it is removed from the list + */ inline Graph::node * Graph::next_active() { node *i; @@ -232,45 +246,45 @@ namespace ck for (a0 = i->first; a0; a0 = a0->next) if (a0->sister->r_cap) { - j = a0->head; - if (!j->is_sink && (a = j->parent)) - { - /* checking the origin of j */ - d = 0; - while (1) - { - if (j->TS == TIME) - { - d += j->DIST; - break; - } - a = j->parent; - d++; - if (a == TERMINAL) - { - j->TS = TIME; - j->DIST = 1; - break; - } - if (a == ORPHAN) { d = INFINITE_D; break; } - j = a->head; - } - if (d < INFINITE_D) /* j originates from the source - done */ + j = a0->head; + if (!j->is_sink && (a = j->parent)) { - if (d < d_min) + /* checking the origin of j */ + d = 0; + while (1) { - a0_min = a0; - d_min = d; + if (j->TS == TIME) + { + d += j->DIST; + break; + } + a = j->parent; + d++; + if (a == TERMINAL) + { + j->TS = TIME; + j->DIST = 1; + break; + } + if (a == ORPHAN) { d = INFINITE_D; break; } + j = a->head; } - /* set marks along the path */ - for (j = a0->head; j->TS != TIME; j = j->parent->head) + if (d < INFINITE_D) /* j originates from the source - done */ { - j->TS = TIME; - j->DIST = d--; + if (d < d_min) + { + a0_min = a0; + d_min = d; + } + /* set marks along the path */ + for (j = a0->head; j->TS != TIME; j = j->parent->head) + { + j->TS = TIME; + j->DIST = d--; + } } } } - } if ((i->parent = a0_min)) { @@ -316,45 +330,45 @@ namespace ck for (a0 = i->first; a0; a0 = a0->next) if (a0->r_cap) { - j = a0->head; - if (j->is_sink && (a = j->parent)) - { - /* checking the origin of j */ - d = 0; - while (1) - { - if (j->TS == TIME) - { - d += j->DIST; - break; - } - a = j->parent; - d++; - if (a == TERMINAL) - { - j->TS = TIME; - j->DIST = 1; - break; - } - if (a == ORPHAN) { d = INFINITE_D; break; } - j = a->head; - } - if (d < INFINITE_D) /* j originates from the sink - done */ + j = a0->head; + if (j->is_sink && (a = j->parent)) { - if (d < d_min) + /* checking the origin of j */ + d = 0; + while (1) { - a0_min = a0; - d_min = d; + if (j->TS == TIME) + { + d += j->DIST; + break; + } + a = j->parent; + d++; + if (a == TERMINAL) + { + j->TS = TIME; + j->DIST = 1; + break; + } + if (a == ORPHAN) { d = INFINITE_D; break; } + j = a->head; } - /* set marks along the path */ - for (j = a0->head; j->TS != TIME; j = j->parent->head) + if (d < INFINITE_D) /* j originates from the sink - done */ { - j->TS = TIME; - j->DIST = d--; + if (d < d_min) + { + a0_min = a0; + d_min = d; + } + /* set marks along the path */ + for (j = a0->head; j->TS != TIME; j = j->parent->head) + { + j->TS = TIME; + j->DIST = d--; + } } } } - } if ((i->parent = a0_min)) { @@ -419,24 +433,24 @@ namespace ck for (a = i->first; a; a = a->next) if (a->r_cap) { - j = a->head; - if (!j->parent) - { - j->is_sink = 0; - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - set_active(j); - } - else if (j->is_sink) break; - else if (j->TS <= i->TS && - j->DIST > i->DIST) - { - /* heuristic - trying to make the distance from j to the source shorter */ - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - } + j = a->head; + if (!j->parent) + { + j->is_sink = 0; + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + set_active(j); + } + else if (j->is_sink) break; + else if (j->TS <= i->TS && + j->DIST > i->DIST) + { + /* heuristic - trying to make the distance from j to the source shorter */ + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + } } } else @@ -445,24 +459,24 @@ namespace ck for (a = i->first; a; a = a->next) if (a->sister->r_cap) { - j = a->head; - if (!j->parent) - { - j->is_sink = 1; - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - set_active(j); - } - else if (!j->is_sink) { a = a->sister; break; } - else if (j->TS <= i->TS && - j->DIST > i->DIST) - { - /* heuristic - trying to make the distance from j to the sink shorter */ - j->parent = a->sister; - j->TS = i->TS; - j->DIST = i->DIST + 1; - } + j = a->head; + if (!j->parent) + { + j->is_sink = 1; + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + set_active(j); + } + else if (!j->is_sink) { a = a->sister; break; } + else if (j->TS <= i->TS && + j->DIST > i->DIST) + { + /* heuristic - trying to make the distance from j to the sink shorter */ + j->parent = a->sister; + j->TS = i->TS; + j->DIST = i->DIST + 1; + } } } @@ -513,4 +527,4 @@ namespace ck return SINK; } -} \ No newline at end of file +} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp b/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp new file mode 100644 index 0000000..2865a30 --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLBSP.cpp @@ -0,0 +1,85 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "BackgroundSubtractorLBSP.h" +#include "DistanceUtils.h" +#include "RandUtils.h" +#include <iostream> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <iomanip> +#include <exception> + +#ifndef SIZE_MAX +# if __WORDSIZE == 64 +# define SIZE_MAX (18446744073709551615UL) +# else +# define SIZE_MAX (4294967295U) +# endif +#endif + +// local define used to determine the default median blur kernel size +#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9) + +BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) + : m_nImgChannels(0) + , m_nImgType(0) + , m_nLBSPThresholdOffset(nLBSPThresholdOffset) + , m_fRelLBSPThreshold(fRelLBSPThreshold) + , m_nTotPxCount(0) + , m_nTotRelevantPxCount(0) + , m_nFrameIndex(SIZE_MAX) + , m_nFramesSinceLastReset(0) + , m_nModelResetCooldown(0) + , m_aPxIdxLUT(nullptr) + , m_aPxInfoLUT(nullptr) + , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) + , m_bInitialized(false) + , m_bAutoModelResetEnabled(true) + , m_bUsingMovingCamera(false) + , nDebugCoordX(0), nDebugCoordY(0) { + CV_Assert(m_fRelLBSPThreshold >= 0); +} + +BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {} + +void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) { + this->initialize(oInitImg, cv::Mat()); +} + +/*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const { + return nullptr; +}*/ + +cv::Mat BackgroundSubtractorLBSP::getROICopy() const { + return m_oROI.clone(); +} + +void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) { + LBSP::validateROI(oROI); + CV_Assert(cv::countNonZero(oROI) > 0); + if (m_bInitialized) { + cv::Mat oLatestBackgroundImage; + getBackgroundImage(oLatestBackgroundImage); + initialize(oLatestBackgroundImage, oROI); + } + else + m_oROI = oROI.clone(); +} + +void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) { + m_bAutoModelResetEnabled = bVal; +} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP.h b/package_bgs/LBSP/BackgroundSubtractorLBSP.h new file mode 100644 index 0000000..ef0576c --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLBSP.h @@ -0,0 +1,101 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <opencv2/features2d/features2d.hpp> +#include <opencv2/video/background_segm.hpp> +#include "LBSP.h" + +/*! + Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). + + For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background + Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection + in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ +class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor { +public: + //! full constructor + BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); + //! default destructor + virtual ~BackgroundSubtractorLBSP(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; + //! unused, always returns nullptr + //virtual cv::AlgorithmInfo* info() const; + //! returns a copy of the ROI used for descriptor extraction + virtual cv::Mat getROICopy() const; + //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) + virtual void setROI(cv::Mat& oROI); + //! turns automatic model reset on or off + void setAutomaticModelReset(bool); + +protected: + struct PxInfoBase { + int nImgCoord_Y; + int nImgCoord_X; + size_t nModelIdx; + }; + //! background model ROI used for LBSP descriptor extraction (specific to the input image size) + cv::Mat m_oROI; + //! input image size + cv::Size m_oImgSize; + //! input image channel size + size_t m_nImgChannels; + //! input image type + int m_nImgType; + //! LBSP internal threshold offset value, used to reduce texture noise in dark regions + const size_t m_nLBSPThresholdOffset; + //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) + const float m_fRelLBSPThreshold; + //! total number of pixels (depends on the input frame size) & total number of relevant pixels + size_t m_nTotPxCount, m_nTotRelevantPxCount; + //! current frame index, frame count since last model reset & model reset cooldown counters + size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; + //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities + size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; + //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) + size_t* m_aPxIdxLUT; + //! internal pixel info LUT for all possible pixel indexes + PxInfoBase* m_aPxInfoLUT; + //! default kernel size for median blur post-proc filtering + const int m_nDefaultMedianBlurKernelSize; + //! specifies whether the algorithm is fully initialized or not + bool m_bInitialized; + //! specifies whether automatic model resets are enabled or not + bool m_bAutoModelResetEnabled; + //! specifies whether the camera is considered moving or not + bool m_bUsingMovingCamera; + //! copy of latest pixel intensities (used when refreshing model) + cv::Mat m_oLastColorFrame; + //! copy of latest descriptors (used when refreshing model) + cv::Mat m_oLastDescFrame; + //! the foreground mask generated by the method at [t-1] + cv::Mat m_oLastFGMask; + +public: + // ######## DEBUG PURPOSES ONLY ########## + int nDebugCoordX, nDebugCoordY; + std::string sDebugName; +}; + diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp b/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp new file mode 100644 index 0000000..4e5d4a6 --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLBSP_.cpp @@ -0,0 +1,79 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "BackgroundSubtractorLBSP_.h" +#include "DistanceUtils.h" +#include "RandUtils.h" +#include <iostream> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <iomanip> +#include <exception> + +// local define used to determine the default median blur kernel size +#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9) + +BackgroundSubtractorLBSP_::BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) + : m_nImgChannels(0) + , m_nImgType(0) + , m_nLBSPThresholdOffset(nLBSPThresholdOffset) + , m_fRelLBSPThreshold(fRelLBSPThreshold) + , m_nTotPxCount(0) + , m_nTotRelevantPxCount(0) + , m_nFrameIndex(SIZE_MAX) + , m_nFramesSinceLastReset(0) + , m_nModelResetCooldown(0) + , m_aPxIdxLUT(nullptr) + , m_aPxInfoLUT(nullptr) + , m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) + , m_bInitialized(false) + , m_bAutoModelResetEnabled(true) + , m_bUsingMovingCamera(false) + , m_nDebugCoordX(0) + , m_nDebugCoordY(0) + , m_pDebugFS(nullptr) { + CV_Assert(m_fRelLBSPThreshold >= 0); +} + +BackgroundSubtractorLBSP_::~BackgroundSubtractorLBSP_() {} + +void BackgroundSubtractorLBSP_::initialize(const cv::Mat& oInitImg) { + this->initialize(oInitImg, cv::Mat()); +} +/* +cv::AlgorithmInfo* BackgroundSubtractorLBSP_::info() const { + return nullptr; +} +*/ +cv::Mat BackgroundSubtractorLBSP_::getROICopy() const { + return m_oROI.clone(); +} + +void BackgroundSubtractorLBSP_::setROI(cv::Mat& oROI) { + LBSP_::validateROI(oROI); + CV_Assert(cv::countNonZero(oROI) > 0); + if (m_bInitialized) { + cv::Mat oLatestBackgroundImage; + getBackgroundImage(oLatestBackgroundImage); + initialize(oLatestBackgroundImage, oROI); + } + else + m_oROI = oROI.clone(); +} + +void BackgroundSubtractorLBSP_::setAutomaticModelReset(bool bVal) { + m_bAutoModelResetEnabled = bVal; +} diff --git a/package_bgs/LBSP/BackgroundSubtractorLBSP_.h b/package_bgs/LBSP/BackgroundSubtractorLBSP_.h new file mode 100644 index 0000000..861f78a --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLBSP_.h @@ -0,0 +1,107 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <opencv2/features2d/features2d.hpp> +#include <opencv2/video/background_segm.hpp> +#include "LBSP_.h" + +/*! + Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). + + For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background + Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection + in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ +class BackgroundSubtractorLBSP_ : public cv::BackgroundSubtractor { +public: + //! full constructor + BackgroundSubtractorLBSP_(float fRelLBSPThreshold, size_t nLBSPThresholdOffset = 0); + //! default destructor + virtual ~BackgroundSubtractorLBSP_(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) = 0; + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRate = 0) = 0; + //! unused, always returns nullptr + //virtual cv::AlgorithmInfo* info() const; + //! returns a copy of the ROI used for descriptor extraction + virtual cv::Mat getROICopy() const; + //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) + virtual void setROI(cv::Mat& oROI); + //! turns automatic model reset on or off + void setAutomaticModelReset(bool); + +protected: + struct PxInfoBase { + int nImgCoord_Y; + int nImgCoord_X; + size_t nModelIdx; + }; + //! background model ROI used for LBSP descriptor extraction (specific to the input image size) + cv::Mat m_oROI; + //! input image size + cv::Size m_oImgSize; + //! input image channel size + size_t m_nImgChannels; + //! input image type + int m_nImgType; + //! LBSP internal threshold offset value, used to reduce texture noise in dark regions + const size_t m_nLBSPThresholdOffset; + //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) + const float m_fRelLBSPThreshold; + //! total number of pixels (depends on the input frame size) & total number of relevant pixels + size_t m_nTotPxCount, m_nTotRelevantPxCount; + //! current frame index, frame count since last model reset & model reset cooldown counters + size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; + //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities + size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX + 1]; + //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) + size_t* m_aPxIdxLUT; + //! internal pixel info LUT for all possible pixel indexes + PxInfoBase* m_aPxInfoLUT; + //! default kernel size for median blur post-proc filtering + const int m_nDefaultMedianBlurKernelSize; + //! specifies whether the algorithm is fully initialized or not + bool m_bInitialized; + //! specifies whether automatic model resets are enabled or not + bool m_bAutoModelResetEnabled; + //! specifies whether the camera is considered moving or not + bool m_bUsingMovingCamera; + //! copy of latest pixel intensities (used when refreshing model) + cv::Mat m_oLastColorFrame; + //! copy of latest descriptors (used when refreshing model) + cv::Mat m_oLastDescFrame; + //! the foreground mask generated by the method at [t-1] + cv::Mat m_oLastFGMask; + +private: + //! copy constructor -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers + BackgroundSubtractorLBSP_(const BackgroundSubtractorLBSP_&); + //! assignment operator -- disabled since this class (and its children) use lots of dynamic structs based on raw pointers + BackgroundSubtractorLBSP_& operator=(const BackgroundSubtractorLBSP_&); + +public: + // ######## DEBUG PURPOSES ONLY ########## + int m_nDebugCoordX, m_nDebugCoordY; + std::string m_sDebugName; + cv::FileStorage* m_pDebugFS; +}; diff --git a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp b/package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp new file mode 100644 index 0000000..9648c5c --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLOBSTER.cpp @@ -0,0 +1,342 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "BackgroundSubtractorLOBSTER.h" +#include "DistanceUtils.h" +#include "RandUtils.h" +#include <iostream> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <iomanip> + +BackgroundSubtractorLOBSTER::BackgroundSubtractorLOBSTER(float fRelLBSPThreshold + , size_t nLBSPThresholdOffset + , size_t nDescDistThreshold + , size_t nColorDistThreshold + , size_t nBGSamples + , size_t nRequiredBGSamples) + : BackgroundSubtractorLBSP(fRelLBSPThreshold, nLBSPThresholdOffset) + , m_nColorDistThreshold(nColorDistThreshold) + , m_nDescDistThreshold(nDescDistThreshold) + , m_nBGSamples(nBGSamples) + , m_nRequiredBGSamples(nRequiredBGSamples) { + CV_Assert(m_nRequiredBGSamples <= m_nBGSamples); + m_bAutoModelResetEnabled = false; // @@@@@@ not supported here for now +} + +BackgroundSubtractorLOBSTER::~BackgroundSubtractorLOBSTER() { + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; +} + +void BackgroundSubtractorLOBSTER::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { + CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); + CV_Assert(oInitImg.isContinuous()); + CV_Assert(oInitImg.type() == CV_8UC1 || oInitImg.type() == CV_8UC3); + if (oInitImg.type() == CV_8UC3) { + std::vector<cv::Mat> voInitImgChannels; + cv::split(oInitImg, voInitImgChannels); + if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) + std::cout << std::endl << "\tBackgroundSubtractorLOBSTER : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; + } + cv::Mat oNewBGROI; + if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { + oNewBGROI.create(oInitImg.size(), CV_8UC1); + oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); + } + else if (oROI.empty()) + oNewBGROI = m_oROI; + else { + CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); + CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); + oNewBGROI = oROI.clone(); + } + LBSP::validateROI(oNewBGROI); + const size_t nROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nROIPxCount > 0); + m_oROI = oNewBGROI; + m_oImgSize = oInitImg.size(); + m_nImgType = oInitImg.type(); + m_nImgChannels = oInitImg.channels(); + m_nTotPxCount = m_oImgSize.area(); + m_nTotRelevantPxCount = nROIPxCount; + m_nFrameIndex = 0; + m_nFramesSinceLastReset = 0; + m_nModelResetCooldown = 0; + m_oLastFGMask.create(m_oImgSize, CV_8UC1); + m_oLastFGMask = cv::Scalar_<uchar>(0); + m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_oLastColorFrame = cv::Scalar_<uchar>::all(0); + m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_oLastDescFrame = cv::Scalar_<ushort>::all(0); + m_voBGColorSamples.resize(m_nBGSamples); + m_voBGDescSamples.resize(m_nBGSamples); + for (size_t s = 0; s < m_nBGSamples; ++s) { + m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); + m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); + } + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; + m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; + m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; + if (m_nImgChannels == 1) { + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((t*m_fRelLBSPThreshold + m_nLBSPThresholdOffset) / 2); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; + const size_t nDescIter = nPxIter * 2; + LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); + ++nModelIter; + } + } + } + else { //m_nImgChannels==3 + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(t*m_fRelLBSPThreshold + m_nLBSPThresholdOffset); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + for (size_t c = 0; c < 3; ++c) { + m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; + LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); + } + ++nModelIter; + } + } + } + m_bInitialized = true; + refreshModel(1.0f); +} + +void BackgroundSubtractorLOBSTER::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { + // == refresh + CV_Assert(m_bInitialized); + CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f); + const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples; + const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0; + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2)); + } + } + } + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2)); + } + } + } + } + } + } +} + +void BackgroundSubtractorLOBSTER::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate) { + CV_Assert(m_bInitialized); + CV_Assert(learningRate > 0); + cv::Mat oInputImg = _image.getMat(); + CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); + CV_Assert(oInputImg.isContinuous()); + _fgmask.create(m_oImgSize, CV_8UC1); + cv::Mat oCurrFGMask = _fgmask.getMat(); + oCurrFGMask = cv::Scalar_<uchar>(0); + const size_t nLearningRate = (size_t)ceil(learningRate); + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nDescIter = nPxIter * 2; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const uchar nCurrColor = oInputImg.data[nPxIter]; + size_t nGoodSamplesCount = 0, nModelIdx = 0; + ushort nCurrInputDesc; + while (nGoodSamplesCount < m_nRequiredBGSamples && nModelIdx < m_nBGSamples) { + const uchar nBGColor = m_voBGColorSamples[nModelIdx].data[nPxIter]; + { + const size_t nColorDist = L1dist(nCurrColor, nBGColor); + if (nColorDist > m_nColorDistThreshold / 2) + goto failedcheck1ch; + LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInputDesc); + const size_t nDescDist = hdist(nCurrInputDesc, *((ushort*)(m_voBGDescSamples[nModelIdx].data + nDescIter))); + if (nDescDist > m_nDescDistThreshold) + goto failedcheck1ch; + nGoodSamplesCount++; + } + failedcheck1ch: + nModelIdx++; + } + if (nGoodSamplesCount < m_nRequiredBGSamples) + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + else { + if ((rand() % nLearningRate) == 0) { + const size_t nSampleModelIdx = rand() % m_nBGSamples; + ushort& nRandInputDesc = *((ushort*)(m_voBGDescSamples[nSampleModelIdx].data + nDescIter)); + LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nRandInputDesc); + m_voBGColorSamples[nSampleModelIdx].data[nPxIter] = nCurrColor; + } + if ((rand() % nLearningRate) == 0) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSampleModelIdx = rand() % m_nBGSamples; + ushort& nRandInputDesc = m_voBGDescSamples[nSampleModelIdx].at<ushort>(nSampleImgCoord_Y, nSampleImgCoord_X); + LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nRandInputDesc); + m_voBGColorSamples[nSampleModelIdx].at<uchar>(nSampleImgCoord_Y, nSampleImgCoord_X) = nCurrColor; + } + } + } + } + else { //m_nImgChannels==3 + const size_t nCurrDescDistThreshold = m_nDescDistThreshold * 3; + const size_t nCurrColorDistThreshold = m_nColorDistThreshold * 3; + const size_t nCurrSCDescDistThreshold = nCurrDescDistThreshold / 2; + const size_t nCurrSCColorDistThreshold = nCurrColorDistThreshold / 2; + const size_t desc_row_step = m_voBGDescSamples[0].step.p[0]; + const size_t img_row_step = m_voBGColorSamples[0].step.p[0]; + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const size_t nPxIterRGB = nPxIter * 3; + const size_t nDescIterRGB = nPxIterRGB * 2; + const uchar* const anCurrColor = oInputImg.data + nPxIterRGB; + size_t nGoodSamplesCount = 0, nModelIdx = 0; + ushort anCurrInputDesc[3]; + while (nGoodSamplesCount < m_nRequiredBGSamples && nModelIdx < m_nBGSamples) { + const ushort* const anBGDesc = (ushort*)(m_voBGDescSamples[nModelIdx].data + nDescIterRGB); + const uchar* const anBGColor = m_voBGColorSamples[nModelIdx].data + nPxIterRGB; + size_t nTotColorDist = 0; + size_t nTotDescDist = 0; + for (size_t c = 0; c < 3; ++c) { + const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]); + if (nColorDist > nCurrSCColorDistThreshold) + goto failedcheck3ch; + LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInputDesc[c]); + const size_t nDescDist = hdist(anCurrInputDesc[c], anBGDesc[c]); + if (nDescDist > nCurrSCDescDistThreshold) + goto failedcheck3ch; + nTotColorDist += nColorDist; + nTotDescDist += nDescDist; + } + if (nTotDescDist <= nCurrDescDistThreshold && nTotColorDist <= nCurrColorDistThreshold) + nGoodSamplesCount++; + failedcheck3ch: + nModelIdx++; + } + if (nGoodSamplesCount < m_nRequiredBGSamples) + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + else { + if ((rand() % nLearningRate) == 0) { + const size_t nSampleModelIdx = rand() % m_nBGSamples; + ushort* anRandInputDesc = ((ushort*)(m_voBGDescSamples[nSampleModelIdx].data + nDescIterRGB)); + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anRandInputDesc); + for (size_t c = 0; c < 3; ++c) + *(m_voBGColorSamples[nSampleModelIdx].data + nPxIterRGB + c) = anCurrColor[c]; + } + if ((rand() % nLearningRate) == 0) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSampleModelIdx = rand() % m_nBGSamples; + ushort* anRandInputDesc = ((ushort*)(m_voBGDescSamples[nSampleModelIdx].data + desc_row_step*nSampleImgCoord_Y + 6 * nSampleImgCoord_X)); + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anRandInputDesc); + for (size_t c = 0; c < 3; ++c) + *(m_voBGColorSamples[nSampleModelIdx].data + img_row_step*nSampleImgCoord_Y + 3 * nSampleImgCoord_X + c) = anCurrColor[c]; + } + } + } + } + cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nDefaultMedianBlurKernelSize); + m_oLastFGMask.copyTo(oCurrFGMask); +} + +void BackgroundSubtractorLOBSTER::getBackgroundImage(cv::OutputArray backgroundImage) const { + CV_DbgAssert(m_bInitialized); + cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t s = 0; s < m_nBGSamples; ++s) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x; + const size_t idx_flt32 = idx_nimg * 4; + float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + idx_flt32); + const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg; + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples; + } + } + } + oAvgBGImg.convertTo(backgroundImage, CV_8U); +} + +void BackgroundSubtractorLOBSTER::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { + CV_Assert(LBSP::DESC_SIZE == 2); + CV_Assert(m_bInitialized); + cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x; + const size_t idx_flt32 = idx_ndesc * 2; + float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + idx_flt32); + const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc); + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size(); + } + } + } + oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); +} diff --git a/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h b/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h new file mode 100644 index 0000000..d69fd1c --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorLOBSTER.h @@ -0,0 +1,83 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "BackgroundSubtractorLBSP.h" + +//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold +#define BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.365f) +//! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset +#define BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD (0) +//! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold +#define BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD (4) +//! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold +#define BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD (30) +//! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples +#define BGSLOBSTER_DEFAULT_NB_BG_SAMPLES (35) +//! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples +#define BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) +//! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator() +#define BGSLOBSTER_DEFAULT_LEARNING_RATE (16) + +/*! + LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and + G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014. + + This algorithm is currently NOT thread-safe. + */ +class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP { +public: + //! full constructor + BackgroundSubtractorLOBSTER(float fRelLBSPThreshold = BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nLBSPThresholdOffset = BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD, + size_t nDescDistThreshold = BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD, + size_t nColorDistThreshold = BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD, + size_t nBGSamples = BGSLOBSTER_DEFAULT_NB_BG_SAMPLES, + size_t nRequiredBGSamples = BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); + //! default destructor + virtual ~BackgroundSubtractorLOBSTER(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all samples based on the last analyzed frame + virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = BGSLOBSTER_DEFAULT_LEARNING_RATE); + //! returns a copy of the latest reconstructed background image + void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + +protected: + //! absolute color distance threshold + const size_t m_nColorDistThreshold; + //! absolute descriptor distance threshold + const size_t m_nDescDistThreshold; + //! number of different samples per pixel/block to be taken from input frames to build the background model + const size_t m_nBGSamples; + //! number of similar samples needed to consider the current pixel/block as 'background' + const size_t m_nRequiredBGSamples; + //! background model pixel intensity samples + std::vector<cv::Mat> m_voBGColorSamples; + //! background model descriptors samples + std::vector<cv::Mat> m_voBGDescSamples; +}; + diff --git a/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp b/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp new file mode 100644 index 0000000..6c48df3 --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorPAWCS.cpp @@ -0,0 +1,1349 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "BackgroundSubtractorPAWCS.h" +#include "DistanceUtils.h" +#include "RandUtils.h" +#include <iostream> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <iomanip> + +/* + * + * Intrinsic configuration parameters are defined here; tuning these for better + * performance should not be required in most cases -- although improvements in + * very specific scenarios are always possible. + * + */ + //! parameter used for dynamic distance threshold adjustments ('R(x)') +#define FEEDBACK_R_VAR (0.01f) +//! parameters used to adjust the variation step size of 'v(x)' +#define FEEDBACK_V_INCR (1.000f) +#define FEEDBACK_V_DECR (0.100f) +//! parameters used to scale dynamic learning rate adjustments ('T(x)') +#define FEEDBACK_T_DECR (0.2500f) +#define FEEDBACK_T_INCR (0.5000f) +#define FEEDBACK_T_LOWER (1.0000f) +#define FEEDBACK_T_UPPER (256.00f) +//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values +#define UNSTABLE_REG_RATIO_MIN (0.100f) +#define UNSTABLE_REG_RDIST_MIN (3.000f) +//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons +#define LBSPDESC_RATIO_MIN (0.100f) +#define LBSPDESC_RATIO_MAX (0.500f) +//! parameters used to trigger auto model resets in our frame-level component +#define FRAMELEVEL_MIN_L1DIST_THRES (45) +#define FRAMELEVEL_MIN_CDIST_THRES (FRAMELEVEL_MIN_L1DIST_THRES/10) +#define FRAMELEVEL_DOWNSAMPLE_RATIO (8) +//! parameters used to downscale gword maps & scale thresholds to make comparisons easier +#define GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO (2) +#define GWORD_DEFAULT_NB_INIT_SAMPL_PASSES (2) +#define GWORD_DESC_THRES_BITS_MATCH_FACTOR (4) + +// local define used to specify the default frame size (320x240 = QVGA) +#define DEFAULT_FRAME_SIZE cv::Size(320,240) +// local define used to specify the default lword/gword update rate (16 = like vibe) +#define DEFAULT_RESAMPLING_RATE (16) +// local define used to specify the bootstrap window size for faster model stabilization +#define DEFAULT_BOOTSTRAP_WIN_SIZE (500) +// local define for the amount of weight offset to apply to words, making sure new words aren't always better than old ones +#define DEFAULT_LWORD_WEIGHT_OFFSET (DEFAULT_BOOTSTRAP_WIN_SIZE*2) +// local define used to set the default local word occurrence increment +#define DEFAULT_LWORD_OCC_INCR 1 +// local define for the maximum weight a word can achieve before cutting off occ incr (used to make sure model stays good for long-term uses) +#define DEFAULT_LWORD_MAX_WEIGHT (1.0f) +// local define for the initial weight of a new word (used to make sure old words aren't worse off than new seeds) +#define DEFAULT_LWORD_INIT_WEIGHT (1.0f/m_nLocalWordWeightOffset) +// local define used to specify the desc dist threshold offset used for unstable regions +#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) +// local define used to specify the min descriptor bit count for flat regions +#define FLAT_REGION_BIT_COUNT (s_nDescMaxDataRange_1ch/8) + +static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; +static const size_t s_nDescMaxDataRange_1ch = LBSP_::DESC_SIZE * 8; +static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; +static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; + +BackgroundSubtractorPAWCS::BackgroundSubtractorPAWCS(float fRelLBSPThreshold + , size_t nDescDistThresholdOffset + , size_t nMinColorDistThreshold + , size_t nMaxNbWords + , size_t nSamplesForMovingAvgs) + : BackgroundSubtractorLBSP_(fRelLBSPThreshold) + , m_nMinColorDistThreshold(nMinColorDistThreshold) + , m_nDescDistThresholdOffset(nDescDistThresholdOffset) + , m_nMaxLocalWords(nMaxNbWords) + , m_nCurrLocalWords(0) + , m_nMaxGlobalWords(nMaxNbWords / 2) + , m_nCurrGlobalWords(0) + , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) + , m_fLastNonFlatRegionRatio(0.0f) + , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) + , m_nDownSampledROIPxCount(0) + , m_nLocalWordWeightOffset(DEFAULT_LWORD_WEIGHT_OFFSET) + , m_apLocalWordDict(nullptr) + , m_aLocalWordList_1ch(nullptr) + , m_pLocalWordListIter_1ch(nullptr) + , m_aLocalWordList_3ch(nullptr) + , m_pLocalWordListIter_3ch(nullptr) + , m_apGlobalWordDict(nullptr) + , m_aGlobalWordList_1ch(nullptr) + , m_pGlobalWordListIter_1ch(nullptr) + , m_aGlobalWordList_3ch(nullptr) + , m_pGlobalWordListIter_3ch(nullptr) + , m_aPxInfoLUT_PAWCS(nullptr) { + CV_Assert(m_nMaxLocalWords > 0 && m_nMaxGlobalWords > 0); +} + +BackgroundSubtractorPAWCS::~BackgroundSubtractorPAWCS() { + CleanupDictionaries(); +} + +void BackgroundSubtractorPAWCS::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { + // == init + CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); + CV_Assert(oInitImg.isContinuous()); + CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); + if (oInitImg.type() == CV_8UC3) { + std::vector<cv::Mat> voInitImgChannels; + cv::split(oInitImg, voInitImgChannels); + if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) + std::cout << std::endl << "\tBackgroundSubtractorPAWCS : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; + } + cv::Mat oNewBGROI; + if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { + oNewBGROI.create(oInitImg.size(), CV_8UC1); + oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); + } + else if (oROI.empty()) + oNewBGROI = m_oROI; + else { + CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); + CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); + oNewBGROI = oROI.clone(); + cv::Mat oTempROI; + cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP_::PATCH_SIZE / 2); + cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); + } + const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nOrigROIPxCount > 0); + LBSP_::validateROI(oNewBGROI); + const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nFinalROIPxCount > 0); + CleanupDictionaries(); + m_oROI = oNewBGROI; + m_oImgSize = oInitImg.size(); + m_nImgType = oInitImg.type(); + m_nImgChannels = oInitImg.channels(); + m_nTotPxCount = m_oImgSize.area(); + m_nTotRelevantPxCount = nFinalROIPxCount; + m_nFrameIndex = 0; + m_nFramesSinceLastReset = 0; + m_nModelResetCooldown = 0; + m_bUsingMovingCamera = false; + m_oDownSampledFrameSize_MotionAnalysis = cv::Size(m_oImgSize.width / FRAMELEVEL_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_DOWNSAMPLE_RATIO); + m_oDownSampledFrameSize_GlobalWordLookup = cv::Size(m_oImgSize.width / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO, m_oImgSize.height / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO); + cv::resize(m_oROI, m_oDownSampledROI_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + m_fLastNonFlatRegionRatio = 0.0f; + m_nCurrLocalWords = m_nMaxLocalWords; + if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { + const float fRegionSizeScaleFactor = (float)m_nTotPxCount / DEFAULT_FRAME_SIZE.area(); + const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + fRegionSizeScaleFactor) + m_nDefaultMedianBlurKernelSize, m_nDefaultMedianBlurKernelSize + 4); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_nCurrGlobalWords = m_nMaxGlobalWords; + m_oDownSampledROI_MotionAnalysis |= UCHAR_MAX / 2; + } + else { + const float fRegionSizeScaleFactor = (float)nOrigROIPxCount / DEFAULT_FRAME_SIZE.area(); + const int nRawMedianBlurKernelSize = std::min((int)floor(0.5f + m_nDefaultMedianBlurKernelSize*fRegionSizeScaleFactor * 2) + (m_nDefaultMedianBlurKernelSize - 4), m_nDefaultMedianBlurKernelSize); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_nCurrGlobalWords = std::min((size_t)std::pow(m_nMaxGlobalWords*fRegionSizeScaleFactor, 2) + 1, m_nMaxGlobalWords); + } + if (m_nImgChannels == 1) { + m_nCurrLocalWords = std::max(m_nCurrLocalWords / 2, (size_t)1); + m_nCurrGlobalWords = std::max(m_nCurrGlobalWords / 2, (size_t)1); + } + m_nDownSampledROIPxCount = (size_t)cv::countNonZero(m_oDownSampledROI_MotionAnalysis); + m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; + m_oIllumUpdtRegionMask.create(m_oImgSize, CV_8UC1); + m_oIllumUpdtRegionMask = cv::Scalar_<uchar>(0); + m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); + m_oUpdateRateFrame = cv::Scalar(FEEDBACK_T_LOWER); + m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdFrame = cv::Scalar(2.0f); + m_oDistThresholdVariationFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdVariationFrame = cv::Scalar(FEEDBACK_V_INCR * 10); + m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); + m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize_MotionAnalysis, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); + m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); + m_oUnstableRegionMask = cv::Scalar_<uchar>(0); + m_oBlinksFrame.create(m_oImgSize, CV_8UC1); + m_oBlinksFrame = cv::Scalar_<uchar>(0); + m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize_MotionAnalysis, CV_8UC((int)m_nImgChannels)); + m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); + m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_oLastColorFrame = cv::Scalar_<uchar>::all(0); + m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_oLastDescFrame = cv::Scalar_<ushort>::all(0); + m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask.create(m_oImgSize, CV_8UC1); + m_oLastFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); + m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); + m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); + m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); + m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); + m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oTempGlobalWordWeightDiffFactor.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + m_oTempGlobalWordWeightDiffFactor = cv::Scalar(-0.1f); + m_oMorphExStructElement = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); + m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; + memset(m_aPxIdxLUT, 0, sizeof(size_t)*m_nTotRelevantPxCount); + m_aPxInfoLUT_PAWCS = new PxInfo_PAWCS[m_nTotPxCount]; + memset(m_aPxInfoLUT_PAWCS, 0, sizeof(PxInfo_PAWCS)*m_nTotPxCount); + m_aPxInfoLUT = m_aPxInfoLUT_PAWCS; + m_apLocalWordDict = new LocalWordBase*[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_apLocalWordDict, 0, sizeof(LocalWordBase*)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_apGlobalWordDict = new GlobalWordBase*[m_nCurrGlobalWords]; + memset(m_apGlobalWordDict, 0, sizeof(GlobalWordBase*)*m_nCurrGlobalWords); + if (m_nImgChannels == 1) { + CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); + CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + m_aLocalWordList_1ch = new LocalWord_1ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_aLocalWordList_1ch, 0, sizeof(LocalWord_1ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_pLocalWordListIter_1ch = m_aLocalWordList_1ch; + m_aGlobalWordList_1ch = new GlobalWord_1ch[m_nCurrGlobalWords]; + m_pGlobalWordListIter_1ch = m_aGlobalWordList_1ch; + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; + m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; + for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_1ch[nGlobalWordIdxIter]); + m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; + const size_t nDescIter = nPxIter * 2; + LBSP_::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); + ++nModelIter; + } + } + } + else { //m_nImgChannels==3 + CV_DbgAssert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); + CV_DbgAssert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + m_aLocalWordList_3ch = new LocalWord_3ch[m_nTotRelevantPxCount*m_nCurrLocalWords]; + memset(m_aLocalWordList_3ch, 0, sizeof(LocalWord_3ch)*m_nTotRelevantPxCount*m_nCurrLocalWords); + m_pLocalWordListIter_3ch = m_aLocalWordList_3ch; + m_aGlobalWordList_3ch = new GlobalWord_3ch[m_nCurrGlobalWords]; + m_pGlobalWordListIter_3ch = m_aGlobalWordList_3ch; + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT_PAWCS[nPxIter].nModelIdx = nModelIter; + m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx = (size_t)((m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)*m_oDownSampledFrameSize_GlobalWordLookup.width + (m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X / GWORD_LOOKUP_MAPS_DOWNSAMPLE_RATIO)) * 4; + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT = new GlobalWordBase*[m_nCurrGlobalWords]; + for (size_t nGlobalWordIdxIter = 0; nGlobalWordIdxIter < m_nCurrGlobalWords; ++nGlobalWordIdxIter) + m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordIdxIter] = &(m_aGlobalWordList_3ch[nGlobalWordIdxIter]); + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + for (size_t c = 0; c < 3; ++c) { + m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; + LBSP_::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); + } + ++nModelIter; + } + } + } + m_bInitialized = true; + refreshModel(1, 0); +} + +void BackgroundSubtractorPAWCS::refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate) { + // == refresh + CV_Assert(m_bInitialized); + CV_Assert(fOccDecrFrac >= 0.0f && fOccDecrFrac <= 1.0f); + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + // == refresh: local decr + if (fOccDecrFrac > 0.0f) { + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord) + pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); + } + } + const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; + const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; + for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { + // == refresh: local resampling + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { + const uchar nSampleColor = m_oLastColorFrame.data[nSamplePxIdx]; + const size_t nSampleDescIdx = nSamplePxIdx * 2; + const ushort nSampleIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); + bool bFoundUninitd = false; + size_t nLocalWordIdx; + for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord + && L1dist(nSampleColor, pCurrLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold + && hdist(nSampleIntraDesc, pCurrLocalWord->oFeature.anDesc[0]) <= nCurrDescDistThreshold) { + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + break; + } + else if (!pCurrLocalWord) + bFoundUninitd = true; + } + if (nLocalWordIdx == m_nCurrLocalWords) { + nLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_1ch++ : (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + pCurrLocalWord->oFeature.anColor[0] = nSampleColor; + pCurrLocalWord->oFeature.anDesc[0] = nSampleIntraDesc; + pCurrLocalWord->nOccurrences = nBaseOccCount; + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + --nLocalWordIdx; + } + } + } + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + // == refresh: local random resampling + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (!pCurrLocalWord) { + const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); + const LocalWord_1ch* pRefLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; + const int nRandColorOffset = (rand() % (nCurrColorDistThreshold + 1)) - (int)nCurrColorDistThreshold / 2; + pCurrLocalWord = m_pLocalWordListIter_1ch++; + pCurrLocalWord->oFeature.anColor[0] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[0] + nRandColorOffset); + pCurrLocalWord->oFeature.anDesc[0] = pRefLocalWord->oFeature.anDesc[0]; + pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + } + } + } + CV_Assert(m_aLocalWordList_1ch == (m_pLocalWordListIter_1ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); + cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); + size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); + for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: global resampling + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + const LocalWord_1ch* pRefBestLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx]; + const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + const uchar nRefBestLocalWordDescBITS = (uchar)popcount(pRefBestLocalWord->oFeature.anDesc[0]); + bool bFoundUninitd = false; + size_t nGlobalWordIdx; + for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (pCurrGlobalWord + && L1dist(pCurrGlobalWord->oFeature.anColor[0], pRefBestLocalWord->oFeature.anColor[0]) <= nCurrColorDistThreshold + && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + else if (!pCurrGlobalWord) + bFoundUninitd = true; + } + if (nGlobalWordIdx == m_nCurrGlobalWords) { + nGlobalWordIdx = m_nCurrGlobalWords - 1; + GlobalWord_1ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_1ch++ : (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + pCurrGlobalWord->oFeature.anColor[0] = pRefBestLocalWord->oFeature.anColor[0]; + pCurrGlobalWord->oFeature.anDesc[0] = pRefBestLocalWord->oFeature.anDesc[0]; + pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; + fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; + } + oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; + while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + --nGlobalWordIdx; + } + } + } + } + nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); + } + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_1ch* pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (!pCurrGlobalWord) { + pCurrGlobalWord = m_pGlobalWordListIter_1ch++; + pCurrGlobalWord->oFeature.anColor[0] = 0; + pCurrGlobalWord->oFeature.anDesc[0] = 0; + pCurrGlobalWord->nDescBITS = 0; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + } + CV_Assert((size_t)(m_pGlobalWordListIter_1ch - m_aGlobalWordList_1ch) == m_nCurrGlobalWords && m_aGlobalWordList_1ch == (m_pGlobalWordListIter_1ch - m_nCurrGlobalWords)); + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + // == refresh: local decr + if (fOccDecrFrac > 0.0f) { + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord) + pCurrLocalWord->nOccurrences -= (size_t)(fOccDecrFrac*pCurrLocalWord->nOccurrences); + } + } + const size_t nCurrWordOccIncr = DEFAULT_LWORD_OCC_INCR; + const size_t nTotLocalSamplingIterCount = (s_nSamplesInitPatternWidth*s_nSamplesInitPatternHeight) * 2; + for (size_t nLocalSamplingIter = 0; nLocalSamplingIter < nTotLocalSamplingIterCount; ++nLocalSamplingIter) { + // == refresh: local resampling + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X, m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nSamplePxIdx]) { + const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; + const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; + const uchar* const anSampleColor = m_oLastColorFrame.data + nSamplePxRGBIdx; + const ushort* const anSampleIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); + bool bFoundUninitd = false; + size_t nLocalWordIdx; + for (nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (pCurrLocalWord + && cmixdist<3>(anSampleColor, pCurrLocalWord->oFeature.anColor) <= nCurrTotColorDistThreshold + && hdist<3>(anSampleIntraDesc, pCurrLocalWord->oFeature.anDesc) <= nCurrTotDescDistThreshold) { + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + break; + } + else if (!pCurrLocalWord) + bFoundUninitd = true; + } + if (nLocalWordIdx == m_nCurrLocalWords) { + nLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pCurrLocalWord = bFoundUninitd ? m_pLocalWordListIter_3ch++ : (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = anSampleColor[c]; + pCurrLocalWord->oFeature.anDesc[c] = anSampleIntraDesc[c]; + } + pCurrLocalWord->nOccurrences = nBaseOccCount; + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + while (nLocalWordIdx > 0 && (!m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1] || GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset) > GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1], m_nFrameIndex, m_nLocalWordWeightOffset))) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + --nLocalWordIdx; + } + } + } + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + for (size_t nLocalWordIdx = 1; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + // == refresh: local random resampling + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + if (!pCurrLocalWord) { + const size_t nRandLocalWordIdx = (rand() % nLocalWordIdx); + const LocalWord_3ch* pRefLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nRandLocalWordIdx]; + const int nRandColorOffset = (rand() % (nCurrTotColorDistThreshold / 3 + 1)) - (int)(nCurrTotColorDistThreshold / 6); + pCurrLocalWord = m_pLocalWordListIter_3ch++; + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = cv::saturate_cast<uchar>((int)pRefLocalWord->oFeature.anColor[c] + nRandColorOffset); + pCurrLocalWord->oFeature.anDesc[c] = pRefLocalWord->oFeature.anDesc[c]; + } + pCurrLocalWord->nOccurrences = std::max((size_t)(pRefLocalWord->nOccurrences*((float)(m_nCurrLocalWords - nLocalWordIdx) / m_nCurrLocalWords)), (size_t)1); + pCurrLocalWord->nFirstOcc = m_nFrameIndex; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx] = pCurrLocalWord; + } + } + } + } + CV_Assert(m_aLocalWordList_3ch == (m_pLocalWordListIter_3ch - m_nTotRelevantPxCount*m_nCurrLocalWords)); + cv::Mat oGlobalDictPresenceLookupMap(m_oImgSize, CV_8UC1, cv::Scalar_<uchar>(0)); + size_t nPxIterIncr = std::max(m_nTotPxCount / m_nCurrGlobalWords, (size_t)1); + for (size_t nSamplingPasses = 0; nSamplingPasses < GWORD_DEFAULT_NB_INIT_SAMPL_PASSES; ++nSamplingPasses) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: global resampling + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if ((nPxIter%nPxIterIncr) == 0) { // <=(m_nCurrGlobalWords) gwords from (m_nCurrGlobalWords) equally spaced pixels + if (bForceFGUpdate || !m_oLastFGMask_dilated.data[nPxIter]) { + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const size_t nFloatIter = nPxIter * 4; + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + const float fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + CV_Assert(m_apLocalWordDict[nLocalDictIdx]); + const LocalWord_3ch* pRefBestLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx]; + const float fRefBestLocalWordWeight = GetLocalWordWeight(pRefBestLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + const uchar nRefBestLocalWordDescBITS = (uchar)popcount<3>(pRefBestLocalWord->oFeature.anDesc); + bool bFoundUninitd = false; + size_t nGlobalWordIdx; + for (nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (pCurrGlobalWord + && L1dist(nRefBestLocalWordDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(pRefBestLocalWord->oFeature.anColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + else if (!pCurrGlobalWord) + bFoundUninitd = true; + } + if (nGlobalWordIdx == m_nCurrGlobalWords) { + nGlobalWordIdx = m_nCurrGlobalWords - 1; + GlobalWord_3ch* pCurrGlobalWord = bFoundUninitd ? m_pGlobalWordListIter_3ch++ : (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = pRefBestLocalWord->oFeature.anColor[c]; + pCurrGlobalWord->oFeature.anDesc[c] = pRefBestLocalWord->oFeature.anDesc[c]; + } + pCurrGlobalWord->nDescBITS = nRefBestLocalWordDescBITS; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + float& fCurrGlobalWordLocalWeight = *(float*)(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fRefBestLocalWordWeight) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight += fRefBestLocalWordWeight; + fCurrGlobalWordLocalWeight += fRefBestLocalWordWeight; + } + oGlobalDictPresenceLookupMap.data[nPxIter] = UCHAR_MAX; + while (nGlobalWordIdx > 0 && (!m_apGlobalWordDict[nGlobalWordIdx - 1] || m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight)) { + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + --nGlobalWordIdx; + } + } + } + } + nPxIterIncr = std::max(nPxIterIncr / 3, (size_t)1); + } + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + GlobalWord_3ch* pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[nGlobalWordIdx]; + if (!pCurrGlobalWord) { + pCurrGlobalWord = m_pGlobalWordListIter_3ch++; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = 0; + pCurrGlobalWord->oFeature.anDesc[c] = 0; + } + pCurrGlobalWord->nDescBITS = 0; + pCurrGlobalWord->oSpatioOccMap.create(m_oDownSampledFrameSize_GlobalWordLookup, CV_32FC1); + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx] = pCurrGlobalWord; + } + } + CV_Assert((size_t)(m_pGlobalWordListIter_3ch - m_aGlobalWordList_3ch) == m_nCurrGlobalWords && m_aGlobalWordList_3ch == (m_pGlobalWordListIter_3ch - m_nCurrGlobalWords)); + } + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + // == refresh: per-px global word sort + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) + std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); + else + fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; + } + } +} + +void BackgroundSubtractorPAWCS::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { + // == process + CV_Assert(m_bInitialized); + cv::Mat oInputImg = _image.getMat(); + CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); + CV_Assert(oInputImg.isContinuous()); + _fgmask.create(m_oImgSize, CV_8UC1); + cv::Mat oCurrFGMask = _fgmask.getMat(); + memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); + const bool bBootstrapping = ++m_nFrameIndex <= DEFAULT_BOOTSTRAP_WIN_SIZE; + const size_t nCurrSamplesForMovingAvg_LT = bBootstrapping ? m_nSamplesForMovingAvgs / 2 : m_nSamplesForMovingAvgs; + const size_t nCurrSamplesForMovingAvg_ST = nCurrSamplesForMovingAvg_LT / 4; + const float fRollAvgFactor_LT = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_LT); + const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, nCurrSamplesForMovingAvg_ST); + const size_t nCurrGlobalWordUpdateRate = bBootstrapping ? DEFAULT_RESAMPLING_RATE / 2 : DEFAULT_RESAMPLING_RATE; + size_t nFlatRegionCount = 0; + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nDescIter = nPxIter * 2; + const size_t nFloatIter = nPxIter * 4; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const uchar nCurrColor = oInputImg.data[nPxIter]; + uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; + ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); + size_t nMinColorDist = s_nColorMaxDataRange_1ch; + size_t nMinDescDist = s_nDescMaxDataRange_1ch; + float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); + float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); + float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); + float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); + float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); + float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); + const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; + uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; + const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + ushort nCurrInterDesc, nCurrIntraDesc; + LBSP_::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); + const uchar nCurrIntraDescBITS = (uchar)popcount(nCurrIntraDesc); + const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT; + if (bCurrRegionIsFlat) + ++nFlatRegionCount; + const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); + const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); + const size_t nCurrColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET); + size_t nLocalWordIdx = 0; + float fPotentialLocalWordsWeightSum = 0.0f; + float fLastLocalWordWeight = FLT_MAX; + while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + { + const size_t nColorDist = L1dist(nCurrColor, pCurrLocalWord->oFeature.anColor[0]); + const size_t nIntraDescDist = hdist(nCurrIntraDesc, pCurrLocalWord->oFeature.anDesc[0]); + LBSP_::computeGrayscaleDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor[0], nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]], nCurrInterDesc); + const size_t nInterDescDist = hdist(nCurrInterDesc, pCurrLocalWord->oFeature.anDesc[0]); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) + && nColorDist <= nCurrColorDistThreshold + && nColorDist >= nCurrColorDistThreshold / 2 + && nIntraDescDist <= nCurrDescDistThreshold / 2 + && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { + // == illum updt + pCurrLocalWord->oFeature.anColor[0] = nCurrColor; + pCurrLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; + m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; + m_oIllumUpdtRegionMask.data[nPxIter] = 2; + } + if (nDescDist <= nCurrDescDistThreshold && nColorDist <= nCurrColorDistThreshold) { + fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + nMinColorDist = std::min(nMinColorDist, nColorDist); + nMinDescDist = std::min(nMinDescDist, nDescDist); + } + } + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + while (nLocalWordIdx < m_nCurrLocalWords) { + const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { + // == background + const float fNormalizedMinDist = std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); + if ((rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_1ch* pCurrGlobalWord = nullptr; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold + && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + } + if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { + pCurrGlobalWord = (GlobalWord_1ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; + pCurrGlobalWord->oFeature.anColor[0] = nCurrColor; + pCurrGlobalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + } + float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { + pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; + fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; + } + } + } + } + else { + // == foreground + const float fNormalizedMinDist = std::max(std::max((float)nMinColorDist / s_nColorMaxDataRange_1ch, (float)nMinDescDist / s_nDescMaxDataRange_1ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_1ch* pCurrGlobalWord; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_1ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(pCurrGlobalWord->oFeature.anColor[0], nCurrColor) <= nCurrColorDistThreshold + && L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR) + break; + } + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) + nCurrRegionSegmVal = UCHAR_MAX; + else { + const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) + nCurrRegionSegmVal = UCHAR_MAX; + } + } + else + nCurrRegionSegmVal = UCHAR_MAX; + if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pNewLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; + pNewLocalWord->oFeature.anColor[0] = nCurrColor; + pNewLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pNewLocalWord->nOccurrences = nCurrWordOccIncr; + pNewLocalWord->nFirstOcc = m_nFrameIndex; + pNewLocalWord->nLastOcc = m_nFrameIndex; + } + } + // == neighb updt + if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { + //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (m_oROI.data[nSamplePxIdx]) { + const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; + size_t nNeighborLocalWordIdx = 0; + float fNeighborPotentialLocalWordsWeightSum = 0.0f; + while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + const size_t nNeighborColorDist = L1dist(nCurrColor, pNeighborLocalWord->oFeature.anColor[0]); + const size_t nNeighborIntraDescDist = hdist(nCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc[0]); + const bool bNeighborRegionIsFlat = popcount(pNeighborLocalWord->oFeature.anDesc[0]) < FLAT_REGION_BIT_COUNT; + const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; + if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborIntraDescDist <= nCurrDescDistThreshold) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + } + else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { + const size_t nSampleDescIdx = nSamplePxIdx * 2; + ushort& nNeighborLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nSampleDescIdx)); + const size_t nNeighborLastIntraDescDist = hdist(nCurrIntraDesc, nNeighborLastIntraDesc); + if (nNeighborColorDist <= nCurrColorDistThreshold && nNeighborLastIntraDescDist <= nCurrDescDistThreshold / 2) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + } + } + ++nNeighborLocalWordIdx; + } + if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + nNeighborLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_1ch* pNeighborLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + pNeighborLocalWord->oFeature.anColor[0] = nCurrColor; + pNeighborLocalWord->oFeature.anDesc[0] = nCurrIntraDesc; + pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; + pNeighborLocalWord->nFirstOcc = m_nFrameIndex; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + } + } + } + if (nCurrRegionIllumUpdtVal) + nCurrRegionIllumUpdtVal -= 1; + // == feedback adj + bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; + if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) + fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); + else + fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); + if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; + else + fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); + if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) + fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); + else + fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); + nLastIntraDesc = nCurrIntraDesc; + nLastColor = nCurrColor; + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + const size_t nFloatIter = nPxIter * 4; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + const uchar* const anCurrColor = oInputImg.data + nPxRGBIter; + uchar* anLastColor = m_oLastColorFrame.data + nPxRGBIter; + ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescRGBIter)); + size_t nMinTotColorDist = s_nColorMaxDataRange_3ch; + size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; + float& fCurrMeanRawSegmRes_LT = *(float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanRawSegmRes_ST = *(float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter); + float& fCurrMeanFinalSegmRes_LT = *(float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter); + float& fCurrMeanFinalSegmRes_ST = *(float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter); + float& fCurrDistThresholdFactor = *(float*)(m_oDistThresholdFrame.data + nFloatIter); + float& fCurrDistThresholdVariationFactor = *(float*)(m_oDistThresholdVariationFrame.data + nFloatIter); + float& fCurrLearningRate = *(float*)(m_oUpdateRateFrame.data + nFloatIter); + float& fCurrMeanMinDist_LT = *(float*)(m_oMeanMinDistFrame_LT.data + nFloatIter); + float& fCurrMeanMinDist_ST = *(float*)(m_oMeanMinDistFrame_ST.data + nFloatIter); + const float fBestLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + const float fLocalWordsWeightSumThreshold = fBestLocalWordWeight / (fCurrDistThresholdFactor * 2); + uchar& bCurrRegionIsUnstable = m_oUnstableRegionMask.data[nPxIter]; + uchar& nCurrRegionIllumUpdtVal = m_oIllumUpdtRegionMask.data[nPxIter]; + uchar& nCurrRegionSegmVal = oCurrFGMask.data[nPxIter]; + const bool bCurrRegionIsROIBorder = m_oROI.data[nPxIter] < UCHAR_MAX; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + ushort anCurrInterDesc[3], anCurrIntraDesc[3]; + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP_::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); + const uchar nCurrIntraDescBITS = (uchar)popcount<3>(anCurrIntraDesc); + const bool bCurrRegionIsFlat = nCurrIntraDescBITS < FLAT_REGION_BIT_COUNT * 2; + if (bCurrRegionIsFlat) + ++nFlatRegionCount; + const size_t nCurrWordOccIncr = (DEFAULT_LWORD_OCC_INCR + m_nModelResetCooldown) << int(bCurrRegionIsFlat || bBootstrapping); + const size_t nCurrLocalWordUpdateRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : bCurrRegionIsFlat ? (size_t)ceil(fCurrLearningRate + FEEDBACK_T_LOWER) / 2 : (size_t)ceil(fCurrLearningRate); + const size_t nCurrTotColorDistThreshold = (size_t)(sqrt(fCurrDistThresholdFactor)*m_nMinColorDistThreshold) * 3; + const size_t nCurrTotDescDistThreshold = (((size_t)1 << ((size_t)floor(fCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (bCurrRegionIsUnstable*UNSTAB_DESC_DIST_OFFSET)) * 3; + size_t nLocalWordIdx = 0; + float fPotentialLocalWordsWeightSum = 0.0f; + float fLastLocalWordWeight = FLT_MAX; + while (nLocalWordIdx < m_nCurrLocalWords && fPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + const float fCurrLocalWordWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + { + const size_t nTotColorL1Dist = L1dist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); + const size_t nColorDistortion = cdist<3>(anCurrColor, pCurrLocalWord->oFeature.anColor); + const size_t nTotColorMixDist = cmixdist(nTotColorL1Dist, nColorDistortion); + const size_t nTotIntraDescDist = hdist<3>(anCurrIntraDesc, pCurrLocalWord->oFeature.anDesc); + const size_t anCurrInterLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[0]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[1]],m_anLBSPThreshold_8bitLUT[pCurrLocalWord->oFeature.anColor[2]] }; + LBSP_::computeRGBDescriptor(oInputImg, pCurrLocalWord->oFeature.anColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrInterLBSPThresholds, anCurrInterDesc); + const size_t nTotInterDescDist = hdist<3>(anCurrInterDesc, pCurrLocalWord->oFeature.anDesc); + const size_t nTotDescDist = (nTotIntraDescDist + nTotInterDescDist) / 2; + if ((!bCurrRegionIsUnstable || bCurrRegionIsFlat || bCurrRegionIsROIBorder) + && nTotColorMixDist <= nCurrTotColorDistThreshold + && nTotColorL1Dist >= nCurrTotColorDistThreshold / 2 + && nTotIntraDescDist <= nCurrTotDescDistThreshold / 2 + && (rand() % (nCurrRegionIllumUpdtVal ? (nCurrLocalWordUpdateRate / 2 + 1) : nCurrLocalWordUpdateRate)) == 0) { + // == illum updt + for (size_t c = 0; c < 3; ++c) { + pCurrLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pCurrLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + m_oIllumUpdtRegionMask.data[nPxIter - 1] = 1 & m_oROI.data[nPxIter - 1]; + m_oIllumUpdtRegionMask.data[nPxIter + 1] = 1 & m_oROI.data[nPxIter + 1]; + m_oIllumUpdtRegionMask.data[nPxIter] = 2; + } + if (nTotDescDist <= nCurrTotDescDistThreshold && nTotColorMixDist <= nCurrTotColorDistThreshold) { + fPotentialLocalWordsWeightSum += fCurrLocalWordWeight; + pCurrLocalWord->nLastOcc = m_nFrameIndex; + if ((!m_oLastFGMask.data[nPxIter] || m_bUsingMovingCamera) && fCurrLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pCurrLocalWord->nOccurrences += nCurrWordOccIncr; + nMinTotColorDist = std::min(nMinTotColorDist, nTotColorMixDist); + nMinTotDescDist = std::min(nMinTotDescDist, nTotDescDist); + } + } + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + while (nLocalWordIdx < m_nCurrLocalWords) { + const float fCurrLocalWordWeight = GetLocalWordWeight(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_nFrameIndex, m_nLocalWordWeightOffset); + if (fCurrLocalWordWeight > fLastLocalWordWeight) { + std::swap(m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx], m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx - 1]); + } + else + fLastLocalWordWeight = fCurrLocalWordWeight; + ++nLocalWordIdx; + } + if (fPotentialLocalWordsWeightSum >= fLocalWordsWeightSumThreshold || bCurrRegionIsROIBorder) { + // == background + const float fNormalizedMinDist = std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT); + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST); + if ((rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_3ch* pCurrGlobalWord = nullptr; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + } + if (nGlobalWordLUTIdx != m_nCurrGlobalWords || (rand() % (nCurrLocalWordUpdateRate * 2)) == 0) { + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) { + pCurrGlobalWord = (GlobalWord_3ch*)m_apGlobalWordDict[m_nCurrGlobalWords - 1]; + for (size_t c = 0; c < 3; ++c) { + pCurrGlobalWord->oFeature.anColor[c] = anCurrColor[c]; + pCurrGlobalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pCurrGlobalWord->nDescBITS = nCurrIntraDescBITS; + pCurrGlobalWord->oSpatioOccMap = cv::Scalar(0.0f); + pCurrGlobalWord->fLatestWeight = 0.0f; + } + float& fCurrGlobalWordLocalWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight < fPotentialLocalWordsWeightSum) { + pCurrGlobalWord->fLatestWeight += fPotentialLocalWordsWeightSum; + fCurrGlobalWordLocalWeight += fPotentialLocalWordsWeightSum; + } + } + } + } + else { + // == foreground + const float fNormalizedMinDist = std::max(std::max((float)nMinTotColorDist / s_nColorMaxDataRange_3ch, (float)nMinTotDescDist / s_nDescMaxDataRange_3ch), (fLocalWordsWeightSumThreshold - fPotentialLocalWordsWeightSum) / fLocalWordsWeightSumThreshold); + fCurrMeanMinDist_LT = fCurrMeanMinDist_LT*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + fCurrMeanMinDist_ST = fCurrMeanMinDist_ST*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + fCurrMeanRawSegmRes_LT = fCurrMeanRawSegmRes_LT*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + fCurrMeanRawSegmRes_ST = fCurrMeanRawSegmRes_ST*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + if (bCurrRegionIsFlat || (rand() % nCurrLocalWordUpdateRate) == 0) { + size_t nGlobalWordLUTIdx; + GlobalWord_3ch* pCurrGlobalWord; + for (nGlobalWordLUTIdx = 0; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + pCurrGlobalWord = (GlobalWord_3ch*)m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]; + if (L1dist(nCurrIntraDescBITS, pCurrGlobalWord->nDescBITS) <= nCurrTotDescDistThreshold / GWORD_DESC_THRES_BITS_MATCH_FACTOR + && cmixdist<3>(anCurrColor, pCurrGlobalWord->oFeature.anColor) <= nCurrTotColorDistThreshold) + break; + } + if (nGlobalWordLUTIdx == m_nCurrGlobalWords) + nCurrRegionSegmVal = UCHAR_MAX; + else { + const float fGlobalWordLocalizedWeight = *(float*)(pCurrGlobalWord->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fPotentialLocalWordsWeightSum + fGlobalWordLocalizedWeight / (bCurrRegionIsFlat ? 2 : 4) < fLocalWordsWeightSumThreshold) + nCurrRegionSegmVal = UCHAR_MAX; + } + } + else + nCurrRegionSegmVal = UCHAR_MAX; + if (fPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + const size_t nNewLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pNewLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nNewLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pNewLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pNewLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pNewLocalWord->nOccurrences = nCurrWordOccIncr; + pNewLocalWord->nFirstOcc = m_nFrameIndex; + pNewLocalWord->nLastOcc = m_nFrameIndex; + } + } + // == neighb updt + if ((!nCurrRegionSegmVal && (rand() % nCurrLocalWordUpdateRate) == 0) || bCurrRegionIsROIBorder || m_bUsingMovingCamera) { + //if((!nCurrRegionSegmVal && (rand()%(nCurrRegionIllumUpdtVal?(nCurrLocalWordUpdateRate/2+1):nCurrLocalWordUpdateRate))==0) || bCurrRegionIsROIBorder) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + if (bCurrRegionIsFlat || bCurrRegionIsROIBorder || m_bUsingMovingCamera) + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP_::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (m_oROI.data[nSamplePxIdx]) { + const size_t nNeighborLocalDictIdx = m_aPxInfoLUT_PAWCS[nSamplePxIdx].nModelIdx*m_nCurrLocalWords; + size_t nNeighborLocalWordIdx = 0; + float fNeighborPotentialLocalWordsWeightSum = 0.0f; + while (nNeighborLocalWordIdx < m_nCurrLocalWords && fNeighborPotentialLocalWordsWeightSum < fLocalWordsWeightSumThreshold) { + LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + const size_t nNeighborTotColorL1Dist = L1dist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); + const size_t nNeighborColorDistortion = cdist<3>(anCurrColor, pNeighborLocalWord->oFeature.anColor); + const size_t nNeighborTotColorMixDist = cmixdist(nNeighborTotColorL1Dist, nNeighborColorDistortion); + const size_t nNeighborTotIntraDescDist = hdist<3>(anCurrIntraDesc, pNeighborLocalWord->oFeature.anDesc); + const bool bNeighborRegionIsFlat = popcount<3>(pNeighborLocalWord->oFeature.anDesc) < FLAT_REGION_BIT_COUNT * 2; + const size_t nNeighborWordOccIncr = bNeighborRegionIsFlat ? nCurrWordOccIncr * 2 : nCurrWordOccIncr; + if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + } + else if (!oCurrFGMask.data[nSamplePxIdx] && bCurrRegionIsFlat && (bBootstrapping || (rand() % nCurrLocalWordUpdateRate) == 0)) { + const size_t nSamplePxRGBIdx = nSamplePxIdx * 3; + const size_t nSampleDescRGBIdx = nSamplePxRGBIdx * 2; + ushort* anNeighborLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nSampleDescRGBIdx)); + const size_t nNeighborTotLastIntraDescDist = hdist<3>(anCurrIntraDesc, anNeighborLastIntraDesc); + if (nNeighborTotColorMixDist <= nCurrTotColorDistThreshold && nNeighborTotLastIntraDescDist <= nCurrTotDescDistThreshold / 2) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + for (size_t c = 0; c < 3; ++c) + pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + else { + const bool bNeighborLastRegionIsFlat = popcount<3>(anNeighborLastIntraDesc) < FLAT_REGION_BIT_COUNT * 2; + if (bNeighborLastRegionIsFlat && bCurrRegionIsFlat && + nNeighborTotLastIntraDescDist + nNeighborTotIntraDescDist <= nCurrTotDescDistThreshold && + nNeighborColorDistortion <= nCurrTotColorDistThreshold / 4) { + const float fNeighborLocalWordWeight = GetLocalWordWeight(pNeighborLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fNeighborPotentialLocalWordsWeightSum += fNeighborLocalWordWeight; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + if (fNeighborLocalWordWeight < DEFAULT_LWORD_MAX_WEIGHT) + pNeighborLocalWord->nOccurrences += nNeighborWordOccIncr; + for (size_t c = 0; c < 3; ++c) + pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; + } + } + } + ++nNeighborLocalWordIdx; + } + if (fNeighborPotentialLocalWordsWeightSum < DEFAULT_LWORD_INIT_WEIGHT) { + nNeighborLocalWordIdx = m_nCurrLocalWords - 1; + LocalWord_3ch* pNeighborLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nNeighborLocalDictIdx + nNeighborLocalWordIdx]; + for (size_t c = 0; c < 3; ++c) { + pNeighborLocalWord->oFeature.anColor[c] = anCurrColor[c]; + pNeighborLocalWord->oFeature.anDesc[c] = anCurrIntraDesc[c]; + } + pNeighborLocalWord->nOccurrences = nCurrWordOccIncr; + pNeighborLocalWord->nFirstOcc = m_nFrameIndex; + pNeighborLocalWord->nLastOcc = m_nFrameIndex; + } + } + } + if (nCurrRegionIllumUpdtVal) + nCurrRegionIllumUpdtVal -= 1; + // == feedback adj + bCurrRegionIsUnstable = fCurrDistThresholdFactor > UNSTABLE_REG_RDIST_MIN || (fCurrMeanRawSegmRes_LT - fCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (fCurrMeanRawSegmRes_ST - fCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN; + if (m_oLastFGMask.data[nPxIter] || (std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && nCurrRegionSegmVal)) + fCurrLearningRate = std::min(fCurrLearningRate + FEEDBACK_T_INCR / (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST)*fCurrDistThresholdVariationFactor), FEEDBACK_T_UPPER); + else + fCurrLearningRate = std::max(fCurrLearningRate - FEEDBACK_T_DECR*fCurrDistThresholdVariationFactor / std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST), FEEDBACK_T_LOWER); + if (std::max(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (fCurrDistThresholdVariationFactor) += bBootstrapping ? FEEDBACK_V_INCR * 2 : FEEDBACK_V_INCR; + else + fCurrDistThresholdVariationFactor = std::max(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR*((bBootstrapping || bCurrRegionIsFlat) ? 2 : m_oLastFGMask.data[nPxIter] ? 0.5f : 1), FEEDBACK_V_DECR); + if (fCurrDistThresholdFactor < std::pow(1.0f + std::min(fCurrMeanMinDist_LT, fCurrMeanMinDist_ST) * 2, 2)) + fCurrDistThresholdFactor += FEEDBACK_R_VAR*(fCurrDistThresholdVariationFactor - FEEDBACK_V_DECR); + else + fCurrDistThresholdFactor = std::max(fCurrDistThresholdFactor - FEEDBACK_R_VAR / fCurrDistThresholdVariationFactor, 1.0f); + for (size_t c = 0; c < 3; ++c) { + anLastIntraDesc[c] = anCurrIntraDesc[c]; + anLastColor[c] = anCurrColor[c]; + } + } + } + const bool bRecalcGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate << 5)); + const bool bUpdateGlobalWords = !(m_nFrameIndex % (nCurrGlobalWordUpdateRate)); + cv::Mat oLastFGMask_dilated_inverted_downscaled; + if (bUpdateGlobalWords) + cv::resize(m_oLastFGMask_dilated_inverted, oLastFGMask_dilated_inverted_downscaled, m_oDownSampledFrameSize_GlobalWordLookup, 0, 0, cv::INTER_NEAREST); + for (size_t nGlobalWordIdx = 0; nGlobalWordIdx < m_nCurrGlobalWords; ++nGlobalWordIdx) { + if (bRecalcGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = GetGlobalWordWeight(m_apGlobalWordDict[nGlobalWordIdx]); + if (m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight < 1.0f) { + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight = 0.0f; + m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap = cv::Scalar(0.0f); + } + } + if (bUpdateGlobalWords && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > 0.0f) { + cv::accumulateProduct(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_oTempGlobalWordWeightDiffFactor, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, oLastFGMask_dilated_inverted_downscaled); + m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight *= 0.9f; + cv::blur(m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, m_apGlobalWordDict[nGlobalWordIdx]->oSpatioOccMap, cv::Size(3, 3), cv::Point(-1, -1), cv::BORDER_REPLICATE); + } + if (nGlobalWordIdx > 0 && m_apGlobalWordDict[nGlobalWordIdx]->fLatestWeight > m_apGlobalWordDict[nGlobalWordIdx - 1]->fLatestWeight) + std::swap(m_apGlobalWordDict[nGlobalWordIdx], m_apGlobalWordDict[nGlobalWordIdx - 1]); + } + if (bUpdateGlobalWords) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nGlobalWordMapLookupIdx = m_aPxInfoLUT_PAWCS[nPxIter].nGlobalWordMapLookupIdx; + float fLastGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[0]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + for (size_t nGlobalWordLUTIdx = 1; nGlobalWordLUTIdx < m_nCurrGlobalWords; ++nGlobalWordLUTIdx) { + const float fCurrGlobalWordLocalWeight = *(float*)(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx]->oSpatioOccMap.data + nGlobalWordMapLookupIdx); + if (fCurrGlobalWordLocalWeight > fLastGlobalWordLocalWeight) + std::swap(m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx], m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT[nGlobalWordLUTIdx - 1]); + else + fLastGlobalWordLocalWeight = fCurrGlobalWordLocalWeight; + } + } + } + cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); + cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); + m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); + oCurrFGMask.copyTo(m_oLastRawFGMask); + cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, m_oMorphExStructElement); + m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); + cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); + cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); + cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); + cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); + cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); + cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + m_oLastFGMask.copyTo(oCurrFGMask); + cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); + cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); + const float fCurrNonFlatRegionRatio = (float)(m_nTotRelevantPxCount - nFlatRegionCount) / m_nTotRelevantPxCount; + if (fCurrNonFlatRegionRatio < LBSPDESC_RATIO_MIN && m_fLastNonFlatRegionRatio < LBSPDESC_RATIO_MIN) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 4)) + --m_anLBSPThreshold_8bitLUT[t]; + } + else if (fCurrNonFlatRegionRatio > LBSPDESC_RATIO_MAX && m_fLastNonFlatRegionRatio > LBSPDESC_RATIO_MAX) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) + ++m_anLBSPThreshold_8bitLUT[t]; + } + m_fLastNonFlatRegionRatio = fCurrNonFlatRegionRatio; + cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); + const float fCurrMeanL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)m_oMeanDownSampledLastDistFrame_ST.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, m_oDownSampledROI_MotionAnalysis.data) / m_nDownSampledROIPxCount; + if (!m_bAutoModelResetEnabled && fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES * 2) + m_bAutoModelResetEnabled = true; + if (m_bAutoModelResetEnabled || m_bUsingMovingCamera) { + if ((m_nFrameIndex%DEFAULT_BOOTSTRAP_WIN_SIZE) == 0) { + cv::Mat oCurrBackgroundImg, oDownSampledBackgroundImg; + getBackgroundImage(oCurrBackgroundImg); + cv::resize(oCurrBackgroundImg, oDownSampledBackgroundImg, m_oDownSampledFrameSize_MotionAnalysis, 0, 0, cv::INTER_AREA); + cv::Mat oDownSampledBackgroundImg_32F; oDownSampledBackgroundImg.convertTo(oDownSampledBackgroundImg_32F, CV_32F); + const float fCurrModelL1DistRatio = L1dist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; + const float fCurrModelCDistRatio = cdist((float*)m_oMeanDownSampledLastDistFrame_LT.data, (float*)oDownSampledBackgroundImg_32F.data, m_oMeanDownSampledLastDistFrame_LT.total(), m_nImgChannels, cv::Mat(m_oDownSampledROI_MotionAnalysis == UCHAR_MAX).data) / m_nDownSampledROIPxCount; + if (m_bUsingMovingCamera && fCurrModelL1DistRatio < FRAMELEVEL_MIN_L1DIST_THRES / 4 && fCurrModelCDistRatio < FRAMELEVEL_MIN_CDIST_THRES / 4) { + m_nLocalWordWeightOffset = DEFAULT_LWORD_WEIGHT_OFFSET; + m_bUsingMovingCamera = false; + refreshModel(1, 1, true); + } + else if (bBootstrapping && !m_bUsingMovingCamera && (fCurrModelL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES || fCurrModelCDistRatio >= FRAMELEVEL_MIN_CDIST_THRES)) { + m_nLocalWordWeightOffset = 5; + m_bUsingMovingCamera = true; + refreshModel(1, 1, true); + } + } + if (m_nFramesSinceLastReset > DEFAULT_BOOTSTRAP_WIN_SIZE * 2) + m_bAutoModelResetEnabled = false; + else if (fCurrMeanL1DistRatio >= FRAMELEVEL_MIN_L1DIST_THRES && m_nModelResetCooldown == 0) { + m_nFramesSinceLastReset = 0; + refreshModel(m_nLocalWordWeightOffset / 8, 0, true); + m_nModelResetCooldown = nCurrSamplesForMovingAvg_ST; + m_oUpdateRateFrame = cv::Scalar(1.0f); + } + else if (!bBootstrapping) + ++m_nFramesSinceLastReset; + } + if (m_nModelResetCooldown > 0) + --m_nModelResetCooldown; +} + +void BackgroundSubtractorPAWCS::getBackgroundImage(cv::OutputArray backgroundImage) const { // @@@ add option to reconstruct from gwords? + CV_Assert(m_bInitialized); + cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nLocalDictIdx = nModelIter*m_nCurrLocalWords; + const int nCurrImgCoord_X = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT_PAWCS[nPxIter].nImgCoord_Y; + if (m_nImgChannels == 1) { + float fTotWeight = 0.0f; + float fTotColor = 0.0f; + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_1ch* pCurrLocalWord = (LocalWord_1ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + fTotColor += (float)pCurrLocalWord->oFeature.anColor[0] * fCurrWeight; + fTotWeight += fCurrWeight; + } + oAvgBGImg.at<float>(nCurrImgCoord_Y, nCurrImgCoord_X) = fTotColor / fTotWeight; + } + else { //m_nImgChannels==3 + float fTotWeight = 0.0f; + float fTotColor[3] = { 0.0f,0.0f,0.0f }; + for (size_t nLocalWordIdx = 0; nLocalWordIdx < m_nCurrLocalWords; ++nLocalWordIdx) { + LocalWord_3ch* pCurrLocalWord = (LocalWord_3ch*)m_apLocalWordDict[nLocalDictIdx + nLocalWordIdx]; + float fCurrWeight = GetLocalWordWeight(pCurrLocalWord, m_nFrameIndex, m_nLocalWordWeightOffset); + for (size_t c = 0; c < 3; ++c) + fTotColor[c] += (float)pCurrLocalWord->oFeature.anColor[c] * fCurrWeight; + fTotWeight += fCurrWeight; + } + oAvgBGImg.at<cv::Vec3f>(nCurrImgCoord_Y, nCurrImgCoord_X) = cv::Vec3f(fTotColor[0] / fTotWeight, fTotColor[1] / fTotWeight, fTotColor[2] / fTotWeight); + } + } + oAvgBGImg.convertTo(backgroundImage, CV_8U); +} + +void BackgroundSubtractorPAWCS::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { + CV_Assert(LBSP_::DESC_SIZE == 2); + CV_Assert(m_bInitialized); + cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + // @@@@@@ TO BE REWRITTEN FOR WORD-BASED RECONSTRUCTION + /*for(size_t n=0; n<m_voBGDescSamples.size(); ++n) { + for(int y=0; y<m_oImgSize.height; ++y) { + for(int x=0; x<m_oImgSize.width; ++x) { + const size_t nDescIter = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x; + const size_t nFloatIter = nDescIter*2; + float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter); + const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+nDescIter); + for(size_t c=0; c<m_nImgChannels; ++c) + oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size(); + } + } + }*/ + oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); +} + +void BackgroundSubtractorPAWCS::CleanupDictionaries() { + if (m_aLocalWordList_1ch) { + delete[] m_aLocalWordList_1ch; + m_aLocalWordList_1ch = nullptr; + m_pLocalWordListIter_1ch = nullptr; + } + else if (m_aLocalWordList_3ch) { + delete[] m_aLocalWordList_3ch; + m_aLocalWordList_3ch = nullptr; + m_pLocalWordListIter_3ch = nullptr; + } + if (m_apLocalWordDict) { + delete[] m_apLocalWordDict; + m_apLocalWordDict = nullptr; + } + if (m_aGlobalWordList_1ch) { + delete[] m_aGlobalWordList_1ch; + m_aGlobalWordList_1ch = nullptr; + m_pGlobalWordListIter_1ch = nullptr; + } + else if (m_aGlobalWordList_3ch) { + delete[] m_aGlobalWordList_3ch; + m_aGlobalWordList_3ch = nullptr; + m_pGlobalWordListIter_3ch = nullptr; + } + if (m_apGlobalWordDict) { + delete[] m_apGlobalWordDict; + m_apGlobalWordDict = nullptr; + } + if (m_aPxInfoLUT_PAWCS) { + for (size_t nPxIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) + delete[] m_aPxInfoLUT_PAWCS[nPxIter].apGlobalDictSortLUT; + delete[] m_aPxInfoLUT_PAWCS; + m_aPxInfoLUT = nullptr; + m_aPxInfoLUT_PAWCS = nullptr; + } + if (m_aPxIdxLUT) { + delete[] m_aPxIdxLUT; + m_aPxIdxLUT = nullptr; + } +} + +float BackgroundSubtractorPAWCS::GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset) { + return (float)(w->nOccurrences) / ((w->nLastOcc - w->nFirstOcc) + (nCurrFrame - w->nLastOcc) * 2 + nOffset); +} + +float BackgroundSubtractorPAWCS::GetGlobalWordWeight(const GlobalWordBase* w) { + return (float)cv::sum(w->oSpatioOccMap).val[0]; +} diff --git a/package_bgs/LBSP/BackgroundSubtractorPAWCS.h b/package_bgs/LBSP/BackgroundSubtractorPAWCS.h new file mode 100644 index 0000000..cafa48c --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorPAWCS.h @@ -0,0 +1,169 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "BackgroundSubtractorLBSP_.h" + +//! defines the default value for BackgroundSubtractorLBSP_::m_fRelLBSPThreshold +#define BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f) +//! defines the default value for BackgroundSubtractorPAWCS::m_nDescDistThresholdOffset +#define BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (2) +//! defines the default value for BackgroundSubtractorPAWCS::m_nMinColorDistThreshold +#define BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD (20) +//! defines the default value for BackgroundSubtractorPAWCS::m_nMaxLocalWords and m_nMaxGlobalWords +#define BGSPAWCS_DEFAULT_MAX_NB_WORDS (50) +//! defines the default value for BackgroundSubtractorPAWCS::m_nSamplesForMovingAvgs +#define BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100) + +/*! + Pixel-based Adaptive Word Consensus Segmenter (PAWCS) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., + "A Self-Adjusting Approach to Change Detection Based on Background Word Consensus", in WACV 2015. + + This algorithm is currently NOT thread-safe. + */ +class BackgroundSubtractorPAWCS : public BackgroundSubtractorLBSP_ { +public: + //! full constructor + BackgroundSubtractorPAWCS(float fRelLBSPThreshold = BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nDescDistThresholdOffset = BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, + size_t nMinColorDistThreshold = BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD, + size_t nMaxNbWords = BGSPAWCS_DEFAULT_MAX_NB_WORDS, + size_t nSamplesForMovingAvgs = BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + //! default destructor + virtual ~BackgroundSubtractorPAWCS(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all local (+ global) dictionaries based on the last analyzed frame + virtual void refreshModel(size_t nBaseOccCount, float fOccDecrFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); + //! returns a copy of the latest reconstructed background image + virtual void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + +protected: + template<size_t nChannels> + struct ColorLBSPFeature { + uchar anColor[nChannels]; + ushort anDesc[nChannels]; + }; + struct LocalWordBase { + size_t nFirstOcc; + size_t nLastOcc; + size_t nOccurrences; + }; + template<typename T> + struct LocalWord : LocalWordBase { + T oFeature; + }; + struct GlobalWordBase { + float fLatestWeight; + cv::Mat oSpatioOccMap; + uchar nDescBITS; + }; + template<typename T> + struct GlobalWord : GlobalWordBase { + T oFeature; + }; + typedef LocalWord<ColorLBSPFeature<1>> LocalWord_1ch; + typedef LocalWord<ColorLBSPFeature<3>> LocalWord_3ch; + typedef GlobalWord<ColorLBSPFeature<1>> GlobalWord_1ch; + typedef GlobalWord<ColorLBSPFeature<3>> GlobalWord_3ch; + struct PxInfo_PAWCS : PxInfoBase { + size_t nGlobalWordMapLookupIdx; + GlobalWordBase** apGlobalDictSortLUT; + }; + //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) + const size_t m_nMinColorDistThreshold; + //! absolute descriptor distance threshold offset + const size_t m_nDescDistThresholdOffset; + //! max/curr number of local words used to build background submodels (for a single pixel, similar to 'N' in ViBe/PBAS, may vary based on img/channel size) + size_t m_nMaxLocalWords, m_nCurrLocalWords; + //! max/curr number of global words used to build the global background model (may vary based on img/channel size) + size_t m_nMaxGlobalWords, m_nCurrGlobalWords; + //! number of samples to use to compute the learning rate of moving averages + const size_t m_nSamplesForMovingAvgs; + //! last calculated non-flat region ratio + float m_fLastNonFlatRegionRatio; + //! current kernel size for median blur post-proc filtering + int m_nMedianBlurKernelSize; + //! specifies the downsampled frame size used for cam motion analysis & gword lookup maps + cv::Size m_oDownSampledFrameSize_MotionAnalysis, m_oDownSampledFrameSize_GlobalWordLookup; + //! downsampled version of the ROI used for cam motion analysis + cv::Mat m_oDownSampledROI_MotionAnalysis; + //! total pixel count for the downsampled ROIs + size_t m_nDownSampledROIPxCount; + //! current local word weight offset + size_t m_nLocalWordWeightOffset; + + //! word lists & dictionaries + LocalWordBase** m_apLocalWordDict; + LocalWord_1ch* m_aLocalWordList_1ch, *m_pLocalWordListIter_1ch; + LocalWord_3ch* m_aLocalWordList_3ch, *m_pLocalWordListIter_3ch; + GlobalWordBase** m_apGlobalWordDict; + GlobalWord_1ch* m_aGlobalWordList_1ch, *m_pGlobalWordListIter_1ch; + GlobalWord_3ch* m_aGlobalWordList_3ch, *m_pGlobalWordListIter_3ch; + PxInfo_PAWCS* m_aPxInfoLUT_PAWCS; + + //! a lookup map used to keep track of regions where illumination recently changed + cv::Mat m_oIllumUpdtRegionMask; + //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) + cv::Mat m_oUpdateRateFrame; + //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) + cv::Mat m_oDistThresholdFrame; + //! per-pixel distance threshold variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) + cv::Mat m_oDistThresholdVariationFrame; + //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') + cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; + //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and force global model resets automatically) + cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; + //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) + cv::Mat m_oUnstableRegionMask; + //! per-pixel blink detection map ('Z(x)') + cv::Mat m_oBlinksFrame; + //! pre-allocated matrix used to downsample the input frame when needed + cv::Mat m_oDownSampledFrame_MotionAnalysis; + //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) + cv::Mat m_oLastRawFGMask; + + //! pre-allocated CV_8UC1 matrices used to speed up morph ops + cv::Mat m_oFGMask_PreFlood; + cv::Mat m_oFGMask_FloodedHoles; + cv::Mat m_oLastFGMask_dilated; + cv::Mat m_oLastFGMask_dilated_inverted; + cv::Mat m_oCurrRawFGBlinkMask; + cv::Mat m_oLastRawFGBlinkMask; + cv::Mat m_oTempGlobalWordWeightDiffFactor; + cv::Mat m_oMorphExStructElement; + + //! internal cleanup function for the dictionary structures + void CleanupDictionaries(); + //! internal weight lookup function for local words + static float GetLocalWordWeight(const LocalWordBase* w, size_t nCurrFrame, size_t nOffset); + //! internal weight lookup function for global words + static float GetGlobalWordWeight(const GlobalWordBase* w); +}; diff --git a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp new file mode 100644 index 0000000..3dcc1b8 --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.cpp @@ -0,0 +1,753 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "BackgroundSubtractorSuBSENSE.h" +#include "DistanceUtils.h" +#include "RandUtils.h" +#include <iostream> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/highgui/highgui.hpp> +#include <iomanip> + +/* + * + * Intrinsic parameters for our method are defined here; tuning these for better + * performance should not be required in most cases -- although improvements in + * very specific scenarios are always possible. + * + */ + //! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic +#define GHOSTDET_D_MAX (0.010f) // defines 'negligible' change here +#define GHOSTDET_S_MIN (0.995f) // defines the required minimum local foreground saturation value +//! parameter used to scale dynamic distance threshold adjustments ('R(x)') +#define FEEDBACK_R_VAR (0.01f) +//! parameters used to adjust the variation step size of 'v(x)' +#define FEEDBACK_V_INCR (1.000f) +#define FEEDBACK_V_DECR (0.100f) +//! parameters used to scale dynamic learning rate adjustments ('T(x)') +#define FEEDBACK_T_DECR (0.2500f) +#define FEEDBACK_T_INCR (0.5000f) +#define FEEDBACK_T_LOWER (2.0000f) +#define FEEDBACK_T_UPPER (256.00f) +//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values +#define UNSTABLE_REG_RATIO_MIN (0.100f) +#define UNSTABLE_REG_RDIST_MIN (3.000f) +//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons +#define LBSPDESC_NONZERO_RATIO_MIN (0.100f) +#define LBSPDESC_NONZERO_RATIO_MAX (0.500f) +//! parameters used to define model reset/learning rate boosts in our frame-level component +#define FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD (m_nMinColorDistThreshold/2) +#define FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO (8) + +// local define used to display debug information +#define DISPLAY_SUBSENSE_DEBUG_INFO 0 +// local define used to specify the default frame size (320x240 = QVGA) +#define DEFAULT_FRAME_SIZE cv::Size(320,240) +// local define used to specify the color dist threshold offset used for unstable regions +#define STAB_COLOR_DIST_OFFSET (m_nMinColorDistThreshold/5) +// local define used to specify the desc dist threshold offset used for unstable regions +#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) + +static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; +static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE * 8; +static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch * 3; +static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch * 3; + +BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold + , size_t nDescDistThresholdOffset + , size_t nMinColorDistThreshold + , size_t nBGSamples + , size_t nRequiredBGSamples + , size_t nSamplesForMovingAvgs) + : BackgroundSubtractorLBSP(fRelLBSPThreshold) + , m_nMinColorDistThreshold(nMinColorDistThreshold) + , m_nDescDistThresholdOffset(nDescDistThresholdOffset) + , m_nBGSamples(nBGSamples) + , m_nRequiredBGSamples(nRequiredBGSamples) + , m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) + , m_fLastNonZeroDescRatio(0.0f) + , m_bLearningRateScalingEnabled(true) + , m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER) + , m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER) + , m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) + , m_bUse3x3Spread(true) { + CV_Assert(m_nBGSamples > 0 && m_nRequiredBGSamples <= m_nBGSamples); + CV_Assert(m_nMinColorDistThreshold >= STAB_COLOR_DIST_OFFSET); +} + +BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() { + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; +} + +void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { + // == init + CV_Assert(!oInitImg.empty() && oInitImg.cols > 0 && oInitImg.rows > 0); + CV_Assert(oInitImg.isContinuous()); + CV_Assert(oInitImg.type() == CV_8UC3 || oInitImg.type() == CV_8UC1); + if (oInitImg.type() == CV_8UC3) { + std::vector<cv::Mat> voInitImgChannels; + cv::split(oInitImg, voInitImgChannels); + if (!cv::countNonZero((voInitImgChannels[0] != voInitImgChannels[1]) | (voInitImgChannels[2] != voInitImgChannels[1]))) + std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; + } + cv::Mat oNewBGROI; + if (oROI.empty() && (m_oROI.empty() || oROI.size() != oInitImg.size())) { + oNewBGROI.create(oInitImg.size(), CV_8UC1); + oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); + } + else if (oROI.empty()) + oNewBGROI = m_oROI; + else { + CV_Assert(oROI.size() == oInitImg.size() && oROI.type() == CV_8UC1); + CV_Assert(cv::countNonZero((oROI < UCHAR_MAX)&(oROI > 0)) == 0); + oNewBGROI = oROI.clone(); + cv::Mat oTempROI; + cv::dilate(oNewBGROI, oTempROI, cv::Mat(), cv::Point(-1, -1), LBSP::PATCH_SIZE / 2); + cv::bitwise_or(oNewBGROI, oTempROI / 2, oNewBGROI); + } + const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nOrigROIPxCount > 0); + LBSP::validateROI(oNewBGROI); + const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); + CV_Assert(nFinalROIPxCount > 0); + m_oROI = oNewBGROI; + m_oImgSize = oInitImg.size(); + m_nImgType = oInitImg.type(); + m_nImgChannels = oInitImg.channels(); + m_nTotPxCount = m_oImgSize.area(); + m_nTotRelevantPxCount = nFinalROIPxCount; + m_nFrameIndex = 0; + m_nFramesSinceLastReset = 0; + m_nModelResetCooldown = 0; + m_fLastNonZeroDescRatio = 0.0f; + const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width; + if (nOrigROIPxCount >= m_nTotPxCount / 2 && (int)m_nTotPxCount >= DEFAULT_FRAME_SIZE.area()) { + m_bLearningRateScalingEnabled = true; + m_bAutoModelResetEnabled = true; + m_bUse3x3Spread = !(nTotImgPixels > DEFAULT_FRAME_SIZE.area() * 2); + const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels / DEFAULT_FRAME_SIZE.area() + 0.5f) + m_nDefaultMedianBlurKernelSize, 14); + m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize % 2) ? nRawMedianBlurKernelSize : nRawMedianBlurKernelSize - 1; + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; + } + else { + m_bLearningRateScalingEnabled = false; + m_bAutoModelResetEnabled = false; + m_bUse3x3Spread = true; + m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize; + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER * 2; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER * 2; + } + m_oUpdateRateFrame.create(m_oImgSize, CV_32FC1); + m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap); + m_oDistThresholdFrame.create(m_oImgSize, CV_32FC1); + m_oDistThresholdFrame = cv::Scalar(1.0f); + m_oVariationModulatorFrame.create(m_oImgSize, CV_32FC1); + m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR + m_oMeanLastDistFrame.create(m_oImgSize, CV_32FC1); + m_oMeanLastDistFrame = cv::Scalar(0.0f); + m_oMeanMinDistFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); + m_oMeanMinDistFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); + m_oDownSampledFrameSize = cv::Size(m_oImgSize.width / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO, m_oImgSize.height / FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO); + m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); + m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize, CV_32FC((int)m_nImgChannels)); + m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanRawSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_LT.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); + m_oMeanFinalSegmResFrame_ST.create(m_oImgSize, CV_32FC1); + m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); + m_oUnstableRegionMask.create(m_oImgSize, CV_8UC1); + m_oUnstableRegionMask = cv::Scalar_<uchar>(0); + m_oBlinksFrame.create(m_oImgSize, CV_8UC1); + m_oBlinksFrame = cv::Scalar_<uchar>(0); + m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize, CV_8UC((int)m_nImgChannels)); + m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); + m_oLastColorFrame.create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_oLastColorFrame = cv::Scalar_<uchar>::all(0); + m_oLastDescFrame.create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_oLastDescFrame = cv::Scalar_<ushort>::all(0); + m_oLastRawFGMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask.create(m_oImgSize, CV_8UC1); + m_oLastFGMask = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); + m_oLastFGMask_dilated_inverted.create(m_oImgSize, CV_8UC1); + m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); + m_oFGMask_FloodedHoles.create(m_oImgSize, CV_8UC1); + m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); + m_oFGMask_PreFlood.create(m_oImgSize, CV_8UC1); + m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); + m_oCurrRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_oLastRawFGBlinkMask.create(m_oImgSize, CV_8UC1); + m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); + m_voBGColorSamples.resize(m_nBGSamples); + m_voBGDescSamples.resize(m_nBGSamples); + for (size_t s = 0; s < m_nBGSamples; ++s) { + m_voBGColorSamples[s].create(m_oImgSize, CV_8UC((int)m_nImgChannels)); + m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); + m_voBGDescSamples[s].create(m_oImgSize, CV_16UC((int)m_nImgChannels)); + m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); + } + if (m_aPxIdxLUT) + delete[] m_aPxIdxLUT; + if (m_aPxInfoLUT) + delete[] m_aPxInfoLUT; + m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; + m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; + if (m_nImgChannels == 1) { + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1] == 1); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold) / 3); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; + const size_t nDescIter = nPxIter * 2; + LBSP::computeGrayscaleDescriptor(oInitImg, oInitImg.data[nPxIter], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]], *((ushort*)(m_oLastDescFrame.data + nDescIter))); + ++nModelIter; + } + } + } + else { //m_nImgChannels==3 + CV_Assert(m_oLastColorFrame.step.p[0] == (size_t)m_oImgSize.width * 3 && m_oLastColorFrame.step.p[1] == 3); + CV_Assert(m_oLastDescFrame.step.p[0] == m_oLastColorFrame.step.p[0] * 2 && m_oLastDescFrame.step.p[1] == m_oLastColorFrame.step.p[1] * 2); + for (size_t t = 0; t <= UCHAR_MAX; ++t) + m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + t*m_fRelLBSPThreshold); + for (size_t nPxIter = 0, nModelIter = 0; nPxIter < m_nTotPxCount; ++nPxIter) { + if (m_oROI.data[nPxIter]) { + m_aPxIdxLUT[nModelIter] = nPxIter; + m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter / m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; + m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; + const size_t nPxRGBIter = nPxIter * 3; + const size_t nDescRGBIter = nPxRGBIter * 2; + for (size_t c = 0; c < 3; ++c) { + m_oLastColorFrame.data[nPxRGBIter + c] = oInitImg.data[nPxRGBIter + c]; + LBSP::computeSingleRGBDescriptor(oInitImg, oInitImg.data[nPxRGBIter + c], m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter + c]], ((ushort*)(m_oLastDescFrame.data + nDescRGBIter))[c]); + } + ++nModelIter; + } + } + } + m_bInitialized = true; + refreshModel(1.0f); +} + +void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { + // == refresh + CV_Assert(m_bInitialized); + CV_Assert(fSamplesRefreshFrac > 0.0f && fSamplesRefreshFrac <= 1.0f); + const size_t nModelsToRefresh = fSamplesRefreshFrac < 1.0f ? (size_t)(fSamplesRefreshFrac*m_nBGSamples) : m_nBGSamples; + const size_t nRefreshStartPos = fSamplesRefreshFrac < 1.0f ? rand() % m_nBGSamples : 0; + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + nPxIter * 2)) = *((ushort*)(m_oLastDescFrame.data + nSamplePxIdx * 2)); + } + } + } + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + if (bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { + for (size_t nCurrModelIdx = nRefreshStartPos; nCurrModelIdx < nRefreshStartPos + nModelsToRefresh; ++nCurrModelIdx) { + int nSampleImgCoord_Y, nSampleImgCoord_X; + getRandSamplePosition(nSampleImgCoord_X, nSampleImgCoord_Y, m_aPxInfoLUT[nPxIter].nImgCoord_X, m_aPxInfoLUT[nPxIter].nImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + if (bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { + const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter * 3 + c] = m_oLastColorFrame.data[nSamplePxIdx * 3 + c]; + *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data + (nPxIter * 3 + c) * 2)) = *((ushort*)(m_oLastDescFrame.data + (nSamplePxIdx * 3 + c) * 2)); + } + } + } + } + } + } +} + +void BackgroundSubtractorSuBSENSE::apply(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { + // == process + CV_Assert(m_bInitialized); + cv::Mat oInputImg = _image.getMat(); + CV_Assert(oInputImg.type() == m_nImgType && oInputImg.size() == m_oImgSize); + CV_Assert(oInputImg.isContinuous()); + _fgmask.create(m_oImgSize, CV_8UC1); + cv::Mat oCurrFGMask = _fgmask.getMat(); + memset(oCurrFGMask.data, 0, oCurrFGMask.cols*oCurrFGMask.rows); + size_t nNonZeroDescCount = 0; + const float fRollAvgFactor_LT = 1.0f / std::min(++m_nFrameIndex, m_nSamplesForMovingAvgs); + const float fRollAvgFactor_ST = 1.0f / std::min(m_nFrameIndex, m_nSamplesForMovingAvgs / 4); + if (m_nImgChannels == 1) { + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const size_t nDescIter = nPxIter * 2; + const size_t nFloatIter = nPxIter * 4; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const uchar nCurrColor = oInputImg.data[nPxIter]; + size_t nMinDescDist = s_nDescMaxDataRange_1ch; + size_t nMinSumDist = s_nColorMaxDataRange_1ch; + float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); + float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); + float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); + float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); + float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); + float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); + ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data + nDescIter)); + uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; + const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)) / 2; + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); + ushort nCurrInterDesc, nCurrIntraDesc; + LBSP::computeGrayscaleDescriptor(oInputImg, nCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nCurrColor], nCurrIntraDesc); + m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; + size_t nGoodSamplesCount = 0, nSampleIdx = 0; + while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { + const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter]; + { + const size_t nColorDist = L1dist(nCurrColor, nBGColor); + if (nColorDist > nCurrColorDistThreshold) + goto failedcheck1ch; + const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIter)); + const size_t nIntraDescDist = hdist(nCurrIntraDesc, nBGIntraDesc); + LBSP::computeGrayscaleDescriptor(oInputImg, nBGColor, nCurrImgCoord_X, nCurrImgCoord_Y, m_anLBSPThreshold_8bitLUT[nBGColor], nCurrInterDesc); + const size_t nInterDescDist = hdist(nCurrInterDesc, nBGIntraDesc); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + if (nDescDist > nCurrDescDistThreshold) + goto failedcheck1ch; + const size_t nSumDist = std::min((nDescDist / 4)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); + if (nSumDist > nCurrColorDistThreshold) + goto failedcheck1ch; + if (nMinDescDist > nDescDist) + nMinDescDist = nDescDist; + if (nMinSumDist > nSumDist) + nMinSumDist = nSumDist; + nGoodSamplesCount++; + } + failedcheck1ch: + nSampleIdx++; + } + const float fNormalizedLastDist = ((float)L1dist(nLastColor, nCurrColor) / s_nColorMaxDataRange_1ch + (float)hdist(nLastIntraDesc, nCurrIntraDesc) / s_nDescMaxDataRange_1ch) / 2; + *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; + if (nGoodSamplesCount < m_nRequiredBGSamples) { + // == foreground + const float fNormalizedMinDist = std::min(1.0f, ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; + } + } + else { + // == background + const float fNormalizedMinDist = ((float)nMinSumDist / s_nColorMaxDataRange_1ch + (float)nMinDescDist / s_nDescMaxDataRange_1ch) / 2; + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); + const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); + if ((rand() % nLearningRate) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIter)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; + } + int nSampleImgCoord_Y, nSampleImgCoord_X; + const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; + if (bCurrUsing3x3Spread) + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t n_rand = rand(); + const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + const size_t idx_rand_flt32 = idx_rand_uchar * 4; + const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); + const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); + if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 + || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { + const size_t idx_rand_ushrt = idx_rand_uchar * 2; + const size_t s_rand = rand() % m_nBGSamples; + *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt)) = nCurrIntraDesc; + m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor; + } + } + if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { + if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) + *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); + } + else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) + *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); + if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) + *pfCurrLearningRate = m_fCurrLearningRateLowerCap; + else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) + *pfCurrLearningRate = m_fCurrLearningRateUpperCap; + if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (*pfCurrVariationFactor) += FEEDBACK_V_INCR; + else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { + (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; + if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) + (*pfCurrVariationFactor) = FEEDBACK_V_DECR; + } + if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) + (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); + else { + (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); + if ((*pfCurrDistThresholdFactor) < 1.0f) + (*pfCurrDistThresholdFactor) = 1.0f; + } + if (popcount(nCurrIntraDesc) >= 2) + ++nNonZeroDescCount; + nLastIntraDesc = nCurrIntraDesc; + nLastColor = nCurrColor; + } + } + else { //m_nImgChannels==3 + for (size_t nModelIter = 0; nModelIter < m_nTotRelevantPxCount; ++nModelIter) { + const size_t nPxIter = m_aPxIdxLUT[nModelIter]; + const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; + const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; + const size_t nPxIterRGB = nPxIter * 3; + const size_t nDescIterRGB = nPxIterRGB * 2; + const size_t nFloatIter = nPxIter * 4; + const uchar* const anCurrColor = oInputImg.data + nPxIterRGB; + size_t nMinTotDescDist = s_nDescMaxDataRange_3ch; + size_t nMinTotSumDist = s_nColorMaxDataRange_3ch; + float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data + nFloatIter); + float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data + nFloatIter); + float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data + nFloatIter)); + float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data + nFloatIter)); + float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data + nFloatIter)); + float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data + nFloatIter)); + float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data + nFloatIter)); + ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data + nDescIterRGB)); + uchar* anLastColor = m_oLastColorFrame.data + nPxIterRGB; + const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold) - ((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)); + const size_t nCurrDescDistThreshold = ((size_t)1 << ((size_t)floor(*pfCurrDistThresholdFactor + 0.5f))) + m_nDescDistThresholdOffset + (m_oUnstableRegionMask.data[nPxIter] * UNSTAB_DESC_DIST_OFFSET); + const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold * 3; + const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold * 3; + const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold / 2; + ushort anCurrInterDesc[3], anCurrIntraDesc[3]; + const size_t anCurrIntraLBSPThresholds[3] = { m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]] }; + LBSP::computeRGBDescriptor(oInputImg, anCurrColor, nCurrImgCoord_X, nCurrImgCoord_Y, anCurrIntraLBSPThresholds, anCurrIntraDesc); + m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor) > UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT - *pfCurrMeanFinalSegmRes_LT) > UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST - *pfCurrMeanFinalSegmRes_ST) > UNSTABLE_REG_RATIO_MIN) ? 1 : 0; + size_t nGoodSamplesCount = 0, nSampleIdx = 0; + while (nGoodSamplesCount < m_nRequiredBGSamples && nSampleIdx < m_nBGSamples) { + const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data + nDescIterRGB); + const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data + nPxIterRGB; + size_t nTotDescDist = 0; + size_t nTotSumDist = 0; + for (size_t c = 0; c < 3; ++c) { + const size_t nColorDist = L1dist(anCurrColor[c], anBGColor[c]); + if (nColorDist > nCurrSCColorDistThreshold) + goto failedcheck3ch; + const size_t nIntraDescDist = hdist(anCurrIntraDesc[c], anBGIntraDesc[c]); + LBSP::computeSingleRGBDescriptor(oInputImg, anBGColor[c], nCurrImgCoord_X, nCurrImgCoord_Y, c, m_anLBSPThreshold_8bitLUT[anBGColor[c]], anCurrInterDesc[c]); + const size_t nInterDescDist = hdist(anCurrInterDesc[c], anBGIntraDesc[c]); + const size_t nDescDist = (nIntraDescDist + nInterDescDist) / 2; + const size_t nSumDist = std::min((nDescDist / 2)*(s_nColorMaxDataRange_1ch / s_nDescMaxDataRange_1ch) + nColorDist, s_nColorMaxDataRange_1ch); + if (nSumDist > nCurrSCColorDistThreshold) + goto failedcheck3ch; + nTotDescDist += nDescDist; + nTotSumDist += nSumDist; + } + if (nTotDescDist > nCurrTotDescDistThreshold || nTotSumDist > nCurrTotColorDistThreshold) + goto failedcheck3ch; + if (nMinTotDescDist > nTotDescDist) + nMinTotDescDist = nTotDescDist; + if (nMinTotSumDist > nTotSumDist) + nMinTotSumDist = nTotSumDist; + nGoodSamplesCount++; + failedcheck3ch: + nSampleIdx++; + } + const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor, anCurrColor) / s_nColorMaxDataRange_3ch + (float)hdist<3>(anLastIntraDesc, anCurrIntraDesc) / s_nDescMaxDataRange_3ch) / 2; + *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f - fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; + if (nGoodSamplesCount < m_nRequiredBGSamples) { + // == foreground + const float fNormalizedMinDist = std::min(1.0f, ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2 + (float)(m_nRequiredBGSamples - nGoodSamplesCount) / m_nRequiredBGSamples); + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT) + fRollAvgFactor_LT; + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST) + fRollAvgFactor_ST; + oCurrFGMask.data[nPxIter] = UCHAR_MAX; + if (m_nModelResetCooldown && (rand() % (size_t)FEEDBACK_T_LOWER) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; + } + } + } + else { + // == background + const float fNormalizedMinDist = ((float)nMinTotSumDist / s_nColorMaxDataRange_3ch + (float)nMinTotDescDist / s_nDescMaxDataRange_3ch) / 2; + *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f - fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; + *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f - fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; + *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f - fRollAvgFactor_LT); + *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f - fRollAvgFactor_ST); + const size_t nLearningRate = learningRateOverride > 0 ? (size_t)ceil(learningRateOverride) : (size_t)ceil(*pfCurrLearningRate); + if ((rand() % nLearningRate) == 0) { + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + nDescIterRGB + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + nPxIterRGB + c) = anCurrColor[c]; + } + } + int nSampleImgCoord_Y, nSampleImgCoord_X; + const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; + if (bCurrUsing3x3Spread) + getRandNeighborPosition_3x3(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + else + getRandNeighborPosition_5x5(nSampleImgCoord_X, nSampleImgCoord_Y, nCurrImgCoord_X, nCurrImgCoord_Y, LBSP::PATCH_SIZE / 2, m_oImgSize); + const size_t n_rand = rand(); + const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; + const size_t idx_rand_flt32 = idx_rand_uchar * 4; + const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data + idx_rand_flt32)); + const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data + idx_rand_flt32)); + if ((n_rand % (bCurrUsing3x3Spread ? nLearningRate : (nLearningRate / 2 + 1))) == 0 + || (fRandMeanRawSegmRes > GHOSTDET_S_MIN && fRandMeanLastDist < GHOSTDET_D_MAX && (n_rand % ((size_t)m_fCurrLearningRateLowerCap)) == 0)) { + const size_t idx_rand_uchar_rgb = idx_rand_uchar * 3; + const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb * 2; + const size_t s_rand = rand() % m_nBGSamples; + for (size_t c = 0; c < 3; ++c) { + *((ushort*)(m_voBGDescSamples[s_rand].data + idx_rand_ushrt_rgb + 2 * c)) = anCurrIntraDesc[c]; + *(m_voBGColorSamples[s_rand].data + idx_rand_uchar_rgb + c) = anCurrColor[c]; + } + } + } + if (m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) < UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { + if ((*pfCurrLearningRate) < m_fCurrLearningRateUpperCap) + *pfCurrLearningRate += FEEDBACK_T_INCR / (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); + } + else if ((*pfCurrLearningRate) > m_fCurrLearningRateLowerCap) + *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor) / std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST); + if ((*pfCurrLearningRate) < m_fCurrLearningRateLowerCap) + *pfCurrLearningRate = m_fCurrLearningRateLowerCap; + else if ((*pfCurrLearningRate) > m_fCurrLearningRateUpperCap) + *pfCurrLearningRate = m_fCurrLearningRateUpperCap; + if (std::max(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) > UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) + (*pfCurrVariationFactor) += FEEDBACK_V_INCR; + else if ((*pfCurrVariationFactor) > FEEDBACK_V_DECR) { + (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter] ? FEEDBACK_V_DECR / 4 : m_oUnstableRegionMask.data[nPxIter] ? FEEDBACK_V_DECR / 2 : FEEDBACK_V_DECR; + if ((*pfCurrVariationFactor) < FEEDBACK_V_DECR) + (*pfCurrVariationFactor) = FEEDBACK_V_DECR; + } + if ((*pfCurrDistThresholdFactor) < std::pow(1.0f + std::min(*pfCurrMeanMinDist_LT, *pfCurrMeanMinDist_ST) * 2, 2)) + (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor - FEEDBACK_V_DECR); + else { + (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR / (*pfCurrVariationFactor); + if ((*pfCurrDistThresholdFactor) < 1.0f) + (*pfCurrDistThresholdFactor) = 1.0f; + } + if (popcount<3>(anCurrIntraDesc) >= 4) + ++nNonZeroDescCount; + for (size_t c = 0; c < 3; ++c) { + anLastIntraDesc[c] = anCurrIntraDesc[c]; + anLastColor[c] = anCurrColor[c]; + } + } + } +#if DISPLAY_SUBSENSE_DEBUG_INFO + std::cout << std::endl; + cv::Point dbgpt(nDebugCoordX, nDebugCoordY); + cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized); + cv::circle(oMeanMinDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanMinDistFrameNormalized, oMeanMinDistFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("d_min(x)", oMeanMinDistFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized); + cv::circle(oMeanLastDistFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanLastDistFrameNormalized, oMeanLastDistFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("d_last(x)", oMeanLastDistFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl; + cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized); + cv::circle(oMeanRawSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanRawSegmResFrameNormalized, oMeanRawSegmResFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("s_avg(x)", oMeanRawSegmResFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized); + cv::circle(oMeanFinalSegmResFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oMeanFinalSegmResFrameNormalized, oMeanFinalSegmResFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("z_avg(x)", oMeanFinalSegmResFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl; + cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized, CV_32FC1, 0.25f, -0.25f); + cv::circle(oDistThresholdFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oDistThresholdFrameNormalized, oDistThresholdFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("r(x)", oDistThresholdFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl; + cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame, oVariationModulatorFrameNormalized, 0, 255, cv::NORM_MINMAX, CV_8UC1); + cv::circle(oVariationModulatorFrameNormalized, dbgpt, 5, cv::Scalar(255)); + cv::resize(oVariationModulatorFrameNormalized, oVariationModulatorFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("v(x)", oVariationModulatorFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl; + cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized, CV_32FC1, 1.0f / FEEDBACK_T_UPPER, -FEEDBACK_T_LOWER / FEEDBACK_T_UPPER); + cv::circle(oUpdateRateFrameNormalized, dbgpt, 5, cv::Scalar(1.0f)); + cv::resize(oUpdateRateFrameNormalized, oUpdateRateFrameNormalized, DEFAULT_FRAME_SIZE); + cv::imshow("t(x)", oUpdateRateFrameNormalized); + std::cout << std::fixed << std::setprecision(5) << " t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl; +#endif //DISPLAY_SUBSENSE_DEBUG_INFO + cv::bitwise_xor(oCurrFGMask, m_oLastRawFGMask, m_oCurrRawFGBlinkMask); + cv::bitwise_or(m_oCurrRawFGBlinkMask, m_oLastRawFGBlinkMask, m_oBlinksFrame); + m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); + oCurrFGMask.copyTo(m_oLastRawFGMask); + cv::morphologyEx(oCurrFGMask, m_oFGMask_PreFlood, cv::MORPH_CLOSE, cv::Mat()); + m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); + cv::floodFill(m_oFGMask_FloodedHoles, cv::Point(0, 0), UCHAR_MAX); + cv::bitwise_not(m_oFGMask_FloodedHoles, m_oFGMask_FloodedHoles); + cv::erode(m_oFGMask_PreFlood, m_oFGMask_PreFlood, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_or(oCurrFGMask, m_oFGMask_FloodedHoles, oCurrFGMask); + cv::bitwise_or(oCurrFGMask, m_oFGMask_PreFlood, oCurrFGMask); + cv::medianBlur(oCurrFGMask, m_oLastFGMask, m_nMedianBlurKernelSize); + cv::dilate(m_oLastFGMask, m_oLastFGMask_dilated, cv::Mat(), cv::Point(-1, -1), 3); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + cv::bitwise_not(m_oLastFGMask_dilated, m_oLastFGMask_dilated_inverted); + cv::bitwise_and(m_oBlinksFrame, m_oLastFGMask_dilated_inverted, m_oBlinksFrame); + m_oLastFGMask.copyTo(oCurrFGMask); + cv::addWeighted(m_oMeanFinalSegmResFrame_LT, (1.0f - fRollAvgFactor_LT), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_LT, 0, m_oMeanFinalSegmResFrame_LT, CV_32F); + cv::addWeighted(m_oMeanFinalSegmResFrame_ST, (1.0f - fRollAvgFactor_ST), m_oLastFGMask, (1.0 / UCHAR_MAX)*fRollAvgFactor_ST, 0, m_oMeanFinalSegmResFrame_ST, CV_32F); + const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount / m_nTotRelevantPxCount; + if (fCurrNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio < LBSPDESC_NONZERO_RATIO_MIN) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] > cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + ceil(t*m_fRelLBSPThreshold / 4))) + --m_anLBSPThreshold_8bitLUT[t]; + } + else if (fCurrNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio > LBSPDESC_NONZERO_RATIO_MAX) { + for (size_t t = 0; t <= UCHAR_MAX; ++t) + if (m_anLBSPThreshold_8bitLUT[t] < cv::saturate_cast<uchar>(m_nLBSPThresholdOffset + UCHAR_MAX*m_fRelLBSPThreshold)) + ++m_anLBSPThreshold_8bitLUT[t]; + } + m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio; + if (m_bLearningRateScalingEnabled) { + cv::resize(oInputImg, m_oDownSampledFrame_MotionAnalysis, m_oDownSampledFrameSize, 0, 0, cv::INTER_AREA); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_LT, fRollAvgFactor_LT); + cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis, m_oMeanDownSampledLastDistFrame_ST, fRollAvgFactor_ST); + size_t nTotColorDiff = 0; + for (int i = 0; i < m_oMeanDownSampledLastDistFrame_ST.rows; ++i) { + const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0] * i; + for (int j = 0; j < m_oMeanDownSampledLastDistFrame_ST.cols; ++j) { + const size_t idx2 = idx1 + m_oMeanDownSampledLastDistFrame_ST.step.p[1] * j; + nTotColorDiff += (m_nImgChannels == 1) ? + (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))) / 2 + : //(m_nImgChannels==3) + std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2))), + std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 4)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 4))), + (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data + idx2 + 8)) - (*(float*)(m_oMeanDownSampledLastDistFrame_LT.data + idx2 + 8))))); + } + } + const float fCurrColorDiffRatio = (float)nTotColorDiff / (m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols); + if (m_bAutoModelResetEnabled) { + if (m_nFramesSinceLastReset > 1000) + m_bAutoModelResetEnabled = false; + else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown == 0) { + m_nFramesSinceLastReset = 0; + refreshModel(0.1f); // reset 10% of the bg model + m_nModelResetCooldown = m_nSamplesForMovingAvgs / 4; + m_oUpdateRateFrame = cv::Scalar(1.0f); + } + else + ++m_nFramesSinceLastReset; + } + else if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD * 2) { + m_nFramesSinceLastReset = 0; + m_bAutoModelResetEnabled = true; + } + if (fCurrColorDiffRatio >= FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD / 2) { + m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER >> (int)(fCurrColorDiffRatio / 2), 1); + m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER >> (int)(fCurrColorDiffRatio / 2), 1); + } + else { + m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; + m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; + } + if (m_nModelResetCooldown > 0) + --m_nModelResetCooldown; + } +} + +void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const { + CV_Assert(m_bInitialized); + cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t s = 0; s < m_nBGSamples; ++s) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_nimg = m_voBGColorSamples[s].step.p[0] * y + m_voBGColorSamples[s].step.p[1] * x; + const size_t nFloatIter = idx_nimg * 4; + float* oAvgBgImgPtr = (float*)(oAvgBGImg.data + nFloatIter); + const uchar* const oBGImgPtr = m_voBGColorSamples[s].data + idx_nimg; + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgImgPtr[c] += ((float)oBGImgPtr[c]) / m_nBGSamples; + } + } + } + oAvgBGImg.convertTo(backgroundImage, CV_8U); +} + +void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { + CV_Assert(LBSP::DESC_SIZE == 2); + CV_Assert(m_bInitialized); + cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize, CV_32FC((int)m_nImgChannels)); + for (size_t n = 0; n < m_voBGDescSamples.size(); ++n) { + for (int y = 0; y < m_oImgSize.height; ++y) { + for (int x = 0; x < m_oImgSize.width; ++x) { + const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0] * y + m_voBGDescSamples[n].step.p[1] * x; + const size_t nFloatIter = idx_ndesc * 2; + float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data + nFloatIter); + const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data + idx_ndesc); + for (size_t c = 0; c < m_nImgChannels; ++c) + oAvgBgDescPtr[c] += ((float)oBGDescPtr[c]) / m_voBGDescSamples.size(); + } + } + } + oAvgBGDesc.convertTo(backgroundDescImage, CV_16U); +} diff --git a/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h new file mode 100644 index 0000000..9950ea4 --- /dev/null +++ b/package_bgs/LBSP/BackgroundSubtractorSuBSENSE.h @@ -0,0 +1,129 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "BackgroundSubtractorLBSP.h" + +//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold +#define BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f) +//! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset +#define BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (3) +//! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold +#define BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD (30) +//! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples +#define BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES (50) +//! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples +#define BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) +//! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs +#define BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100) + +/*! + Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm. + + Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). + For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. + + For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., + "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014. + + This algorithm is currently NOT thread-safe. + */ +class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP { +public: + //! full constructor + BackgroundSubtractorSuBSENSE(float fRelLBSPThreshold = BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, + size_t nDescDistThresholdOffset = BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, + size_t nMinColorDistThreshold = BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD, + size_t nBGSamples = BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES, + size_t nRequiredBGSamples = BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES, + size_t nSamplesForMovingAvgs = BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + //! default destructor + virtual ~BackgroundSubtractorSuBSENSE(); + //! (re)initiaization method; needs to be called before starting background subtraction + virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); + //! refreshes all samples based on the last analyzed frame + virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate = false); + //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0) + virtual void apply(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride = 0); + //! returns a copy of the latest reconstructed background image + void getBackgroundImage(cv::OutputArray backgroundImage) const; + //! returns a copy of the latest reconstructed background descriptors image + void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; + +protected: + //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) + const size_t m_nMinColorDistThreshold; + //! absolute descriptor distance threshold offset + const size_t m_nDescDistThresholdOffset; + //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS) + const size_t m_nBGSamples; + //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS) + const size_t m_nRequiredBGSamples; + //! number of samples to use to compute the learning rate of moving averages + const size_t m_nSamplesForMovingAvgs; + //! last calculated non-zero desc ratio + float m_fLastNonZeroDescRatio; + //! specifies whether Tmin/Tmax scaling is enabled or not + bool m_bLearningRateScalingEnabled; + //! current learning rate caps + float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap; + //! current kernel size for median blur post-proc filtering + int m_nMedianBlurKernelSize; + //! specifies the px update spread range + bool m_bUse3x3Spread; + //! specifies the downsampled frame size used for cam motion analysis + cv::Size m_oDownSampledFrameSize; + + //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS) + std::vector<cv::Mat> m_voBGColorSamples; + //! background model descriptors samples + std::vector<cv::Mat> m_voBGDescSamples; + + //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) + cv::Mat m_oUpdateRateFrame; + //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) + cv::Mat m_oDistThresholdFrame; + //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) + cv::Mat m_oVariationModulatorFrame; + //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence) + cv::Mat m_oMeanLastDistFrame; + //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') + cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; + //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally) + cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; + //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) + cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; + //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) + cv::Mat m_oUnstableRegionMask; + //! per-pixel blink detection map ('Z(x)') + cv::Mat m_oBlinksFrame; + //! pre-allocated matrix used to downsample the input frame when needed + cv::Mat m_oDownSampledFrame_MotionAnalysis; + //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) + cv::Mat m_oLastRawFGMask; + + //! pre-allocated CV_8UC1 matrices used to speed up morph ops + cv::Mat m_oFGMask_PreFlood; + cv::Mat m_oFGMask_FloodedHoles; + cv::Mat m_oLastFGMask_dilated; + cv::Mat m_oLastFGMask_dilated_inverted; + cv::Mat m_oCurrRawFGBlinkMask; + cv::Mat m_oLastRawFGBlinkMask; +}; + diff --git a/package_bgs/LBSP/DistanceUtils.h b/package_bgs/LBSP/DistanceUtils.h new file mode 100644 index 0000000..9eabca4 --- /dev/null +++ b/package_bgs/LBSP/DistanceUtils.h @@ -0,0 +1,332 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <opencv2/core/types_c.h> + +//! computes the L1 distance between two integer values +template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) { + return (size_t)abs((int)a-b); +} + +//! computes the L1 distance between two float values +template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) { + return fabs((float)a-(float)b); +} + +//! computes the L1 distance between two generic arrays +template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) { + decltype(L1dist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L1dist(a[c],b[c]); + return oResult; +} + +//! computes the L1 distance between two generic arrays +template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) { + decltype(L1dist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L1dist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L1dist<nChannels>(a+n,b+n); + } + return oResult; +} + +//! computes the L1 distance between two generic arrays +template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L1dist<1>(a,b,nElements,m); + case 2: return L1dist<2>(a,b,nElements,m); + case 3: return L1dist<3>(a,b,nElements,m); + case 4: return L1dist<4>(a,b,nElements,m); + default: return 0; + } +} + +//! computes the L1 distance between two opencv vectors +template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L1dist<nChannels>(a_array,b_array); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//! computes the squared L2 distance between two generic variables +template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) { + auto oResult = L1dist(a,b); + return oResult*oResult; +} + +//! computes the squared L2 distance between two generic arrays +template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) { + decltype(L2sqrdist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L2sqrdist(a[c],b[c]); + return oResult; +} + +//! computes the squared L2 distance between two generic arrays +template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) { + decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + return oResult; +} + +//! computes the squared L2 distance between two generic arrays +template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L2sqrdist<1>(a,b,nElements,m); + case 2: return L2sqrdist<2>(a,b,nElements,m); + case 3: return L2sqrdist<3>(a,b,nElements,m); + case 4: return L2sqrdist<4>(a,b,nElements,m); + default: return 0; + } +} + +//! computes the squared L2 distance between two opencv vectors +template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L2sqrdist<nChannels>(a_array,b_array); +} + +//! computes the L2 distance between two generic arrays +template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) { + decltype(L2sqrdist(*a,*b)) oResult = 0; + for(size_t c=0; c<nChannels; ++c) + oResult += L2sqrdist(a[c],b[c]); + return sqrt((float)oResult); +} + +//! computes the L2 distance between two generic arrays +template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) { + decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += L2sqrdist<nChannels>(a+n,b+n); + } + return sqrt((float)oResult); +} + +//! computes the squared L2 distance between two generic arrays +template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) { + CV_Assert(nChannels>0 && nChannels<=4); + switch(nChannels) { + case 1: return L2dist<1>(a,b,nElements,m); + case 2: return L2dist<2>(a,b,nElements,m); + case 3: return L2dist<3>(a,b,nElements,m); + case 4: return L2dist<4>(a,b,nElements,m); + default: return 0; + } +} + +//! computes the L2 distance between two opencv vectors +template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return L2dist<nChannels>(a_array,b_array); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//! computes the color distortion between two integer arrays +template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) { + static_assert(nChannels>1,"cdist: requires more than one channel"); + size_t curr_sqr = 0; + bool bSkip = true; + for(size_t c=0; c<nChannels; ++c) { + curr_sqr += curr[c]*curr[c]; + bSkip = bSkip&(bg[c]<=0); + } + if(bSkip) + return (size_t)sqrt((float)curr_sqr); + size_t bg_sqr = 0; + size_t mix = 0; + for(size_t c=0; c<nChannels; ++c) { + bg_sqr += bg[c]*bg[c]; + mix += curr[c]*bg[c]; + } + return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr)); +} + +//! computes the color distortion between two float arrays +template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) { + static_assert(nChannels>1,"cdist: requires more than one channel"); + float curr_sqr = 0; + bool bSkip = true; + for(size_t c=0; c<nChannels; ++c) { + curr_sqr += (float)curr[c]*curr[c]; + bSkip = bSkip&(bg[c]<=0); + } + if(bSkip) + return sqrt(curr_sqr); + float bg_sqr = 0; + float mix = 0; + for(size_t c=0; c<nChannels; ++c) { + bg_sqr += (float)bg[c]*bg[c]; + mix += (float)curr[c]*bg[c]; + } + return sqrt(curr_sqr-((mix*mix)/bg_sqr)); +} + +//! computes the color distortion between two generic arrays +template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) { + decltype(cdist<nChannels>(a,b)) oResult = 0; + size_t nTotElements = nElements*nChannels; + if(m) { + for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) + if(m[i]) + oResult += cdist<nChannels>(a+n,b+n); + } + else { + for(size_t n=0; n<nTotElements; n+=nChannels) + oResult += cdist<nChannels>(a+n,b+n); + } + return oResult; +} + +//! computes the color distortion between two generic arrays +template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) { + CV_Assert(nChannels>1 && nChannels<=4); + switch(nChannels) { + case 2: return cdist<2>(a,b,nElements,m); + case 3: return cdist<3>(a,b,nElements,m); + case 4: return cdist<4>(a,b,nElements,m); + default: return 0; + } +} + +//! computes the color distortion between two opencv vectors +template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) { + T a_array[nChannels], b_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) { + a_array[c] = a[(int)c]; + b_array[c] = b[(int)c]; + } + return cdist<nChannels>(a_array,b_array); +} + +//! computes a color distortion-distance mix using two generic distances +template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) { + return (oL1Distance/2+oCDistortion*4); +} + +//! computes a color distoirtion-distance mix using two generic arrays +template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) { + return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); +} + +template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) { + return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//! popcount LUT for 8-bit vectors +static const uchar popcount_LUT8[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +//! computes the population count of an N-byte vector using an 8-bit popcount LUT +template<typename T> static inline size_t popcount(T x) { + size_t nBytes = sizeof(T); + size_t nResult = 0; + for(size_t l=0; l<nBytes; ++l) + nResult += popcount_LUT8[(uchar)(x>>l*8)]; + return nResult; +} + +//! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT +template<typename T> static inline size_t hdist(T a, T b) { + return popcount(a^b); +} + +//! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT +template<typename T> static inline size_t gdist(T a, T b) { + return L1dist(popcount(a),popcount(b)); +} + +//! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT +template<size_t nChannels, typename T> static inline size_t popcount(const T* x) { + size_t nBytes = sizeof(T); + size_t nResult = 0; + for(size_t c=0; c<nChannels; ++c) + for(size_t l=0; l<nBytes; ++l) + nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)]; + return nResult; +} + +//! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT +template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) { + T xor_array[nChannels]; + for(size_t c=0; c<nChannels; ++c) + xor_array[c] = a[c]^b[c]; + return popcount<nChannels>(xor_array); +} + +//! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT +template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) { + return L1dist(popcount<nChannels>(a),popcount<nChannels>(b)); +} diff --git a/package_bgs/LBSP/LBSP.cpp b/package_bgs/LBSP/LBSP.cpp new file mode 100644 index 0000000..4ec17b9 --- /dev/null +++ b/package_bgs/LBSP/LBSP.cpp @@ -0,0 +1,334 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "LBSP.h" + +LBSP::LBSP(size_t nThreshold) + : m_bOnlyUsingAbsThreshold(true) + , m_fRelThreshold(0) // unused + , m_nThreshold(nThreshold) + , m_oRefImage() {} + +LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset) + : m_bOnlyUsingAbsThreshold(false) + , m_fRelThreshold(fRelThreshold) + , m_nThreshold(nThresholdOffset) + , m_oRefImage() { + CV_Assert(m_fRelThreshold >= 0); +} + +LBSP::~LBSP() {} + +void LBSP::read(const cv::FileNode& /*fn*/) { + // ... = fn["..."]; +} + +void LBSP::write(cv::FileStorage& /*fs*/) const { + //fs << "..." << ...; +} + +void LBSP::setReference(const cv::Mat& img) { + CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); + m_oRefImage = img; +} + +int LBSP::descriptorSize() const { + return DESC_SIZE; +} + +int LBSP::descriptorType() const { + return CV_16U; +} + +bool LBSP::isUsingRelThreshold() const { + return !m_bOnlyUsingAbsThreshold; +} + +float LBSP::getRelThreshold() const { + return m_fRelThreshold; +} + +size_t LBSP::getAbsThreshold() const { + return m_nThreshold; +} + +static inline void lbsp_computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } +} + +static inline void lbsp_computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } +} + +static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } +} + +static inline void lbsp_computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } +} + +void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + lbsp_computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); +} + +void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { + CV_Assert(voImageCollection.size() == vvoPointCollection.size()); + voDescCollection.resize(voImageCollection.size()); + for (size_t i = 0; i < voImageCollection.size(); i++) + compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); +} + +void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + lbsp_computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); +} + +void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { + CV_DbgAssert(!voKeypoints.empty()); + CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); + CV_DbgAssert(oSize.width > 0 && oSize.height > 0); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); + const size_t nChannels = (size_t)oDescriptors.channels(); + const size_t nKeyPoints = voKeypoints.size(); + if (nChannels == 1) { + oOutput.create(oSize, CV_16UC1); + oOutput = cv::Scalar_<ushort>(0); + for (size_t k = 0; k < nKeyPoints; ++k) + oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); + } + else { //nChannels==3 + oOutput.create(oSize, CV_16UC3); + oOutput = cv::Scalar_<ushort>(0, 0, 0); + for (size_t k = 0; k < nKeyPoints; ++k) { + ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); + const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); + const size_t idx = 3 * (int)voKeypoints[k].pt.x; + for (size_t n = 0; n < 3; ++n) + output_ptr[idx + n] = desc_ptr[n]; + } + } +} + +void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { + CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); + CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); + CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); + CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); + const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); + const size_t nChannels = CV_MAT_CN(oDesc1.type()); + const size_t _step_row = oDesc1.step.p[0]; + if (nChannels == 1) { + oOutput.create(oDesc1.size(), CV_8UC1); + oOutput = cv::Scalar(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + for (int j = 0; j < oDesc1.cols; ++j) + oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); + } + } + else { //nChannels==3 + if (bForceMergeChannels) + oOutput.create(oDesc1.size(), CV_8UC1); + else + oOutput.create(oDesc1.size(), CV_8UC3); + oOutput = cv::Scalar::all(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; + for (int j = 0; j < oDesc1.cols; ++j) { + for (size_t n = 0; n < 3; ++n) { + const size_t idx2 = 3 * j + n; + if (bForceMergeChannels) + output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); + else + output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); + } + } + } + } +} + +void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); +} + +void LBSP::validateROI(cv::Mat& oROI) { + CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); + cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); + const size_t nBorderSize = PATCH_SIZE / 2; + const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); + cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); + oROI = oROI_new; +} diff --git a/package_bgs/LBSP/LBSP.h b/package_bgs/LBSP/LBSP.h new file mode 100644 index 0000000..c908eaa --- /dev/null +++ b/package_bgs/LBSP/LBSP.h @@ -0,0 +1,134 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> +#include "DistanceUtils.h" + +/*! + Local Binary Similarity Pattern (LBSP) feature extractor + + Note 1: both grayscale and RGB/BGR images may be used with this extractor. + Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...). + + For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local + Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ +class LBSP : public cv::DescriptorExtractor { +public: + //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons + LBSP(size_t nThreshold); + //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons + LBSP(float fRelThreshold, size_t nThresholdOffset = 0); + //! default destructor + virtual ~LBSP(); + //! loads extractor params from the specified file node @@@@ not impl + virtual void read(const cv::FileNode&); + //! writes extractor params to the specified file storage @@@@ not impl + virtual void write(cv::FileStorage&) const; + //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) + virtual void setReference(const cv::Mat&); + //! returns the current descriptor size, in bytes + virtual int descriptorSize() const; + //! returns the current descriptor data type + virtual int descriptorType() const; + //! returns whether this extractor is using a relative threshold or not + virtual bool isUsingRelThreshold() const; + //! returns the current relative threshold used for comparisons (-1 = invalid/not used) + virtual float getRelThreshold() const; + //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) + virtual size_t getAbsThreshold() const; + + //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) + void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) + void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) + inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC1); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_1ch.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_3ch1t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) + inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); + CV_DbgAssert(LBSP::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP::PATCH_SIZE / 2 && _y >= (int)LBSP::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_s3ch.i" + } + + //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations + static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); + //! utility function, used to illustrate the difference between two descriptor images + static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); + //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border + static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); + //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border + static void validateROI(cv::Mat& oROI); + //! utility, specifies the pixel size of the pattern used (width and height) + static const size_t PATCH_SIZE = 5; + //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') + static const size_t DESC_SIZE = 2; + +protected: + //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output + virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + + const bool m_bOnlyUsingAbsThreshold; + const float m_fRelThreshold; + const size_t m_nThreshold; + cv::Mat m_oRefImage; +}; diff --git a/package_bgs/LBSP/LBSP_.cpp b/package_bgs/LBSP/LBSP_.cpp new file mode 100644 index 0000000..ff5c8e8 --- /dev/null +++ b/package_bgs/LBSP/LBSP_.cpp @@ -0,0 +1,334 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "LBSP_.h" + +LBSP_::LBSP_(size_t nThreshold) + : m_bOnlyUsingAbsThreshold(true) + , m_fRelThreshold(0) // unused + , m_nThreshold(nThreshold) + , m_oRefImage() {} + +LBSP_::LBSP_(float fRelThreshold, size_t nThresholdOffset) + : m_bOnlyUsingAbsThreshold(false) + , m_fRelThreshold(fRelThreshold) + , m_nThreshold(nThresholdOffset) + , m_oRefImage() { + CV_Assert(m_fRelThreshold >= 0); +} + +LBSP_::~LBSP_() {} + +void LBSP_::read(const cv::FileNode& /*fn*/) { + // ... = fn["..."]; +} + +void LBSP_::write(cv::FileStorage& /*fs*/) const { + //fs << "..." << ...; +} + +void LBSP_::setReference(const cv::Mat& img) { + CV_DbgAssert(img.empty() || img.type() == CV_8UC1 || img.type() == CV_8UC3); + m_oRefImage = img; +} + +int LBSP_::descriptorSize() const { + return DESC_SIZE; +} + +int LBSP_::descriptorType() const { + return CV_16U; +} + +bool LBSP_::isUsingRelThreshold() const { + return !m_bOnlyUsingAbsThreshold; +} + +float LBSP_::getRelThreshold() const { + return m_fRelThreshold; +} + +size_t LBSP_::getAbsThreshold() const { + return m_nThreshold; +} + +static inline void LBSP__computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } +} + +static inline void LBSP__computeImpl(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create((int)nKeyPoints, 1, CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>((int)k); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create((int)nKeyPoints, 1, CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * k)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } +} + +static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + size_t _t) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); +#include "LBSP_16bits_dbcross_3ch1t.i" + } + } +} + +static inline void LBSP__computeImpl2(const cv::Mat& oInputImg, + const cv::Mat& oRefImg, + const std::vector<cv::KeyPoint>& voKeyPoints, + cv::Mat& oDesc, + float fThreshold, + size_t nThresholdOffset) { + CV_DbgAssert(oRefImg.empty() || (oRefImg.size == oInputImg.size && oRefImg.type() == oInputImg.type())); + CV_DbgAssert(oInputImg.type() == CV_8UC1 || oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(fThreshold >= 0); + const size_t nChannels = (size_t)oInputImg.channels(); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* _data = oInputImg.data; + const uchar* _refdata = oRefImg.empty() ? oInputImg.data : oRefImg.data; + const size_t nKeyPoints = voKeyPoints.size(); + if (nChannels == 1) { + oDesc.create(oInputImg.size(), CV_16UC1); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar _ref = _refdata[_step_row*(_y)+_x]; + ushort& _res = oDesc.at<ushort>(_y, _x); + const size_t _t = (size_t)(_ref*fThreshold) + nThresholdOffset; +#include "LBSP_16bits_dbcross_1ch.i" + } + } + else { //nChannels==3 + oDesc.create(oInputImg.size(), CV_16UC3); + for (size_t k = 0; k < nKeyPoints; ++k) { + const int _x = (int)voKeyPoints[k].pt.x; + const int _y = (int)voKeyPoints[k].pt.y; + const uchar* _ref = _refdata + _step_row*(_y)+3 * (_x); + ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0] * _y + oDesc.step.p[1] * _x)); + const size_t _t[3] = { (size_t)(_ref[0] * fThreshold) + nThresholdOffset,(size_t)(_ref[1] * fThreshold) + nThresholdOffset,(size_t)(_ref[2] * fThreshold) + nThresholdOffset }; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + } +} + +void LBSP_::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + LBSP__computeImpl2(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); +} + +void LBSP_::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { + CV_Assert(voImageCollection.size() == vvoPointCollection.size()); + voDescCollection.resize(voImageCollection.size()); + for (size_t i = 0; i < voImageCollection.size(); i++) + compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); +} + +void LBSP_::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { + CV_Assert(!oImage.empty()); + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImage.size(), PATCH_SIZE / 2); + cv::KeyPointsFilter::runByKeypointSize(voKeypoints, std::numeric_limits<float>::epsilon()); + if (voKeypoints.empty()) { + oDescriptors.release(); + return; + } + if (m_bOnlyUsingAbsThreshold) + LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_nThreshold); + else + LBSP__computeImpl(oImage, m_oRefImage, voKeypoints, oDescriptors, m_fRelThreshold, m_nThreshold); +} + +void LBSP_::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { + CV_DbgAssert(!voKeypoints.empty()); + CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols == 1); + CV_DbgAssert(oSize.width > 0 && oSize.height > 0); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDescriptors.type() == CV_16UC1 || oDescriptors.type() == CV_16UC3); + const size_t nChannels = (size_t)oDescriptors.channels(); + const size_t nKeyPoints = voKeypoints.size(); + if (nChannels == 1) { + oOutput.create(oSize, CV_16UC1); + oOutput = cv::Scalar_<ushort>(0); + for (size_t k = 0; k < nKeyPoints; ++k) + oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); + } + else { //nChannels==3 + oOutput.create(oSize, CV_16UC3); + oOutput = cv::Scalar_<ushort>(0, 0, 0); + for (size_t k = 0; k < nKeyPoints; ++k) { + ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0] * (int)voKeypoints[k].pt.y); + const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0] * k); + const size_t idx = 3 * (int)voKeypoints[k].pt.x; + for (size_t n = 0; n < 3; ++n) + output_ptr[idx + n] = desc_ptr[n]; + } + } +} + +void LBSP_::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { + CV_DbgAssert(oDesc1.size() == oDesc2.size() && oDesc1.type() == oDesc2.type()); + CV_DbgAssert(DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(oDesc1.type() == CV_16UC1 || oDesc1.type() == CV_16UC3); + CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type()) == CV_16U); + CV_DbgAssert(DESC_SIZE * 8 <= UCHAR_MAX); + CV_DbgAssert(oDesc1.step.p[0] == oDesc2.step.p[0] && oDesc1.step.p[1] == oDesc2.step.p[1]); + const float fScaleFactor = (float)UCHAR_MAX / (DESC_SIZE * 8); + const size_t nChannels = CV_MAT_CN(oDesc1.type()); + const size_t _step_row = oDesc1.step.p[0]; + if (nChannels == 1) { + oOutput.create(oDesc1.size(), CV_8UC1); + oOutput = cv::Scalar(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + for (int j = 0; j < oDesc1.cols; ++j) + oOutput.at<uchar>(i, j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j], desc2_ptr[j])); + } + } + else { //nChannels==3 + if (bForceMergeChannels) + oOutput.create(oDesc1.size(), CV_8UC1); + else + oOutput.create(oDesc1.size(), CV_8UC3); + oOutput = cv::Scalar::all(0); + for (int i = 0; i < oDesc1.rows; ++i) { + const size_t idx = _step_row*i; + const ushort* const desc1_ptr = (ushort*)(oDesc1.data + idx); + const ushort* const desc2_ptr = (ushort*)(oDesc2.data + idx); + uchar* output_ptr = oOutput.data + oOutput.step.p[0] * i; + for (int j = 0; j < oDesc1.cols; ++j) { + for (size_t n = 0; n < 3; ++n) { + const size_t idx2 = 3 * j + n; + if (bForceMergeChannels) + output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])) / 3); + else + output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2], desc2_ptr[idx2])); + } + } + } + } +} + +void LBSP_::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { + cv::KeyPointsFilter::runByImageBorder(voKeypoints, oImgSize, PATCH_SIZE / 2); +} + +void LBSP_::validateROI(cv::Mat& oROI) { + CV_Assert(!oROI.empty() && oROI.type() == CV_8UC1); + cv::Mat oROI_new(oROI.size(), CV_8UC1, cv::Scalar_<uchar>(0)); + const size_t nBorderSize = PATCH_SIZE / 2; + const cv::Rect nROI_inner(nBorderSize, nBorderSize, oROI.cols - nBorderSize * 2, oROI.rows - nBorderSize * 2); + cv::Mat(oROI, nROI_inner).copyTo(cv::Mat(oROI_new, nROI_inner)); + oROI = oROI_new; +} diff --git a/package_bgs/LBSP/LBSP_.h b/package_bgs/LBSP/LBSP_.h new file mode 100644 index 0000000..819174a --- /dev/null +++ b/package_bgs/LBSP/LBSP_.h @@ -0,0 +1,134 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <opencv2/core/core.hpp> +#include <opencv2/imgproc/imgproc.hpp> +#include <opencv2/features2d/features2d.hpp> +#include "DistanceUtils.h" + +/*! + Local Binary Similarity Pattern (LBSP) feature extractor + + Note 1: both grayscale and RGB/BGR images may be used with this extractor. + Note 2: using LBSP_::compute2(...) is logically equivalent to using LBSP_::compute(...) followed by LBSP_::reshapeDesc(...). + + For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local + Binary Similarity Patterns", in CRV 2013. + + This algorithm is currently NOT thread-safe. + */ +class LBSP_ : public cv::Feature2D { +public: + //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons + LBSP_(size_t nThreshold); + //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons + LBSP_(float fRelThreshold, size_t nThresholdOffset = 0); + //! default destructor + virtual ~LBSP_(); + //! loads extractor params from the specified file node @@@@ not impl + virtual void read(const cv::FileNode&); + //! writes extractor params to the specified file storage @@@@ not impl + virtual void write(cv::FileStorage&) const; + //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) + virtual void setReference(const cv::Mat&); + //! returns the current descriptor size, in bytes + virtual int descriptorSize() const; + //! returns the current descriptor data type + virtual int descriptorType() const; + //! returns whether this extractor is using a relative threshold or not + virtual bool isUsingRelThreshold() const; + //! returns the current relative threshold used for comparisons (-1 = invalid/not used) + virtual float getRelThreshold() const; + //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) + virtual size_t getAbsThreshold() const; + + //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) + void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + //! batch version of LBSP_::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) + void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) + inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC1); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_1ch.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_3ch3t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) + inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_3ch1t.i" + } + + //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) + inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { + CV_DbgAssert(!oInputImg.empty()); + CV_DbgAssert(oInputImg.type() == CV_8UC3 && _c < 3); + CV_DbgAssert(LBSP_::DESC_SIZE == 2); // @@@ also relies on a constant desc size + CV_DbgAssert(_x >= (int)LBSP_::PATCH_SIZE / 2 && _y >= (int)LBSP_::PATCH_SIZE / 2); + CV_DbgAssert(_x < oInputImg.cols - (int)LBSP_::PATCH_SIZE / 2 && _y < oInputImg.rows - (int)LBSP_::PATCH_SIZE / 2); + const size_t _step_row = oInputImg.step.p[0]; + const uchar* const _data = oInputImg.data; +#include "LBSP_16bits_dbcross_s3ch.i" + } + + //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations + static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); + //! utility function, used to illustrate the difference between two descriptor images + static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels = false); + //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border + static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); + //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border + static void validateROI(cv::Mat& oROI); + //! utility, specifies the pixel size of the pattern used (width and height) + static const size_t PATCH_SIZE = 5; + //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') + static const size_t DESC_SIZE = 2; + +protected: + //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output + virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; + + const bool m_bOnlyUsingAbsThreshold; + const float m_fRelThreshold; + const size_t m_nThreshold; + cv::Mat m_oRefImage; +}; diff --git a/package_bgs/pl/LBSP_16bits_dbcross_1ch.i b/package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i similarity index 100% rename from package_bgs/pl/LBSP_16bits_dbcross_1ch.i rename to package_bgs/LBSP/LBSP_16bits_dbcross_1ch.i diff --git a/package_bgs/pl/LBSP_16bits_dbcross_3ch1t.i b/package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i similarity index 100% rename from package_bgs/pl/LBSP_16bits_dbcross_3ch1t.i rename to package_bgs/LBSP/LBSP_16bits_dbcross_3ch1t.i diff --git a/package_bgs/pl/LBSP_16bits_dbcross_3ch3t.i b/package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i similarity index 100% rename from package_bgs/pl/LBSP_16bits_dbcross_3ch3t.i rename to package_bgs/LBSP/LBSP_16bits_dbcross_3ch3t.i diff --git a/package_bgs/pl/LBSP_16bits_dbcross_s3ch.i b/package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i similarity index 100% rename from package_bgs/pl/LBSP_16bits_dbcross_s3ch.i rename to package_bgs/LBSP/LBSP_16bits_dbcross_s3ch.i diff --git a/package_bgs/LBSP/RandUtils.h b/package_bgs/LBSP/RandUtils.h new file mode 100644 index 0000000..f676ca0 --- /dev/null +++ b/package_bgs/LBSP/RandUtils.h @@ -0,0 +1,112 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +/*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)' +static const int s_nSamplesInitPatternWidth = 3; +static const int s_nSamplesInitPatternHeight = 3; +static const int s_nSamplesInitPatternTot = 256; +static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { + {19, 32, 19,}, + {32, 52, 32,}, + {19, 32, 19,}, +};*/ + +// gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)' +static const int s_nSamplesInitPatternWidth = 7; +static const int s_nSamplesInitPatternHeight = 7; +static const int s_nSamplesInitPatternTot = 512; +static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { + {2, 4, 6, 7, 6, 4, 2,}, + {4, 8, 12, 14, 12, 8, 4,}, + {6, 12, 21, 25, 21, 12, 6,}, + {7, 14, 25, 28, 25, 14, 7,}, + {6, 12, 21, 25, 21, 12, 6,}, + {4, 8, 12, 14, 12, 8, 4,}, + {2, 4, 6, 7, 6, 4, 2,}, +}; + +//! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check. +static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = 1+rand()%s_nSamplesInitPatternTot; + for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) { + for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) { + r -= s_anSamplesInitPattern[y_sample][x_sample]; + if(r<=0) + goto stop; + } + } +stop: + x_sample += x_orig-s_nSamplesInitPatternWidth/2; + y_sample += y_orig-s_nSamplesInitPatternHeight/2; + if(x_sample<border) + x_sample = border; + else if(x_sample>=imgsize.width-border) + x_sample = imgsize.width-border-1; + if(y_sample<border) + y_sample = border; + else if(y_sample>=imgsize.height-border) + y_sample = imgsize.height-border-1; +} + +// simple 8-connected (3x3) neighbors pattern +static const int s_anNeighborPatternSize_3x3 = 8; +static const int s_anNeighborPattern_3x3[8][2] = { + {-1, 1}, { 0, 1}, { 1, 1}, + {-1, 0}, { 1, 0}, + {-1,-1}, { 0,-1}, { 1,-1}, +}; + +//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. +static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = rand()%s_anNeighborPatternSize_3x3; + x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0]; + y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1]; + if(x_neighbor<border) + x_neighbor = border; + else if(x_neighbor>=imgsize.width-border) + x_neighbor = imgsize.width-border-1; + if(y_neighbor<border) + y_neighbor = border; + else if(y_neighbor>=imgsize.height-border) + y_neighbor = imgsize.height-border-1; +} + +// 5x5 neighbors pattern +static const int s_anNeighborPatternSize_5x5 = 24; +static const int s_anNeighborPattern_5x5[24][2] = { + {-2, 2}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 2}, + {-2, 1}, {-1, 1}, { 0, 1}, { 1, 1}, { 2, 1}, + {-2, 0}, {-1, 0}, { 1, 0}, { 2, 0}, + {-2,-1}, {-1,-1}, { 0,-1}, { 1,-1}, { 2,-1}, + {-2,-2}, {-1,-2}, { 0,-2}, { 1,-2}, { 2,-2}, +}; + +//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. +static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { + int r = rand()%s_anNeighborPatternSize_5x5; + x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0]; + y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1]; + if(x_neighbor<border) + x_neighbor = border; + else if(x_neighbor>=imgsize.width-border) + x_neighbor = imgsize.width-border-1; + if(y_neighbor<border) + y_neighbor = border; + else if(y_neighbor>=imgsize.height-border) + y_neighbor = imgsize.height-border-1; +} diff --git a/package_bgs/lb/LBSimpleGaussian.cpp b/package_bgs/LBSimpleGaussian.cpp similarity index 61% rename from package_bgs/lb/LBSimpleGaussian.cpp rename to package_bgs/LBSimpleGaussian.cpp index f0ce6fc..9ce071c 100644 --- a/package_bgs/lb/LBSimpleGaussian.cpp +++ b/package_bgs/LBSimpleGaussian.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "LBSimpleGaussian.h" -LBSimpleGaussian::LBSimpleGaussian() : firstTime(true), showOutput(true), sensitivity(66), noiseVariance(162), learningRate(18) +using namespace bgslibrary::algorithms; + +LBSimpleGaussian::LBSimpleGaussian() : + sensitivity(66), noiseVariance(162), learningRate(18) { std::cout << "LBSimpleGaussian()" << std::endl; + setup("./config/LBSimpleGaussian.xml"); } LBSimpleGaussian::~LBSimpleGaussian() @@ -29,55 +33,47 @@ LBSimpleGaussian::~LBSimpleGaussian() void LBSimpleGaussian::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - loadConfig(); - IplImage *frame = new IplImage(img_input); - - if(firstTime) - { - saveConfig(); + if (firstTime) + { int w = cvGetSize(frame).width; int h = cvGetSize(frame).height; - m_pBGModel = new BGModelGauss(w,h); + m_pBGModel = new BGModelGauss(w, h); m_pBGModel->InitModel(frame); } - - m_pBGModel->setBGModelParameter(0,sensitivity); - m_pBGModel->setBGModelParameter(1,noiseVariance); - m_pBGModel->setBGModelParameter(2,learningRate); + + m_pBGModel->setBGModelParameter(0, sensitivity); + m_pBGModel->setBGModelParameter(1, noiseVariance); + m_pBGModel->setBGModelParameter(2, learningRate); m_pBGModel->UpdateModel(frame); - img_foreground = cv::Mat(m_pBGModel->GetFG()); - img_background = cv::Mat(m_pBGModel->GetBG()); - - if(showOutput) + img_foreground = cv::cvarrToMat(m_pBGModel->GetFG()); + img_background = cv::cvarrToMat(m_pBGModel->GetBG()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { cv::imshow("SG Mask", img_foreground); cv::imshow("SG Model", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); - + delete frame; - + firstTime = false; } -//void LBSimpleGaussian::finish(void) -//{ -// delete m_pBGModel; -//} - void LBSimpleGaussian::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBSimpleGaussian.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "sensitivity", sensitivity); cvWriteInt(fs, "noiseVariance", noiseVariance); @@ -89,12 +85,12 @@ void LBSimpleGaussian::saveConfig() void LBSimpleGaussian::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/LBSimpleGaussian.xml", 0, CV_STORAGE_READ); - - sensitivity = cvReadIntByName(fs, 0, "sensitivity", 66); - noiseVariance = cvReadIntByName(fs, 0, "noiseVariance", 162); - learningRate = cvReadIntByName(fs, 0, "learningRate", 18); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + sensitivity = cvReadIntByName(fs, nullptr, "sensitivity", 66); + noiseVariance = cvReadIntByName(fs, nullptr, "noiseVariance", 162); + learningRate = cvReadIntByName(fs, nullptr, "learningRate", 18); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/lb/LBSimpleGaussian.h b/package_bgs/LBSimpleGaussian.h similarity index 57% rename from package_bgs/lb/LBSimpleGaussian.h rename to package_bgs/LBSimpleGaussian.h index bfefd3e..5c82923 100644 --- a/package_bgs/lb/LBSimpleGaussian.h +++ b/package_bgs/LBSimpleGaussian.h @@ -16,39 +16,33 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "BGModelGauss.h" - -#include "../IBGS.h" +#include "IBGS.h" +#include "lb/BGModelGauss.h" using namespace lb_library; using namespace lb_library::SimpleGaussian; -class LBSimpleGaussian : public IBGS +namespace bgslibrary { -private: - bool firstTime; - bool showOutput; - - BGModel* m_pBGModel; - int sensitivity; - int noiseVariance; - int learningRate; - - cv::Mat img_foreground; - cv::Mat img_background; - -public: - LBSimpleGaussian(); - ~LBSimpleGaussian(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - //void finish(void); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file + namespace algorithms + { + class LBSimpleGaussian : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int noiseVariance; + int learningRate; + + public: + LBSimpleGaussian(); + ~LBSimpleGaussian(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/LOBSTER.cpp b/package_bgs/LOBSTER.cpp new file mode 100644 index 0000000..dc48a63 --- /dev/null +++ b/package_bgs/LOBSTER.cpp @@ -0,0 +1,98 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "LOBSTER.h" + +using namespace bgslibrary::algorithms; + +LOBSTER::LOBSTER() : + pLOBSTER(nullptr), + fRelLBSPThreshold(BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), + nLBSPThresholdOffset(BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD), + nDescDistThreshold(BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD), + nColorDistThreshold(BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD), + nBGSamples(BGSLOBSTER_DEFAULT_NB_BG_SAMPLES), + nRequiredBGSamples(BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES) +{ + std::cout << "LOBSTER()" << std::endl; + setup("./config/LOBSTER.xml"); +} + +LOBSTER::~LOBSTER() +{ + if (pLOBSTER) + delete pLOBSTER; + std::cout << "~LOBSTER()" << std::endl; +} + +void LOBSTER::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) + { + pLOBSTER = new BackgroundSubtractorLOBSTER( + fRelLBSPThreshold, nLBSPThresholdOffset, nDescDistThreshold, + nColorDistThreshold, nBGSamples, nRequiredBGSamples); + + pLOBSTER->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pLOBSTER->apply(img_input, img_foreground); + pLOBSTER->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + imshow("LOBSTER FG", img_foreground); + imshow("LOBSTER BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void LOBSTER::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); + cvWriteInt(fs, "nLBSPThresholdOffset", nLBSPThresholdOffset); + cvWriteInt(fs, "nDescDistThreshold", nDescDistThreshold); + cvWriteInt(fs, "nColorDistThreshold", nColorDistThreshold); + cvWriteInt(fs, "nBGSamples", nBGSamples); + cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void LOBSTER::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); + nLBSPThresholdOffset = cvReadIntByName(fs, nullptr, "nLBSPThresholdOffset", BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD); + nDescDistThreshold = cvReadIntByName(fs, nullptr, "nDescDistThreshold", BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD); + nColorDistThreshold = cvReadIntByName(fs, nullptr, "nColorDistThreshold", BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD); + nBGSamples = cvReadIntByName(fs, nullptr, "nBGSamples", BGSLOBSTER_DEFAULT_NB_BG_SAMPLES); + nRequiredBGSamples = cvReadIntByName(fs, nullptr, "nRequiredBGSamples", BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/LOBSTER.h b/package_bgs/LOBSTER.h new file mode 100644 index 0000000..41ba882 --- /dev/null +++ b/package_bgs/LOBSTER.h @@ -0,0 +1,49 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "LBSP/BackgroundSubtractorLOBSTER.h" + +namespace bgslibrary +{ + namespace algorithms + { + class LOBSTER : public IBGS + { + private: + BackgroundSubtractorLOBSTER* pLOBSTER; + + float fRelLBSPThreshold; + size_t nLBSPThresholdOffset; + size_t nDescDistThreshold; + size_t nColorDistThreshold; + size_t nBGSamples; + size_t nRequiredBGSamples; + + public: + LOBSTER(); + ~LOBSTER(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/MixtureOfGaussianV1BGS.cpp b/package_bgs/MixtureOfGaussianV1.cpp similarity index 53% rename from package_bgs/MixtureOfGaussianV1BGS.cpp rename to package_bgs/MixtureOfGaussianV1.cpp index 51d41eb..e56609a 100644 --- a/package_bgs/MixtureOfGaussianV1BGS.cpp +++ b/package_bgs/MixtureOfGaussianV1.cpp @@ -14,27 +14,27 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "MixtureOfGaussianV1BGS.h" +#include "MixtureOfGaussianV1.h" -MixtureOfGaussianV1BGS::MixtureOfGaussianV1BGS() : firstTime(true), alpha(0.05), enableThreshold(true), threshold(15), showOutput(true) +#if CV_MAJOR_VERSION == 2 + +using namespace bgslibrary::algorithms; + +MixtureOfGaussianV1::MixtureOfGaussianV1() : + alpha(0.05), enableThreshold(true), threshold(15) { - std::cout << "MixtureOfGaussianV1BGS()" << std::endl; + std::cout << "MixtureOfGaussianV1()" << std::endl; + setup("./config/MixtureOfGaussianV1.xml"); } -MixtureOfGaussianV1BGS::~MixtureOfGaussianV1BGS() +MixtureOfGaussianV1::~MixtureOfGaussianV1() { - std::cout << "~MixtureOfGaussianV1BGS()" << std::endl; + std::cout << "~MixtureOfGaussianV1()" << std::endl; } -void MixtureOfGaussianV1BGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void MixtureOfGaussianV1::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); //------------------------------------------------------------------ // BackgroundSubtractorMOG @@ -43,26 +43,30 @@ void MixtureOfGaussianV1BGS::process(const cv::Mat &img_input, cv::Mat &img_outp // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm. // // The class implements the algorithm described in: - // P. KadewTraKuPong and R. Bowden, - // An improved adaptive background mixture model for real-time tracking with shadow detection, + // P. KadewTraKuPong and R. Bowden, + // An improved adaptive background mixture model for real-time tracking with shadow detection, // Proc. 2nd European Workshp on Advanced Video-Based Surveillance Systems, 2001 //------------------------------------------------------------------ mog(img_input, img_foreground, alpha); - cv::Mat img_background; mog.getBackgroundImage(img_background); - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - if(showOutput) + if (img_foreground.empty()) + img_foreground = cv::Mat::zeros(img_input.size(), img_input.type()); + + if (img_background.empty()) + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) { - if (!img_foreground.empty()) - cv::imshow("GMM FG (KadewTraKuPong&Bowden)", img_foreground); - - if (!img_background.empty()) - cv::imshow("GMM BG (KadewTraKuPong&Bowden)", img_background); + cv::imshow("GMM FG (KadewTraKuPong&Bowden)", img_foreground); + cv::imshow("GMM BG (KadewTraKuPong&Bowden)", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -70,9 +74,9 @@ void MixtureOfGaussianV1BGS::process(const cv::Mat &img_input, cv::Mat &img_outp firstTime = false; } -void MixtureOfGaussianV1BGS::saveConfig() +void MixtureOfGaussianV1::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV1BGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "alpha", alpha); cvWriteInt(fs, "enableThreshold", enableThreshold); @@ -82,14 +86,15 @@ void MixtureOfGaussianV1BGS::saveConfig() cvReleaseFileStorage(&fs); } -void MixtureOfGaussianV1BGS::loadConfig() +void MixtureOfGaussianV1::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV1BGS.xml", 0, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, 0, "alpha", 0.05); - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } +#endif diff --git a/package_bgs/MixtureOfGaussianV1BGS.h b/package_bgs/MixtureOfGaussianV1.h similarity index 59% rename from package_bgs/MixtureOfGaussianV1BGS.h rename to package_bgs/MixtureOfGaussianV1.h index f735a13..e18dbdb 100644 --- a/package_bgs/MixtureOfGaussianV1BGS.h +++ b/package_bgs/MixtureOfGaussianV1.h @@ -16,32 +16,38 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once +#include "opencv2/core/version.hpp" +#if CV_MAJOR_VERSION == 2 + #include <iostream> #include <opencv2/opencv.hpp> - #include <opencv2/video/background_segm.hpp> #include "IBGS.h" -class MixtureOfGaussianV1BGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::BackgroundSubtractorMOG mog; - cv::Mat img_foreground; - double alpha; - bool enableThreshold; - int threshold; - bool showOutput; - -public: - MixtureOfGaussianV1BGS(); - ~MixtureOfGaussianV1BGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class MixtureOfGaussianV1 : public IBGS + { + private: + cv::BackgroundSubtractorMOG mog; + double alpha; + bool enableThreshold; + int threshold; + + public: + MixtureOfGaussianV1(); + ~MixtureOfGaussianV1(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} + +#endif diff --git a/package_bgs/MixtureOfGaussianV2BGS.cpp b/package_bgs/MixtureOfGaussianV2.cpp similarity index 60% rename from package_bgs/MixtureOfGaussianV2BGS.cpp rename to package_bgs/MixtureOfGaussianV2.cpp index 5ce33a3..085b1a9 100644 --- a/package_bgs/MixtureOfGaussianV2BGS.cpp +++ b/package_bgs/MixtureOfGaussianV2.cpp @@ -14,27 +14,31 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "MixtureOfGaussianV2BGS.h" +#include "MixtureOfGaussianV2.h" -MixtureOfGaussianV2BGS::MixtureOfGaussianV2BGS() : firstTime(true), alpha(0.05), enableThreshold(true), threshold(15), showOutput(true) +using namespace bgslibrary::algorithms; + +MixtureOfGaussianV2::MixtureOfGaussianV2() : + alpha(0.05), enableThreshold(true), threshold(15) { - std::cout << "MixtureOfGaussianV2BGS()" << std::endl; + std::cout << "MixtureOfGaussianV2()" << std::endl; + setup("./config/MixtureOfGaussianV2.xml"); } -MixtureOfGaussianV2BGS::~MixtureOfGaussianV2BGS() +MixtureOfGaussianV2::~MixtureOfGaussianV2() { - std::cout << "~MixtureOfGaussianV2BGS()" << std::endl; + std::cout << "~MixtureOfGaussianV2()" << std::endl; } -void MixtureOfGaussianV2BGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void MixtureOfGaussianV2::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); + init(img_input, img_output, img_bgmodel); - if(firstTime) - saveConfig(); + if (firstTime) { +#if CV_MAJOR_VERSION == 3 + mog = cv::createBackgroundSubtractorMOG2(); +#endif + } //------------------------------------------------------------------ // BackgroundSubtractorMOG2 @@ -43,29 +47,34 @@ void MixtureOfGaussianV2BGS::process(const cv::Mat &img_input, cv::Mat &img_outp // Gaussian Mixture-based Backbround/Foreground Segmentation Algorithm. // // The class implements the Gaussian mixture model background subtraction described in: - // (1) Z.Zivkovic, Improved adaptive Gausian mixture model for background subtraction, International Conference Pattern Recognition, UK, August, 2004, + // (1) Z.Zivkovic, Improved adaptive Gausian mixture model for background subtraction, International Conference Pattern Recognition, UK, August, 2004, // The code is very fast and performs also shadow detection. Number of Gausssian components is adapted per pixel. // - // (2) Z.Zivkovic, F. van der Heijden, Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction, - // Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. - // The algorithm similar to the standard Stauffer&Grimson algorithm with additional selection of the number of the Gaussian components based on: - // Z.Zivkovic, F.van der Heijden, Recursive unsupervised learning of finite mixture models, IEEE Trans. on Pattern Analysis and Machine Intelligence, + // (2) Z.Zivkovic, F. van der Heijden, Efficient Adaptive Density Estimation per Image Pixel for the Task of Background Subtraction, + // Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. + // The algorithm similar to the standard Stauffer&Grimson algorithm with additional selection of the number of the Gaussian components based on: + // Z.Zivkovic, F.van der Heijden, Recursive unsupervised learning of finite mixture models, IEEE Trans. on Pattern Analysis and Machine Intelligence, // vol.26, no.5, pages 651-656, 2004. //------------------------------------------------------------------ +#if CV_MAJOR_VERSION == 2 mog(img_input, img_foreground, alpha); - - cv::Mat img_background; mog.getBackgroundImage(img_background); +#elif CV_MAJOR_VERSION == 3 + mog->apply(img_input, img_foreground, alpha); + mog->getBackgroundImage(img_background); +#endif - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) { - cv::imshow("GMM (Zivkovic&Heijden)", img_foreground); - cv::imshow("GMM BKG (Zivkovic&Heijden)", img_background); + cv::imshow("GMM FG (Zivkovic&Heijden)", img_foreground); + cv::imshow("GMM BG (Zivkovic&Heijden)", img_background); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -73,9 +82,9 @@ void MixtureOfGaussianV2BGS::process(const cv::Mat &img_input, cv::Mat &img_outp firstTime = false; } -void MixtureOfGaussianV2BGS::saveConfig() +void MixtureOfGaussianV2::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV2BGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "alpha", alpha); cvWriteInt(fs, "enableThreshold", enableThreshold); @@ -85,14 +94,14 @@ void MixtureOfGaussianV2BGS::saveConfig() cvReleaseFileStorage(&fs); } -void MixtureOfGaussianV2BGS::loadConfig() +void MixtureOfGaussianV2::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MixtureOfGaussianV2BGS.xml", 0, CV_STORAGE_READ); - - alpha = cvReadRealByName(fs, 0, "alpha", 0.05); - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.05); + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/MixtureOfGaussianV2BGS.h b/package_bgs/MixtureOfGaussianV2.h similarity index 57% rename from package_bgs/MixtureOfGaussianV2BGS.h rename to package_bgs/MixtureOfGaussianV2.h index a14ff0b..edc8add 100644 --- a/package_bgs/MixtureOfGaussianV2BGS.h +++ b/package_bgs/MixtureOfGaussianV2.h @@ -18,30 +18,35 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - #include <opencv2/video/background_segm.hpp> #include "IBGS.h" -class MixtureOfGaussianV2BGS : public IBGS +namespace bgslibrary { -private: - bool firstTime; - cv::BackgroundSubtractorMOG2 mog; - cv::Mat img_foreground; - double alpha; - bool enableThreshold; - int threshold; - bool showOutput; - -public: - MixtureOfGaussianV2BGS(); - ~MixtureOfGaussianV2BGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class MixtureOfGaussianV2 : public IBGS + { + private: +#if CV_MAJOR_VERSION == 2 + cv::BackgroundSubtractorMOG2 mog; +#elif CV_MAJOR_VERSION == 3 + cv::Ptr<cv::BackgroundSubtractorMOG2> mog; +#endif + double alpha; + bool enableThreshold; + int threshold; + + public: + MixtureOfGaussianV2(); + ~MixtureOfGaussianV2(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/sjn/SJN_MultiCueBGS.cpp b/package_bgs/MultiCue.cpp similarity index 83% rename from package_bgs/sjn/SJN_MultiCueBGS.cpp rename to package_bgs/MultiCue.cpp index 83db6ec..7717842 100644 --- a/package_bgs/sjn/SJN_MultiCueBGS.cpp +++ b/package_bgs/MultiCue.cpp @@ -21,12 +21,16 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // - Code by: SeungJon Noh // //------------------------------------------------------------------------------------------------------------------------------------// //#include "StdAfx.h" -#include "SJN_MultiCueBGS.h" -SJN_MultiCueBGS::SJN_MultiCueBGS() : firstTime(true), showOutput(true) +#include "MultiCue.h" + +using namespace bgslibrary::algorithms::libMultiCue; +using namespace bgslibrary::algorithms; + +MultiCue::MultiCue() { //---------------------------------- // User adjustable parameters - //---------------------------------- + //---------------------------------- g_iTrainingPeriod = 20; //the training period (The parameter t in the paper) g_iT_ModelThreshold = 1; //the threshold for texture-model based BGS. (The parameter tau_T in the paper) g_iC_ModelThreshold = 10; //the threshold for appearance based verification. (The parameter tau_A in the paper) @@ -37,15 +41,15 @@ SJN_MultiCueBGS::SJN_MultiCueBGS() : firstTime(true), showOutput(true) g_nColorTrainVolRange = 20; //the codebook size factor for color models. (The parameter eta_1 in the paper) g_bAbsorptionEnable = TRUE; //If TRUE, cache-book is also modeled for ghost region removal. - g_iAbsortionPeriod = 200; //the period to absorb static ghost regions + g_iAbsortionPeriod = 200; //the period to absorb static ghost regions g_iRWidth = 160, g_iRHeight = 120; //Frames are precessed after reduced in this size . //------------------------------------ // For codebook maintenance //------------------------------------ - g_iBackClearPeriod = 300; //the period to clear background models - g_iCacheClearPeriod = 30; //the period to clear cache-book models + g_iBackClearPeriod = 300; //the period to clear background models + g_iCacheClearPeriod = 30; //the period to clear cache-book models //------------------------------------ // Initialization of other parameters @@ -57,38 +61,37 @@ SJN_MultiCueBGS::SJN_MultiCueBGS() : firstTime(true), showOutput(true) g_bForegroundMapEnable = FALSE; //TRUE only when BGS is successful g_bModelMemAllocated = FALSE; //To handle memory.. g_bNonModelMemAllocated = FALSE; //To handle memory.. + + std::cout << "MultiCue()" << std::endl; + setup("./config/MultiCue.xml"); } -SJN_MultiCueBGS::~SJN_MultiCueBGS(void){ +MultiCue::~MultiCue(void) +{ Destroy(); + std::cout << "~MultiCue()" << std::endl; } //-----------------------------------------------------------------------------------------------------------------------------------------// // the main function to background modeling and subtraction // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel){ - - if (img_input.empty()) - return; - - loadConfig(); - - if (firstTime) - saveConfig(); +void MultiCue::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); //--STep1: Background Modeling--// //IplImage* frame = &IplImage(img_input); IplImage* frame = new IplImage(img_input); IplImage* result_image = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3); cvSetZero(result_image); - - if (g_iFrameCount <= g_iTrainingPeriod){ + if (g_iFrameCount <= g_iTrainingPeriod) + { BackgroundModeling_Par(frame); g_iFrameCount++; } - //--Step2: Background Subtraction--// - else{ + else + { g_bForegroundMapEnable = FALSE; ForegroundExtraction(frame); @@ -99,33 +102,35 @@ void SJN_MultiCueBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv: } delete frame; - cv::Mat temp(result_image, TRUE); - temp.copyTo(img_output); - + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + img_foreground = cv::cvarrToMat(result_image, TRUE); cvReleaseImage(&result_image); +#ifndef MEX_COMPILE_FLAG if (showOutput) - { - cv::imshow("MultiCueBGS FG", img_output); - } + cv::imshow("MultiCue FG", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); firstTime = false; } -void SJN_MultiCueBGS::saveConfig() +void MultiCue::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MultiCueBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); } -void SJN_MultiCueBGS::loadConfig() +void MultiCue::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MultiCueBGS.xml", 0, CV_STORAGE_READ); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } @@ -133,7 +138,7 @@ void SJN_MultiCueBGS::loadConfig() //-----------------------------------------------------------------------------------------------------------------------------------------// // the system initialization function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::Initialize(IplImage* frame) +void MultiCue::Initialize(IplImage* frame) { int i, j; @@ -148,15 +153,15 @@ void SJN_MultiCueBGS::Initialize(IplImage* frame) g_ResizedFrame = cvCreateImage(cvSize(g_iRWidth, g_iRHeight), IPL_DEPTH_8U, 3); g_aGaussFilteredFrame = (uchar***)malloc(sizeof(uchar**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_aGaussFilteredFrame[i] = (uchar**)malloc(sizeof(uchar*)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++) g_aGaussFilteredFrame[i][j] = (uchar*)malloc(sizeof(uchar)* 3); + for (j = 0; j < g_iRWidth; j++) g_aGaussFilteredFrame[i][j] = (uchar*)malloc(sizeof(uchar) * 3); } g_aXYZFrame = (uchar***)malloc(sizeof(uchar**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_aXYZFrame[i] = (uchar**)malloc(sizeof(uchar*)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++) g_aXYZFrame[i][j] = (uchar*)malloc(sizeof(uchar)* 3); + for (j = 0; j < g_iRWidth; j++) g_aXYZFrame[i][j] = (uchar*)malloc(sizeof(uchar) * 3); } g_aLandmarkArray = (uchar**)malloc(sizeof(uchar*)*g_iRHeight); @@ -203,30 +208,30 @@ void SJN_MultiCueBGS::Initialize(IplImage* frame) //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to release allocated memories // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::Destroy() +void MultiCue::Destroy() { if (g_bModelMemAllocated == FALSE && g_bNonModelMemAllocated == FALSE) return; short nNeighborNum = g_nNeighborNum; - if (g_bModelMemAllocated == TRUE){ + if (g_bModelMemAllocated == TRUE) { T_ReleaseTextureModelRelatedMemory(); C_ReleaseColorModelRelatedMemory(); g_bModelMemAllocated = FALSE; } - if (g_bNonModelMemAllocated == TRUE){ + if (g_bNonModelMemAllocated == TRUE) { cvReleaseImage(&g_ResizedFrame); - for (int i = 0; i < g_iRHeight; i++){ + for (int i = 0; i < g_iRHeight; i++) { for (int j = 0; j < g_iRWidth; j++) free(g_aGaussFilteredFrame[i][j]); free(g_aGaussFilteredFrame[i]); } free(g_aGaussFilteredFrame); - for (int i = 0; i < g_iRHeight; i++){ + for (int i = 0; i < g_iRHeight; i++) { for (int j = 0; j < g_iRWidth; j++) free(g_aXYZFrame[i][j]); free(g_aXYZFrame[i]); } @@ -256,7 +261,7 @@ void SJN_MultiCueBGS::Destroy() //-----------------------------------------------------------------------------------------------------------------------------------------// // the preprocessing function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::PreProcessing(IplImage* frame){ +void MultiCue::PreProcessing(IplImage* frame) { //image resize ReduceImageSize(frame, g_ResizedFrame); @@ -271,7 +276,7 @@ void SJN_MultiCueBGS::PreProcessing(IplImage* frame){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the background modeling function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::BackgroundModeling_Par(IplImage* frame){ +void MultiCue::BackgroundModeling_Par(IplImage* frame) { //initialization if (g_iFrameCount == 0) Initialize(frame); @@ -285,8 +290,8 @@ void SJN_MultiCueBGS::BackgroundModeling_Par(IplImage* frame){ float fLearningRate = g_fLearningRate * 4; //Step2: background modeling - for (int i = iH_Start; i < iH_end; i++){ - for (int j = iW_Start; j < iW_end; j++){ + for (int i = iH_Start; i < iH_end; i++) { + for (int j = iW_Start; j < iW_end; j++) { point center; center.m_nX = j; center.m_nY = i; @@ -297,9 +302,9 @@ void SJN_MultiCueBGS::BackgroundModeling_Par(IplImage* frame){ } //Step3: Clear non-essential codewords - if (g_iFrameCount == g_iTrainingPeriod){ - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + if (g_iFrameCount == g_iTrainingPeriod) { + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { T_ClearNonEssentialEntries(g_iTrainingPeriod, g_TextureModel[i][j]); C_ClearNonEssentialEntries(g_iTrainingPeriod, g_ColorModel[i][j]); @@ -312,7 +317,7 @@ void SJN_MultiCueBGS::BackgroundModeling_Par(IplImage* frame){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the background subtraction function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::ForegroundExtraction(IplImage* frame){ +void MultiCue::ForegroundExtraction(IplImage* frame) { //Step1:pre-processing PreProcessing(frame); @@ -332,9 +337,9 @@ void SJN_MultiCueBGS::ForegroundExtraction(IplImage* frame){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the post-processing function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::PostProcessing(IplImage* frame){ +void MultiCue::PostProcessing(IplImage* frame) { - //Step1: morphological operation + //Step1: morphological operation MorphologicalOpearions(g_aLandmarkArray, g_aResizedForeMap, 0.5, 5, g_iRWidth, g_iRHeight); g_bForegroundMapEnable = TRUE; @@ -361,20 +366,20 @@ void SJN_MultiCueBGS::PostProcessing(IplImage* frame){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the background-model update function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::UpdateModel_Par(){ +void MultiCue::UpdateModel_Par() { short nNeighborNum = g_nNeighborNum; //Step1: update map construction - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { g_aUpdateMap[i][j] = TRUE; } } - for (int k = 0; k < g_BoundBoxInfo->m_iBoundBoxNum; k++){ - if (g_BoundBoxInfo->m_ValidBox[k] == TRUE){ - for (int i = g_BoundBoxInfo->m_aRUpper[k]; i <= g_BoundBoxInfo->m_aRBottom[k]; i++){ - for (int j = g_BoundBoxInfo->m_aRLeft[k]; j <= g_BoundBoxInfo->m_aRRight[k]; j++){ + for (int k = 0; k < g_BoundBoxInfo->m_iBoundBoxNum; k++) { + if (g_BoundBoxInfo->m_ValidBox[k] == TRUE) { + for (int i = g_BoundBoxInfo->m_aRUpper[k]; i <= g_BoundBoxInfo->m_aRBottom[k]; i++) { + for (int j = g_BoundBoxInfo->m_aRLeft[k]; j <= g_BoundBoxInfo->m_aRRight[k]; j++) { g_aUpdateMap[i][j] = FALSE; } } @@ -387,16 +392,16 @@ void SJN_MultiCueBGS::UpdateModel_Par(){ float fLearningRate = (float)g_fLearningRate; - for (int i = iH_Start; i < iH_End; i++){ - for (int j = iW_Start; j < iW_End; j++){ + for (int i = iH_Start; i < iH_End; i++) { + for (int j = iW_Start; j < iW_End; j++) { point center; center.m_nX = j; center.m_nY = i; - if (g_aUpdateMap[i][j] == TRUE){ - //model update + if (g_aUpdateMap[i][j] == TRUE) { + //model update T_ModelConstruction(g_nTextureTrainVolRange, fLearningRate, g_aXYZFrame, center, g_aNeighborDirection[i][j], g_TextureModel[i][j]); C_CodebookConstruction(g_aXYZFrame[i][j], j, i, g_nColorTrainVolRange, fLearningRate, g_ColorModel[i][j]); @@ -406,7 +411,7 @@ void SJN_MultiCueBGS::UpdateModel_Par(){ } else { - if (g_bAbsorptionEnable == TRUE){ + if (g_bAbsorptionEnable == TRUE) { //model update T_ModelConstruction(g_nTextureTrainVolRange, fLearningRate, g_aXYZFrame, center, g_aNeighborDirection[i][j], g_TCacheBook[i][j]); C_CodebookConstruction(g_aXYZFrame[i][j], j, i, g_nColorTrainVolRange, fLearningRate, g_CCacheBook[i][j]); @@ -419,7 +424,7 @@ void SJN_MultiCueBGS::UpdateModel_Par(){ } //clearing non-essential codewords for cache-books - if (g_bAbsorptionEnable == TRUE){ + if (g_bAbsorptionEnable == TRUE) { T_ClearNonEssentialEntriesForCachebook(g_aLandmarkArray[i][j], g_aTReferredIndex[i][j], 10, g_TCacheBook[i][j]); C_ClearNonEssentialEntriesForCachebook(g_aLandmarkArray[i][j], g_aCReferredIndex[i][j], 10, g_CCacheBook[i][j]); } @@ -431,16 +436,16 @@ void SJN_MultiCueBGS::UpdateModel_Par(){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the color based verification function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, - point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr){ +void MultiCue::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, + point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr) { int iBound_w = g_iRWidth - g_nRadius; int iBound_h = g_iRHeight - g_nRadius; - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { - if (i < g_nRadius || i >= iBound_h || j<g_nRadius || j >= iBound_w) { + if (i < g_nRadius || i >= iBound_h || j < g_nRadius || j >= iBound_w) { aLandmarkArr[i][j] = 0; continue; } @@ -448,14 +453,14 @@ void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRa double tmp = aConfMap[i][j]; if (tmp > fConfThre) aLandmarkArr[i][j] = 255; - else{ + else { aLandmarkArr[i][j] = 0; //Calculating texture amount in the background double dBackAmt, dCnt; dBackAmt = dCnt = 0; - for (int m = 0; m < iNehborNum; m++){ - for (int n = 0; n < TModel[i][j][m]->m_iNumEntries; n++){ + for (int m = 0; m < iNehborNum; m++) { + for (int n = 0; n < TModel[i][j][m]->m_iNumEntries; n++) { dBackAmt += TModel[i][j][m]->m_Codewords[n]->m_fMean; dCnt++; } @@ -464,7 +469,7 @@ void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRa //Calculating texture amount in the input image double dTemp, dInputAmt = 0; - for (int m = 0; m < iNehborNum; m++){ + for (int m = 0; m < iNehborNum; m++) { dTemp = aXYZ[i][j][2] - aXYZ[aNeiDir[i][j][m].m_nY][aNeiDir[i][j][m].m_nX][2]; if (dTemp >= 0) dInputAmt += dTemp; @@ -473,13 +478,13 @@ void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRa } //If there are only few textures in both background and input image - if (dBackAmt < 50 && dInputAmt < 50){ + if (dBackAmt < 50 && dInputAmt < 50) { //Conduct color codebook matching BOOL bMatched = FALSE; - for (int m = 0; m < CModel[i][j]->m_iNumEntries; m++){ + for (int m = 0; m < CModel[i][j]->m_iNumEntries; m++) { int iMatchedCount = 0; - for (int n = 0; n < 3; n++){ + for (int n = 0; n < 3; n++) { double dLowThre = CModel[i][j]->m_Codewords[m]->m_dMean[n] - nTrainVolRange - 10; double dHighThre = CModel[i][j]->m_Codewords[m]->m_dMean[n] + nTrainVolRange + 10; @@ -505,13 +510,13 @@ void SJN_MultiCueBGS::CreateLandmarkArray_Par(float fConfThre, short nTrainVolRa //-----------------------------------------------------------------------------------------------------------------------------------------// // the Gaussian filtering function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame){ +void MultiCue::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame) { double dSigma = 0.7; - if (dSigma == 0){ - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + if (dSigma == 0) { + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { aFilteredFrame[i][j][0] = frame->imageData[i*frame->widthStep + j * 3]; aFilteredFrame[i][j][1] = frame->imageData[i*frame->widthStep + j * 3 + 1]; aFilteredFrame[i][j][2] = frame->imageData[i*frame->widthStep + j * 3 + 2]; @@ -520,16 +525,16 @@ void SJN_MultiCueBGS::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame } else { - cv::Mat temp_img(frame, TRUE); + cv::Mat temp_img = cv::cvarrToMat(frame, TRUE); cv::GaussianBlur(temp_img, temp_img, cv::Size(7, 7), dSigma); //Store results into aFilteredFrame[][][] //IplImage* img = &IplImage(temp_img); IplImage* img = new IplImage(temp_img); - int iWidthStep = img->widthStep; + //int iWidthStep = img->widthStep; - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { aFilteredFrame[i][j][0] = img->imageData[i*img->widthStep + j * 3]; aFilteredFrame[i][j][1] = img->imageData[i*img->widthStep + j * 3 + 1]; aFilteredFrame[i][j][2] = img->imageData[i*img->widthStep + j * 3 + 2]; @@ -542,7 +547,7 @@ void SJN_MultiCueBGS::GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame //------------------------------------------------------------------------------------------------------------------------------------// // the image resize function // //------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::ReduceImageSize(IplImage* SrcImage, IplImage* DstImage){ +void MultiCue::ReduceImageSize(IplImage* SrcImage, IplImage* DstImage) { int iChannel = 3; @@ -550,8 +555,8 @@ void SJN_MultiCueBGS::ReduceImageSize(IplImage* SrcImage, IplImage* DstImage){ double dResizeFactor_h = (double)g_iHeight / (double)g_iRHeight; - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { int iSrcY = (int)(i*dResizeFactor_h); int iSrcX = (int)(j*dResizeFactor_w); @@ -565,18 +570,18 @@ void SJN_MultiCueBGS::ReduceImageSize(IplImage* SrcImage, IplImage* DstImage){ //------------------------------------------------------------------------------------------------------------------------------------// // the color space conversion function // //------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ){ +void MultiCue::BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ) { double dH_ratio = (2 * PI) / 360; - for (int i = 0; i < g_iRHeight; i++){ + for (int i = 0; i < g_iRHeight; i++) { double dR, dG, dB; double dMax, dMin; double dH, dS, dV; - for (int j = 0; j < g_iRWidth; j++){ + for (int j = 0; j < g_iRWidth; j++) { dB = (double)(aBGR[i][j][0]) / 255; dG = (double)(aBGR[i][j][1]) / 255; @@ -593,13 +598,13 @@ void SJN_MultiCueBGS::BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ){ //Get S, H if (dV == 0) dS = dH = 0; - else{ + else { //S value dS = (dMax - dMin) / dMax; if (dS == 0) dH = 0; - else{ + else { //H value if (dMax == dR) { dH = 60 * (dG - dB) / dS; @@ -622,7 +627,7 @@ void SJN_MultiCueBGS::BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to get enlarged confidence map // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::GetEnlargedMap(float** aOriginMap, float** aEnlargedMap){ +void MultiCue::GetEnlargedMap(float** aOriginMap, float** aEnlargedMap) { int i, j; short nSrcX; @@ -639,8 +644,8 @@ void SJN_MultiCueBGS::GetEnlargedMap(float** aOriginMap, float** aEnlargedMap){ double dScaleFactor_w = ((double)g_iWidth) / ((double)g_iRWidth); double dScaleFactor_h = ((double)g_iHeight) / ((double)g_iRHeight); - for (i = 0; i < g_iHeight; i++){ - for (j = 0; j < g_iWidth; j++){ + for (i = 0; i < g_iHeight; i++) { + for (j = 0; j < g_iWidth; j++) { //backward mapping nSrcY = (int)(i / dScaleFactor_h); nSrcX = (int)(j / dScaleFactor_w); @@ -668,7 +673,7 @@ void SJN_MultiCueBGS::GetEnlargedMap(float** aOriginMap, float** aEnlargedMap){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the morphological operation function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight){ +void MultiCue::MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight) { int iOffset = (int)(iMaskSize / 2); @@ -676,28 +681,28 @@ void SJN_MultiCueBGS::MorphologicalOpearions(uchar** aInput, uchar** aOutput, do int iBound_h = iHeight - iOffset; uchar** aTemp = (uchar**)malloc(sizeof(uchar*)*iHeight); - for (int i = 0; i < iHeight; i++){ + for (int i = 0; i < iHeight; i++) { aTemp[i] = (uchar*)malloc(sizeof(uchar)*iWidth); } - for (int i = 0; i < iHeight; i++){ - for (int j = 0; j < iWidth; j++){ + for (int i = 0; i < iHeight; i++) { + for (int j = 0; j < iWidth; j++) { aTemp[i][j] = aInput[i][j]; } } int iThreshold = (int)(iMaskSize*iMaskSize*dThresholdRatio); - for (int i = 0; i < iHeight; i++){ - for (int j = 0; j < iWidth; j++){ + for (int i = 0; i < iHeight; i++) { + for (int j = 0; j < iWidth; j++) { - if (i < iOffset || i >= iBound_h || j < iOffset || j >= iBound_w){ + if (i < iOffset || i >= iBound_h || j < iOffset || j >= iBound_w) { aOutput[i][j] = 0; continue; } int iCnt = 0; - for (int m = -iOffset; m <= iOffset; m++){ - for (int n = -iOffset; n <= iOffset; n++){ + for (int m = -iOffset; m <= iOffset; m++) { + for (int n = -iOffset; n <= iOffset; n++) { if (aTemp[i + m][j + n] == 255) iCnt++; } } @@ -708,7 +713,7 @@ void SJN_MultiCueBGS::MorphologicalOpearions(uchar** aInput, uchar** aOutput, do } - for (int i = 0; i < iHeight; i++){ + for (int i = 0; i < iHeight; i++) { free(aTemp[i]); } free(aTemp); @@ -717,7 +722,7 @@ void SJN_MultiCueBGS::MorphologicalOpearions(uchar** aInput, uchar** aOutput, do //-----------------------------------------------------------------------------------------------------------------------------------------// // 2-raster scan pass based labeling function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLabelTable){ +void MultiCue::Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLabelTable) { int x, y, i; // pass 1,2 int cnt = 0; // pass 1 int label = 0; // pass 2 @@ -730,45 +735,45 @@ void SJN_MultiCueBGS::Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLa int* aTable1 = (int*)malloc(iSize / 2 * sizeof(int)); int* aTable2 = (int*)malloc(iSize / 2 * sizeof(int)); - memset(aPass1, 0, (iSize)* sizeof(int)); - for (y = 1; y < (g_iRHeight); y++){ - for (x = 1; x < (g_iRWidth); x++){ + memset(aPass1, 0, (iSize) * sizeof(int)); + for (y = 1; y < (g_iRHeight); y++) { + for (x = 1; x < (g_iRWidth); x++) { aLabelTable[y][x] = 0; } } - for (i = 0; i < iTableSize; i++){ + for (i = 0; i < iTableSize; i++) { aTable1[i] = i; } memset(aTable2, 0, iTableSize * sizeof(int)); // pass 1 - for (y = 1; y < (g_iRHeight); y++){ - for (x = 1; x < (g_iRWidth); x++){ + for (y = 1; y < (g_iRHeight); y++) { + for (x = 1; x < (g_iRWidth); x++) { - if (aBinaryArray[y][x] == 255){ // fore ground?? + if (aBinaryArray[y][x] == 255) { // fore ground?? int up, le; up = aPass1[(y - 1)*(g_iRWidth)+(x)]; // up index le = aPass1[(y)*(g_iRWidth)+(x - 1)]; // left index // case - if (up == 0 && le == 0){ + if (up == 0 && le == 0) { ++cnt; aPass1[y * g_iRWidth + x] = cnt; } - else if (up != 0 && le != 0){ - if (up > le){ + else if (up != 0 && le != 0) { + if (up > le) { aPass1[y *g_iRWidth + x] = le; aTable1[up] = aTable1[le]; // update table1 table1 } - else{ + else { aPass1[y * g_iRWidth + x] = up; aTable1[le] = aTable1[up]; // update table1 table1 } } - else{ + else { aPass1[y * g_iRWidth + x] = up + le; } @@ -778,13 +783,13 @@ void SJN_MultiCueBGS::Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLa } // pass 2 - for (y = 1; y < (g_iRHeight); y++){ - for (x = 1; x < (g_iRWidth); x++){ + for (y = 1; y < (g_iRHeight); y++) { + for (x = 1; x < (g_iRWidth); x++) { - if (aPass1[y * g_iRWidth + x]){ + if (aPass1[y * g_iRWidth + x]) { int v = aTable1[aPass1[y * g_iRWidth + x]]; - if (aTable2[v] == 0){ + if (aTable2[v] == 0) { ++label; aTable2[v] = label; } @@ -804,12 +809,12 @@ void SJN_MultiCueBGS::Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLa //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to set bounding boxes for each candidate foreground regions // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){ +void MultiCue::SetBoundingBox(int iLabelCount, int** aLabelTable) { int iBoundBoxIndex; g_BoundBoxInfo->m_iBoundBoxNum = iLabelCount; - for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++) { g_BoundBoxInfo->m_aRLeft[i] = 9999; //left g_BoundBoxInfo->m_aRUpper[i] = 9999; //top g_BoundBoxInfo->m_aRRight[i] = 0; //right @@ -817,8 +822,8 @@ void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){ } //Step1: Set tight bounding boxes - for (int i = 1; i<g_iRHeight; i++){ - for (int j = 1; j<g_iRWidth; j++){ + for (int i = 1; i < g_iRHeight; i++) { + for (int j = 1; j < g_iRWidth; j++) { if ((aLabelTable[i][j] == 0)) continue; @@ -835,7 +840,7 @@ void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){ //Step2: Add margins. int iBoundary_w = (int)(g_iRWidth / 80), iBoundary_h = (int)(g_iRHeight / 60); - for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++) { g_BoundBoxInfo->m_aRLeft[i] -= iBoundary_w; if (g_BoundBoxInfo->m_aRLeft[i] < g_nRadius) g_BoundBoxInfo->m_aRLeft[i] = g_nRadius; //left @@ -853,7 +858,7 @@ void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){ double dH_ratio = (double)g_iHeight / (double)g_iRHeight; double dW_ratio = (double)g_iWidth / (double)g_iRWidth; - for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < g_BoundBoxInfo->m_iBoundBoxNum; i++) { g_BoundBoxInfo->m_aLeft[i] = (int)(g_BoundBoxInfo->m_aRLeft[i] * dW_ratio); g_BoundBoxInfo->m_aUpper[i] = (int)(g_BoundBoxInfo->m_aRUpper[i] * dH_ratio); g_BoundBoxInfo->m_aRight[i] = (int)(g_BoundBoxInfo->m_aRRight[i] * dW_ratio); @@ -865,7 +870,7 @@ void SJN_MultiCueBGS::SetBoundingBox(int iLabelCount, int** aLabelTable){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the box verification function // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){ +void MultiCue::BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo) { //Step1: Verification by the bounding box size EvaluateBoxSize(BoundBoxInfo); @@ -875,7 +880,7 @@ void SJN_MultiCueBGS::BoundBoxVerification(IplImage* frame, uchar** aResForeMap, //Step3: Counting the # of valid box g_iForegroundNum = 0; - for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++) { if (BoundBoxInfo->m_ValidBox[i] == TRUE) g_iForegroundNum++; } } @@ -883,7 +888,7 @@ void SJN_MultiCueBGS::BoundBoxVerification(IplImage* frame, uchar** aResForeMap, //-----------------------------------------------------------------------------------------------------------------------------------------// // the size based verification // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo){ +void MultiCue::EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo) { //Set thresholds int iLowThreshold_w, iHighThreshold_w; @@ -897,7 +902,7 @@ void SJN_MultiCueBGS::EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo){ int iBoxWidth, iBoxHeight; //Perform verification. - for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++) { iBoxWidth = BoundBoxInfo->m_aRRight[i] - BoundBoxInfo->m_aRLeft[i]; iBoxHeight = BoundBoxInfo->m_aRBottom[i] - BoundBoxInfo->m_aRUpper[i]; @@ -912,7 +917,7 @@ void SJN_MultiCueBGS::EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo){ //------------------------------------------------------------------------------------------------------------------------------------// // overlapped region removal // //------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){ +void MultiCue::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo) { BOOL *aValidBoxFlag = new BOOL[SrcBoxInfo->m_iBoundBoxNum]; for (int i = 0; i < SrcBoxInfo->m_iBoundBoxNum; i++) aValidBoxFlag[i] = TRUE; @@ -924,7 +929,7 @@ void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){ int iThreshold, iCount, iSmall_Idx, iLarge_Idx; double dThreRatio = 0.7; - for (int i = 0; i < SrcBoxInfo->m_iBoundBoxNum; i++){ + for (int i = 0; i < SrcBoxInfo->m_iBoundBoxNum; i++) { if (SrcBoxInfo->m_ValidBox[i] == FALSE) { aValidBoxFlag[i] = FALSE; @@ -933,7 +938,7 @@ void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){ size1 = (aRight[i] - aLeft[i]) * (aBottom[i] - aTop[i]); - for (int j = i; j < SrcBoxInfo->m_iBoundBoxNum; j++){ + for (int j = i; j < SrcBoxInfo->m_iBoundBoxNum; j++) { if ((i == j) || (SrcBoxInfo->m_ValidBox[j] == FALSE)) continue; //Setting threshold for checking overlapped region size @@ -950,8 +955,8 @@ void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){ //Calculating overlapped region size iCount = 0; - for (int m = aLeft[iSmall_Idx]; m < aRight[iSmall_Idx]; m++){ - for (int n = aTop[iSmall_Idx]; n<aBottom[iSmall_Idx]; n++){ + for (int m = aLeft[iSmall_Idx]; m < aRight[iSmall_Idx]; m++) { + for (int n = aTop[iSmall_Idx]; n < aBottom[iSmall_Idx]; n++) { if (aLeft[iLarge_Idx] <= m && m <= aRight[iLarge_Idx] && aTop[iLarge_Idx] <= n && n <= aBottom[iLarge_Idx]) iCount++; } } @@ -968,20 +973,20 @@ void SJN_MultiCueBGS::EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo){ //-----------------------------------------------------------------------------------------------------------------------------------------// // appearance based verification // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){ +void MultiCue::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo) { double dThreshold = 10; BOOL** aUpdateMap = (BOOL**)malloc(sizeof(BOOL*)*g_iRHeight); - for (int i = 0; i < g_iRHeight; i++){ + for (int i = 0; i < g_iRHeight; i++) { aUpdateMap[i] = (BOOL*)malloc(sizeof(BOOL)*g_iRWidth); for (int j = 0; j < g_iRWidth; j++) aUpdateMap[i][j] = FALSE; } //Step1: Conduct fore-region evaluation to identify ghost regions - for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++){ - if (BoundBoxInfo->m_ValidBox[i] == TRUE){ + for (int i = 0; i < BoundBoxInfo->m_iBoundBoxNum; i++) { + if (BoundBoxInfo->m_ValidBox[i] == TRUE) { int iWin_w = BoundBoxInfo->m_aRRight[i] - BoundBoxInfo->m_aRLeft[i]; int iWin_h = BoundBoxInfo->m_aRBottom[i] - BoundBoxInfo->m_aRUpper[i]; @@ -999,8 +1004,8 @@ void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, //Generating edge image from aResForeMap IplImage* edge_fore = cvCreateImage(cvSize(iWin_w, iWin_h), IPL_DEPTH_8U, 1); - for (int m = BoundBoxInfo->m_aRUpper[i]; m < BoundBoxInfo->m_aRBottom[i]; m++){ - for (int n = BoundBoxInfo->m_aRLeft[i]; n<BoundBoxInfo->m_aRRight[i]; n++){ + for (int m = BoundBoxInfo->m_aRUpper[i]; m < BoundBoxInfo->m_aRBottom[i]; m++) { + for (int n = BoundBoxInfo->m_aRLeft[i]; n < BoundBoxInfo->m_aRRight[i]; n++) { edge_fore->imageData[(m - BoundBoxInfo->m_aRUpper[i])*edge_fore->widthStep + (n - BoundBoxInfo->m_aRLeft[i])] = (char)aResForeMap[m][n]; } } @@ -1011,8 +1016,8 @@ void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, //Recording evaluation result if (distance > dThreshold) { - for (int m = BoundBoxInfo->m_aRUpper[i]; m < BoundBoxInfo->m_aRBottom[i]; m++){ - for (int n = BoundBoxInfo->m_aRLeft[i]; n < BoundBoxInfo->m_aRRight[i]; n++){ + for (int m = BoundBoxInfo->m_aRUpper[i]; m < BoundBoxInfo->m_aRBottom[i]; m++) { + for (int n = BoundBoxInfo->m_aRLeft[i]; n < BoundBoxInfo->m_aRRight[i]; n++) { aUpdateMap[m][n] = TRUE; } } @@ -1029,9 +1034,9 @@ void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, //Step2: Adding information fo ghost region pixels to background model float fLearningRate = g_fLearningRate; - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ - if (aUpdateMap[i][j] == TRUE){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { + if (aUpdateMap[i][j] == TRUE) { point center; center.m_nX = j; center.m_nY = i; @@ -1053,16 +1058,16 @@ void SJN_MultiCueBGS::EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to calculate partial undirected Hausdorff distance(forward distance) // // //-----------------------------------------------------------------------------------------------------------------------------------------// -double SJN_MultiCueBGS::CalculateHausdorffDist(IplImage* input_image, IplImage* model_image){ +double MultiCue::CalculateHausdorffDist(IplImage* input_image, IplImage* model_image) { //Step1: Generating imag vectors //For reduce errors, points at the image boundary are excluded - vector<point> vInput, vModel; + std::vector<point> vInput, vModel; point temp; - //input image --> input vector - for (int i = 0; i < input_image->height; i++){ - for (int j = 0; j < input_image->width; j++){ + //input image --> input vector + for (int i = 0; i < input_image->height; i++) { + for (int j = 0; j < input_image->width; j++) { if ((uchar)input_image->imageData[i*input_image->widthStep + j] == 0) continue; @@ -1071,8 +1076,8 @@ double SJN_MultiCueBGS::CalculateHausdorffDist(IplImage* input_image, IplImage* } } //model image --> model vector - for (int i = 0; i < model_image->height; i++){ - for (int j = 0; j < model_image->width; j++){ + for (int i = 0; i < model_image->height; i++) { + for (int j = 0; j < model_image->width; j++) { if ((uchar)model_image->imageData[i*model_image->widthStep + j] == 0) continue; temp.m_nX = j; temp.m_nY = i; @@ -1086,12 +1091,12 @@ double SJN_MultiCueBGS::CalculateHausdorffDist(IplImage* input_image, IplImage* //Step2: Calculating forward distance h(Model,Image) double dDist, temp1, temp2, dMinDist; - vector<double> vTempDist; + std::vector<double> vTempDist; - for (auto iter_m = vModel.begin(); iter_m < vModel.end(); iter_m++){ + for (auto iter_m = vModel.begin(); iter_m < vModel.end(); iter_m++) { dMinDist = 9999999; - for (auto iter_i = vInput.begin(); iter_i < vInput.end(); iter_i++){ + for (auto iter_i = vInput.begin(); iter_i < vInput.end(); iter_i++) { temp1 = (*iter_m).m_nX - (*iter_i).m_nX; temp2 = (*iter_m).m_nY - (*iter_i).m_nY; dDist = temp1*temp1 + temp2*temp2; @@ -1114,15 +1119,15 @@ double SJN_MultiCueBGS::CalculateHausdorffDist(IplImage* input_image, IplImage* //-----------------------------------------------------------------------------------------------------------------------------------------// // function to remove non-valid bounding boxes fore fore-candidates // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo){ +void MultiCue::RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo) { int iBoxNum = BoundBoxInfo->m_iBoundBoxNum; - for (int k = 0; k < iBoxNum; k++){ + for (int k = 0; k < iBoxNum; k++) { - if (BoundBoxInfo->m_ValidBox[k] == FALSE){ - for (int i = BoundBoxInfo->m_aRUpper[k]; i < BoundBoxInfo->m_aRBottom[k]; i++){ - for (int j = BoundBoxInfo->m_aRLeft[k]; j < BoundBoxInfo->m_aRRight[k]; j++){ + if (BoundBoxInfo->m_ValidBox[k] == FALSE) { + for (int i = BoundBoxInfo->m_aRUpper[k]; i < BoundBoxInfo->m_aRBottom[k]; i++) { + for (int j = BoundBoxInfo->m_aRLeft[k]; j < BoundBoxInfo->m_aRRight[k]; j++) { if (aResForeMap[i][j] == 255) aResForeMap[i][j] = 0; } } @@ -1134,15 +1139,15 @@ void SJN_MultiCueBGS::RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBo //-----------------------------------------------------------------------------------------------------------------------------------------// // the function returning a foreground binary-map // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::GetForegroundMap(IplImage* return_image, IplImage* input_frame){ +void MultiCue::GetForegroundMap(IplImage* return_image, IplImage* input_frame) { if (g_bForegroundMapEnable == FALSE) return; IplImage* temp_image = cvCreateImage(cvSize(g_iRWidth, g_iRHeight), IPL_DEPTH_8U, 3); - if (input_frame == NULL){ - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + if (input_frame == NULL) { + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { temp_image->imageData[i*temp_image->widthStep + j * 3] = (char)g_aResizedForeMap[i][j]; temp_image->imageData[i*temp_image->widthStep + j * 3 + 1] = (char)g_aResizedForeMap[i][j]; temp_image->imageData[i*temp_image->widthStep + j * 3 + 2] = (char)g_aResizedForeMap[i][j]; @@ -1150,7 +1155,7 @@ void SJN_MultiCueBGS::GetForegroundMap(IplImage* return_image, IplImage* input_f } } - else{ + else { cvResize(input_frame, temp_image); CvScalar MixColor; @@ -1158,8 +1163,8 @@ void SJN_MultiCueBGS::GetForegroundMap(IplImage* return_image, IplImage* input_f MixColor.val[1] = 0; //G MixColor.val[2] = 255; //R - for (int i = 0; i < g_iRHeight; i++){ - for (int j = 0; j < g_iRWidth; j++){ + for (int i = 0; i < g_iRHeight; i++) { + for (int j = 0; j < g_iRWidth; j++) { if (g_aResizedForeMap[i][j] == 255) { @@ -1187,15 +1192,15 @@ void SJN_MultiCueBGS::GetForegroundMap(IplImage* return_image, IplImage* input_f //-----------------------------------------------------------------------------------------------------------------------------------------// // the initialization function for the texture-models // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){ +void MultiCue::T_AllocateTextureModelRelatedMemory() { int i, j, k; //neighborhood system related int iMaxNeighborArraySize = 8; g_aNeighborDirection = (point***)malloc(sizeof(point**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_aNeighborDirection[i] = (point**)malloc(sizeof(point*)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { g_aNeighborDirection[i][j] = (point*)malloc(sizeof(point)*iMaxNeighborArraySize); } } @@ -1204,11 +1209,11 @@ void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){ //texture-model related int iElementArraySize = 6; g_TextureModel = (TextureModel****)malloc(sizeof(TextureModel***)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_TextureModel[i] = (TextureModel***)malloc(sizeof(TextureModel**)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { g_TextureModel[i][j] = (TextureModel**)malloc(sizeof(TextureModel*)*g_nNeighborNum); - for (k = 0; k < g_nNeighborNum; k++){ + for (k = 0; k < g_nNeighborNum; k++) { g_TextureModel[i][j][k] = (TextureModel*)malloc(sizeof(TextureModel)); g_TextureModel[i][j][k]->m_Codewords = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*iElementArraySize); g_TextureModel[i][j][k]->m_iElementArraySize = iElementArraySize; @@ -1223,16 +1228,16 @@ void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){ for (i = 0; i < g_iRHeight; i++) g_aTextureConfMap[i] = (float*)malloc(sizeof(float)*g_iRWidth); //cache-book related - if (g_bAbsorptionEnable == TRUE){ + if (g_bAbsorptionEnable == TRUE) { iElementArraySize = iElementArraySize / 2; if (iElementArraySize < 3)iElementArraySize = 3; g_TCacheBook = (TextureModel****)malloc(sizeof(TextureModel***)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_TCacheBook[i] = (TextureModel***)malloc(sizeof(TextureModel**)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { g_TCacheBook[i][j] = (TextureModel**)malloc(sizeof(TextureModel*)*g_nNeighborNum); - for (k = 0; k < g_nNeighborNum; k++){ + for (k = 0; k < g_nNeighborNum; k++) { g_TCacheBook[i][j][k] = (TextureModel*)malloc(sizeof(TextureModel)); g_TCacheBook[i][j][k]->m_Codewords = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*iElementArraySize); g_TCacheBook[i][j][k]->m_iElementArraySize = iElementArraySize; @@ -1245,13 +1250,13 @@ void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){ g_aTReferredIndex = (short***)malloc(sizeof(short**)*g_iRHeight); g_aTContinuousCnt = (short***)malloc(sizeof(short**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_aTReferredIndex[i] = (short**)malloc(sizeof(short*)*g_iRWidth); g_aTContinuousCnt[i] = (short**)malloc(sizeof(short*)*g_iRWidth); for (j = 0; j < g_iRWidth; j++) { g_aTReferredIndex[i][j] = (short*)malloc(sizeof(short)*g_nNeighborNum); g_aTContinuousCnt[i][j] = (short*)malloc(sizeof(short)*g_nNeighborNum); - for (k = 0; k < g_nNeighborNum; k++){ + for (k = 0; k < g_nNeighborNum; k++) { g_aTReferredIndex[i][j][k] = -1; g_aTContinuousCnt[i][j][k] = 0; } @@ -1262,13 +1267,13 @@ void SJN_MultiCueBGS::T_AllocateTextureModelRelatedMemory(){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the memory release function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){ +void MultiCue::T_ReleaseTextureModelRelatedMemory() { int i, j, k, m; short nNeighborNum = g_nNeighborNum; - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ - for (k = 0; k < nNeighborNum; k++){ + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { + for (k = 0; k < nNeighborNum; k++) { for (m = 0; m < g_TextureModel[i][j][k]->m_iNumEntries; m++) free(g_TextureModel[i][j][k]->m_Codewords[m]); free(g_TextureModel[i][j][k]->m_Codewords); free(g_TextureModel[i][j][k]); @@ -1278,7 +1283,7 @@ void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){ } free(g_TextureModel); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { for (j = 0; j < g_iRWidth; j++) free(g_aNeighborDirection[i][j]); free(g_aNeighborDirection[i]); } @@ -1287,10 +1292,10 @@ void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){ for (i = 0; i < g_iRHeight; i++) free(g_aTextureConfMap[i]); free(g_aTextureConfMap); - if (g_bAbsorptionEnable == TRUE){ - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ - for (k = 0; k < nNeighborNum; k++){ + if (g_bAbsorptionEnable == TRUE) { + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { + for (k = 0; k < nNeighborNum; k++) { for (m = 0; m < g_TCacheBook[i][j][k]->m_iNumEntries; m++) free(g_TCacheBook[i][j][k]->m_Codewords[m]); free(g_TCacheBook[i][j][k]->m_Codewords); free(g_TCacheBook[i][j][k]); @@ -1300,8 +1305,8 @@ void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){ } free(g_TCacheBook); - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { free(g_aTReferredIndex[i][j]); free(g_aTContinuousCnt[i][j]); } @@ -1317,7 +1322,7 @@ void SJN_MultiCueBGS::T_ReleaseTextureModelRelatedMemory(){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the codebook construction function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningRate, uchar*** aXYZ, point center, point* aNei, TextureModel** aModel){ +void MultiCue::T_ModelConstruction(short nTrainVolRange, float fLearningRate, uchar*** aXYZ, point center, point* aNei, TextureModel** aModel) { int i, j; int iMatchedIndex; @@ -1329,15 +1334,15 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR float fNegLearningRate = 1 - fLearningRate; - //for all neighboring pairs - for (i = 0; i < nNeighborNum; i++){ + //for all neighboring pairs + for (i = 0; i < nNeighborNum; i++) { fDifference = (float)(aXYZ[center.m_nY][center.m_nX][2] - aXYZ[aNei[i].m_nY][aNei[i].m_nX][2]); //Step1: matching iMatchedIndex = -1; - for (j = 0; j < aModel[i]->m_iNumEntries; j++){ - if (aModel[i]->m_Codewords[j]->m_fLowThre <= fDifference && fDifference <= aModel[i]->m_Codewords[j]->m_fHighThre){ + for (j = 0; j < aModel[i]->m_iNumEntries; j++) { + if (aModel[i]->m_Codewords[j]->m_fLowThre <= fDifference && fDifference <= aModel[i]->m_Codewords[j]->m_fHighThre) { iMatchedIndex = j; break; } @@ -1345,12 +1350,12 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR aModel[i]->m_iTotal++; //Step2: adding a new element - if (iMatchedIndex == -1){ + if (iMatchedIndex == -1) { //element array - if (aModel[i]->m_iElementArraySize == aModel[i]->m_iNumEntries){ + if (aModel[i]->m_iElementArraySize == aModel[i]->m_iNumEntries) { aModel[i]->m_iElementArraySize += 5; TextureCodeword **temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*aModel[i]->m_iElementArraySize); - for (j = 0; j < aModel[i]->m_iNumEntries; j++){ + for (j = 0; j < aModel[i]->m_iNumEntries; j++) { temp[j] = aModel[i]->m_Codewords[j]; aModel[i]->m_Codewords[j] = NULL; } @@ -1370,7 +1375,7 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR } //Step3: update - else{ + else { fDiffMean = aModel[i]->m_Codewords[iMatchedIndex]->m_fMean; aModel[i]->m_Codewords[iMatchedIndex]->m_fMean = fLearningRate*fDifference + fNegLearningRate*fDiffMean; @@ -1381,10 +1386,10 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR } //cache-book handling - if (aModel[i]->m_bID == 1){ + if (aModel[i]->m_bID == 1) { //1. m_iMNRL update int negTime; - for (j = 0; j < aModel[i]->m_iNumEntries; j++){ + for (j = 0; j < aModel[i]->m_iNumEntries; j++) { //m_iMNRL update negTime = aModel[i]->m_iTotal - aModel[i]->m_Codewords[j]->m_iT_last_time + aModel[i]->m_Codewords[j]->m_iT_first_time - 1; if (aModel[i]->m_Codewords[j]->m_iMNRL < negTime) aModel[i]->m_Codewords[j]->m_iMNRL = negTime; @@ -1395,18 +1400,18 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR if (g_bAbsorptionEnable == TRUE) g_aTReferredIndex[center.m_nY][center.m_nX][i] = -1; } - else{ + else { //1. m_iMNRL update if (iMatchedIndex == -1) aModel[i]->m_Codewords[aModel[i]->m_iNumEntries - 1]->m_iMNRL = 0; //2. g_aTReferredIndex[center.m_nY][center.m_nX][i] update - if (iMatchedIndex == -1){ + if (iMatchedIndex == -1) { g_aTReferredIndex[center.m_nY][center.m_nX][i] = aModel[i]->m_iNumEntries - 1; g_aTContinuousCnt[center.m_nY][center.m_nX][i] = 1; } - else{ + else { if (iMatchedIndex == g_aTReferredIndex[center.m_nY][center.m_nX][i]) g_aTContinuousCnt[center.m_nY][center.m_nX][i]++; - else{ + else { g_aTReferredIndex[center.m_nY][center.m_nX][i] = iMatchedIndex; g_aTContinuousCnt[center.m_nY][center.m_nX][i] = 1; } @@ -1420,7 +1425,7 @@ void SJN_MultiCueBGS::T_ModelConstruction(short nTrainVolRange, float fLearningR //-----------------------------------------------------------------------------------------------------------------------------------------// // Clear non-essential codewords of the given codebook // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel){ +void MultiCue::T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel) { int i, n; int iStaleThresh = (int)(nClearNum*0.5); int iKeepCnt; @@ -1430,7 +1435,7 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** TextureModel* c; - for (n = 0; n < nNeighborNum; n++){ + for (n = 0; n < nNeighborNum; n++) { c = aModel[n]; if (c->m_iTotal < nClearNum) continue; //(being operated only when c[w][h]->m_iTotal == nClearNum) @@ -1441,7 +1446,7 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** iKeepCnt = 0; //Step2: Find non-essential code-words - for (i = 0; i<c->m_iNumEntries; i++){ + for (i = 0; i < c->m_iNumEntries; i++) { if (c->m_Codewords[i]->m_iMNRL > iStaleThresh) { aKeep[i] = 0; //removal candidate } @@ -1452,20 +1457,20 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** } //Step3: Perform removal - if (iKeepCnt == 0 || iKeepCnt == c->m_iNumEntries){ - for (i = 0; i < c->m_iNumEntries; i++){ + if (iKeepCnt == 0 || iKeepCnt == c->m_iNumEntries) { + for (i = 0; i < c->m_iNumEntries; i++) { c->m_Codewords[i]->m_iT_first_time = 1; c->m_Codewords[i]->m_iT_last_time = 1; c->m_Codewords[i]->m_iMNRL = 0; } } - else{ + else { iKeepCnt = 0; TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*c->m_iNumEntries); - for (i = 0; i < c->m_iNumEntries; i++){ - if (aKeep[i] == 1){ + for (i = 0; i < c->m_iNumEntries; i++) { + if (aKeep[i] == 1) { temp[iKeepCnt] = c->m_Codewords[i]; temp[iKeepCnt]->m_iT_first_time = 1; temp[iKeepCnt]->m_iT_last_time = 1; @@ -1491,21 +1496,21 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntries(short nClearNum, TextureModel** //-----------------------------------------------------------------------------------------------------------------------------------------// // Clear non-essential codewords of the given codebook (only for the cache-book) // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook){ +void MultiCue::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook) { int i, n; short nNeighborNum = g_nNeighborNum; TextureModel* c; short nReferredIdx; - for (n = 0; n < nNeighborNum; n++){ + for (n = 0; n < nNeighborNum; n++) { c = pCachebook[n]; nReferredIdx = nReferredIdxArr[n]; //pCachebook->m_iTotal < nClearNum? --> MNRL update if (c->m_iTotal < nClearNum) { - for (i = 0; i < c->m_iNumEntries; i++){ + for (i = 0; i < c->m_iNumEntries; i++) { if (bLandmark == 255 && i == nReferredIdx) c->m_Codewords[i]->m_iMNRL = 0; else c->m_Codewords[i]->m_iMNRL++; } @@ -1514,7 +1519,7 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh } //Perform clearing - else{ + else { int iStaleThreshold = 5; int* aKeep; @@ -1523,8 +1528,8 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh aKeep = (int*)malloc(sizeof(int)*c->m_iNumEntries); nKeepCnt = 0; - for (i = 0; i < c->m_iNumEntries; i++){ - if (c->m_Codewords[i]->m_iMNRL < iStaleThreshold){ + for (i = 0; i < c->m_iNumEntries; i++) { + if (c->m_Codewords[i]->m_iMNRL < iStaleThreshold) { aKeep[i] = 1; nKeepCnt++; } @@ -1537,8 +1542,8 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*c->m_iElementArraySize); nKeepCnt = 0; - for (i = 0; i < c->m_iNumEntries; i++){ - if (aKeep[i] == 1){ + for (i = 0; i < c->m_iNumEntries; i++) { + if (aKeep[i] == 1) { temp[nKeepCnt] = c->m_Codewords[i]; temp[nKeepCnt]->m_iMNRL = 0; nKeepCnt++; @@ -1564,7 +1569,7 @@ void SJN_MultiCueBGS::T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to generate texture confidence maps // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel){ +void MultiCue::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel) { int iBound_w = g_iRWidth - g_nRadius; int iBound_h = g_iRHeight - g_nRadius; @@ -1572,10 +1577,10 @@ void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, short nNeighborNum = g_nNeighborNum; float fPadding = 5; - for (int h = 0; h < g_iRHeight; h++){ - for (int w = 0; w < g_iRWidth; w++){ + for (int h = 0; h < g_iRHeight; h++) { + for (int w = 0; w < g_iRWidth; w++) { - if (h < g_nRadius || h >= iBound_h || w < g_nRadius || w >= iBound_w){ + if (h < g_nRadius || h >= iBound_h || w < g_nRadius || w >= iBound_w) { aTextureMap[h][w] = 0; continue; } @@ -1585,7 +1590,7 @@ void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, float fDifference; point nei; - for (int i = 0; i < nNeighborNum; i++){ + for (int i = 0; i < nNeighborNum; i++) { nei.m_nX = aNeiDirArr[h][w][i].m_nX; nei.m_nY = aNeiDirArr[h][w][i].m_nY; @@ -1594,8 +1599,8 @@ void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, if (fDifference < 0) fDiffSum -= fDifference; else fDiffSum += fDifference; - for (int j = 0; j < aModel[h][w][i]->m_iNumEntries; j++){ - if (aModel[h][w][i]->m_Codewords[j]->m_fLowThre - fPadding <= fDifference && fDifference <= aModel[h][w][i]->m_Codewords[j]->m_fHighThre + fPadding){ + for (int j = 0; j < aModel[h][w][i]->m_iNumEntries; j++) { + if (aModel[h][w][i]->m_Codewords[j]->m_fLowThre - fPadding <= fDifference && fDifference <= aModel[h][w][i]->m_Codewords[j]->m_fHighThre + fPadding) { nMatchedCount++; break; } @@ -1609,21 +1614,21 @@ void SJN_MultiCueBGS::T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, //-----------------------------------------------------------------------------------------------------------------------------------------// // Absorbing Ghost Non-background Region Update // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache){ +void MultiCue::T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache) { int i, j, k; int iLeavingIndex; - short g_nRadius = 2; + //short g_nRadius = 2; short nNeighborNum = g_nNeighborNum; - for (i = 0; i < nNeighborNum; i++){ + for (i = 0; i < nNeighborNum; i++) { //set iLeavingIndex if (aContinuCnt[pos.m_nY][pos.m_nX][i] < iAbsorbCnt) continue; iLeavingIndex = aRefferedIndex[pos.m_nY][pos.m_nX][i]; //array expansion - if (pModel[i]->m_iElementArraySize == pModel[i]->m_iNumEntries){ + if (pModel[i]->m_iElementArraySize == pModel[i]->m_iNumEntries) { pModel[i]->m_iElementArraySize = pModel[i]->m_iElementArraySize + 5; TextureCodeword** temp = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*pModel[i]->m_iElementArraySize); for (j = 0; j < pModel[i]->m_iNumEntries; j++) temp[j] = pModel[i]->m_Codewords[j]; @@ -1643,9 +1648,9 @@ void SJN_MultiCueBGS::T_Absorption(int iAbsorbCnt, point pos, short*** aContinuC k = 0; TextureCodeword **temp_Cache = (TextureCodeword**)malloc(sizeof(TextureCodeword*)*pCache[i]->m_iElementArraySize); - for (j = 0; j < pCache[i]->m_iNumEntries; j++){ + for (j = 0; j < pCache[i]->m_iNumEntries; j++) { if (j == iLeavingIndex) continue; - else{ + else { temp_Cache[k] = pCache[i]->m_Codewords[j]; k++; } @@ -1659,7 +1664,7 @@ void SJN_MultiCueBGS::T_Absorption(int iAbsorbCnt, point pos, short*** aContinuC //-----------------------------------------------------------------------------------------------------------------------------------------// // the function to set neighborhood system // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::T_SetNeighborDirection(point*** aNeighborPos){ +void MultiCue::T_SetNeighborDirection(point*** aNeighborPos) { int i, j, k; point* aSearchDirection = (point*)malloc(sizeof(point)*g_nNeighborNum); @@ -1683,9 +1688,9 @@ void SJN_MultiCueBGS::T_SetNeighborDirection(point*** aNeighborPos){ point temp_pos; - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ - for (k = 0; k < g_nNeighborNum; k++){ + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { + for (k = 0; k < g_nNeighborNum; k++) { temp_pos.m_nX = j + aSearchDirection[k].m_nX; temp_pos.m_nY = i + aSearchDirection[k].m_nY; @@ -1707,16 +1712,16 @@ void SJN_MultiCueBGS::T_SetNeighborDirection(point*** aNeighborPos){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the color-model initialization function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_AllocateColorModelRelatedMemory(){ +void MultiCue::C_AllocateColorModelRelatedMemory() { int i, j; int iElementArraySize = 10; //codebook initialization g_ColorModel = (ColorModel***)malloc(sizeof(ColorModel**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_ColorModel[i] = (ColorModel**)malloc(sizeof(ColorModel*)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { //initialization of each CodeBookArray. g_ColorModel[i][j] = (ColorModel*)malloc(sizeof(ColorModel)); g_ColorModel[i][j]->m_Codewords = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*iElementArraySize); @@ -1728,13 +1733,13 @@ void SJN_MultiCueBGS::C_AllocateColorModelRelatedMemory(){ } //cache-book initialization - if (g_bAbsorptionEnable == TRUE){ + if (g_bAbsorptionEnable == TRUE) { iElementArraySize = 3; g_CCacheBook = (ColorModel***)malloc(sizeof(ColorModel**)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_CCacheBook[i] = (ColorModel**)malloc(sizeof(ColorModel*)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { //initialization of each CodeBookArray. g_CCacheBook[i][j] = (ColorModel*)malloc(sizeof(ColorModel)); g_CCacheBook[i][j]->m_Codewords = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*iElementArraySize); @@ -1747,10 +1752,10 @@ void SJN_MultiCueBGS::C_AllocateColorModelRelatedMemory(){ g_aCReferredIndex = (short**)malloc(sizeof(short*)*g_iRHeight); g_aCContinuousCnt = (short**)malloc(sizeof(short*)*g_iRHeight); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { g_aCReferredIndex[i] = (short*)malloc(sizeof(short)*g_iRWidth); g_aCContinuousCnt[i] = (short*)malloc(sizeof(short)*g_iRWidth); - for (j = 0; j < g_iRWidth; j++){ + for (j = 0; j < g_iRWidth; j++) { g_aCReferredIndex[i][j] = -1; g_aCContinuousCnt[i][j] = 0; } @@ -1761,12 +1766,12 @@ void SJN_MultiCueBGS::C_AllocateColorModelRelatedMemory(){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the memory release function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_ReleaseColorModelRelatedMemory(){ +void MultiCue::C_ReleaseColorModelRelatedMemory() { int i, j, k; - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ - for (k = 0; k < g_ColorModel[i][j]->m_iNumEntries; k++){ + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { + for (k = 0; k < g_ColorModel[i][j]->m_iNumEntries; k++) { free(g_ColorModel[i][j]->m_Codewords[k]); } free(g_ColorModel[i][j]->m_Codewords); @@ -1776,10 +1781,10 @@ void SJN_MultiCueBGS::C_ReleaseColorModelRelatedMemory(){ } free(g_ColorModel); - if (g_bAbsorptionEnable == TRUE){ - for (i = 0; i < g_iRHeight; i++){ - for (j = 0; j < g_iRWidth; j++){ - for (k = 0; k < g_CCacheBook[i][j]->m_iNumEntries; k++){ + if (g_bAbsorptionEnable == TRUE) { + for (i = 0; i < g_iRHeight; i++) { + for (j = 0; j < g_iRWidth; j++) { + for (k = 0; k < g_CCacheBook[i][j]->m_iNumEntries; k++) { free(g_CCacheBook[i][j]->m_Codewords[k]); } free(g_CCacheBook[i][j]->m_Codewords); @@ -1789,7 +1794,7 @@ void SJN_MultiCueBGS::C_ReleaseColorModelRelatedMemory(){ } free(g_CCacheBook); - for (i = 0; i < g_iRHeight; i++){ + for (i = 0; i < g_iRHeight; i++) { free(g_aCReferredIndex[i]); free(g_aCContinuousCnt[i]); } @@ -1801,7 +1806,7 @@ void SJN_MultiCueBGS::C_ReleaseColorModelRelatedMemory(){ //-----------------------------------------------------------------------------------------------------------------------------------------// // the codebook construction function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC){ +void MultiCue::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC) { //Step1: matching short nMatchedIndex; @@ -1810,14 +1815,14 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh nMatchedIndex = -1; - for (int i = 0; i < pC->m_iNumEntries; i++){ + for (int i = 0; i < pC->m_iNumEntries; i++) { //Checking X - if (pC->m_Codewords[i]->m_dMean[0] - nTrainVolRange <= aP[0] && aP[0] <= pC->m_Codewords[i]->m_dMean[0] + nTrainVolRange){ + if (pC->m_Codewords[i]->m_dMean[0] - nTrainVolRange <= aP[0] && aP[0] <= pC->m_Codewords[i]->m_dMean[0] + nTrainVolRange) { //Checking Y - if (pC->m_Codewords[i]->m_dMean[1] - nTrainVolRange <= aP[1] && aP[1] <= pC->m_Codewords[i]->m_dMean[1] + nTrainVolRange){ + if (pC->m_Codewords[i]->m_dMean[1] - nTrainVolRange <= aP[1] && aP[1] <= pC->m_Codewords[i]->m_dMean[1] + nTrainVolRange) { //Checking Z - if (pC->m_Codewords[i]->m_dMean[2] - nTrainVolRange <= aP[2] && aP[2] <= pC->m_Codewords[i]->m_dMean[2] + nTrainVolRange){ + if (pC->m_Codewords[i]->m_dMean[2] - nTrainVolRange <= aP[2] && aP[2] <= pC->m_Codewords[i]->m_dMean[2] + nTrainVolRange) { nMatchedIndex = i; break; } @@ -1828,11 +1833,11 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh pC->m_iTotal = pC->m_iTotal + 1; //Step2 : adding a new element - if (nMatchedIndex == -1){ - if (pC->m_iElementArraySize == pC->m_iNumEntries){ + if (nMatchedIndex == -1) { + if (pC->m_iElementArraySize == pC->m_iNumEntries) { pC->m_iElementArraySize = pC->m_iElementArraySize + 5; ColorCodeword **temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pC->m_iElementArraySize); - for (int j = 0; j < pC->m_iNumEntries; j++){ + for (int j = 0; j < pC->m_iNumEntries; j++) { temp[j] = pC->m_Codewords[j]; pC->m_Codewords[j] = NULL; } @@ -1853,7 +1858,7 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh } //Step3 : update - else{ + else { //m_dMean update pC->m_Codewords[nMatchedIndex]->m_dMean[0] = (fLearningRate*aP[0]) + fNegLearningRate*pC->m_Codewords[nMatchedIndex]->m_dMean[0];//X pC->m_Codewords[nMatchedIndex]->m_dMean[1] = (fLearningRate*aP[1]) + fNegLearningRate*pC->m_Codewords[nMatchedIndex]->m_dMean[1];//Y @@ -1863,10 +1868,10 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh } //cache-book handling - if (pC->m_bID == 1){ + if (pC->m_bID == 1) { //1. m_iMNRL update int iNegTime; - for (int i = 0; i < pC->m_iNumEntries; i++){ + for (int i = 0; i < pC->m_iNumEntries; i++) { //m_iMNRL update iNegTime = pC->m_iTotal - pC->m_Codewords[i]->m_iT_last_time + pC->m_Codewords[i]->m_iT_first_time - 1; if (pC->m_Codewords[i]->m_iMNRL < iNegTime) pC->m_Codewords[i]->m_iMNRL = iNegTime; @@ -1876,18 +1881,18 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh if (g_bAbsorptionEnable == TRUE) g_aCReferredIndex[iPosY][iPosX] = -1; } - else{ + else { //1. m_iMNRL update: if (nMatchedIndex == -1) pC->m_Codewords[pC->m_iNumEntries - 1]->m_iMNRL = 0; //2. g_aCReferredIndex[iPosY][iPosX] update - if (nMatchedIndex == -1){ + if (nMatchedIndex == -1) { g_aCReferredIndex[iPosY][iPosX] = pC->m_iNumEntries - 1; g_aCContinuousCnt[iPosY][iPosX] = 1; } - else{ + else { if (nMatchedIndex == g_aCReferredIndex[iPosY][iPosX]) g_aCContinuousCnt[iPosY][iPosX]++; - else{ + else { g_aCReferredIndex[iPosY][iPosX] = nMatchedIndex; g_aCContinuousCnt[iPosY][iPosX] = 1; } @@ -1898,7 +1903,7 @@ void SJN_MultiCueBGS::C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, sh //-----------------------------------------------------------------------------------------------------------------------------------------// // Clear non-essential codewords of the given codebook // // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel){ +void MultiCue::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel) { int i; short nStaleThresh = (int)(nClearNum*0.5); short nKeepCnt; @@ -1914,7 +1919,7 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pM nKeepCnt = 0; //Step2: Find non-essential codewords - for (i = 0; i<pC->m_iNumEntries; i++){ + for (i = 0; i < pC->m_iNumEntries; i++) { if (pC->m_Codewords[i]->m_iMNRL > nStaleThresh) { aKeep[i] = 0; //removal } @@ -1925,19 +1930,19 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pM } //Step3: Perform removal - if (nKeepCnt == 0 || nKeepCnt == pC->m_iNumEntries){ - for (i = 0; i < pC->m_iNumEntries; i++){ + if (nKeepCnt == 0 || nKeepCnt == pC->m_iNumEntries) { + for (i = 0; i < pC->m_iNumEntries; i++) { pC->m_Codewords[i]->m_iT_first_time = 1; pC->m_Codewords[i]->m_iT_last_time = 1; pC->m_Codewords[i]->m_iMNRL = 0; } } - else{ + else { nKeepCnt = 0; ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pC->m_iNumEntries); - for (i = 0; i < pC->m_iNumEntries; i++){ - if (aKeep[i] == 1){ + for (i = 0; i < pC->m_iNumEntries; i++) { + if (aKeep[i] == 1) { temp[nKeepCnt] = pC->m_Codewords[i]; temp[nKeepCnt]->m_iT_first_time = 1; temp[nKeepCnt]->m_iT_last_time = 1; @@ -1962,11 +1967,11 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntries(short nClearNum, ColorModel* pM //-----------------------------------------------------------------------------------------------------------------------------------------// // Clear non-essential codewords of the given codebook (for cache-book) // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook){ +void MultiCue::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook) { int i; if (pCachebook->m_iTotal < nClearNum) { - for (i = 0; i < pCachebook->m_iNumEntries; i++){ + for (i = 0; i < pCachebook->m_iNumEntries; i++) { if (bLandmark == 255 && i == nReferredIdx) pCachebook->m_Codewords[i]->m_iMNRL = 0; else pCachebook->m_Codewords[i]->m_iMNRL++; } @@ -1974,7 +1979,7 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh pCachebook->m_iTotal++; } - else{ + else { int iStaleThreshold = 5; int* aKeep; @@ -1983,8 +1988,8 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh aKeep = (int*)malloc(sizeof(int)*pCachebook->m_iNumEntries); nKeepCnt = 0; - for (i = 0; i < pCachebook->m_iNumEntries; i++){ - if (pCachebook->m_Codewords[i]->m_iMNRL < iStaleThreshold){ + for (i = 0; i < pCachebook->m_iNumEntries; i++) { + if (pCachebook->m_Codewords[i]->m_iMNRL < iStaleThreshold) { aKeep[i] = 1; nKeepCnt++; } @@ -1997,8 +2002,8 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pCachebook->m_iElementArraySize); nKeepCnt = 0; - for (i = 0; i < pCachebook->m_iNumEntries; i++){ - if (aKeep[i] == 1){ + for (i = 0; i < pCachebook->m_iNumEntries; i++) { + if (aKeep[i] == 1) { temp[nKeepCnt] = pCachebook->m_Codewords[i]; temp[nKeepCnt]->m_iMNRL = 0; nKeepCnt++; @@ -2022,7 +2027,7 @@ void SJN_MultiCueBGS::C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, sh //-----------------------------------------------------------------------------------------------------------------------------------------// // the ghost-region absorption function // //-----------------------------------------------------------------------------------------------------------------------------------------// -void SJN_MultiCueBGS::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache){ +void MultiCue::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache) { //set iLeavingIndex if (aContinuCnt[pos.m_nY][pos.m_nX] < iAbsorbCnt) return; @@ -2030,7 +2035,7 @@ void SJN_MultiCueBGS::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCn int iLeavingIndex = aRefferedIndex[pos.m_nY][pos.m_nX]; //array expansion - if (pModel->m_iElementArraySize == pModel->m_iNumEntries){ + if (pModel->m_iElementArraySize == pModel->m_iNumEntries) { pModel->m_iElementArraySize = pModel->m_iElementArraySize + 5; ColorCodeword** temp = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pModel->m_iElementArraySize); for (int i = 0; i < pModel->m_iNumEntries; i++) temp[i] = pModel->m_Codewords[i]; @@ -2051,9 +2056,9 @@ void SJN_MultiCueBGS::C_Absorption(int iAbsorbCnt, point pos, short** aContinuCn int k = 0; ColorCodeword **pTempCache = (ColorCodeword**)malloc(sizeof(ColorCodeword*)*pCache->m_iElementArraySize); - for (int i = 0; i < pCache->m_iNumEntries; i++){ + for (int i = 0; i < pCache->m_iNumEntries; i++) { if (i == iLeavingIndex) continue; - else{ + else { pTempCache[k] = pCache->m_Codewords[i]; k++; } diff --git a/package_bgs/MultiCue.h b/package_bgs/MultiCue.h new file mode 100644 index 0000000..44524e0 --- /dev/null +++ b/package_bgs/MultiCue.h @@ -0,0 +1,254 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#define MIN3(x,y,z) ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z))) +#define MAX3(x,y,z) ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z))) + +#ifndef PI +#define PI 3.14159 +#endif + +typedef int BOOL; + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#if !defined(__APPLE__) +#include <malloc.h> +#endif +#include "math.h" + +#include <vector> +#include <algorithm> +#include <opencv2/opencv.hpp> + +#include "IBGS.h" + +//------------------------------------Structure Lists-------------------------------------// +namespace bgslibrary +{ + namespace algorithms + { + namespace libMultiCue + { + struct point { + short m_nX; + short m_nY; + }; + + struct neighbor_pos { + short m_nX; + short m_nY; + }; + //1) Bounding Box Structure + struct BoundingBoxInfo { + int m_iBoundBoxNum; //# of bounding boxes for all foreground and false-positive blobs + int m_iArraySize; //the size of the below arrays to store bounding box information + + short *m_aLeft, *m_aRight, *m_aUpper, *m_aBottom; //arrays to store bounding box information for (the original frame size) + short *m_aRLeft, *m_aRRight, *m_aRUpper, *m_aRBottom; //arrays to store bounding box information for (the reduced frame size) + BOOL* m_ValidBox; //If this value is true, the corresponding bounding box is for a foreground blob. + //Else, it is for a false-positive blob + }; + + //2) Texture Model Structure + struct TextureCodeword { + int m_iMNRL; //the maximum negative run-length + int m_iT_first_time; //the first access time + int m_iT_last_time; //the last access time + + float m_fLowThre; //a low threshold for the matching + float m_fHighThre; //a high threshold for the matching + float m_fMean; //mean of the codeword + }; + + struct TextureModel { + TextureCodeword** m_Codewords; //the texture-codeword Array + + int m_iTotal; //# of learned samples after the last clear process + int m_iElementArraySize; //the array size of m_Codewords + int m_iNumEntries; //# of codewords + + BOOL m_bID; //id=1 --> background model, id=0 --> cachebook + }; + + //3) Color Model Structure + struct ColorCodeword { + int m_iMNRL; //the maximum negative run-length + int m_iT_first_time; //the first access time + int m_iT_last_time; //the last access time + + double m_dMean[3]; //mean vector of the codeword + + }; + + struct ColorModel { + ColorCodeword** m_Codewords; //the color-codeword Array + + int m_iTotal; //# of learned samples after the last clear process + int m_iElementArraySize; //the array size of m_Codewords + int m_iNumEntries; //# of codewords + + BOOL m_bID; //id=1 --> background model, id=0 --> cachebookk + }; + } + } +} + +namespace bgslibrary +{ + namespace algorithms + { + using namespace bgslibrary::algorithms::libMultiCue; + + class MultiCue : public IBGS + { + private: + void saveConfig(); + void loadConfig(); + + public: + MultiCue(); + ~MultiCue(); + + public: + //---------------------------------------------------- + // APIs and User-Adjustable Parameters + //---------------------------------------------------- + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); //the main function to background modeling and subtraction + + void GetForegroundMap(IplImage* return_image, IplImage* input_frame = NULL); //the function returning a foreground binary-map + void Destroy(); //the function to release allocated memories + + int g_iTrainingPeriod; //the training period (The parameter t in the paper) + int g_iT_ModelThreshold; //the threshold for texture-model based BGS. (The parameter tau_T in the paper) + int g_iC_ModelThreshold; //the threshold for appearance based verification. (The parameter tau_A in the paper) + + float g_fLearningRate; //the learning rate for background models. (The parameter alpha in the paper) + + short g_nTextureTrainVolRange; //the codebook size factor for texture models. (The parameter k in the paper) + short g_nColorTrainVolRange; //the codebook size factor for color models. (The parameter eta_1 in the paper) + + public: + //---------------------------------------------------- + // Implemented Function Lists + //---------------------------------------------------- + + //--1) General Functions + void Initialize(IplImage* frame); + + void PreProcessing(IplImage* frame); + void ReduceImageSize(IplImage* SrcImage, IplImage* DstImage); + void GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame); + void BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ); + + void BackgroundModeling_Par(IplImage* frame); + void ForegroundExtraction(IplImage* frame); + void CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, + point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr); + + void PostProcessing(IplImage* frame); + void MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight); + void Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLabelTable); + void SetBoundingBox(int iLabelCount, int** aLabelTable); + void BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); + void EvaluateBoxSize(BoundingBoxInfo* BoundBoxInfo); + void EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo); + void EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); + double CalculateHausdorffDist(IplImage* input_image, IplImage* model_image); + void RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); + + void UpdateModel_Par(); + void GetEnlargedMap(float** aOriginMap, float** aEnlargedMap); + + //--2) Texture Model Related Functions + void T_AllocateTextureModelRelatedMemory(); + void T_ReleaseTextureModelRelatedMemory(); + void T_SetNeighborDirection(point*** aNeighborPos); + void T_ModelConstruction(short nTrainVolRange, float fLearningRate, uchar*** aXYZ, point center, point* aNei, TextureModel** aModel); + void T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel); + void T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook); + void T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel); + void T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache); + + //--3) Color Model Related Functions + void C_AllocateColorModelRelatedMemory(); + void C_ReleaseColorModelRelatedMemory(); + void C_CodebookConstruction(uchar* aP, int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC); + void C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel); + void C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook); + void C_Absorption(int iAbsorbCnt, point pos, short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache); + public: + //---------------------------------------------------- + // Implemented Variable Lists + //---------------------------------------------------- + + //--1) General Variables + int g_iFrameCount; //the counter of processed frames + + int g_iBackClearPeriod; //the period to clear background models + int g_iCacheClearPeriod; //the period to clear cache-book models + + int g_iAbsortionPeriod; //the period to absorb static ghost regions + BOOL g_bAbsorptionEnable; //If True, procedures for ghost region absorption are activated. + + BOOL g_bModelMemAllocated; //To handle memory.. + BOOL g_bNonModelMemAllocated; //To handle memory.. + + float g_fConfidenceThre; //the final decision threshold + + int g_iWidth, g_iHeight; //width and height of input frames + int g_iRWidth, g_iRHeight; //width and height of reduced frames (For efficiency, the reduced size of frames are processed) + int g_iForegroundNum; //# of detected foreground regions + BOOL g_bForegroundMapEnable; //TRUE only when BGS is successful + + IplImage* g_ResizedFrame; //reduced size of frame (For efficiency, the reduced size of frames are processed) + uchar*** g_aGaussFilteredFrame; + uchar*** g_aXYZFrame; + uchar** g_aLandmarkArray; //the landmark map + uchar** g_aResizedForeMap; //the resized foreground map + uchar** g_aForegroundMap; //the final foreground map + BOOL** g_aUpdateMap; //the location map of update candidate pixels + + BoundingBoxInfo* g_BoundBoxInfo; //the array of bounding boxes of each foreground blob + + //--2) Texture Model Related + TextureModel**** g_TextureModel; //the texture background model + TextureModel**** g_TCacheBook; //the texture cache-book + short*** g_aTReferredIndex; //To handle cache-book + short*** g_aTContinuousCnt; //To handle cache-book + point*** g_aNeighborDirection; + float**g_aTextureConfMap; //the texture confidence map + + short g_nNeighborNum; //# of neighborhoods + short g_nRadius; + short g_nBoundarySize; + + //--3) Texture Model Related + ColorModel*** g_ColorModel; //the color background model + ColorModel*** g_CCacheBook; //the color cache-book + short** g_aCReferredIndex; //To handle cache-book + short** g_aCContinuousCnt; //To handle cache-book + }; + } +} diff --git a/package_bgs/jmo/MultiLayerBGS.cpp b/package_bgs/MultiLayer.cpp similarity index 65% rename from package_bgs/jmo/MultiLayerBGS.cpp rename to package_bgs/MultiLayer.cpp index 03e223f..180d88d 100644 --- a/package_bgs/jmo/MultiLayerBGS.cpp +++ b/package_bgs/MultiLayer.cpp @@ -14,36 +14,40 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "MultiLayerBGS.h" +#include "MultiLayer.h" -MultiLayerBGS::MultiLayerBGS() : firstTime(true), frameNumber(0), showOutput(true), -saveModel(false), disableDetectMode(true), disableLearning(false), detectAfter(0), bg_model_preload(""), loadDefaultParams(true) +using namespace bgslibrary::algorithms; + +MultiLayer::MultiLayer() : + frameNumber(0), saveModel(false), disableDetectMode(true), disableLearning(false), + detectAfter(0), bg_model_preload(""), loadDefaultParams(true) { - std::cout << "MultiLayerBGS()" << std::endl; + std::cout << "MultiLayer()" << std::endl; + setup("./config/MultiLayer.xml"); } -MultiLayerBGS::~MultiLayerBGS() +MultiLayer::~MultiLayer() { finish(); - std::cout << "~MultiLayerBGS()" << std::endl; + std::cout << "~MultiLayer()" << std::endl; } -void MultiLayerBGS::setStatus(Status _status) +void MultiLayer::setStatus(Status _status) { status = _status; } -void MultiLayerBGS::finish(void) +void MultiLayer::finish() { if (bg_model_preload.empty()) { - bg_model_preload = "./models/MultiLayerBGSModel.yml"; + bg_model_preload = "./MultiLayerModel.yml"; saveConfig(); } if (status == MLBGS_LEARN && saveModel == true) { - std::cout << "MultiLayerBGS saving background model: " << bg_model_preload << std::endl; + std::cout << "MultiLayer saving background model: " << bg_model_preload << std::endl; BGS->Save(bg_model_preload.c_str()); } @@ -57,13 +61,9 @@ void MultiLayerBGS::finish(void) delete BGS; } -void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void MultiLayer::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if (img_input.empty()) - return; - - loadConfig(); - + init(img_input, img_output, img_bgmodel); CvSize img_size = cvSize(cvCeil((double)img_input.size().width), cvCeil((double)img_input.size().height)); if (firstTime) @@ -72,10 +72,10 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M status = MLBGS_LEARN; if (status == MLBGS_LEARN) - std::cout << "MultiLayerBGS in LEARN mode" << std::endl; + std::cout << "MultiLayer in LEARN mode" << std::endl; if (status == MLBGS_DETECT) - std::cout << "MultiLayerBGS in DETECT mode" << std::endl; + std::cout << "MultiLayer in DETECT mode" << std::endl; org_img = new IplImage(img_input); @@ -93,7 +93,7 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M if (bg_model_preload.empty() == false) { - std::cout << "MultiLayerBGS loading background model: " << bg_model_preload << std::endl; + std::cout << "MultiLayer loading background model: " << bg_model_preload << std::endl; BGS->Load(bg_model_preload.c_str()); } @@ -102,14 +102,14 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M BGS->m_disableLearning = disableLearning; if (disableLearning) - std::cout << "MultiLayerBGS disabled learning in DETECT mode" << std::endl; + std::cout << "MultiLayer disabled learning in DETECT mode" << std::endl; else - std::cout << "MultiLayerBGS enabled learning in DETECT mode" << std::endl; + std::cout << "MultiLayer enabled learning in DETECT mode" << std::endl; } if (loadDefaultParams) { - std::cout << "MultiLayerBGS loading default params" << std::endl; + std::cout << "MultiLayer loading default params" << std::endl; max_mode_num = 5; weight_updating_constant = 5.0; @@ -127,7 +127,7 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M bilater_filter_sigma_r = 0.1f; } else - std::cout << "MultiLayerBGS loading config params" << std::endl; + std::cout << "MultiLayer loading config params" << std::endl; BGS->m_nMaxLBPModeNum = max_mode_num; BGS->m_fWeightUpdatingConstant = weight_updating_constant; @@ -186,9 +186,6 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M } BGS->SetParameters(max_mode_num, mode_learn_rate_per_second, weight_learn_rate_per_second, init_mode_weight); - - saveConfig(); - delete org_img; } @@ -199,7 +196,7 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M if (detectAfter > 0 && detectAfter == frameNumber) { - std::cout << "MultiLayerBGS in DETECT mode" << std::endl; + std::cout << "MultiLayer in DETECT mode" << std::endl; status = MLBGS_DETECT; @@ -212,9 +209,9 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M BGS->m_disableLearning = disableLearning; if (disableLearning) - std::cout << "MultiLayerBGS disabled learning in DETECT mode" << std::endl; + std::cout << "MultiLayer disabled learning in DETECT mode" << std::endl; else - std::cout << "MultiLayerBGS enabled learning in DETECT mode" << std::endl; + std::cout << "MultiLayer enabled learning in DETECT mode" << std::endl; } IplImage* img = new IplImage(img_input); @@ -228,15 +225,17 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M BGS->GetForegroundMaskImage(fg_mask_img); BGS->MergeImages(4, img, bg_img, fg_prob_img3, fg_img, merged_img); - img_merged = cv::Mat(merged_img); - img_foreground = cv::Mat(fg_mask_img); - img_background = cv::Mat(bg_img); + img_merged = cv::cvarrToMat(merged_img); + img_foreground = cv::cvarrToMat(fg_mask_img); + img_background = cv::cvarrToMat(bg_img); +#ifndef MEX_COMPILE_FLAG if (showOutput) { cv::imshow("MLBGS Layers", img_merged); cv::imshow("MLBGS FG Mask", img_foreground); } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -248,9 +247,9 @@ void MultiLayerBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::M frameNumber++; } -void MultiLayerBGS::saveConfig() +void MultiLayer::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MultiLayerBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteString(fs, "preloadModel", bg_model_preload.c_str()); cvWriteInt(fs, "saveModel", saveModel); @@ -289,43 +288,43 @@ void MultiLayerBGS::saveConfig() cvReleaseFileStorage(&fs); } -void MultiLayerBGS::loadConfig() +void MultiLayer::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/MultiLayerBGS.xml", 0, CV_STORAGE_READ); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); - bg_model_preload = cvReadStringByName(fs, 0, "preloadModel", ""); - saveModel = cvReadIntByName(fs, 0, "saveModel", false); - detectAfter = cvReadIntByName(fs, 0, "detectAfter", 0); - disableDetectMode = cvReadIntByName(fs, 0, "disableDetectMode", true); - disableLearning = cvReadIntByName(fs, 0, "disableLearningInDetecMode", false); - loadDefaultParams = cvReadIntByName(fs, 0, "loadDefaultParams", true); + bg_model_preload = cvReadStringByName(fs, nullptr, "preloadModel", ""); + saveModel = cvReadIntByName(fs, nullptr, "saveModel", false); + detectAfter = cvReadIntByName(fs, nullptr, "detectAfter", 0); + disableDetectMode = cvReadIntByName(fs, nullptr, "disableDetectMode", true); + disableLearning = cvReadIntByName(fs, nullptr, "disableLearningInDetecMode", false); + loadDefaultParams = cvReadIntByName(fs, nullptr, "loadDefaultParams", true); - max_mode_num = cvReadIntByName(fs, 0, "max_mode_num", 5); + max_mode_num = cvReadIntByName(fs, nullptr, "max_mode_num", 5); weight_updating_constant = cvReadRealByName(fs, 0, "weight_updating_constant", 5.0); - texture_weight = cvReadRealByName(fs, 0, "texture_weight", 0.5); - bg_mode_percent = cvReadRealByName(fs, 0, "bg_mode_percent", 0.6); - pattern_neig_half_size = cvReadIntByName(fs, 0, "pattern_neig_half_size", 4); - pattern_neig_gaus_sigma = cvReadRealByName(fs, 0, "pattern_neig_gaus_sigma", 3.0); - bg_prob_threshold = cvReadRealByName(fs, 0, "bg_prob_threshold", 0.2); - bg_prob_updating_threshold = cvReadRealByName(fs, 0, "bg_prob_updating_threshold", 0.2); - robust_LBP_constant = cvReadIntByName(fs, 0, "robust_LBP_constant", 3); - min_noised_angle = cvReadRealByName(fs, 0, "min_noised_angle", 0.01768); - shadow_rate = cvReadRealByName(fs, 0, "shadow_rate", 0.6); - highlight_rate = cvReadRealByName(fs, 0, "highlight_rate", 1.2); - bilater_filter_sigma_s = cvReadRealByName(fs, 0, "bilater_filter_sigma_s", 3.0); - bilater_filter_sigma_r = cvReadRealByName(fs, 0, "bilater_filter_sigma_r", 0.1); - - frame_duration = cvReadRealByName(fs, 0, "frame_duration", 0.1); - - learn_mode_learn_rate_per_second = cvReadRealByName(fs, 0, "learn_mode_learn_rate_per_second", 0.5); - learn_weight_learn_rate_per_second = cvReadRealByName(fs, 0, "learn_weight_learn_rate_per_second", 0.5); - learn_init_mode_weight = cvReadRealByName(fs, 0, "learn_init_mode_weight", 0.05); - - detect_mode_learn_rate_per_second = cvReadRealByName(fs, 0, "detect_mode_learn_rate_per_second", 0.01); - detect_weight_learn_rate_per_second = cvReadRealByName(fs, 0, "detect_weight_learn_rate_per_second", 0.01); - detect_init_mode_weight = cvReadRealByName(fs, 0, "detect_init_mode_weight", 0.001); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + texture_weight = cvReadRealByName(fs, nullptr, "texture_weight", 0.5); + bg_mode_percent = cvReadRealByName(fs, nullptr, "bg_mode_percent", 0.6); + pattern_neig_half_size = cvReadIntByName(fs, nullptr, "pattern_neig_half_size", 4); + pattern_neig_gaus_sigma = cvReadRealByName(fs, nullptr, "pattern_neig_gaus_sigma", 3.0); + bg_prob_threshold = cvReadRealByName(fs, nullptr, "bg_prob_threshold", 0.2); + bg_prob_updating_threshold = cvReadRealByName(fs, nullptr, "bg_prob_updating_threshold", 0.2); + robust_LBP_constant = cvReadIntByName(fs, nullptr, "robust_LBP_constant", 3); + min_noised_angle = cvReadRealByName(fs, nullptr, "min_noised_angle", 0.01768); + shadow_rate = cvReadRealByName(fs, nullptr, "shadow_rate", 0.6); + highlight_rate = cvReadRealByName(fs, nullptr, "highlight_rate", 1.2); + bilater_filter_sigma_s = cvReadRealByName(fs, nullptr, "bilater_filter_sigma_s", 3.0); + bilater_filter_sigma_r = cvReadRealByName(fs, nullptr, "bilater_filter_sigma_r", 0.1); + + frame_duration = cvReadRealByName(fs, nullptr, "frame_duration", 0.1); + + learn_mode_learn_rate_per_second = cvReadRealByName(fs, nullptr, "learn_mode_learn_rate_per_second", 0.5); + learn_weight_learn_rate_per_second = cvReadRealByName(fs, nullptr, "learn_weight_learn_rate_per_second", 0.5); + learn_init_mode_weight = cvReadRealByName(fs, nullptr, "learn_init_mode_weight", 0.05); + + detect_mode_learn_rate_per_second = cvReadRealByName(fs, nullptr, "detect_mode_learn_rate_per_second", 0.01); + detect_weight_learn_rate_per_second = cvReadRealByName(fs, nullptr, "detect_weight_learn_rate_per_second", 0.01); + detect_init_mode_weight = cvReadRealByName(fs, nullptr, "detect_init_mode_weight", 0.001); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/MultiLayer.h b/package_bgs/MultiLayer.h new file mode 100644 index 0000000..af7e128 --- /dev/null +++ b/package_bgs/MultiLayer.h @@ -0,0 +1,99 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "MultiLayer/CMultiLayerBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class MultiLayer : public IBGS + { + public: + enum Status + { + MLBGS_NONE = -1, + MLBGS_LEARN = 0, + MLBGS_DETECT = 1 + }; + + private: + long long frameNumber; + cv::Mat img_merged; + bool saveModel; + bool disableDetectMode; + bool disableLearning; + int detectAfter; + CMultiLayerBGS* BGS; + Status status; + IplImage* img; + IplImage* org_img; + IplImage* fg_img; + IplImage* bg_img; + IplImage* fg_prob_img; + IplImage* fg_mask_img; + IplImage* fg_prob_img3; + IplImage* merged_img; + std::string bg_model_preload; + + bool loadDefaultParams; + + int max_mode_num; + float weight_updating_constant; + float texture_weight; + float bg_mode_percent; + int pattern_neig_half_size; + float pattern_neig_gaus_sigma; + float bg_prob_threshold; + float bg_prob_updating_threshold; + int robust_LBP_constant; + float min_noised_angle; + float shadow_rate; + float highlight_rate; + float bilater_filter_sigma_s; + float bilater_filter_sigma_r; + + float frame_duration; + + float mode_learn_rate_per_second; + float weight_learn_rate_per_second; + float init_mode_weight; + + float learn_mode_learn_rate_per_second; + float learn_weight_learn_rate_per_second; + float learn_init_mode_weight; + + float detect_mode_learn_rate_per_second; + float detect_weight_learn_rate_per_second; + float detect_init_mode_weight; + + public: + MultiLayer(); + ~MultiLayer(); + + void setStatus(Status status); + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void finish(); + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/jmo/BGS.h b/package_bgs/MultiLayer/BGS.h similarity index 98% rename from package_bgs/jmo/BGS.h rename to package_bgs/MultiLayer/BGS.h index c506df2..ad2129b 100644 --- a/package_bgs/jmo/BGS.h +++ b/package_bgs/MultiLayer/BGS.h @@ -40,10 +40,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#if !defined(_BGS_H_) -#define _BGS_H_ +#pragma once -#include <opencv2/opencv.hpp> +#include "OpenCvLegacyIncludes.h" // TODO check these defines are not used (or not redundant with real params) @@ -211,6 +210,3 @@ class IMAGE_BG_MODEL delete[] pixel_PATTERNs; } }; - - -#endif // !defined(_BGS_H_) diff --git a/package_bgs/jmo/BackgroundSubtractionAPI.h b/package_bgs/MultiLayer/BackgroundSubtractionAPI.h similarity index 89% rename from package_bgs/jmo/BackgroundSubtractionAPI.h rename to package_bgs/MultiLayer/BackgroundSubtractionAPI.h index bb39611..409fa40 100644 --- a/package_bgs/jmo/BackgroundSubtractionAPI.h +++ b/package_bgs/MultiLayer/BackgroundSubtractionAPI.h @@ -60,12 +60,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // char image for the output // ////////////////////////////////////////////////////////////////////// +#pragma once - -#if !defined(_BACKGROUND_SUBTRACTION_API_H_) -#define _BACKGROUND_SUBTRACTION_API_H_ - -#include <opencv2/opencv.hpp> +#include "OpenCvLegacyIncludes.h" class CBackgroundSubtractionAPI { @@ -79,14 +76,14 @@ public: void Init(int width, int height); //------------------------------------------------------------- - // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND + // PROVIDE A MASK TO DEFINE THE SET OF POINTS WHERE BACKGROUND // SUBTRACTION DOES NOT NEED TO BE PERFORMED - // - // mode is useful to specify if the points to remove from + // + // mode is useful to specify if the points to remove from // processing are in addition to the ones potentially // removed according to the configuration file, - // or if they are the only ones to be removed - // + // or if they are the only ones to be removed + // // mode=0 : provided points need to be removed // in addition to those already removed // mode=1 : the provided points are the only one to remove @@ -96,12 +93,12 @@ public: void SetValidPointMask(IplImage* maskImage, int mode); //------------------------------------------------------------- - // + // // set the frame rate, to adjust the update parameters // to the actual frame rate. // Can be called only once at initialisation, // but in online cases, can be used to indicate - // the time interval during the last processed frame + // the time interval during the last processed frame // // frameDuration is in millisecond void SetFrameRate(float frameDuration); @@ -113,31 +110,31 @@ public: // Here assumes that the input image will contain RGB images. // The memory of this image is handled by the caller. // - // The return value indicate whether the actual Background + // The return value indicate whether the actual Background // Subtraction algorithm handles RGB images (1) or not (0). - // + // int SetRGBInputImage(IplImage * inputImage); //------------------------------------------------------------- // PROVIDE A POINTER TO THE RESULT IMAGE // INDICATE WHERE THE BACKGROUND RESULT NEED TO BE STORED - // + // // The return value is 1 if correct image format is provided, // otherwise the return value is 0. // e.g. fg_mask_img = cvCreateImage(imgSize, IPL_DEPTH_8U, 1); int SetForegroundMaskImage(IplImage *fg_mask_img); - // The return value is 1 if the function is implemented + // The return value is 1 if the function is implemented // with correct format, otherwise the return value is 0 // e.g. fg_prob_img = cvCreateImage(imgSize, IPL_DEPTH_32F, 1); int SetForegroundProbImage(IplImage *fg_prob_img); //------------------------------------------------------------- - // This function should be called each time a new image is + // This function should be called each time a new image is // available in the input image. - // + // // The return value is 1 if everything goes well, - // otherwise the return value is 0. + // otherwise the return value is 0. // int Process(); @@ -150,9 +147,7 @@ public: //------------------------------------------------------------- // this function should load the parameters necessary - // for the processing of the background subtraction or + // for the processing of the background subtraction or // load background model information void Load(char *bg_model_fn); }; - -#endif // !defined(_BACKGROUND_SUBTRACTION_API_H_) diff --git a/package_bgs/jmo/BlobExtraction.cpp b/package_bgs/MultiLayer/BlobExtraction.cpp similarity index 91% rename from package_bgs/jmo/BlobExtraction.cpp rename to package_bgs/MultiLayer/BlobExtraction.cpp index 81857eb..7aecd65 100644 --- a/package_bgs/jmo/BlobExtraction.cpp +++ b/package_bgs/MultiLayer/BlobExtraction.cpp @@ -55,47 +55,47 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. //! Indica si la connectivitat es a 8 (si es desactiva es a 4) #define B_CONNECTIVITAT_8 -//! si la imatge �s c�clica verticalment (els blobs que toquen +//! si la imatge és cÃclica verticalment (els blobs que toquen //! les vores superior i inferior no es consideren externs) #define IMATGE_CICLICA_VERTICAL 1 -//! si la imatge �s c�clica horitzontalment (els blobs que toquen +//! si la imatge és cÃclica horitzontalment (els blobs que toquen //! les vores dreta i esquerra no es consideren externs) #define IMATGE_CICLICA_HORITZONTAL 0 #define PERIMETRE_DIAGONAL (1.41421356237310 - 2) #define SQRT2 1.41421356237310 -// color dels p�xels de la m�scara per ser exteriors +// color dels pÃxels de la mà scara per ser exteriors #define PIXEL_EXTERIOR 0 #include "BlobResult.h" #include "BlobExtraction.h" -#include <opencv2/legacy/compat.hpp> +#include "OpenCvLegacyIncludes.h" namespace Blob { /** - - FUNCI�: BlobAnalysis - - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal - - PAR�METRES: - - inputImage: Imatge d'entrada. Ha de ser d'un sol canal - - threshold: Nivell de gris per considerar un pixel blanc o negre - - maskImage: Imatge de m�scara fora de la cual no es calculen els blobs. A m�s, - els blobs que toquen els pixels de la m�scara a 0, s�n considerats - externs - - borderColor: Color del marc de la imatge (0=black or 1=white) - - findmoments: calcula els moments dels blobs o no - - RegionData: on es desar� el resultat - - RESULTAT: - - retorna true si tot ha anat b�, false si no. Deixa el resultat a blobs. - - RESTRICCIONS: - - La imatge d'entrada ha de ser d'un sol canal - - AUTOR: dgrossman@cdr.stanford.edu - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptaci� a les OpenCV - */ + - FUNCIÓ: BlobAnalysis + - FUNCIONALITAT: Extreu els blobs d'una imatge d'un sol canal + - PARÀMETRES: + - inputImage: Imatge d'entrada. Ha de ser d'un sol canal + - threshold: Nivell de gris per considerar un pixel blanc o negre + - maskImage: Imatge de mà scara fora de la cual no es calculen els blobs. A més, + els blobs que toquen els pixels de la mà scara a 0, són considerats + externs + - borderColor: Color del marc de la imatge (0=black or 1=white) + - findmoments: calcula els moments dels blobs o no + - RegionData: on es desarà el resultat + - RESULTAT: + - retorna true si tot ha anat bé, false si no. Deixa el resultat a blobs. + - RESTRICCIONS: + - La imatge d'entrada ha de ser d'un sol canal + - AUTOR: dgrossman@cdr.stanford.edu + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + - fpinyol@cvc.uab.es, rborras@cvc.uab.es: adaptació a les OpenCV + */ bool BlobAnalysis(IplImage* inputImage, uchar threshold, IplImage* maskImage, @@ -151,13 +151,13 @@ namespace Blob if (!CV_IS_IMAGE(inputImage) || !CV_IS_IMAGE(maskImage)) return false; - // comprova que la m�scara tingui les mateixes dimensions que la imatge + // comprova que la mà scara tingui les mateixes dimensions que la imatge if (inputImage->width != maskImage->width || inputImage->height != maskImage->height) { return false; } - // comprova que la m�scara sigui una imatge d'un sol canal (grayscale) + // comprova que la mà scara sigui una imatge d'un sol canal (grayscale) if (maskImage->nChannels != 1) { return false; @@ -167,16 +167,16 @@ namespace Blob // Initialize Transition array Transition = new int[(Rows + 2)*(Cols + 2)]; - memset(Transition, 0, (Rows + 2) * (Cols + 2)*sizeof(int)); + memset(Transition, 0, (Rows + 2) * (Cols + 2) * sizeof(int)); Transition[0] = Transition[(Rows + 1) * (Cols + 2)] = Cols + 2; // Start at the beginning of the image (startCol, startRow) pImage = inputImage->imageData + startCol - 1 + startRow * inputImage->widthStep; /* - Paral�lelitzaci� del c�lcul de la matriu de transicions - Fem que cada iteraci� del for el faci un thread o l'altre ( tenim 2 possibles threads ) - */ + Paral·lelització del cà lcul de la matriu de transicions + Fem que cada iteració del for el faci un thread o l'altre ( tenim 2 possibles threads ) + */ if (maskImage == NULL) { imatgePerimetreExtern = NULL; @@ -184,7 +184,7 @@ namespace Blob //Fill Transition array for (iRow = 1; iRow < Rows + 1; iRow++) // Choose a row of Bordered image { - TransitionOffset = iRow*(Cols + 2); //per a que sigui paral�litzable + TransitionOffset = iRow*(Cols + 2); //per a que sigui paral·litzable iTran = 0; // Index into Transition array Tran = 0; // No transitions at row start LastCell = borderColor; @@ -218,12 +218,12 @@ namespace Blob } else { - //maskImage not NULL: Cal rec�rrer la m�scara tamb� per calcular la matriu de transicions + //maskImage not NULL: Cal recòrrer la mà scara també per calcular la matriu de transicions char perimeter; char *pPerimetre; - // creem la imatge que contindr� el perimetre extern de cada pixel + // creem la imatge que contindrà el perimetre extern de cada pixel imatgePerimetreExtern = cvCreateImage(cvSize(maskImage->width, maskImage->height), IPL_DEPTH_8U, 1); cvSetZero(imatgePerimetreExtern); @@ -255,9 +255,9 @@ namespace Blob } /*//////////////////////////////////////////////////////////////////////// - Calcul de la imatge amb els pixels externs - ////////////////////////////////////////////////////////////////////////*/ - // pels pixels externs no cal calcular res pq no hi accedir-hem + Calcul de la imatge amb els pixels externs + ////////////////////////////////////////////////////////////////////////*/ + // pels pixels externs no cal calcular res pq no hi accedir-hem if ((iCol > 0) && (iCol < Cols)) { if (*pMask == PIXEL_EXTERIOR) @@ -277,7 +277,7 @@ namespace Blob // pixels a l'est i oest de l'actual if (iRow < imatgePerimetreExtern->height) { - if ((iCol>0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++; + if ((iCol > 0) && (*(pMask - 1) == PIXEL_EXTERIOR)) perimeter++; if ((iCol < imatgePerimetreExtern->width - 1) && (*(pMask + 1) == PIXEL_EXTERIOR)) perimeter++; } @@ -323,7 +323,7 @@ namespace Blob // Last |xxx |xxxxoo |xxxxxxx|xxxxxxx|ooxxxxx|ooxxx |ooxxxxx| xxx| // This | yyy| yyy| yyyy | yyyyy|yyyyyyy|yyyyyyy|yyyy |yyyy | // Here o is optional - // + // // Here are the primitive tests to distinguish these 6 cases: // A) Last end < This start - 1 OR NOT Note: -1 // B) This end < Last start OR NOT @@ -409,7 +409,7 @@ namespace Blob uchar imagevalue; bool CandidatExterior = false; - // apuntadors als blobs de la regi� actual i last + // apuntadors als blobs de la regió actual i last CBlob *regionDataThisRegion, *regionDataLastRegion; LastRegion = new int[Cols + 2]; @@ -431,7 +431,7 @@ namespace Blob ThisIndexCount = 1; ThisRegion[0] = 0; // Border region - // beginning of the image + // beginning of the image // en cada linia, pimage apunta al primer pixel de la fila pImage = inputImage->imageData - 1 + startCol + startRow * inputImage->widthStep; //the mask should be the same size as image Roi, so don't take into account the offset @@ -457,9 +457,9 @@ namespace Blob { int Index = ThisOffset + j; int TranVal = Transition[Index]; - if (TranVal > 0) ThisIndexCount = j + 1; // stop at highest + if (TranVal > 0) ThisIndexCount = j + 1; // stop at highest - if (ThisRegion[j] == -1) { EndLast = 1; } + if (ThisRegion[j] == -1) { EndLast = 1; } if (TranVal < 0) { EndThis = 1; } if (EndLast > 0 && EndThis > 0) { break; } @@ -505,7 +505,7 @@ namespace Blob #endif #if !IMATGE_CICLICA_HORITZONTAL ThisStart <= 1 || ThisEnd >= Cols || -#endif +#endif GetExternPerimeter(ThisStart, ThisEnd, ThisRow, inputImage->width, inputImage->height, imatgePerimetreExtern) ) { @@ -601,7 +601,7 @@ namespace Blob //afegim la cantonada a ThisRegion if (ThisRegionNum != -1) { - // afegim dos vertexs si s�n diferents, nom�s + // afegim dos vertexs si són diferents, només if (ThisStart - 1 != ThisEnd) { actualedge.x = ThisStart - 1; @@ -615,7 +615,7 @@ namespace Blob //afegim la cantonada a ThisRegion if (LastRegionNum != -1 && LastRegionNum != ThisRegionNum) { - // afegim dos vertexs si s�n diferents, nom�s + // afegim dos vertexs si són diferents, només if (ThisStart - 1 != ThisEnd) { actualedge.x = ThisStart - 1; @@ -662,8 +662,8 @@ namespace Blob SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); if (CandidatExterior) ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); + inputImage->width, inputImage->height, + imatgePerimetreExtern); } @@ -728,8 +728,8 @@ namespace Blob SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); if (CandidatExterior) ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); + inputImage->width, inputImage->height, + imatgePerimetreExtern); } @@ -789,8 +789,8 @@ namespace Blob SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); if (CandidatExterior) ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); + inputImage->width, inputImage->height, + imatgePerimetreExtern); } else if (TestMatch && !TestKnown) // Same color and unknown @@ -986,8 +986,8 @@ namespace Blob SubsumedRegion = NewSubsume(SubsumedRegion, HighRegionNum); if (CandidatExterior) ThisExternPerimeter = GetExternPerimeter(ThisStart, ThisEnd, ThisRow, - inputImage->width, inputImage->height, - imatgePerimetreExtern); + inputImage->width, inputImage->height, + imatgePerimetreExtern); } else if (TestMatch && !TestKnown) @@ -1077,7 +1077,7 @@ namespace Blob //|yyyy | #ifdef B_CONNECTIVITAT_8 - // fusionem blobs + // fusionem blobs if (TestMatch) { if (ThisRegionNum > LastRegionNum) @@ -1159,7 +1159,7 @@ namespace Blob } - // compute the mean gray level and its std deviation + // compute the mean gray level and its std deviation if (ThisRow <= Rows) { pImageAux = pImage + ThisStart; @@ -1170,9 +1170,9 @@ namespace Blob { if (maskImage != NULL) { - // nom�s es t� en compte el valor del p�xel de la - // imatge que queda dins de la m�scara - // (de pas, comptem el nombre de p�xels de la m�scara) + // només es té en compte el valor del pÃxel de la + // imatge que queda dins de la mà scara + // (de pas, comptem el nombre de pÃxels de la mà scara) if (((unsigned char)*pMaskAux) != PIXEL_EXTERIOR) { imagevalue = (unsigned char)(*pImageAux); @@ -1200,7 +1200,7 @@ namespace Blob // compute the min and max values of X and Y if (ThisStart - 1 < (int)ThisMinX) ThisMinX = (float)(ThisStart - 1); if (ThisMinX < (float) 0.0) ThisMinX = (float) 0.0; - if (ThisEnd >(int) ThisMaxX) ThisMaxX = (float)ThisEnd; + if (ThisEnd > (int) ThisMaxX) ThisMaxX = (float)ThisEnd; if (ThisRow - 1 < ThisMinY) ThisMinY = ThisRow - 1; if (ThisMinY < (float) 0.0) ThisMinY = (float) 0.0; @@ -1242,10 +1242,10 @@ namespace Blob } // end Main loop if (ErrorFlag != 0) { - delete[] Transition; - delete[] ThisRegion; - delete[] LastRegion; - return false; + delete[] Transition; + delete[] ThisRegion; + delete[] LastRegion; + return false; } // ens situem al primer pixel de la seguent fila pImage = inputImage->imageData - 1 + startCol + (ThisRow + startRow) * inputImage->widthStep; @@ -1254,19 +1254,19 @@ namespace Blob pMask = maskImage->imageData - 1 + ThisRow * maskImage->widthStep; } // end Loop over all rows - // eliminem l'�rea del marc - // i tamb� els p�xels de la m�scara + // eliminem l'à rea del marc + // i també els pÃxels de la mà scara // ATENCIO: PERFER: el fet de restar el nombre_pixels_mascara del - // blob 0 nom�s ser� cert si la m�scara t� contacte amb el marc. - // Si no, s'haur� de trobar quin �s el blob que cont� m�s p�xels del + // blob 0 només serà cert si la mà scara té contacte amb el marc. + // Si no, s'haurà de trobar quin és el blob que conté més pÃxels del // compte. RegionData[0]->area -= (Rows + 1 + Cols + 1) * 2 + nombre_pixels_mascara; - // eliminem el per�metre de m�s: - // - sense marc: 2m+2n (per�metre extern) + // eliminem el perÃmetre de més: + // - sense marc: 2m+2n (perÃmetre extern) // - amb marc: 2(m+2)+2(n+2) = 2m+2n + 8 - // (segurament no �s del tot acurat) - // (i amb les m�scares encara menys...) + // (segurament no és del tot acurat) + // (i amb les mà scares encara menys...) RegionData[0]->perimeter -= 8.0; // Condense the list @@ -1306,7 +1306,7 @@ namespace Blob if (findmoments) { iti = RegionData.begin(); - // Normalize summation fields into moments + // Normalize summation fields into moments for (ThisRegionNum = 0; ThisRegionNum <= HighRegionNum; ThisRegionNum++, iti++) { blobActual = *iti; @@ -1340,10 +1340,10 @@ namespace Blob blobActual->stddev = sqrt( ( - blobActual->stddev * blobActual->area - - blobActual->mean * blobActual->mean - ) / - (blobActual->area*(blobActual->area - 1)) + blobActual->stddev * blobActual->area - + blobActual->mean * blobActual->mean + ) / + (blobActual->area*(blobActual->area - 1)) ); } else @@ -1385,16 +1385,16 @@ namespace Blob } else { - subsumed = (int*)realloc(subsumed, (index_subsume + 1)*sizeof(int)); + subsumed = (int*)realloc(subsumed, (index_subsume + 1) * sizeof(int)); } subsumed[index_subsume] = 0; return subsumed; } /** - Fusiona dos blobs i afegeix el blob les caracter�stiques del blob RegionData[HiNum] - al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum] - */ + Fusiona dos blobs i afegeix el blob les caracterÃstiques del blob RegionData[HiNum] + al blob RegionData[LoNum]. Al final allibera el blob de RegionData[HiNum] + */ void Subsume(blob_vector &RegionData, int HighRegionNum, int* SubsumedRegion, @@ -1440,28 +1440,28 @@ namespace Blob // marquem el blob com a lliure blobHi->etiqueta = -1; - // Atenci�!!!! abans d'eliminar els edges + // Atenció!!!! abans d'eliminar els edges // s'han de traspassar del blob HiNum al blob LoNum blobHi->CopyEdges(*blobLo); blobHi->ClearEdges(); } /** - - FUNCI�: GetExternPerimeter - - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght - - PAR�METRES: - - start: columna d'inici del run - - end: columna final del run - - row: fila del run - - maskImage: m�scara pels pixels externs - - RESULTAT: - - quantitat de perimetre extern d'un run, suposant que �s un blob - d'una �nica fila d'al�ada - - RESTRICCIONS: - - AUTOR: - - DATA DE CREACI�: 2006/02/27 - - MODIFICACI�: Data. Autor. Descripci�. - */ + - FUNCIÓ: GetExternPerimeter + - FUNCIONALITAT: Retorna el perimetre extern d'una run lenght + - PARÀMETRES: + - start: columna d'inici del run + - end: columna final del run + - row: fila del run + - maskImage: mà scara pels pixels externs + - RESULTAT: + - quantitat de perimetre extern d'un run, suposant que és un blob + d'una única fila d'alçada + - RESTRICCIONS: + - AUTOR: + - DATA DE CREACIÓ: 2006/02/27 + - MODIFICACIÓ: Data. Autor. Descripció. + */ double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *imatgePerimetreExtern) { double perimeter = 0.0f; @@ -1474,7 +1474,7 @@ namespace Blob if (row >= height - 1) perimeter += start - end; - // comprovem els pixels que toquen a la m�scara (si s'escau) + // comprovem els pixels que toquen a la mà scara (si s'escau) if (imatgePerimetreExtern != NULL) { if (row <= 0 || row >= height) return perimeter; diff --git a/package_bgs/jmo/BlobExtraction.h b/package_bgs/MultiLayer/BlobExtraction.h similarity index 96% rename from package_bgs/jmo/BlobExtraction.h rename to package_bgs/MultiLayer/BlobExtraction.h index 9f47b02..d8bd1af 100644 --- a/package_bgs/jmo/BlobExtraction.h +++ b/package_bgs/MultiLayer/BlobExtraction.h @@ -49,10 +49,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. //* Email: dgrossman@cdr.stanford.edu *// //* Acknowledgement: the algorithm has been around > 20 yrs *// //***********************************************************// - - -#if !defined(_CLASSE_BLOBEXTRACTION_INCLUDED) -#define _CLASSE_BLOBEXTRACTION_INCLUDED +#pragma once namespace Blob { @@ -71,6 +68,3 @@ namespace Blob //! Retorna el perimetre extern d'una run lenght double GetExternPerimeter(int start, int end, int row, int width, int height, IplImage *maskImage); } - -#endif //_CLASSE_BLOBEXTRACTION_INCLUDED - diff --git a/package_bgs/jmo/BlobLibraryConfiguration.h b/package_bgs/MultiLayer/BlobLibraryConfiguration.h similarity index 95% rename from package_bgs/jmo/BlobLibraryConfiguration.h rename to package_bgs/MultiLayer/BlobLibraryConfiguration.h index b864fc7..0ba18fc 100644 --- a/package_bgs/jmo/BlobLibraryConfiguration.h +++ b/package_bgs/MultiLayer/BlobLibraryConfiguration.h @@ -43,15 +43,16 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. /************************************************************************ BlobLibraryConfiguration.h -FUNCIONALITAT: Configuraci� del comportament global de la llibreria +FUNCIONALITAT: Configuració del comportament global de la llibreria AUTOR: Inspecta S.L. -MODIFICACIONS (Modificaci�, Autor, Data): +MODIFICACIONS (Modificació, Autor, Data): FUNCTIONALITY: Global configuration of the library AUTHOR: Inspecta S.L. MODIFICATIONS (Modification, Author, Date): **************************************************************************/ +#pragma once //! Indica si es volen fer servir les MatrixCV o no //! Use/Not use the MatrixCV class diff --git a/package_bgs/MultiLayer/BlobResult.cpp b/package_bgs/MultiLayer/BlobResult.cpp new file mode 100644 index 0000000..1ec60e3 --- /dev/null +++ b/package_bgs/MultiLayer/BlobResult.cpp @@ -0,0 +1,847 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* --- --- --- +* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. The name of the author may not be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/************************************************************************ +BlobResult.cpp + +FUNCIONALITAT: Implementació de la classe CBlobResult +AUTOR: Inspecta S.L. +MODIFICACIONS (Modificació, Autor, Data): + +**************************************************************************/ + +#include <limits.h> +#include <stdio.h> +#include <functional> +#include <algorithm> +#include "BlobResult.h" +#include "BlobExtraction.h" + +/************************************************************************** +Constructors / Destructors +**************************************************************************/ + +namespace Blob +{ + + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor estandard. + - PARÀMETRES: + - RESULTAT: + - Crea un CBlobResult sense cap blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobResult + - FUNCTIONALITY: Standard constructor + - PARAMETERS: + - RESULT: + - creates an empty set of blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult() + { + m_blobs = blob_vector(); + } + + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seqüència de blobs + amb els blobs resultants de l'anà lisi de blobs de la imatge. + - PARÀMETRES: + - source: imatge d'on s'extreuran els blobs + - mask: mà scara a aplicar. Només es calcularan els blobs on la mà scara sigui + diferent de 0. Els blobs que toquin a un pixel 0 de la mà scara seran + considerats exteriors. + - threshold: llindar que s'aplicarà a la imatge source abans de calcular els blobs + - findmoments: indica si s'han de calcular els moments de cada blob + - RESULTAT: + - objecte CBlobResult amb els blobs de la imatge source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in + the image + - PARAMETERS: + - source: image to extract the blobs from + - mask: optional mask to apply. The blobs will be extracted where the mask is + not 0. All the neighbouring blobs where the mask is 0 will be extern blobs + - threshold: threshold level to apply to the image before computing blobs + - findmoments: true to calculate the blob moments (slower) + - RESULT: + - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS + if some error appears in the BlobAnalysis function + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments) + { + bool success; + + try + { + // cridem la funció amb el marc a true=1=blanc (aixà no unirà els blobs externs) + success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs); + } + catch (...) + { + success = false; + } + + if (!success) throw EXCEPCIO_CALCUL_BLOBS; + } + + /** + - FUNCIÓ: CBlobResult + - FUNCIONALITAT: Constructor de còpia. Inicialitza la seqüència de blobs + amb els blobs del parà metre. + - PARÀMETRES: + - source: objecte que es copiarà + - RESULTAT: + - objecte CBlobResult amb els blobs de l'objecte source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobResult + - FUNCTIONALITY: Copy constructor + - PARAMETERS: + - source: object to copy + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::CBlobResult(const CBlobResult &source) + { + m_blobs = blob_vector(source.GetNumBlobs()); + + // creem el nou a partir del passat com a parà metre + m_blobs = blob_vector(source.GetNumBlobs()); + // copiem els blobs de l'origen a l'actual + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = m_blobs.begin(); + + while (pBlobsSrc != source.m_blobs.end()) + { + // no podem cridar a l'operador = ja que blob_vector és un + // vector de CBlob*. Per tant, creem un blob nou a partir del + // blob original + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + ++pBlobsDst; + } + } + + + + /** + - FUNCIÓ: ~CBlobResult + - FUNCIONALITAT: Destructor estandard. + - PARÀMETRES: + - RESULTAT: + - Allibera la memòria reservada de cadascun dels blobs de la classe + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: ~CBlobResult + - FUNCTIONALITY: Destructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult::~CBlobResult() + { + ClearBlobs(); + } + + /************************************************************************** + Operadors / Operators + **************************************************************************/ + + + /** + - FUNCIÓ: operador = + - FUNCIONALITAT: Assigna un objecte source a l'actual + - PARÀMETRES: + - source: objecte a assignar + - RESULTAT: + - Substitueix els blobs actuals per els de l'objecte source + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Assigment operator + - FUNCTIONALITY: + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult& CBlobResult::operator=(const CBlobResult& source) + { + // si ja són el mateix, no cal fer res + if (this != &source) + { + // alliberem el conjunt de blobs antic + for (int i = 0; i < GetNumBlobs(); i++) + { + delete m_blobs[i]; + } + m_blobs.clear(); + // creem el nou a partir del passat com a parà metre + m_blobs = blob_vector(source.GetNumBlobs()); + // copiem els blobs de l'origen a l'actual + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = m_blobs.begin(); + + while (pBlobsSrc != source.m_blobs.end()) + { + // no podem cridar a l'operador = ja que blob_vector és un + // vector de CBlob*. Per tant, creem un blob nou a partir del + // blob original + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + ++pBlobsDst; + } + } + return *this; + } + + + /** + - FUNCIÓ: operador + + - FUNCIONALITAT: Concatena els blobs de dos CBlobResult + - PARÀMETRES: + - source: d'on s'agafaran els blobs afegits a l'actual + - RESULTAT: + - retorna un nou CBlobResult amb els dos CBlobResult concatenats + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - NOTA: per la implementació, els blobs del parà metre es posen en ordre invers + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: + operator + - FUNCTIONALITY: Joins the blobs in source with the current ones + - PARAMETERS: + - source: object to copy the blobs + - RESULT: + - object with the actual blobs and the source blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlobResult CBlobResult::operator+(const CBlobResult& source) + { + //creem el resultat a partir dels blobs actuals + CBlobResult resultat(*this); + + // reservem memòria per als nous blobs + resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs()); + + // declarem els iterador per recòrrer els blobs d'origen i desti + blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); + blob_vector::iterator pBlobsDst = resultat.m_blobs.end(); + + // insertem els blobs de l'origen a l'actual + while (pBlobsSrc != source.m_blobs.end()) + { + --pBlobsDst; + *pBlobsDst = new CBlob(**pBlobsSrc); + ++pBlobsSrc; + } + + return resultat; + } + + /************************************************************************** + Operacions / Operations + **************************************************************************/ + + /** + - FUNCIÓ: AddBlob + - FUNCIONALITAT: Afegeix un blob al conjunt + - PARÀMETRES: + - blob: blob a afegir + - RESULTAT: + - modifica el conjunt de blobs actual + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 2006/03/01 + - MODIFICACIÓ: Data. Autor. Descripció. + */ + void CBlobResult::AddBlob(CBlob *blob) + { + if (blob != NULL) + m_blobs.push_back(new CBlob(blob)); + } + + + /** + - FUNCIÓ: GetSTLResult + - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe + - PARÀMETRES: + - evaluador: Qualsevol objecte derivat de COperadorBlob + - RESULTAT: + - Retorna un array de double's STL amb el resultat per cada blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetResult + - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class + and returns a vector with the result + - PARAMETERS: + - evaluador: function to apply to each blob (any object derived from the + COperadorBlob class ) + - RESULT: + - vector with all the results in the same order as the blobs + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const + { + if (GetNumBlobs() <= 0) + { + return double_stl_vector(); + } + + // definim el resultat + double_stl_vector result = double_stl_vector(GetNumBlobs()); + // i iteradors sobre els blobs i el resultat + double_stl_vector::iterator itResult = result.begin(); + blob_vector::const_iterator itBlobs = m_blobs.begin(); + + // avaluem la funció en tots els blobs + while (itBlobs != m_blobs.end()) + { + *itResult = (*evaluador)(**itBlobs); + ++itBlobs; + ++itResult; + } + return result; + } + + /** + - FUNCIÓ: GetNumber + - FUNCIONALITAT: Calcula el resultat especificat sobre un únic blob de la classe + - PARÀMETRES: + - evaluador: Qualsevol objecte derivat de COperadorBlob + - indexblob: número de blob del que volem calcular el resultat. + - RESULTAT: + - Retorna un double amb el resultat + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetNumber + - FUNCTIONALITY: Computes the function evaluador on a blob of the class + - PARAMETERS: + - indexBlob: index of the blob to compute the function + - evaluador: function to apply to each blob (any object derived from the + COperadorBlob class ) + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const + { + if (indexBlob < 0 || indexBlob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + return (*evaluador)(*m_blobs[indexBlob]); + } + + /////////////////////////// FILTRAT DE BLOBS //////////////////////////////////// + + /** + - FUNCIÓ: Filter + - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb només + els blobs que han passat el filtre. + El filtrat es basa en especificar condicions sobre un resultat dels blobs + i seleccionar (o excloure) aquells blobs que no compleixen una determinada + condicio + - PARÀMETRES: + - dst: variable per deixar els blobs filtrats + - filterAction: acció de filtrat. Incloure els blobs trobats (B_INCLUDE), + o excloure els blobs trobats (B_EXCLUDE) + - evaluador: Funció per evaluar els blobs (qualsevol objecte derivat de COperadorBlob + - Condition: tipus de condició que ha de superar la mesura (FilterType) + sobre cada blob per a ser considerat. + B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, + B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE + - LowLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) + - HighLimit: valor numèric per a la comparació (Condition) de la mesura (FilterType) + (només té sentit per a aquelles condicions que tenen dos valors + (B_INSIDE, per exemple). + - RESULTAT: + - Deixa els blobs resultants del filtrat a destination + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Filter + - FUNCTIONALITY: Get some blobs from the class based on conditions on measures + of the blobs. + - PARAMETERS: + - dst: where to store the selected blobs + - filterAction: B_INCLUDE: include the blobs which pass the filter in the result + B_EXCLUDE: exclude the blobs which pass the filter in the result + - evaluador: Object to evaluate the blob + - Condition: How to decide if the result returned by evaluador on each blob + is included or not. It can be: + B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, + B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE + - LowLimit: numerical value to evaluate the Condition on evaluador(blob) + - HighLimit: numerical value to evaluate the Condition on evaluador(blob). + Only useful for B_INSIDE and B_OUTSIDE + - RESULT: + - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) + the Condition on the result returned by evaluador on each blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::Filter(CBlobResult &dst, + int filterAction, + funcio_calculBlob *evaluador, + int condition, + double lowLimit, double highLimit /*=0*/) + + { + int i, numBlobs; + bool resultavaluacio; + double_stl_vector avaluacioBlobs; + double_stl_vector::iterator itavaluacioBlobs; + + if (GetNumBlobs() <= 0) return; + if (!evaluador) return; + //avaluem els blobs amb la funció pertinent + avaluacioBlobs = GetSTLResult(evaluador); + itavaluacioBlobs = avaluacioBlobs.begin(); + numBlobs = GetNumBlobs(); + switch (condition) + { + case B_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs == lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_NOT_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs != lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_GREATER: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs > lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_LESS: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs < lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_GREATER_OR_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs >= lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_LESS_OR_EQUAL: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = *itavaluacioBlobs <= lowLimit; + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_INSIDE: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit); + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + case B_OUTSIDE: + for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) + { + resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit); + if ((resultavaluacio && filterAction == B_INCLUDE) || + (!resultavaluacio && filterAction == B_EXCLUDE)) + { + dst.m_blobs.push_back(new CBlob(GetBlob(i))); + } + } + break; + } + + + // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult + // ( operacio inline ) + if (&dst == this) + { + // esborrem els primers blobs ( que són els originals ) + // ja que els tindrem replicats al final si passen el filtre + blob_vector::iterator itBlobs = m_blobs.begin(); + for (int i = 0; i < numBlobs; i++) + { + delete *itBlobs; + ++itBlobs; + } + m_blobs.erase(m_blobs.begin(), itBlobs); + } + } + + + /** + - FUNCIÓ: GetBlob + - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1) + - PARÀMETRES: + - indexblob: index del blob a retornar + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: GetBlob + - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs) + - PARAMETERS: + - indexblob: index in the blob array + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob CBlobResult::GetBlob(int indexblob) const + { + if (indexblob < 0 || indexblob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + + return *m_blobs[indexblob]; + } + CBlob *CBlobResult::GetBlob(int indexblob) + { + if (indexblob < 0 || indexblob >= GetNumBlobs()) + RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); + + return m_blobs[indexblob]; + } + + /** + - FUNCIÓ: GetNthBlob + - FUNCIONALITAT: Retorna l'enèssim blob segons un determinat criteri + - PARÀMETRES: + - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob) + - nBlob: index del blob a retornar + - dst: on es retorna el resultat + - RESULTAT: + - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri + en ordre DESCENDENT. Per exemple, per obtenir el blob major: + GetNthBlob( CBlobGetArea(), 0, blobMajor ); + GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob més gran) + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: GetNthBlob + - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria + - PARAMETERS: + - criteri: criteria to order the blob array + - nBlob: index of the returned blob in the ordered blob array + - dst: where to store the result + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const + { + // verifiquem que no estem accedint fora el vector de blobs + if (nBlob < 0 || nBlob >= GetNumBlobs()) + { + //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS ); + dst = CBlob(); + return; + } + + double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat; + double valorEnessim; + + //avaluem els blobs amb la funció pertinent + avaluacioBlobs = GetSTLResult(criteri); + + avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs()); + + // obtenim els nBlob primers resultats (en ordre descendent) + std::partial_sort_copy(avaluacioBlobs.begin(), + avaluacioBlobs.end(), + avaluacioBlobsOrdenat.begin(), + avaluacioBlobsOrdenat.end(), + std::greater<double>()); + + valorEnessim = avaluacioBlobsOrdenat[nBlob]; + + // busquem el primer blob que té el valor n-ssim + double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin(); + + bool trobatBlob = false; + int indexBlob = 0; + while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob) + { + if (*itAvaluacio == valorEnessim) + { + trobatBlob = true; + dst = CBlob(GetBlob(indexBlob)); + } + ++itAvaluacio; + indexBlob++; + } + } + + /** + - FUNCIÓ: ClearBlobs + - FUNCIONALITAT: Elimina tots els blobs de l'objecte + - PARÀMETRES: + - RESULTAT: + - Allibera tota la memòria dels blobs + - RESTRICCIONS: + - AUTOR: Ricard Borrà s Navarra + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: ClearBlobs + - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::ClearBlobs() + { + /*for( int i = 0; i < GetNumBlobs(); i++ ) + { + delete m_blobs[i]; + }*/ + blob_vector::iterator itBlobs = m_blobs.begin(); + while (itBlobs != m_blobs.end()) + { + delete *itBlobs; + ++itBlobs; + } + + m_blobs.clear(); + } + + /** + - FUNCIÓ: RaiseError + - FUNCIONALITAT: Funció per a notificar errors al l'usuari (en debug) i llença + les excepcions + - PARÀMETRES: + - errorCode: codi d'error + - RESULTAT: + - Ensenya un missatge a l'usuari (en debug) i llença una excepció + - RESTRICCIONS: + - AUTOR: Ricard Borrà s Navarra + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: RaiseError + - FUNCTIONALITY: Error handling function + - PARAMETERS: + - errorCode: reason of the error + - RESULT: + - in _DEBUG version, shows a message box with the error. In release is silent. + In both cases throws an exception with the error. + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::RaiseError(const int errorCode) const + { + throw errorCode; + } + + + + /************************************************************************** + Auxiliars / Auxiliary functions + **************************************************************************/ + + + /** + - FUNCIÓ: PrintBlobs + - FUNCIONALITAT: Escriu els parà metres (à rea, perÃmetre, exterior, mitjana) + de tots els blobs a un fitxer. + - PARÀMETRES: + - nom_fitxer: path complet del fitxer amb el resultat + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /* + - FUNCTION: PrintBlobs + - FUNCTIONALITY: Prints some blob features in an ASCII file + - PARAMETERS: + - nom_fitxer: full path + filename to generate + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlobResult::PrintBlobs(char *nom_fitxer) const + { + double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud, + externPerimeter, perimetreConvex, perimetre; + int i; + FILE *fitxer_sortida; + + area = GetSTLResult(CBlobGetArea()); + perimetre = GetSTLResult(CBlobGetPerimeter()); + exterior = GetSTLResult(CBlobGetExterior()); + mitjana = GetSTLResult(CBlobGetMean()); + compacitat = GetSTLResult(CBlobGetCompactness()); + longitud = GetSTLResult(CBlobGetLength()); + externPerimeter = GetSTLResult(CBlobGetExternPerimeter()); + perimetreConvex = GetSTLResult(CBlobGetHullPerimeter()); + + fitxer_sortida = fopen(nom_fitxer, "w"); + + for (i = 0; i < GetNumBlobs(); i++) + { + fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n", + i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]); + } + fclose(fitxer_sortida); + + } + +} diff --git a/package_bgs/jmo/BlobResult.h b/package_bgs/MultiLayer/BlobResult.h similarity index 80% rename from package_bgs/jmo/BlobResult.h rename to package_bgs/MultiLayer/BlobResult.h index b232a97..aa3e37b 100644 --- a/package_bgs/jmo/BlobResult.h +++ b/package_bgs/MultiLayer/BlobResult.h @@ -40,29 +40,26 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/************************************************************************ - BlobResult.h + /************************************************************************ + BlobResult.h - FUNCIONALITAT: Definici� de la classe CBlobResult - AUTOR: Inspecta S.L. - MODIFICACIONS (Modificaci�, Autor, Data): + FUNCIONALITAT: Definició de la classe CBlobResult + AUTOR: Inspecta S.L. + MODIFICACIONS (Modificació, Autor, Data): - FUNCTIONALITY: Definition of the CBlobResult class - AUTHOR: Inspecta S.L. - MODIFICATIONS (Modification, Author, Date): + FUNCTIONALITY: Definition of the CBlobResult class + AUTHOR: Inspecta S.L. + MODIFICATIONS (Modification, Author, Date): - **************************************************************************/ + **************************************************************************/ #pragma once -#if !defined(_CLASSE_BLOBRESULT_INCLUDED) -#define _CLASSE_BLOBRESULT_INCLUDED - #include "BlobLibraryConfiguration.h" #include <math.h> -//#include "cxcore.h" + //#include "cxcore.h" #include <vector> #include <functional> -#include <opencv2/core/types_c.h> +#include "OpenCvLegacyIncludes.h" #include "blob.h" typedef std::vector<double> double_stl_vector; @@ -71,8 +68,8 @@ typedef std::vector<double> double_stl_vector; Filtres / Filters **************************************************************************/ -//! accions que es poden fer amb els filtres -//! Actions performed by a filter (include or exclude blobs) + //! accions que es poden fer amb els filtres + //! Actions performed by a filter (include or exclude blobs) #define B_INCLUDE 1L #define B_EXCLUDE 2L @@ -92,23 +89,23 @@ typedef std::vector<double> double_stl_vector; Excepcions / Exceptions **************************************************************************/ -//! Excepcions llen�ades per les funcions: + //! Excepcions llençades per les funcions: #define EXCEPTION_BLOB_OUT_OF_BOUNDS 1000 #define EXCEPCIO_CALCUL_BLOBS 1001 namespace Blob { - //! definici� de que es un vector de blobs + //! definició de que es un vector de blobs typedef std::vector<CBlob*> blob_vector; /** - Classe que cont� un conjunt de blobs i permet extreure'n propietats - o filtrar-los segons determinats criteris. - Class to calculate the blobs of an image and calculate some properties - on them. Also, the class provides functions to filter the blobs using - some criteria. - */ + Classe que conté un conjunt de blobs i permet extreure'n propietats + o filtrar-los segons determinats criteris. + Class to calculate the blobs of an image and calculate some properties + on them. Also, the class provides functions to filter the blobs using + some criteria. + */ class CBlobResult { public: @@ -119,7 +116,7 @@ namespace Blob //! constructor a partir d'una imatge //! Image constructor, it creates an object with the blobs of the image CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments); - //! constructor de c�pia + //! constructor de còpia //! Copy constructor CBlobResult(const CBlobResult &source); //! Destructor @@ -139,7 +136,7 @@ namespace Blob #ifdef MATRIXCV_ACTIU //! Calcula un valor sobre tots els blobs de la classe retornant una MatrixCV //! Computes some property on all the blobs of the class - double_vector GetResult( funcio_calculBlob *evaluador ) const; + double_vector GetResult(funcio_calculBlob *evaluador) const; #endif //! Calcula un valor sobre tots els blobs de la classe retornant un std::vector<double> //! Computes some property on all the blobs of the class @@ -149,17 +146,17 @@ namespace Blob //! Computes some property on one blob of the class double GetNumber(int indexblob, funcio_calculBlob *evaluador) const; - //! Retorna aquells blobs que compleixen les condicions del filtre en el destination + //! Retorna aquells blobs que compleixen les condicions del filtre en el destination //! Filters the blobs of the class using some property void Filter(CBlobResult &dst, int filterAction, funcio_calculBlob *evaluador, int condition, double lowLimit, double highLimit = 0); - //! Retorna l'en�ssim blob segons un determinat criteri + //! Retorna l'enèssim blob segons un determinat criteri //! Sorts the blobs of the class acording to some criteria and returns the n-th blob void GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const; - //! Retorna el blob en�ssim + //! Retorna el blob enèssim //! Gets the n-th blob of the class ( without sorting ) CBlob GetBlob(int indexblob) const; CBlob *GetBlob(int indexblob); @@ -185,7 +182,7 @@ namespace Blob private: - //! Funci� per gestionar els errors + //! Funció per gestionar els errors //! Function to manage the errors void RaiseError(const int errorCode) const; @@ -197,6 +194,3 @@ namespace Blob }; } - -#endif // !defined(_CLASSE_BLOBRESULT_INCLUDED) - diff --git a/package_bgs/jmo/CMultiLayerBGS.cpp b/package_bgs/MultiLayer/CMultiLayerBGS.cpp similarity index 99% rename from package_bgs/jmo/CMultiLayerBGS.cpp rename to package_bgs/MultiLayer/CMultiLayerBGS.cpp index 6daa9b9..4341736 100644 --- a/package_bgs/jmo/CMultiLayerBGS.cpp +++ b/package_bgs/MultiLayer/CMultiLayerBGS.cpp @@ -53,7 +53,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <fstream> // file I/O #include <cmath> // math includes #include <iostream> // I/O streams -#include <opencv2/legacy/compat.hpp> +#include "OpenCvLegacyIncludes.h" using namespace Blob; @@ -220,16 +220,16 @@ void CMultiLayerBGS::MergeImages(int num, ...) { int img_idx = 0; for (a = 0; a < nRows; a++) - for (b = 0; b < nCols; b++) { - if (img_idx >= num) - break; + for (b = 0; b < nCols; b++) { + if (img_idx >= num) + break; - imgROIRect = cvRect(b * imgSize.width, a * imgSize.height, imgSize.width, imgSize.height); + imgROIRect = cvRect(b * imgSize.width, a * imgSize.height, imgSize.width, imgSize.height); - cvSetImageROI(ppIplImg[num], imgROIRect); - cvCopyImage(ppIplImg[img_idx++], ppIplImg[num]); - cvResetImageROI(ppIplImg[num]); - } + cvSetImageROI(ppIplImg[num], imgROIRect); + cvCopy(ppIplImg[img_idx++], ppIplImg[num]); + cvResetImageROI(ppIplImg[num]); + } delete[] ppIplImg; } @@ -369,7 +369,7 @@ void CMultiLayerBGS::SetBkMaskImage(IplImage *mask_img) { if (m_pBkMaskImg == NULL) { m_pBkMaskImg = cvCreateImage(cvGetSize(mask_img), mask_img->depth, mask_img->nChannels); } - cvCopyImage(mask_img, m_pBkMaskImg); + cvCopy(mask_img, m_pBkMaskImg); } void CMultiLayerBGS::BackgroundSubtractionProcess() { @@ -691,7 +691,7 @@ void CMultiLayerBGS::BackgroundSubtractionProcess() { removed_modes[a] = false; if (LBPs[lbp_idxes[a]].bg_layer_num > curLBP->bg_layer_num && LBPs[lbp_idxes[a]].weight < LBPs[lbp_idxes[a]].max_weight * 0.9f) { /* remove layers */ - //LBPs[lbp_idxes[a]].bg_layer_num = 0; + //LBPs[lbp_idxes[a]].bg_layer_num = 0; removed_modes[a] = true; removed_bg_layers = true; } @@ -835,7 +835,7 @@ void CMultiLayerBGS::GetBackgroundImage(IplImage *bk_img) { ODC.SetImageData(bg_img, org_data); delete[] org_data; - cvCopyImage(m_pBgImg, bk_img); + cvCopy(m_pBgImg, bk_img); } void CMultiLayerBGS::GetForegroundImage(IplImage *fg_img, CvScalar bg_color) { @@ -865,7 +865,7 @@ void CMultiLayerBGS::GetForegroundMaskImage(IplImage *fg_mask_img) { if (m_pROI && (m_pROI->width <= 0 || m_pROI->height <= 0)) return; - //cvCopyImage(m_pFgMaskImg, fg_mask_img); + //cvCopy(m_pFgMaskImg, fg_mask_img); if (m_pROI) { cvSetImageROI(m_pFgMaskImg, *m_pROI); cvSetImageROI(fg_mask_img, *m_pROI); @@ -1391,7 +1391,7 @@ void CMultiLayerBGS::GetCurrentLayeredBackgroundImage(int layered_no, IplImage * } void CMultiLayerBGS::GetColoredBgMultiLayeredImage(IplImage *bg_multi_layer_img, CvScalar *layer_colors) { - cvCopyImage(m_pOrgImg, bg_multi_layer_img); + cvCopy(m_pOrgImg, bg_multi_layer_img); COpencvDataConversion<uchar, uchar> ODC; diff --git a/package_bgs/jmo/CMultiLayerBGS.h b/package_bgs/MultiLayer/CMultiLayerBGS.h similarity index 96% rename from package_bgs/jmo/CMultiLayerBGS.h rename to package_bgs/MultiLayer/CMultiLayerBGS.h index c8698f6..78a0527 100644 --- a/package_bgs/jmo/CMultiLayerBGS.h +++ b/package_bgs/MultiLayer/CMultiLayerBGS.h @@ -43,9 +43,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // BackgroundSubtraction.h: interface for the CBackgroundSubtraction class. // ////////////////////////////////////////////////////////////////////// - -#if !defined(_MULTI_LAYER_BGS_H_) -#define _MULTI_LAYER_BGS_H_ +#pragma once /* Since the used fast cross bilateral filter codes can not be compiled under Windows, @@ -124,16 +122,16 @@ public: float weight_updating_learn_rate_per_second, // mode's weight updating learning rate per second float low_init_mode_weight); // the low initial mode weight - //------------------------------------------------------------- - // PROVIDE A POINTER TO THE INPUT IMAGE - // -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED - // - // Here assumes that the input image will contain RGB images. - // The memory of this image is handled by the caller. - // - // The return value indicate whether the actual Background - // Subtraction algorithm handles RGB images (1) or not (0). - // +//------------------------------------------------------------- +// PROVIDE A POINTER TO THE INPUT IMAGE +// -> INDICATE WHERE THE NEW IMAGE TO PROCESS IS STORED +// +// Here assumes that the input image will contain RGB images. +// The memory of this image is handled by the caller. +// +// The return value indicate whether the actual Background +// Subtraction algorithm handles RGB images (1) or not (0). +// int SetRGBInputImage(IplImage * inputImage, CvRect *roi = NULL); //------------------------------------------------------------- @@ -308,6 +306,3 @@ public: CMultiLayerBGS(); virtual ~CMultiLayerBGS(); }; - -#endif // !defined(_MULTI_LAYER_BGS_H_) - diff --git a/package_bgs/jmo/LocalBinaryPattern.cpp b/package_bgs/MultiLayer/LocalBinaryPattern.cpp similarity index 95% rename from package_bgs/jmo/LocalBinaryPattern.cpp rename to package_bgs/MultiLayer/LocalBinaryPattern.cpp index 6967cf4..060b9ea 100644 --- a/package_bgs/jmo/LocalBinaryPattern.cpp +++ b/package_bgs/MultiLayer/LocalBinaryPattern.cpp @@ -105,13 +105,13 @@ void CLocalBinaryPattern::Initialization(IplImage **first_imgs, int imgs_num, in m_nMaxShift.y = 0; int shift_idx = 0; for (a = 0; a < m_nLBPLevelNum; a++) - for (b = 0; b < m_pNeigPointsNums[a]; b++) { - // compute the offset of neig point - CalNeigPixelOffset(m_pRadiuses[a], m_pNeigPointsNums[a], b, m_pXYShifts[shift_idx].x, m_pXYShifts[shift_idx].y); - m_nMaxShift.x = MAX(m_nMaxShift.x, m_pXYShifts[shift_idx].x); - m_nMaxShift.y = MAX(m_nMaxShift.y, m_pXYShifts[shift_idx].y); - shift_idx++; - } + for (b = 0; b < m_pNeigPointsNums[a]; b++) { + // compute the offset of neig point + CalNeigPixelOffset(m_pRadiuses[a], m_pNeigPointsNums[a], b, m_pXYShifts[shift_idx].x, m_pXYShifts[shift_idx].y); + m_nMaxShift.x = MAX(m_nMaxShift.x, m_pXYShifts[shift_idx].x); + m_nMaxShift.y = MAX(m_nMaxShift.y, m_pXYShifts[shift_idx].y); + shift_idx++; + } m_fRobustWhiteNoise = robust_white_noise; } @@ -155,7 +155,7 @@ void CLocalBinaryPattern::ComputeLBP(PixelLBPStruct *PLBP, CvRect *roi) if (roi) { int x, y; - for (y = 0; y < roi->height; y++) { + for (y = 0; y < roi->height; y++) { _PLBP = PLBP + (y + roi->y)*m_cvImgSize.width + roi->x; for (x = 0; x < roi->width; x++) { cur_pattern = (*_PLBP++).cur_pattern; diff --git a/package_bgs/jmo/LocalBinaryPattern.h b/package_bgs/MultiLayer/LocalBinaryPattern.h similarity index 96% rename from package_bgs/jmo/LocalBinaryPattern.h rename to package_bgs/MultiLayer/LocalBinaryPattern.h index 987a2c2..40d4379 100644 --- a/package_bgs/jmo/LocalBinaryPattern.h +++ b/package_bgs/MultiLayer/LocalBinaryPattern.h @@ -43,11 +43,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // LocalBinaryPattern.h: interface for the CLocalBinaryPattern class. // ////////////////////////////////////////////////////////////////////// +#pragma once -#if !defined(_LOCAL_BINARY_PATTERN_H_) -#define _LOCAL_BINARY_PATTERN_H_ - -#include <opencv2/opencv.hpp> +#include "OpenCvLegacyIncludes.h" #include "BGS.h" @@ -98,6 +96,3 @@ private: IplImage* m_pShiftedImg; }; - -#endif // !defined(_LOCAL_BINARY_PATTERN_H_) - diff --git a/package_bgs/jmo/OpenCvDataConversion.h b/package_bgs/MultiLayer/OpenCvDataConversion.h similarity index 97% rename from package_bgs/jmo/OpenCvDataConversion.h rename to package_bgs/MultiLayer/OpenCvDataConversion.h index a47563e..18371b3 100644 --- a/package_bgs/jmo/OpenCvDataConversion.h +++ b/package_bgs/MultiLayer/OpenCvDataConversion.h @@ -43,11 +43,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // OpencvDataConversion.h: interface for the COpencvDataConversion class. // ////////////////////////////////////////////////////////////////////// +#pragma once -#if !defined(_OPENCV_DATA_CONVERSION_H_) -#define _OPENCV_DATA_CONVERSION_H_ - -#include <opencv2/opencv.hpp> +#include "OpenCvLegacyIncludes.h" #include <stdio.h> template <class TI, class TM> /* class TI - the type of image data, class TM - the type of matrix data */ @@ -219,6 +217,3 @@ public: COpencvDataConversion() {}; virtual ~COpencvDataConversion() {}; }; - -#endif // !defined(_OPENCV_DATA_CONVERSION_H_) - diff --git a/package_bgs/MultiLayer/OpenCvLegacyIncludes.h b/package_bgs/MultiLayer/OpenCvLegacyIncludes.h new file mode 100644 index 0000000..9d30c0e --- /dev/null +++ b/package_bgs/MultiLayer/OpenCvLegacyIncludes.h @@ -0,0 +1,50 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* --- --- --- +* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. The name of the author may not be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +// OpenCvLegacyIncludes.h: necessary includes to compile with OpenCV 3. +// +////////////////////////////////////////////////////////////////////// +#pragma once + +#include "opencv2/core/core_c.h" +#include "opencv2/core/types_c.h" +#include "opencv2/imgproc/imgproc_c.h" diff --git a/package_bgs/MultiLayer/blob.cpp b/package_bgs/MultiLayer/blob.cpp new file mode 100644 index 0000000..5e0fa45 --- /dev/null +++ b/package_bgs/MultiLayer/blob.cpp @@ -0,0 +1,1148 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/* --- --- --- +* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. The name of the author may not be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/************************************************************************ +Blob.cpp + +- FUNCIONALITAT: Implementació de la classe CBlob +- AUTOR: Inspecta S.L. +MODIFICACIONS (Modificació, Autor, Data): + + +FUNCTIONALITY: Implementation of the CBlob class and some helper classes to perform +some calculations on it +AUTHOR: Inspecta S.L. +MODIFICATIONS (Modification, Author, Date): + +**************************************************************************/ + + +#include <limits.h> +#include "blob.h" + +namespace Blob +{ + + /** + - FUNCIÓ: CBlob + - FUNCIONALITAT: Constructor està ndard + - PARÀMETRES: + - RESULTAT: + - inicialització de totes les variables internes i de l'storage i la sequencia + per a les cantonades del blob + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Standard constructor + - PARAMETERS: + - RESULT: + - memory allocation for the blob edges and initialization of member variables + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::CBlob() + { + etiqueta = -1; // Flag indicates null region + exterior = 0; + area = 0.0f; + perimeter = 0.0f; + parent = -1; + minx = LONG_MAX; + maxx = 0; + miny = LONG_MAX; + maxy = 0; + sumx = 0; + sumy = 0; + sumxx = 0; + sumyy = 0; + sumxy = 0; + mean = 0; + stddev = 0; + externPerimeter = 0; + + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + } + + /** + - FUNCIÓ: CBlob + - FUNCIONALITAT: Constructor de còpia + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Copy constructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::CBlob(const CBlob &src) + { + // copiem les propietats del blob origen a l'actual + etiqueta = src.etiqueta; + exterior = src.exterior; + area = src.Area(); + perimeter = src.Perimeter(); + parent = src.parent; + minx = src.minx; + maxx = src.maxx; + miny = src.miny; + maxy = src.maxy; + sumx = src.sumx; + sumy = src.sumy; + sumxx = src.sumxx; + sumyy = src.sumyy; + sumxy = src.sumxy; + mean = src.mean; + stddev = src.stddev; + externPerimeter = src.externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + cvStartReadSeq(src.Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + CBlob::CBlob(const CBlob *src) + { + // copiem les propietats del blob origen a l'actual + etiqueta = src->etiqueta; + exterior = src->exterior; + area = src->Area(); + perimeter = src->Perimeter(); + parent = src->parent; + minx = src->minx; + maxx = src->maxx; + miny = src->miny; + maxy = src->maxy; + sumx = src->sumx; + sumy = src->sumy; + sumxx = src->sumxx; + sumyy = src->sumyy; + sumxy = src->sumxy; + mean = src->mean; + stddev = src->stddev; + externPerimeter = src->externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + cvStartReadSeq(src->Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src->Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + + /** + - FUNCIÓ: ~CBlob + - FUNCIONALITAT: Destructor està ndard + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlob + - FUNCTIONALITY: Standard destructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob::~CBlob() + { + // Eliminar vèrtexs del blob + cvClearSeq(edges); + // i la zona de memòria on són + cvReleaseMemStorage(&m_storage); + } + + /** + - FUNCIÓ: operator= + - FUNCIONALITAT: Operador d'assignació + - PARÀMETRES: + - src: blob a assignar a l'actual + - RESULTAT: + - Substitueix el blob actual per el src + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Assigment operator + - FUNCTIONALITY: Assigns a blob to the current + - PARAMETERS: + - src: blob to assign + - RESULT: + - the current blob is replaced by the src blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CBlob& CBlob::operator=(const CBlob &src) + { + // si ja són el mateix, no cal fer res + if (this != &src) + { + // Eliminar vèrtexs del blob + cvClearSeq(edges); + // i la zona de memòria on són + cvReleaseMemStorage(&m_storage); + + // creem una sequencia buida per als edges + m_storage = cvCreateMemStorage(0); + edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, + sizeof(CvContour), + sizeof(CvPoint), m_storage); + + // copiem les propietats del blob origen a l'actual + etiqueta = src.etiqueta; + exterior = src.exterior; + area = src.Area(); + perimeter = src.Perimeter(); + parent = src.parent; + minx = src.minx; + maxx = src.maxx; + miny = src.miny; + maxy = src.maxy; + sumx = src.sumx; + sumy = src.sumy; + sumxx = src.sumxx; + sumyy = src.sumyy; + sumxy = src.sumxy; + mean = src.mean; + stddev = src.stddev; + externPerimeter = src.externPerimeter; + + // copiem els edges del blob origen a l'actual + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + cvStartReadSeq(src.Edges(), &reader); + cvStartAppendToSeq(edges, &writer); + + for (int i = 0; i < src.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + return *this; + } + + /** + - FUNCIÓ: FillBlob + - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat + - PARÀMETRES: + - imatge: imatge on es vol pintar el el blob + - color: color amb que es vol pintar el blob + - RESULTAT: + - retorna la imatge d'entrada amb el blob pintat + - RESTRICCIONS: + - AUTOR: + - Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: FillBlob + - FUNCTIONALITY: + - Fills the blob with a specified colour + - PARAMETERS: + - imatge: where to paint + - color: colour to paint the blob + - RESULT: + - modifies input image and returns the seed point used to fill the blob + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const + { + + //verifiquem que existeixi el blob i que tingui cantonades + if (edges == NULL || edges->total == 0) return; + + CvPoint edgeactual, pt1, pt2; + CvSeqReader reader; + vectorPunts vectorEdges = vectorPunts(edges->total); + vectorPunts::iterator itEdges, itEdgesSeguent; + bool dinsBlob; + int yActual; + + // passem els punts del blob a un vector de punts de les STL + cvStartReadSeq(edges, &reader); + itEdges = vectorEdges.begin(); + while (itEdges != vectorEdges.end()) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + *itEdges = edgeactual; + ++itEdges; + } + // ordenem el vector per les Y's i les X's d'esquerra a dreta + std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint()); + + // recorrem el vector ordenat i fem linies entre punts consecutius + itEdges = vectorEdges.begin(); + itEdgesSeguent = vectorEdges.begin() + 1; + dinsBlob = true; + while (itEdges != (vectorEdges.end() - 1)) + { + yActual = (*itEdges).y; + + if (((*itEdges).x != (*itEdgesSeguent).x) && + ((*itEdgesSeguent).y == yActual) + ) + { + if (dinsBlob) + { + pt1 = *itEdges; + pt1.x += offsetX; + pt1.y += offsetY; + + pt2 = *itEdgesSeguent; + pt2.x += offsetX; + pt2.y += offsetY; + + cvLine(imatge, pt1, pt2, color); + } + dinsBlob = !dinsBlob; + } + ++itEdges; + ++itEdgesSeguent; + if ((*itEdges).y != yActual) dinsBlob = true; + } + vectorEdges.clear(); + } + + /** + - FUNCIÓ: CopyEdges + - FUNCIONALITAT: Afegeix els vèrtexs del blob al blob destination + - PARÀMETRES: + - destination: blob al que volem afegir els vèrtexs + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CopyEdges + - FUNCTIONALITY: Adds the blob edges to destination + - PARAMETERS: + - destination: where to add the edges + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::CopyEdges(CBlob &destination) const + { + CvSeqReader reader; + CvSeqWriter writer; + CvPoint edgeactual; + + cvStartReadSeq(edges, &reader); + cvStartAppendToSeq(destination.Edges(), &writer); + + for (int i = 0; i < edges->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + CV_WRITE_SEQ_ELEM(edgeactual, writer); + } + + cvEndWriteSeq(&writer); + } + + /** + - FUNCIÓ: ClearEdges + - FUNCIONALITAT: Elimina els vèrtexs del blob + - PARÀMETRES: + - RESULTAT: + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: ClearEdges + - FUNCTIONALITY: Delete current blob edges + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + void CBlob::ClearEdges() + { + // Eliminar vèrtexs del blob eliminat + cvClearSeq(edges); + } + + /** + - FUNCIÓ: GetConvexHull + - FUNCIONALITAT: Retorna el poligon convex del blob + - PARÀMETRES: + - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada) + - RESULTAT: + - true si tot ha anat bé + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetConvexHull + - FUNCTIONALITY: Calculates the convex hull polygon of the blob + - PARAMETERS: + - dst: where to store the result + - RESULT: + - true if no error ocurred + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + bool CBlob::GetConvexHull(CvSeq **dst) const + { + if (edges != NULL && edges->total > 0) + { + *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0); + return true; + } + return false; + } + + /** + - FUNCIÓ: GetEllipse + - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob + - PARÀMETRES: + - RESULTAT: + - estructura amb l'ellipse + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 25-05-2005. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: GetEllipse + - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob + - PARAMETERS: + - RESULT: + - CvBox2D struct with the calculated ellipse + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + CvBox2D CBlob::GetEllipse() const + { + CvBox2D elipse; + // necessitem 6 punts per calcular l'elipse + if (edges != NULL && edges->total > 6) + { + elipse = cvFitEllipse2(edges); + } + else + { + elipse.center.x = 0.0; + elipse.center.y = 0.0; + elipse.size.width = 0.0; + elipse.size.height = 0.0; + elipse.angle = 0.0; + } + return elipse; + } + + + + /*************************************************************************** + Implementació de les classes per al cà lcul de caracterÃstiques sobre el blob + + Implementation of the helper classes to perform operations on blobs + **************************************************************************/ + + /** + - FUNCIÓ: Moment + - FUNCIONALITAT: Calcula el moment pq del blob + - RESULTAT: + - retorna el moment pq especificat o 0 si el moment no està implementat + - RESTRICCIONS: + - Implementats els moments pq: 00, 01, 10, 20, 02 + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: Moment + - FUNCTIONALITY: Calculates the pq moment of the blob + - PARAMETERS: + - RESULT: + - returns the pq moment or 0 if the moment it is not implemented + - RESTRICTIONS: + - Currently, only implemented the 00, 01, 10, 20, 02 pq moments + - AUTHOR: Ricard Borrà s + - CREATION DATE: 20-07-2004. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMoment::operator()(const CBlob &blob) const + { + //Moment 00 + if ((m_p == 0) && (m_q == 0)) + return blob.Area(); + + //Moment 10 + if ((m_p == 1) && (m_q == 0)) + return blob.SumX(); + + //Moment 01 + if ((m_p == 0) && (m_q == 1)) + return blob.SumY(); + + //Moment 20 + if ((m_p == 2) && (m_q == 0)) + return blob.SumXX(); + + //Moment 02 + if ((m_p == 0) && (m_q == 2)) + return blob.SumYY(); + + return 0; + } + + /** + - FUNCIÓ: HullPerimeter + - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob. + Fa servir la funció d'OpenCV cvConvexHull2 per a + calcular el perimetre convex. + + - PARÀMETRES: + - RESULTAT: + - retorna la longitud del perÃmetre convex del blob. Si el blob no té coordenades + associades retorna el perÃmetre normal del blob. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetHullPerimeter + - FUNCTIONALITY: Calculates the convex hull perimeter of the blob + - PARAMETERS: + - RESULT: + - returns the convex hull perimeter of the blob or the perimeter if the + blob edges could not be retrieved + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetHullPerimeter::operator()(const CBlob &blob) const + { + if (blob.Edges() != NULL && blob.Edges()->total > 0) + { + CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); + return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1)); + } + return blob.Perimeter(); + } + + double CBlobGetHullArea::operator()(const CBlob &blob) const + { + if (blob.Edges() != NULL && blob.Edges()->total > 0) + { + CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); + return fabs(cvContourArea(hull)); + } + return blob.Perimeter(); + } + + /** + - FUNCIÓ: MinX_at_MinY + - FUNCIONALITAT: Calcula el valor MinX a MinY. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la X minima en la Y minima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMinXatMinY + - FUNCTIONALITY: Calculates the minimum X on the minimum Y + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMinXatMinY::operator()(const CBlob &blob) const + { + double MinX_at_MinY = LONG_MAX; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY)) + { + MinX_at_MinY = edgeactual.x; + } + } + + return MinX_at_MinY; + } + + /** + - FUNCIÓ: MinY_at_MaxX + - FUNCIONALITAT: Calcula el valor MinX a MaxX. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la Y minima en la X maxima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMinXatMinY + - FUNCTIONALITY: Calculates the minimum Y on the maximum X + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const + { + double MinY_at_MaxX = LONG_MAX; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX)) + { + MinY_at_MaxX = edgeactual.y; + } + } + + return MinY_at_MaxX; + } + + /** + - FUNCIÓ: MaxX_at_MaxY + - FUNCIONALITAT: Calcula el valor MaxX a MaxY. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la X maxima en la Y maxima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMaxXatMaxY + - FUNCTIONALITY: Calculates the maximum X on the maximum Y + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const + { + double MaxX_at_MaxY = LONG_MIN; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY)) + { + MaxX_at_MaxY = edgeactual.x; + } + } + + return MaxX_at_MaxY; + } + + /** + - FUNCIÓ: MaxY_at_MinX + - FUNCIONALITAT: Calcula el valor MaxY a MinX. + - PARÀMETRES: + - blob: blob del que volem calcular el valor + - RESULTAT: + - retorna la Y maxima en la X minima. + - RESTRICCIONS: + - AUTOR: Ricard Borrà s + - DATA DE CREACIÓ: 20-07-2004. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: CBlobGetMaxYatMinX + - FUNCTIONALITY: Calculates the maximum Y on the minimum X + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const + { + double MaxY_at_MinX = LONG_MIN; + + CvSeqReader reader; + CvPoint edgeactual; + + cvStartReadSeq(blob.Edges(), &reader); + + for (int j = 0; j < blob.Edges()->total; j++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX)) + { + MaxY_at_MinX = edgeactual.y; + } + } + + return MaxY_at_MinX; + } + + /** + Retorna l'elongació del blob (longitud/amplada) + */ + /** + - FUNCTION: CBlobGetElongation + - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth ) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - See below to see how the lenght and the breadth are aproximated + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetElongation::operator()(const CBlob &blob) const + { + double ampladaC, longitudC, amplada, longitud; + + ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4; + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + longitud = MAX(longitudC, ampladaC); + amplada = MIN(longitudC, ampladaC); + + return (double)longitud / amplada; + } + + /** + Retorna la compacitat del blob + */ + /** + - FUNCTION: CBlobGetCompactness + - FUNCTIONALITY: Calculates the compactness of the blob + ( maximum for circle shaped blobs, minimum for the rest) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetCompactness::operator()(const CBlob &blob) const + { + if (blob.Area() != 0.0) + return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area()); + else + return 0.0; + } + + /** + Retorna la rugositat del blob + */ + /** + - FUNCTION: CBlobGetRoughness + - FUNCTIONALITY: Calculates the roughness of the blob + ( ratio between perimeter and convex hull perimeter) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetRoughness::operator()(const CBlob &blob) const + { + CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter(); + + double hullPerimeter = getHullPerimeter(blob); + + if (hullPerimeter != 0.0) + return blob.Perimeter() / hullPerimeter;//HullPerimeter(); + + return 0.0; + } + + /** + Retorna la longitud del blob + */ + /** + - FUNCTION: CBlobGetLength + - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - The lenght is an aproximation to the real lenght + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetLength::operator()(const CBlob &blob) const + { + double ampladaC, longitudC; + double tmp; + + tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); + + if (tmp > 0.0) + ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; + // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre + else + ampladaC = (double)(blob.Perimeter()) / 4; + + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + return MAX(longitudC, ampladaC); + } + + /** + Retorna l'amplada del blob + */ + /** + - FUNCTION: CBlobGetBreadth + - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob) + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - The breadth is an aproximation to the real breadth + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetBreadth::operator()(const CBlob &blob) const + { + double ampladaC, longitudC; + double tmp; + + tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); + + if (tmp > 0.0) + ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; + // error intrÃnsec en els cà lculs de l'à rea i el perÃmetre + else + ampladaC = (double)(blob.Perimeter()) / 4; + + if (ampladaC <= 0.0) return 0; + longitudC = (double)blob.Area() / ampladaC; + + return MIN(longitudC, ampladaC); + } + + /** + Calcula la distà ncia entre un punt i el centre del blob + */ + /** + - FUNCTION: CBlobGetDistanceFromPoint + - FUNCTIONALITY: Calculates the euclidean distance between the blob center and + the point specified in the constructor + - PARAMETERS: + - RESULT: + - RESTRICTIONS: + - AUTHOR: Ricard Borrà s + - CREATION DATE: 25-05-2005. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const + { + double xmitjana, ymitjana; + CBlobGetXCenter getXCenter; + CBlobGetYCenter getYCenter; + + xmitjana = m_x - getXCenter(blob); + ymitjana = m_y - getYCenter(blob); + + return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana)); + } + + /** + - FUNCIÓ: BlobGetXYInside + - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular + del blob + - RESULTAT: + - retorna 1 si hi està ; 0 si no + - RESTRICCIONS: + - AUTOR: Francesc Pinyol Margalef + - DATA DE CREACIÓ: 16-01-2006. + - MODIFICACIÓ: Data. Autor. Descripció. + */ + /** + - FUNCTION: BlobGetXYInside + - FUNCTIONALITY: Calculates whether a point is inside the + rectangular bounding box of a blob + - PARAMETERS: + - RESULT: + - returns 1 if it is inside; o if not + - RESTRICTIONS: + - AUTHOR: Francesc Pinyol Margalef + - CREATION DATE: 16-01-2006. + - MODIFICATION: Date. Author. Description. + */ + double CBlobGetXYInside::operator()(const CBlob &blob) const + { + if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0; + + // passem els punts del blob a un vector de punts de les STL + CvSeqReader reader; + CBlob::vectorPunts vectorEdges; + CBlob::vectorPunts::iterator itEdges, itEdgesSeguent; + CvPoint edgeactual; + bool dinsBlob; + + // agafem tots els punts amb la mateixa y que l'actual + cvStartReadSeq(blob.Edges(), &reader); + + for (int i = 0; i < blob.Edges()->total; i++) + { + CV_READ_SEQ_ELEM(edgeactual, reader); + if (edgeactual.y == m_p.y) + vectorEdges.push_back(edgeactual); + } + + if (vectorEdges.empty()) return 0.0; + + // ordenem el vector per les Y's i les X's d'esquerra a dreta + std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint()); + + // recorrem el punts del blob de la mateixa fila que el punt d'entrada + // i mirem si la X del punt d'entrada està entre dos coordenades "plenes" + // del blob + itEdges = vectorEdges.begin(); + itEdgesSeguent = vectorEdges.begin() + 1; + dinsBlob = true; + + while (itEdges != (vectorEdges.end() - 1)) + { + if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob) + { + vectorEdges.clear(); + return 1.0; + } + + ++itEdges; + ++itEdgesSeguent; + dinsBlob = !dinsBlob; + } + + vectorEdges.clear(); + return 0.0; + } + +#ifdef BLOB_OBJECT_FACTORY + + /** + - FUNCIÓ: RegistraTotsOperadors + - FUNCIONALITAT: Registrar tots els operadors definits a blob.h + - PARÀMETRES: + - fabricaOperadorsBlob: fà brica on es registraran els operadors + - RESULTAT: + - Modifica l'objecte fabricaOperadorsBlob + - RESTRICCIONS: + - Només es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb + el mètode Register de la fà brica. + - AUTOR: rborras + - DATA DE CREACIÓ: 2006/05/18 + - MODIFICACIÓ: Data. Autor. Descripció. + */ + void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob) + { + // blob shape + fabricaOperadorsBlob.Register(CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>()); + fabricaOperadorsBlob.Register(CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>()); + fabricaOperadorsBlob.Register(CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>()); + fabricaOperadorsBlob.Register(CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>()); + fabricaOperadorsBlob.Register(CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>()); + fabricaOperadorsBlob.Register(CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>()); + fabricaOperadorsBlob.Register(CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>()); + fabricaOperadorsBlob.Register(CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>()); + + // extern pixels + fabricaOperadorsBlob.Register(CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>()); + fabricaOperadorsBlob.Register(CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>()); + fabricaOperadorsBlob.Register(CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>()); + + + // hull + fabricaOperadorsBlob.Register(CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>()); + fabricaOperadorsBlob.Register(CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>()); + + + // elipse info + fabricaOperadorsBlob.Register(CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>()); + fabricaOperadorsBlob.Register(CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>()); + fabricaOperadorsBlob.Register(CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>()); + fabricaOperadorsBlob.Register(CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>()); + fabricaOperadorsBlob.Register(CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>()); + fabricaOperadorsBlob.Register(CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>()); + + // min an max + fabricaOperadorsBlob.Register(CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>()); + fabricaOperadorsBlob.Register(CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>()); + fabricaOperadorsBlob.Register(CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>()); + fabricaOperadorsBlob.Register(CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>()); + + fabricaOperadorsBlob.Register(CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>()); + fabricaOperadorsBlob.Register(CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>()); + fabricaOperadorsBlob.Register(CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>()); + fabricaOperadorsBlob.Register(CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>()); + + // grey level stats + fabricaOperadorsBlob.Register(CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>()); + fabricaOperadorsBlob.Register(CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>()); + + // coordinate info + fabricaOperadorsBlob.Register(CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>()); + fabricaOperadorsBlob.Register(CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>()); + fabricaOperadorsBlob.Register(CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>()); + fabricaOperadorsBlob.Register(CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>()); + fabricaOperadorsBlob.Register(CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>()); + fabricaOperadorsBlob.Register(CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>()); + + // moments + fabricaOperadorsBlob.Register(CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>()); + + } + +#endif + +} + diff --git a/package_bgs/jmo/blob.h b/package_bgs/MultiLayer/blob.h similarity index 87% rename from package_bgs/jmo/blob.h rename to package_bgs/MultiLayer/blob.h index 67bdf11..b7d5fe1 100644 --- a/package_bgs/jmo/blob.h +++ b/package_bgs/MultiLayer/blob.h @@ -43,9 +43,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. /************************************************************************ Blob.h -FUNCIONALITAT: Definici� de la classe CBlob +FUNCIONALITAT: Definició de la classe CBlob AUTOR: Inspecta S.L. -MODIFICACIONS (Modificaci�, Autor, Data): +MODIFICACIONS (Modificació, Autor, Data): FUNCTIONALITY: Definition of the CBlob class and some helper classes to perform some calculations on it @@ -53,51 +53,46 @@ AUTHOR: Inspecta S.L. MODIFICATIONS (Modification, Author, Date): **************************************************************************/ - -//! Disable warnings referred to 255 character truncation for the std:map -//#pragma warning( disable : 4786 ) - -#ifndef CBLOB_INSPECTA_INCLUDED -#define CBLOB_INSPECTA_INCLUDED +#pragma once //#include "cxcore.h" #include "BlobLibraryConfiguration.h" #include <functional> #include <vector> #include <algorithm> -#include <opencv2/core/types_c.h> -//! Factor de conversi� de graus a radians +#include "OpenCvLegacyIncludes.h" +//! Factor de conversió de graus a radians #define DEGREE2RAD (CV_PI / 180.0) namespace Blob { /** - Classe que representa un blob, ent�s com un conjunt de pixels del - mateix color contigus en una imatge binaritzada. + Classe que representa un blob, entés com un conjunt de pixels del + mateix color contigus en una imatge binaritzada. - Class to represent a blob, a group of connected pixels in a binary image - */ + Class to represent a blob, a group of connected pixels in a binary image + */ class CBlob { public: - //! Constructor est�ndard + //! Constructor està ndard //! Standard constructor CBlob(); - //! Constructor de c�pia + //! Constructor de còpia //! Copy constructor CBlob(const CBlob &src); CBlob(const CBlob *src); - //! Destructor est�ndard + //! Destructor està ndard //! Standard Destructor ~CBlob(); - //! Operador d'assignaci� + //! Operador d'assignació //! Assigment operator CBlob& operator=(const CBlob &src); - //! Indica si el blob est� buit ( no t� cap info associada ) + //! Indica si el blob està buit ( no té cap info associada ) //! Shows if the blob has associated information bool IsEmpty() const { @@ -107,13 +102,13 @@ namespace Blob //! Neteja les cantonades del blob //! Clears the edges of the blob void ClearEdges(); - //! Copia les cantonades del blob a un altre (les afegeix al dest�) + //! Copia les cantonades del blob a un altre (les afegeix al destÃ) //! Adds the blob edges to another blob void CopyEdges(CBlob &destination) const; //! Retorna el poligon convex del blob //! Calculates the convex hull of the blob bool GetConvexHull(CvSeq **dst) const; - //! Calcula l'elipse que s'adapta als v�rtexs del blob + //! Calcula l'elipse que s'adapta als vèrtexs del blob //! Fits an ellipse to the blob edges CvBox2D GetEllipse() const; @@ -124,8 +119,8 @@ namespace Blob //! Funcions GET sobre els valors dels blobs //! Get functions - inline int Label() const { return etiqueta; } - inline int Parent() const { return parent; } + inline int Label() const { return etiqueta; } + inline int Parent() const { return parent; } inline double Area() const { return area; } inline double Perimeter() const { return perimeter; } inline double ExternPerimeter() const { return externPerimeter; } @@ -176,14 +171,14 @@ namespace Blob //! mitjana //! mean of the grey scale values of the blob pixels double mean; - //! desviaci� standard + //! desviació standard //! standard deviation of the grey scale values of the blob pixels double stddev; - //! �rea de mem�ria on es desaran els punts de contorn del blob + //! à rea de memòria on es desaran els punts de contorn del blob //! storage which contains the edges of the blob CvMemStorage *m_storage; - //! Sequ�ncia de punts del contorn del blob + //! Sequència de punts del contorn del blob //! Sequence with the edges of the blob CvSeq *edges; @@ -194,7 +189,7 @@ namespace Blob //! Helper class to compare two CvPoints (for sorting in FillBlob) struct comparaCvPoint : public std::binary_function<CvPoint, CvPoint, bool> { - //! Definim que un punt �s menor com m�s amunt a la dreta estigui + //! Definim que un punt és menor com més amunt a la dreta estigui bool operator()(CvPoint a, CvPoint b) { if (a.y == b.y) @@ -208,22 +203,22 @@ namespace Blob /************************************************************************** - Definici� de les classes per a fer operacions sobre els blobs + Definició de les classes per a fer operacions sobre els blobs - Helper classes to perform operations on blobs - **************************************************************************/ + Helper classes to perform operations on blobs + **************************************************************************/ - //! Classe d'on derivarem totes les operacions sobre els blobs - //! Interface to derive all blob operations + //! Classe d'on derivarem totes les operacions sobre els blobs + //! Interface to derive all blob operations class COperadorBlob { public: - virtual ~COperadorBlob(){}; + virtual ~COperadorBlob() {}; - //! Aplica l'operaci� al blob + //! Aplica l'operació al blob virtual double operator()(const CBlob &blob) const = 0; - //! Obt� el nom de l'operador + //! Obté el nom de l'operador virtual const char *GetNom() const = 0; operator COperadorBlob*() const @@ -236,8 +231,8 @@ namespace Blob #ifdef BLOB_OBJECT_FACTORY /** - Funci� per comparar dos identificadors dins de la f�brica de COperadorBlobs - */ + Funció per comparar dos identificadors dins de la fà brica de COperadorBlobs + */ struct functorComparacioIdOperador { bool operator()(const char* s1, const char* s2) const @@ -249,12 +244,12 @@ namespace Blob //! Definition of Object factory type for COperadorBlob objects typedef ObjectFactory<COperadorBlob, const char *, functorComparacioIdOperador > t_OperadorBlobFactory; - //! Funci� global per a registrar tots els operadors definits a blob.h - void RegistraTotsOperadors( t_OperadorBlobFactory &fabricaOperadorsBlob ); + //! Funció global per a registrar tots els operadors definits a blob.h + void RegistraTotsOperadors(t_OperadorBlobFactory &fabricaOperadorsBlob); #endif - //! Classe per calcular l'�rea d'un blob + //! Classe per calcular l'à rea d'un blob //! Class to get the area of a blob class CBlobGetArea : public COperadorBlob { @@ -284,7 +279,7 @@ namespace Blob } }; - //! Classe que diu si un blob �s extern o no + //! Classe que diu si un blob és extern o no //! Class to get the extern flag of a blob class CBlobGetExterior : public COperadorBlob { @@ -314,7 +309,7 @@ namespace Blob } }; - //! Classe per calcular la desviaci� est�ndard dels nivells de gris d'un blob + //! Classe per calcular la desviació està ndard dels nivells de gris d'un blob //! Class to get the standard deviation of the grey level values of a blob class CBlobGetStdDev : public COperadorBlob { @@ -365,7 +360,7 @@ namespace Blob } }; - //! Classe per calcular la difer�ncia en X del blob + //! Classe per calcular la diferència en X del blob class CBlobGetDiffX : public COperadorBlob { public: @@ -379,7 +374,7 @@ namespace Blob } }; - //! Classe per calcular la difer�ncia en X del blob + //! Classe per calcular la diferència en X del blob class CBlobGetDiffY : public COperadorBlob { public: @@ -398,7 +393,7 @@ namespace Blob class CBlobGetMoment : public COperadorBlob { public: - //! Constructor est�ndard + //! Constructor està ndard //! Standard constructor (gets the 00 moment) CBlobGetMoment() { @@ -434,7 +429,7 @@ namespace Blob } }; - //! Classe per calcular l'�rea del poligon convex d'un blob + //! Classe per calcular l'à rea del poligon convex d'un blob //! Class to calculate the convex hull area of a blob class CBlobGetHullArea : public COperadorBlob { @@ -494,7 +489,7 @@ namespace Blob } }; - //! Classe per a calcular la x m�nima + //! Classe per a calcular la x mÃnima //! Class to get the minimum x class CBlobGetMinX : public COperadorBlob { @@ -509,7 +504,7 @@ namespace Blob } }; - //! Classe per a calcular la x m�xima + //! Classe per a calcular la x mà xima //! Class to get the maximum x class CBlobGetMaxX : public COperadorBlob { @@ -524,7 +519,7 @@ namespace Blob } }; - //! Classe per a calcular la y m�nima + //! Classe per a calcular la y mÃnima //! Class to get the minimum y class CBlobGetMinY : public COperadorBlob { @@ -539,7 +534,7 @@ namespace Blob } }; - //! Classe per a calcular la y m�xima + //! Classe per a calcular la y mà xima //! Class to get the maximum y class CBlobGetMaxY : public COperadorBlob { @@ -579,7 +574,7 @@ namespace Blob } }; - //! Classe per calcular la dist�ncia entre el centre del blob i un punt donat + //! Classe per calcular la distà ncia entre el centre del blob i un punt donat //! Class to calculate the euclidean distance between the center of a blob and a given point class CBlobGetDistanceFromPoint : public COperadorBlob { @@ -603,7 +598,7 @@ namespace Blob } private: - // coordenades del punt on volem calcular la dist�ncia + // coordenades del punt on volem calcular la distà ncia double m_x, m_y; }; @@ -623,8 +618,8 @@ namespace Blob }; //! Classe per calcular el ratio entre el perimetre i nombre pixels externs - //! valors propers a 0 indiquen que la majoria del blob �s intern - //! valors propers a 1 indiquen que la majoria del blob �s extern + //! valors propers a 0 indiquen que la majoria del blob és intern + //! valors propers a 1 indiquen que la majoria del blob és extern //! Class to calculate the ratio between the perimeter and the number of extern pixels class CBlobGetExternPerimeterRatio : public COperadorBlob { @@ -643,8 +638,8 @@ namespace Blob }; //! Classe per calcular el ratio entre el perimetre convex i nombre pixels externs - //! valors propers a 0 indiquen que la majoria del blob �s intern - //! valors propers a 1 indiquen que la majoria del blob �s extern + //! valors propers a 0 indiquen que la majoria del blob és intern + //! valors propers a 1 indiquen que la majoria del blob és extern //! Class to calculate the ratio between the perimeter and the number of extern pixels class CBlobGetExternHullPerimeterRatio : public COperadorBlob { @@ -713,7 +708,7 @@ namespace Blob }; //! Classe per calcular el ratio entre l'area de la elipse i la de la taca - //! Class + //! Class class CBlobGetAreaElipseRatio : public COperadorBlob { public: @@ -755,7 +750,7 @@ namespace Blob } }; - //! Classe per calcular l'orientaci� de l'ellipse del blob en radians + //! Classe per calcular l'orientació de l'ellipse del blob en radians //! Class to calculate the orientation of the ellipse that fits the blob edges in radians class CBlobGetOrientation : public COperadorBlob { @@ -776,7 +771,7 @@ namespace Blob } }; - //! Classe per calcular el cosinus de l'orientaci� de l'ellipse del blob + //! Classe per calcular el cosinus de l'orientació de l'ellipse del blob //! Class to calculate the cosinus of the orientation of the ellipse that fits the blob edges class CBlobGetOrientationCos : public COperadorBlob { @@ -793,7 +788,7 @@ namespace Blob }; - //! Classe per calcular el ratio entre l'eix major i menor de la el�lipse + //! Classe per calcular el ratio entre l'eix major i menor de la el·lipse //! Class to calculate the ratio between both axes of the ellipse class CBlobGetAxisRatio : public COperadorBlob { @@ -816,7 +811,7 @@ namespace Blob class CBlobGetXYInside : public COperadorBlob { public: - //! Constructor est�ndard + //! Constructor està ndard //! Standard constructor CBlobGetXYInside() { @@ -841,6 +836,3 @@ namespace Blob }; } - -#endif //CBLOB_INSPECTA_INCLUDED - diff --git a/package_bgs/PAWCS.cpp b/package_bgs/PAWCS.cpp new file mode 100644 index 0000000..908b3ae --- /dev/null +++ b/package_bgs/PAWCS.cpp @@ -0,0 +1,93 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "PAWCS.h" + +using namespace bgslibrary::algorithms; + +PAWCS::PAWCS() : pPAWCS(nullptr), +fRelLBSPThreshold(BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), +nDescDistThresholdOffset(BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), +nMinColorDistThreshold(BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD), +nMaxNbWords(BGSPAWCS_DEFAULT_MAX_NB_WORDS), +nSamplesForMovingAvgs(BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS) +{ + std::cout << "PAWCS()" << std::endl; + setup("./config/PAWCS.xml"); +} +PAWCS::~PAWCS() +{ + if (pPAWCS) + delete pPAWCS; + std::cout << "~PAWCS()" << std::endl; +} + +void PAWCS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) + { + pPAWCS = new BackgroundSubtractorPAWCS( + fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, + nMaxNbWords, nSamplesForMovingAvgs); + + pPAWCS->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pPAWCS->apply(img_input, img_foreground); + pPAWCS->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + imshow("PAWCS FG", img_foreground); + imshow("PAWCS BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void PAWCS::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); + cvWriteInt(fs, "nDescDistThresholdOffset", nDescDistThresholdOffset); + cvWriteInt(fs, "nMinColorDistThreshold", nMinColorDistThreshold); + cvWriteInt(fs, "nMaxNbWords", nMaxNbWords); + cvWriteInt(fs, "nSamplesForMovingAvgs", nSamplesForMovingAvgs); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void PAWCS::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSPAWCS_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); + nDescDistThresholdOffset = cvReadIntByName(fs, nullptr, "nDescDistThresholdOffset", BGSPAWCS_DEFAULT_DESC_DIST_THRESHOLD_OFFSET); + nMinColorDistThreshold = cvReadIntByName(fs, nullptr, "nMinColorDistThreshold", BGSPAWCS_DEFAULT_MIN_COLOR_DIST_THRESHOLD); + nMaxNbWords = cvReadIntByName(fs, nullptr, "nMaxNbWords", BGSPAWCS_DEFAULT_MAX_NB_WORDS); + nSamplesForMovingAvgs = cvReadIntByName(fs, nullptr, "nSamplesForMovingAvgs", BGSPAWCS_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/PAWCS.h b/package_bgs/PAWCS.h new file mode 100644 index 0000000..173bcf6 --- /dev/null +++ b/package_bgs/PAWCS.h @@ -0,0 +1,48 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "LBSP/BackgroundSubtractorPAWCS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class PAWCS : public IBGS + { + private: + BackgroundSubtractorPAWCS* pPAWCS; + + float fRelLBSPThreshold; + size_t nDescDistThresholdOffset; + size_t nMinColorDistThreshold; + size_t nMaxNbWords; + size_t nSamplesForMovingAvgs; + + public: + PAWCS(); + ~PAWCS(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/PBAS/PBAS.cpp b/package_bgs/PBAS/PBAS.cpp new file mode 100644 index 0000000..bc3ad40 --- /dev/null +++ b/package_bgs/PBAS/PBAS.cpp @@ -0,0 +1,585 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "PBAS.h" + +PBAS::PBAS(void) : N(20), R_lower(18), Raute_min(2), T_lower(2), T_upper(200), R_scale(5), R_incdec(0.05), T_dec(0.05), T_inc(1) +{ + std::cout << "PBAS()" << std::endl; + + //feature vector + alpha = 7.0; + beta = 1.0; + formerMeanNorm = 0; + width = 0; + + //result image + foregroundValue = 255; + backgroundValue = 0; + + //length of random array + countOfRandomNumb = 1000; + + //the T(x_i) value needs initiation + T_init = R_lower; + + //check if something is moving in the picture + isMove = false; + + //for init, count number of runs + runs = 0; + newInitialization(); +} + +void PBAS::newInitialization() +{ + if (!randomN.empty()) + randomN.clear(); + + if (!randomX.empty()) + randomX.clear(); + + if (!randomY.empty()) + randomY.clear(); + + if (!randomMinDist.empty()) + randomMinDist.clear(); + + if (!randomT.empty()) + randomT.clear(); + + if (!randomTN.empty()) + randomTN.clear(); + + for (int l = 0; l < countOfRandomNumb; l++) + { + randomN.push_back((int)randomGenerator.uniform((int)0, (int)N)); + randomX.push_back((int)randomGenerator.uniform(-1, +2)); + randomY.push_back((int)randomGenerator.uniform(-1, +2)); + randomMinDist.push_back((int)randomGenerator.uniform((int)0, (int)N)); + randomT.push_back((int)randomGenerator.uniform((int)0, (int)T_upper)); + randomTN.push_back((int)randomGenerator.uniform((int)0, (int)T_upper)); + } +} + +PBAS::~PBAS(void) +{ + std::cout << "~PBAS()" << std::endl; + + randomN.clear(); + randomX.clear(); + randomY.clear(); + randomMinDist.clear(); + randomT.clear(); + randomTN.clear(); + + for (int k = 0; k < backgroundModel.size(); ++k) + { + if (chans == 1) + { + backgroundModel.at(k).at(0).release(); + backgroundModel.at(k).at(1).release(); + } + else + { + backgroundModel.at(k).at(0).release(); + backgroundModel.at(k).at(1).release(); + backgroundModel.at(k).at(2).release(); + + backgroundModel.at(k).at(3).release(); + backgroundModel.at(k).at(4).release(); + backgroundModel.at(k).at(5).release(); + } + } + + backgroundModel.clear(); + meanMinDist.release(); + + actualR.release(); + actualT.release(); + + sobelX.release(); + sobelY.release(); +} + +bool PBAS::process(cv::Mat* input, cv::Mat* output) +{ + if (width != input->cols) + { + width = input->cols; + chans = input->channels(); + height = input->rows; + + if (input->rows < 1 || input->cols < 1) + { + std::cout << "Error: Occurrence of to small (or empty?) image size in PBAS. STOPPING " << std::endl; + return false; + } + } + + //iniate the background model + init(input); + + resultMap = new cv::Mat(input->rows, input->cols, CV_8UC1); + + //calculate features + calculateFeatures(¤tFeatures, input); + + //set sumMagnitude to zero at beginning and then sum up in the loop + sumMagnitude = 0; + long glCounterFore = 0; + isMove = false; + + //Here starts the whole processing of each pixel of the image + // for each pixel + for (int j = 0; j < resultMap->rows; ++j) + { + resultMap_Pt = resultMap->ptr<uchar>(j); + currentFeaturesM_Pt.clear(); + currentFeaturesC_Pt.clear(); + std::vector<float*> fT; + std::vector<uchar*> uT; + B_Mag_Pts.clear(); + B_Col_Pts.clear(); + + for (int z = 0; z < chans; ++z) + { + currentFeaturesM_Pt.push_back(currentFeatures.at(z).ptr<float>(j)); + currentFeaturesC_Pt.push_back(currentFeatures.at(z + chans).ptr<uchar>(j)); + + B_Mag_Pts.push_back(fT); + + B_Col_Pts.push_back(uT); + } + + meanMinDist_Pt = meanMinDist.ptr<float>(j); + actualR_Pt = actualR.ptr<float>(j); + actualT_Pt = actualT.ptr<float>(j); + + for (int k = 0; k < runs; ++k) + { + for (int z = 0; z < chans; ++z) + { + B_Mag_Pts.at(z).push_back(backgroundModel.at(k).at(z).ptr<float>(j)); + B_Col_Pts.at(z).push_back(backgroundModel.at(k).at(z + chans).ptr<uchar>(j)); + } + } + + for (int i = 0; i < resultMap->cols; ++i) + { + //Compare each pixel to in the worst runtime-case each background model + int count = 0; + int index = 0; + + double norm = 0.0; + double dist = 0.0; + double minDist = 1000.0; + int entry = randomGenerator.uniform(3, countOfRandomNumb - 4); + + do + { + if (chans == 3) + { + norm = sqrt( + (((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0)))*((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0)))) + + (((double)B_Mag_Pts.at(1).at(index)[i] - ((double)*currentFeaturesM_Pt.at(1)))*((double)B_Mag_Pts.at(1).at(index)[i] - ((double)*currentFeaturesM_Pt.at(1)))) + + (((double)B_Mag_Pts.at(2).at(index)[i] - ((double)*currentFeaturesM_Pt.at(2)))*((double)B_Mag_Pts.at(2).at(index)[i] - ((double)*currentFeaturesM_Pt.at(2)))) + ); + + dist = sqrt( + (((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0)))*((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0)))) + + (((double)B_Col_Pts.at(1).at(index)[i] - ((double)*currentFeaturesC_Pt.at(1)))*((double)B_Col_Pts.at(1).at(index)[i] - ((double)*currentFeaturesC_Pt.at(1)))) + + (((double)B_Col_Pts.at(2).at(index)[i] - ((double)*currentFeaturesC_Pt.at(2)))*((double)B_Col_Pts.at(2).at(index)[i] - ((double)*currentFeaturesC_Pt.at(2)))) + ); + } + else + { + norm = abs((((double)B_Mag_Pts.at(0).at(index)[i] - + ((double)*currentFeaturesM_Pt.at(0)))*((double)B_Mag_Pts.at(0).at(index)[i] - ((double)*currentFeaturesM_Pt.at(0))))); + + dist = abs((((double)B_Col_Pts.at(0).at(index)[i] - + ((double)*currentFeaturesC_Pt.at(0)))*((double)B_Col_Pts.at(0).at(index)[i] - ((double)*currentFeaturesC_Pt.at(0)))) + ); + } + dist = ((double)alpha*(norm / formerMeanMag) + beta*dist); + + if ((dist < *actualR_Pt)) + { + ++count; + if (minDist > dist) + minDist = dist; + } + else + { + sumMagnitude += (double)(norm); + ++glCounterFore; + } + ++index; + } while ((count < Raute_min) && (index < runs)); + + + //############################################# + //update backgroundmodel + // is BACKGROUND + if (count >= Raute_min) + { + *resultMap_Pt = 0; + double ratio = std::ceil((double)T_upper / (double)(*actualT_Pt)); + //in the first run every distance is zero, because there is no background model + //in the secont run, we have already one image as background model, hence a + // reasonable minDist could be found -> because of the partly 1/run changing in the running average, we set in the first try meanMinDist to the actual minDist value + if (runs < N && runs > 2) + { + *meanMinDist_Pt = ((((float)(runs - 1)) * (*meanMinDist_Pt)) + (float)minDist) / ((float)runs); + } + else if (runs < N && runs == 2) + { + *meanMinDist_Pt = (float)minDist; + } + + //1. update model + if (runs == N) + { + //Update current pixel + //check if random numer is smaller than ratio + if (randomT.at(entry) < ratio) + { + // replace randomly chosen sample + int rand = randomN.at(entry + 1); //randomGenerator.uniform((int)0,(int)N-1); + for (int z = 0; z < chans; ++z) + { + B_Mag_Pts.at(z).at(rand)[i] = (float)*currentFeaturesM_Pt.at(z); + B_Col_Pts.at(z).at(rand)[i] = (uchar)*currentFeaturesC_Pt.at(z); + + } + + *meanMinDist_Pt = ((((float)(N - 1)) * (*meanMinDist_Pt)) + (float)minDist) / ((float)N); + } + + //Update neighboring pixel model + if (randomTN.at(entry) < ratio) + { + //choose neighboring pixel randomly + int xNeigh = randomX.at(entry) + i; + int yNeigh = randomY.at(entry) + j; + checkValid(&xNeigh, &yNeigh); + + // replace randomly chosen sample + int rand = randomN.at(entry - 1); + for (int z = 0; z < chans; ++z) + { + (backgroundModel.at(rand)).at(z).at<float>(yNeigh, xNeigh) = currentFeatures.at(z).at<float>(yNeigh, xNeigh); + (backgroundModel.at(rand)).at(z + chans).at<uchar>(yNeigh, xNeigh) = currentFeatures.at(z + chans).at<uchar>(yNeigh, xNeigh); + } + } + } + } + else + { + // store pixel as foreground + *resultMap_Pt = 255; + + //there is some movement + isMove = true; + } + + //#######################//#######################//#######################//####################### + //control loops + //#######################//#######################//#######################//####################### + //update R + decisionThresholdRegulator(actualR_Pt, meanMinDist_Pt); + + //update T + learningRateRegulator(actualT_Pt, meanMinDist_Pt, resultMap_Pt); + + //#######################//#######################//#######################//####################### + //#######################//#######################//#######################//####################### + + //jump to next pixel + ++resultMap_Pt; + for (int z = 0; z < chans; ++z) + { + ++currentFeaturesM_Pt.at(z); + ++currentFeaturesC_Pt.at(z); + } + + ++meanMinDist_Pt; + ++actualR_Pt; + ++actualT_Pt; + } + } + + resultMap->copyTo(*output); + + //if there is no foreground -> no magnitudes fount + //-> initiate some low value to prevent diving through zero + double meanMag = sumMagnitude / (double)(glCounterFore + 1); //height*width); + + if (meanMag > 20) + formerMeanMag = meanMag; + else + formerMeanMag = 20; + + delete resultMap; + + for (int z = 0; z < chans; ++z) + { + currentFeatures.at(z + chans).release(); + currentFeatures.at(z).release(); + } + + return true; +} + +void PBAS::decisionThresholdRegulator(float* pt, float* meanDist) +{ + //update R + double tempR = *pt; + double newThresh = (*meanDist)*R_scale; + + if (tempR < newThresh) + { + tempR += tempR * R_incdec; + } + else + { + tempR -= tempR * R_incdec; + } + + if (tempR >= R_lower) + *pt = (float)tempR; + else + *pt = (float)R_lower; +} + +void PBAS::learningRateRegulator(float* pt, float* meanDist, uchar* isFore) +{ + //time update + double tempT = *pt; + + if ((int)*isFore < 128) + { + tempT -= T_inc / (*meanDist + 1.0); + } + else + { + tempT += T_dec / (*meanDist + 1.0); + } + + if (tempT > T_lower && tempT < T_upper) + *pt = (float)tempT; +} + +void PBAS::checkValid(int *x, int *y) +{ + if (*x < 0) + { + *x = 0; + } + else if (*x >= width) + { + *x = width - 1; + } + + if (*y < 0) + { + *y = 0; + } + else if (*y >= height) + { + *y = height - 1; + } +} + +void PBAS::init(cv::Mat* input) +{ + if (runs < N) + { + std::vector<cv::Mat> init; + calculateFeatures(&init, input); + backgroundModel.push_back(init); + + if (chans == 1) + { + init.at(0).release(); + init.at(1).release(); + } + else + { + init.at(0).release(); + init.at(1).release(); + init.at(2).release(); + init.at(3).release(); + init.at(4).release(); + init.at(5).release(); + } + + init.clear(); + + if (runs == 0) + { + meanMinDist.create(input->size(), CV_32FC1); + meanMinDist.zeros(input->rows, input->cols, CV_32FC1); + + actualR.create(input->rows, input->cols, CV_32FC1); + actualT.create(input->rows, input->cols, CV_32FC1); + + float* ptRs, *ptTs; //, *ptM; + for (int rows = 0; rows < actualR.rows; ++rows) + { + ptRs = actualR.ptr<float>(rows); + ptTs = actualT.ptr<float>(rows); + + for (int cols = 0; cols < actualR.cols; ++cols) + { + ptRs[cols] = (float)R_lower; + ptTs[cols] = (float)T_init; + } + } + } + + ++runs; + } +} + +void PBAS::calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage) +{ + if (!feature->empty()) + feature->clear(); + + cv::Mat mag[3], dir; + + if (inputImage->channels() == 3) + { + std::vector<cv::Mat> rgbChannels(3); + cv::split(*inputImage, rgbChannels); + + for (int l = 0; l < 3; ++l) + { + cv::Sobel(rgbChannels.at(l), sobelX, CV_32F, 1, 0, 3, 1, 0.0); + cv::Sobel(rgbChannels.at(l), sobelY, CV_32F, 0, 1, 3, 1, 0.0); + + // Compute the L2 norm and direction of the gradient + cv::cartToPolar(sobelX, sobelY, mag[l], dir, true); + feature->push_back(mag[l]); + sobelX.release(); + sobelY.release(); + } + + feature->push_back(rgbChannels.at(0)); + feature->push_back(rgbChannels.at(1)); + feature->push_back(rgbChannels.at(2)); + rgbChannels.at(0).release(); + rgbChannels.at(1).release(); + rgbChannels.at(2).release(); + } + else + { + cv::Sobel(*inputImage, sobelX, CV_32F, 1, 0, 3, 1, 0.0); + cv::Sobel(*inputImage, sobelY, CV_32F, 0, 1, 3, 1, 0.0); + + // Compute the L2 norm and direction of the gradient + cv::cartToPolar(sobelX, sobelY, mag[0], dir, true); + feature->push_back(mag[0]); + + cv::Mat temp; + inputImage->copyTo(temp); + feature->push_back(temp); + temp.release(); + } + + mag[0].release(); + mag[1].release(); + mag[2].release(); + dir.release(); +} + +void PBAS::setN(int temp) +{ + N = temp; + newInitialization(); +} + +void PBAS::setRaute_min(int temp) +{ + Raute_min = temp; +} + +void PBAS::setR_lower(double temp) +{ + R_lower = temp; +} + +void PBAS::setR_incdec(double temp) +{ + R_incdec = temp; +} + +void PBAS::setR_scale(double temp) +{ + R_scale = temp; +} + +void PBAS::setT_init(double temp) +{ + T_init = temp; +} + +void PBAS::setT_lower(double temp) +{ + T_lower = temp; +} + +void PBAS::setT_upper(double temp) +{ + T_upper = temp; + newInitialization(); +} + +void PBAS::setT_dec(double temp) +{ + T_dec = temp; +} + +void PBAS::setT_inc(double temp) +{ + T_inc = temp; +} + +void PBAS::setAlpha(double temp) +{ + alpha = temp; +} + +void PBAS::setBeta(double temp) +{ + beta = temp; +} + +bool PBAS::isMovement() +{ + return isMove; +} + +//cv::Mat* PBAS::getR1_xi() +//{ +// return &actualR; +//} +// +//cv::Mat* PBAS::getT_xi() +//{ +// return &actualT; +//} diff --git a/package_bgs/PBAS/PBAS.h b/package_bgs/PBAS/PBAS.h new file mode 100644 index 0000000..9014a28 --- /dev/null +++ b/package_bgs/PBAS/PBAS.h @@ -0,0 +1,207 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +//Implementation of the PBAS from: +// +//M. Hofmann, P. Tiefenbacher, G. Rigoll +//"Background Segmentation with Feedback: The Pixel-Based Adaptive Segmenter", +//in proc of IEEE Workshop on Change Detection, 2012 +// +//Note: some changes, to improve the speed and memory requirements, were achieved in comparison to the +//described PBAS algorithm in the paper above. +// +//Example usage: +// //Somewhere during initalization: +// #include "PBAS.h" +// #include <opencv2/opencv.hpp> +// PBAS pbas; +// +// //you might want to change some parameters of the PBAS here... +// .... +// +// //repeat for each frame +// //make gaussian blur for reducing image noise +//cv::Mat bluredImage; +//cv::Mat pbastResult; +//cv::GaussianBlur(singleFrame, bluredImage, cv::Size(5,5), 1.5); +// +// //process image and receive segmentation in pbasResult +//pbas.process(&bluredImage, &pbasResult); +// +// //make medianBlur on the result to reduce "salt and pepper noise" +// //of the per pixel wise segmentation +//cv::medianBlur(pbasResult, pbasResult, 5); +// +// +// +//Author: P.Tiefenbacher, https://sites.google.com/site/pbassegmenter/ +//Technische Universität München, Germany +//Date: 22-May-2012, Version:0.1 +/////////// +#pragma once + +#include <iostream> +#include <opencv2/opencv.hpp> +//#include <highgui.h> + +class PBAS +{ +public: + PBAS(void); + ~PBAS(void); + bool process(cv::Mat* input, cv::Mat* output); + + void setN(int); + void setRaute_min(int); + void setR_lower(double); + void setR_incdec(double); + void setR_scale(double); + void setT_init(double); + void setT_lower(double); + void setT_upper(double); + void setT_dec(double); + void setT_inc(double); + void setAlpha(double); + void setBeta(double); + + bool isMovement(); + + +private: + void calculateFeatures(std::vector<cv::Mat>* feature, cv::Mat* inputImage); + void checkValid(int *x, int *y); + void decisionThresholdRegulator(float* pt, float* meanDistArr); + void learningRateRegulator(float* pt, float* meanDist, uchar* isFore); + void init(cv::Mat*); + void newInitialization(); + + cv::Mat meanMinDist; + float* meanMinDist_Pt; + + + + int width, height; + int chans; + + //balance of feature pixel value to conture value + double alpha, beta; + //################################################################################## + + double formerMeanNorm; + + //define value of foreground/background pixels + int foregroundValue, backgroundValue; + + //################################################################################## + //random number parameters + + //random number generator + cv::RNG randomGenerator; + + //length of random array initialization + long countOfRandomNumb; + + //pre - initialize the randomNumbers for better performance + std::vector<int> randomN, randomMinDist, randomX, randomY, randomT, randomTN; + + //################################################################################### + + //check if something is moving + bool isMove; + + //for init, count number of runs + int runs; + + + cv::Mat* resultMap; + std::vector<cv::Mat> currentFeatures; + + std::vector<float*> currentFeaturesM_Pt; + std::vector<uchar*> currentFeaturesC_Pt; + uchar* resultMap_Pt; + + std::vector<std::vector<float*>>B_Mag_Pts; + std::vector<std::vector<uchar*>>B_Col_Pts; + + double sumMagnitude; + double formerMeanMag; + float formerDistanceBack; + + //#################################################################################### + //N - Number: Defining the size of the background-history-model + // number of samples per pixel + //size of background history B(x_i) + int N; + // background model + std::vector<std::vector<cv::Mat>> backgroundModel; + //#################################################################################### + //#################################################################################### + //R-Threshhold - Variables + //minimal Threshold for foreground and initial value of R(x_i) + // radius of the sphere -> lower border boundary + double R_lower; + + //factor which defines new threshold of R(x_i) together with meanMinDist(x_i) + // scale for the sphere threshhold to define pixel-based Thresholds + double R_scale; + + //decreasing / increasing factor of R(x_i) + // increasing/decreasing factor for the r-Threshold based on the result of rTreshScale * meanMinDistBackground + double R_incdec; + + cv::Mat actualR; + float* actualR_Pt; //new pixel-based r-threshhold -> pointer to arrays + //##################################################################################### + //#################################################################################### + //counter for minimal distance to background + // Defining the number of background-model-images, which have a lowerDIstance to the current Image than defined by the R-Thresholds, that are necessary + // to decide that this pixel is background + int Raute_min; + //##################################################################################### + //#################################################################################### + //initial value of inverse update factor T(x_i) + // Initialize the background-model update rate + double T_init; + + //increasing Factor of the update rate 1/T(x_i) + // scale that defines the increasing of the update rate of the background model, if the current pixel is background + //--> more frequently updates if pixel is background because, there shouln't be any change + double T_inc; + + //upper boundary of T(x_i) + // defining an upper value, that nrSubsampling can achieve, thus it doesn't reach to an infinite value, where actually no update is possible + // at all + double T_upper; + + //lower boundary of T(x_i) + // defining a minimum value for nrSubsampling --> base value 2.0 + double T_lower; + + //decreasing factor of the update rate 1/T(x_i) + // opposite scale to increasingRateScale, for decreasing the update rate of the background model, if the current pixel is foreground + //--> Thesis: Our Foreground is a real moving object -> thus the background-model is good, so don't update it + double T_dec; + + //holds update rate of current pixel + cv::Mat actualT; + float* actualT_Pt; + + //##################################################################################### + + + cv::Mat sobelX, sobelY; +}; + diff --git a/package_bgs/PixelBasedAdaptiveSegmenter.cpp b/package_bgs/PixelBasedAdaptiveSegmenter.cpp new file mode 100644 index 0000000..8a3de97 --- /dev/null +++ b/package_bgs/PixelBasedAdaptiveSegmenter.cpp @@ -0,0 +1,126 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "PixelBasedAdaptiveSegmenter.h" + +using namespace bgslibrary::algorithms; + +PixelBasedAdaptiveSegmenter::PixelBasedAdaptiveSegmenter() : + enableInputBlur(true), enableOutputBlur(true), + alpha(7.0), beta(1.0), N(20), Raute_min(2), R_incdec(0.05), R_lower(18), + R_scale(5), T_dec(0.05), T_inc(1), T_init(18), T_lower(2), T_upper(200) +{ + std::cout << "PixelBasedAdaptiveSegmenter()" << std::endl; + setup("./config/PixelBasedAdaptiveSegmenter.xml"); +} + +PixelBasedAdaptiveSegmenter::~PixelBasedAdaptiveSegmenter() +{ + std::cout << "~PixelBasedAdaptiveSegmenter()" << std::endl; +} + +void PixelBasedAdaptiveSegmenter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) + { + pbas.setAlpha(alpha); + pbas.setBeta(beta); + pbas.setN(N); + pbas.setRaute_min(Raute_min); + pbas.setR_incdec(R_incdec); + pbas.setR_lower(R_lower); + pbas.setR_scale(R_scale); + pbas.setT_dec(T_dec); + pbas.setT_inc(T_inc); + pbas.setT_init(T_init); + pbas.setT_lower(T_lower); + pbas.setT_upper(T_upper); + } + + cv::Mat img_input_new; + if (enableInputBlur) + cv::GaussianBlur(img_input, img_input_new, cv::Size(5, 5), 1.5); + else + img_input.copyTo(img_input_new); + + pbas.process(&img_input_new, &img_foreground); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + + if (enableOutputBlur) + cv::medianBlur(img_foreground, img_foreground, 5); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("PBAS", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); + + firstTime = false; +} + +void PixelBasedAdaptiveSegmenter::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "enableInputBlur", enableInputBlur); + cvWriteInt(fs, "enableOutputBlur", enableOutputBlur); + + cvWriteReal(fs, "alpha", alpha); + cvWriteReal(fs, "beta", beta); + cvWriteInt(fs, "N", N); + cvWriteInt(fs, "Raute_min", Raute_min); + cvWriteReal(fs, "R_incdec", R_incdec); + cvWriteInt(fs, "R_lower", R_lower); + cvWriteInt(fs, "R_scale", R_scale); + cvWriteReal(fs, "T_dec", T_dec); + cvWriteInt(fs, "T_inc", T_inc); + cvWriteInt(fs, "T_init", T_init); + cvWriteInt(fs, "T_lower", T_lower); + cvWriteInt(fs, "T_upper", T_upper); + + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void PixelBasedAdaptiveSegmenter::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableInputBlur = cvReadIntByName(fs, nullptr, "enableInputBlur", true); + enableOutputBlur = cvReadIntByName(fs, nullptr, "enableOutputBlur", true); + + alpha = cvReadRealByName(fs, nullptr, "alpha", 7.0); + beta = cvReadRealByName(fs, nullptr, "beta", 1.0); + N = cvReadIntByName(fs, nullptr, "N", 20); + Raute_min = cvReadIntByName(fs, nullptr, "Raute_min", 2); + R_incdec = cvReadRealByName(fs, nullptr, "R_incdec", 0.05); + R_lower = cvReadIntByName(fs, nullptr, "R_lower", 18); + R_scale = cvReadIntByName(fs, nullptr, "R_scale", 5); + T_dec = cvReadRealByName(fs, nullptr, "T_dec", 0.05); + T_inc = cvReadIntByName(fs, nullptr, "T_inc", 1); + T_init = cvReadIntByName(fs, nullptr, "T_init", 18); + T_lower = cvReadIntByName(fs, nullptr, "T_lower", 2); + T_upper = cvReadIntByName(fs, nullptr, "T_upper", 200); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/PixelBasedAdaptiveSegmenter.h b/package_bgs/PixelBasedAdaptiveSegmenter.h new file mode 100644 index 0000000..36dd0ad --- /dev/null +++ b/package_bgs/PixelBasedAdaptiveSegmenter.h @@ -0,0 +1,58 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "PBAS/PBAS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class PixelBasedAdaptiveSegmenter : public IBGS + { + private: + PBAS pbas; + + bool enableInputBlur; + bool enableOutputBlur; + + float alpha; + float beta; + int N; + int Raute_min; + float R_incdec; + int R_lower; + int R_scale; + float T_dec; + int T_inc; + int T_init; + int T_lower; + int T_upper; + + public: + PixelBasedAdaptiveSegmenter(); + ~PixelBasedAdaptiveSegmenter(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/SigmaDelta.cpp b/package_bgs/SigmaDelta.cpp new file mode 100644 index 0000000..d305226 --- /dev/null +++ b/package_bgs/SigmaDelta.cpp @@ -0,0 +1,101 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "SigmaDelta.h" + +using namespace bgslibrary::algorithms; + +SigmaDelta::SigmaDelta() : + ampFactor(1), minVar(15), maxVar(255), algorithm(sdLaMa091New()) +{ + applyParams(); + std::cout << "SigmaDelta()" << std::endl; + setup("./config/SigmaDelta.xml"); +} + +SigmaDelta::~SigmaDelta() +{ + sdLaMa091Free(algorithm); + std::cout << "~SigmaDelta()" << std::endl; +} + +void SigmaDelta::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) + { + sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step); + img_foreground = cv::Mat(img_input.size(), CV_8UC1); + img_background = cv::Mat(img_input.size(), CV_8UC3); + firstTime = false; + } + else + { + cv::Mat img_output_tmp(img_input.rows, img_input.cols, CV_8UC3); + sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data); + + unsigned char* tmpBuffer = (unsigned char*)img_output_tmp.data; + unsigned char* outBuffer = (unsigned char*)img_foreground.data; + + for (size_t i = 0; i < img_foreground.total(); ++i) { + *outBuffer = *tmpBuffer; + ++outBuffer; + tmpBuffer += img_output_tmp.channels(); + } + } + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("Sigma-Delta", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void SigmaDelta::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "ampFactor", ampFactor); + cvWriteInt(fs, "minVar", minVar); + cvWriteInt(fs, "maxVar", maxVar); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void SigmaDelta::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + ampFactor = cvReadIntByName(fs, nullptr, "ampFactor", 1); + minVar = cvReadIntByName(fs, nullptr, "minVar", 15); + maxVar = cvReadIntByName(fs, nullptr, "maxVar", 255); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + applyParams(); + + cvReleaseFileStorage(&fs); +} + +void SigmaDelta::applyParams() +{ + sdLaMa091SetAmplificationFactor(algorithm, ampFactor); + sdLaMa091SetMinimalVariance(algorithm, minVar); + sdLaMa091SetMaximalVariance(algorithm, maxVar); +} diff --git a/package_bgs/SigmaDelta.h b/package_bgs/SigmaDelta.h new file mode 100644 index 0000000..c7b1a2c --- /dev/null +++ b/package_bgs/SigmaDelta.h @@ -0,0 +1,49 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" + +//extern "C" { +#include "SigmaDelta/sdLaMa091.h" +//} + +namespace bgslibrary +{ + namespace algorithms + { + class SigmaDelta : public IBGS + { + private: + unsigned int ampFactor; + unsigned int minVar; + unsigned int maxVar; + sdLaMa091_t* algorithm; + + public: + SigmaDelta(); + ~SigmaDelta(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + void applyParams(); + }; + } +} diff --git a/package_bgs/bl/sdLaMa091.cpp b/package_bgs/SigmaDelta/sdLaMa091.cpp similarity index 97% rename from package_bgs/bl/sdLaMa091.cpp rename to package_bgs/SigmaDelta/sdLaMa091.cpp index 7071438..286556b 100644 --- a/package_bgs/bl/sdLaMa091.cpp +++ b/package_bgs/SigmaDelta/sdLaMa091.cpp @@ -84,7 +84,7 @@ static inline uint8_t max(uint8_t a, uint8_t b) { } sdLaMa091_t* sdLaMa091New(void) { - sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*) malloc(sizeof(*sdLaMa091)); + sdLaMa091_t* sdLaMa091 = (sdLaMa091_t*)malloc(sizeof(*sdLaMa091)); #ifdef DEFENSIVE_ALLOC if (sdLaMa091 == NULL) { @@ -151,7 +151,7 @@ int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, sdLaMa091->numBytes = stride * height; sdLaMa091->unusedBytes = stride - sdLaMa091->width; - sdLaMa091->Mt = (uint8_t*) malloc(sdLaMa091->numBytes); + sdLaMa091->Mt = (uint8_t*)malloc(sdLaMa091->numBytes); #ifdef DEFENSIVE_ALLOC if (sdLaMa091->Mt == NULL) { outputError("Cannot allocate sdLaMa091->Mt table"); @@ -160,7 +160,7 @@ int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, #endif memcpy(sdLaMa091->Mt, image_data, sdLaMa091->numBytes); - sdLaMa091->Ot = (uint8_t*) malloc(sdLaMa091->numBytes); + sdLaMa091->Ot = (uint8_t*)malloc(sdLaMa091->numBytes); #ifdef DEFENSIVE_ALLOC if (sdLaMa091->Ot == NULL) { outputError("Cannot allocate sdLaMa091->Ot table"); @@ -170,16 +170,16 @@ int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, uint8_t* workOt = sdLaMa091->Ot; for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt) *workOt = 0; - + if (sdLaMa091->unusedBytes > 0) workOt += sdLaMa091->unusedBytes; } - sdLaMa091->Vt = (uint8_t*) malloc(sdLaMa091->numBytes); + sdLaMa091->Vt = (uint8_t*)malloc(sdLaMa091->numBytes); #ifdef DEFENSIVE_ALLOC if (sdLaMa091->Vt == NULL) { outputError("Cannot allocate sdLaMa091->Vt table"); @@ -188,13 +188,13 @@ int32_t sdLaMa091AllocInit_8u_C1R(sdLaMa091_t* sdLaMa091, #endif uint8_t* workVt = sdLaMa091->Vt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workVt) *workVt = sdLaMa091->Vmin; - + if (sdLaMa091->unusedBytes > 0) workVt += sdLaMa091->unusedBytes; } @@ -375,13 +375,13 @@ int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, } #endif - + const uint8_t* workImage = image_data; uint8_t* workMt = sdLaMa091->Mt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt) { if (*workMt < *workImage) ++(*workMt); @@ -389,7 +389,7 @@ int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, --(*workMt); } - + if (sdLaMa091->unusedBytes > 0) { workImage += sdLaMa091->unusedBytes; workMt += sdLaMa091->unusedBytes; @@ -400,14 +400,14 @@ int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, workMt = sdLaMa091->Mt; uint8_t* workOt = sdLaMa091->Ot; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workImage, ++workMt, ++workOt) *workOt = absVal(*workMt - *workImage); - + if (sdLaMa091->unusedBytes > 0) { workImage += sdLaMa091->unusedBytes; workMt += sdLaMa091->unusedBytes; @@ -415,13 +415,13 @@ int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, } } - + workOt = sdLaMa091->Ot; uint8_t* workVt = sdLaMa091->Vt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++workOt, ++workVt) { uint32_t ampOt = sdLaMa091->N * *workOt; @@ -433,30 +433,30 @@ int32_t sdLaMa091Update_8u_C1R(sdLaMa091_t* sdLaMa091, *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); } - + if (sdLaMa091->unusedBytes > 0) { workOt += sdLaMa091->unusedBytes; workVt += sdLaMa091->unusedBytes; } } - + workOt = sdLaMa091->Ot; workVt = sdLaMa091->Vt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->width; ++j, ++segmentation_map, ++workOt, ++workVt) { - + if (*workOt < *workVt) *segmentation_map = BACKGROUND; else *segmentation_map = FOREGROUND; } - + if (sdLaMa091->unusedBytes > 0) { segmentation_map += sdLaMa091->unusedBytes; workOt += sdLaMa091->unusedBytes; @@ -525,13 +525,13 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, } #endif - + const uint8_t* workImage = image_data; uint8_t* workMt = sdLaMa091->Mt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt) { if (*workMt < *workImage) ++(*workMt); @@ -539,26 +539,26 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, --(*workMt); } - + if (sdLaMa091->rgbUnusedBytes > 0) { workImage += sdLaMa091->rgbUnusedBytes; workMt += sdLaMa091->rgbUnusedBytes; } } - + workImage = image_data; workMt = sdLaMa091->Mt; uint8_t* workOt = sdLaMa091->Ot; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workImage, ++workMt, ++workOt) *workOt = absVal(*workMt - *workImage); - + if (sdLaMa091->rgbUnusedBytes > 0) { workImage += sdLaMa091->rgbUnusedBytes; workMt += sdLaMa091->rgbUnusedBytes; @@ -569,9 +569,9 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, workOt = sdLaMa091->Ot; uint8_t* workVt = sdLaMa091->Vt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { uint32_t ampOt = sdLaMa091->N * *workOt; @@ -583,7 +583,7 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, *workVt = max(min(*workVt, sdLaMa091->Vmax), sdLaMa091->Vmin); } - + if (sdLaMa091->rgbUnusedBytes > 0) { workOt += sdLaMa091->rgbUnusedBytes; workVt += sdLaMa091->rgbUnusedBytes; @@ -593,19 +593,19 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, workOt = sdLaMa091->Ot; workVt = sdLaMa091->Vt; - + for (uint32_t i = 0; i < sdLaMa091->numBytes; i += sdLaMa091->stride) { - + uint32_t numColor = 0; - + bool isForeground = false; - + for (uint32_t j = 0; j < sdLaMa091->rgbWidth; ++j, ++workOt, ++workVt) { if (*workOt >= *workVt) isForeground = true; - + if (numColor == BLUE) { if (isForeground) { *segmentation_map = FOREGROUND; @@ -626,7 +626,7 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, numColor = (numColor + 1) % CHANNELS; } - + if (sdLaMa091->rgbUnusedBytes > 0) { segmentation_map += sdLaMa091->rgbUnusedBytes; workOt += sdLaMa091->rgbUnusedBytes; diff --git a/package_bgs/bl/sdLaMa091.h b/package_bgs/SigmaDelta/sdLaMa091.h similarity index 96% rename from package_bgs/bl/sdLaMa091.h rename to package_bgs/SigmaDelta/sdLaMa091.h index bec93fb..cf9e777 100644 --- a/package_bgs/bl/sdLaMa091.h +++ b/package_bgs/SigmaDelta/sdLaMa091.h @@ -14,11 +14,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SD_LA_MA_091_H_ -#define SD_LA_MA_091_H_ +#pragma once #include <errno.h> -#include "stdbool.h" #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -68,5 +66,3 @@ int32_t sdLaMa091Update_8u_C3R(sdLaMa091_t* sdLaMa091, uint8_t* segmentation_map); int32_t sdLaMa091Free(sdLaMa091_t* sdLaMa091); - -#endif diff --git a/package_bgs/StaticFrameDifferenceBGS.cpp b/package_bgs/StaticFrameDifference.cpp similarity index 53% rename from package_bgs/StaticFrameDifferenceBGS.cpp rename to package_bgs/StaticFrameDifference.cpp index 3463c45..2faa40c 100644 --- a/package_bgs/StaticFrameDifferenceBGS.cpp +++ b/package_bgs/StaticFrameDifference.cpp @@ -14,41 +14,41 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "StaticFrameDifferenceBGS.h" +#include "StaticFrameDifference.h" -StaticFrameDifferenceBGS::StaticFrameDifferenceBGS() : firstTime(true), enableThreshold(true), threshold(15), showOutput(true) +using namespace bgslibrary::algorithms; + +StaticFrameDifference::StaticFrameDifference() : + enableThreshold(true), threshold(15) { - std::cout << "StaticFrameDifferenceBGS()" << std::endl; + std::cout << "StaticFrameDifference()" << std::endl; + setup("./config/StaticFrameDifference.xml"); } -StaticFrameDifferenceBGS::~StaticFrameDifferenceBGS() +StaticFrameDifference::~StaticFrameDifference() { - std::cout << "~StaticFrameDifferenceBGS()" << std::endl; + std::cout << "~StaticFrameDifference()" << std::endl; } -void StaticFrameDifferenceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void StaticFrameDifference::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; + init(img_input, img_output, img_bgmodel); - if(img_background.empty()) + if (img_background.empty()) img_input.copyTo(img_background); - - loadConfig(); - - if(firstTime) - saveConfig(); cv::absdiff(img_input, img_background, img_foreground); - if(img_foreground.channels() == 3) + if (img_foreground.channels() == 3) cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) cv::imshow("Static Frame Difference", img_foreground); +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -56,9 +56,9 @@ void StaticFrameDifferenceBGS::process(const cv::Mat &img_input, cv::Mat &img_ou firstTime = false; } -void StaticFrameDifferenceBGS::saveConfig() +void StaticFrameDifference::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/StaticFrameDifferenceBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "enableThreshold", enableThreshold); cvWriteInt(fs, "threshold", threshold); @@ -67,13 +67,13 @@ void StaticFrameDifferenceBGS::saveConfig() cvReleaseFileStorage(&fs); } -void StaticFrameDifferenceBGS::loadConfig() +void StaticFrameDifference::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/StaticFrameDifferenceBGS.xml", 0, CV_STORAGE_READ); - - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/StaticFrameDifference.h b/package_bgs/StaticFrameDifference.h new file mode 100644 index 0000000..8c8474c --- /dev/null +++ b/package_bgs/StaticFrameDifference.h @@ -0,0 +1,42 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class StaticFrameDifference : public IBGS + { + private: + bool enableThreshold; + int threshold; + + public: + StaticFrameDifference(); + ~StaticFrameDifference(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/SuBSENSE.cpp b/package_bgs/SuBSENSE.cpp new file mode 100644 index 0000000..c8a0e5d --- /dev/null +++ b/package_bgs/SuBSENSE.cpp @@ -0,0 +1,96 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "SuBSENSE.h" + +using namespace bgslibrary::algorithms; + +SuBSENSE::SuBSENSE() : + pSubsense(0), + fRelLBSPThreshold(BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), + nDescDistThresholdOffset(BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), + nMinColorDistThreshold(BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD), + nBGSamples(BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES), + nRequiredBGSamples(BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES), + nSamplesForMovingAvgs(BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS) +{ + std::cout << "SuBSENSE()" << std::endl; +} + +SuBSENSE::~SuBSENSE() { + if (pSubsense) + delete pSubsense; + std::cout << "~SuBSENSE()" << std::endl; +} + +void SuBSENSE::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (firstTime) + { + pSubsense = new BackgroundSubtractorSuBSENSE( + fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, + nBGSamples, nRequiredBGSamples, nSamplesForMovingAvgs); + + pSubsense->initialize(img_input, cv::Mat(img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); + firstTime = false; + } + + pSubsense->apply(img_input, img_foreground); + pSubsense->getBackgroundImage(img_background); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { + imshow("SuBSENSE FG", img_foreground); + imshow("SuBSENSE BG", img_background); + } +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); +} + +void SuBSENSE::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); + cvWriteInt(fs, "nDescDistThresholdOffset", nDescDistThresholdOffset); + cvWriteInt(fs, "nMinColorDistThreshold", nMinColorDistThreshold); + cvWriteInt(fs, "nBGSamples", nBGSamples); + cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); + cvWriteInt(fs, "nSamplesForMovingAvgs", nSamplesForMovingAvgs); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void SuBSENSE::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + fRelLBSPThreshold = cvReadRealByName(fs, nullptr, "fRelLBSPThreshold", BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); + nDescDistThresholdOffset = cvReadIntByName(fs, nullptr, "nDescDistThresholdOffset", BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET); + nMinColorDistThreshold = cvReadIntByName(fs, nullptr, "nMinColorDistThreshold", BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD); + nBGSamples = cvReadIntByName(fs, nullptr, "nBGSamples", BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES); + nRequiredBGSamples = cvReadIntByName(fs, nullptr, "nRequiredBGSamples", BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES); + nSamplesForMovingAvgs = cvReadIntByName(fs, nullptr, "nSamplesForMovingAvgs", BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/SuBSENSE.h b/package_bgs/SuBSENSE.h new file mode 100644 index 0000000..9ac9aa6 --- /dev/null +++ b/package_bgs/SuBSENSE.h @@ -0,0 +1,49 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "LBSP/BackgroundSubtractorSuBSENSE.h" + +namespace bgslibrary +{ + namespace algorithms + { + class SuBSENSE : public IBGS + { + private: + BackgroundSubtractorSuBSENSE* pSubsense; + + float fRelLBSPThreshold; + size_t nDescDistThresholdOffset; + size_t nMinColorDistThreshold; + size_t nBGSamples; + size_t nRequiredBGSamples; + size_t nSamplesForMovingAvgs; + + public: + SuBSENSE(); + ~SuBSENSE(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/T2F/FuzzyUtils.cpp b/package_bgs/T2F/FuzzyUtils.cpp new file mode 100644 index 0000000..a151136 --- /dev/null +++ b/package_bgs/T2F/FuzzyUtils.cpp @@ -0,0 +1,512 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "FuzzyUtils.h" + +FuzzyUtils::FuzzyUtils(void) {} + +FuzzyUtils::~FuzzyUtils(void) {} + +void FuzzyUtils::LBP(IplImage* InputImage, IplImage* LBPimage) +{ + PixelUtils p; + + float* neighberPixel = (float*)malloc(9 * sizeof(float)); + float* BinaryValue = (float*)malloc(9 * sizeof(float)); + float* CarreExp = (float*)malloc(9 * sizeof(float)); + float* valLBP = (float*)malloc(1 * sizeof(float)); + + *valLBP = 0; + + int x = 0, y = 0; + + // on implemente les 8 valeurs puissance de 2 qui correspondent aux 8 elem. d'image voisins au elem. d'image central + *(CarreExp + 0) = 1.0; + *(CarreExp + 1) = 2.0; + *(CarreExp + 2) = 4.0; + *(CarreExp + 3) = 8.0; + *(CarreExp + 4) = 0.0; + *(CarreExp + 5) = 16.0; + *(CarreExp + 6) = 32.0; + *(CarreExp + 7) = 64.0; + *(CarreExp + 8) = 128.0; + + //le calcule de LBP + //pour les 4 coins + /* 1.*/ + if (x == 0 && y == 0) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 4, 0); + *valLBP = *valLBP + ((*(BinaryValue + 1))*(*(CarreExp + 1)) + (*(BinaryValue + 2))*(*(CarreExp + 2)) + (*(BinaryValue + 3))*(*(CarreExp + 3))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + + /* 2.*/ + if (x == 0 && y == InputImage->width) + { + *valLBP = 0; + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 4, 1); + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 2))*(*(CarreExp + 2)) + (*(BinaryValue + 3))*(*(CarreExp + 3))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + + /* 3.*/ + if (x == InputImage->height && y == 0) + { + *valLBP = 0; + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 4, 2); + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 1))*(*(CarreExp + 1)) + (*(BinaryValue + 3))*(*(CarreExp + 3))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + + /* 4.*/ + if (x == InputImage->height && y == InputImage->width) + { + *valLBP = 0; + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 4, 3); + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 1))*(*(CarreExp + 1)) + (*(BinaryValue + 2))*(*(CarreExp + 2))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + + //le calcul de LBP pour la première ligne : L(0) + if (x == 0 && (y != 0 && y != InputImage->width)) + { + for (int y = 1; y < InputImage->width - 1; y++) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 6, 4); + *valLBP = 0; + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 1))*(*(CarreExp + 1)) + (*(BinaryValue + 2))*(*(CarreExp + 2)) + (*(BinaryValue + 3))*(*(CarreExp + 3)) + (*(BinaryValue + 5))*(*(CarreExp + 5))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + } + + //le calcul de LBP pour la dernière colonne : C(w) + if ((x != 0 && x != InputImage->height) && y == InputImage->width) + { + for (int x = 1; x < InputImage->height - 1; x++) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 6, 4); + *valLBP = 0; + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 1))*(*(CarreExp + 1)) + (*(BinaryValue + 2))*(*(CarreExp + 2)) + (*(BinaryValue + 3))*(*(CarreExp + 3)) + (*(BinaryValue + 5))*(*(CarreExp + 5))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + } + + //le calcul de LBP pour la dernière ligne : L(h) + if (x == InputImage->height && (y != 0 && y != InputImage->width)) + { + for (int y = 1; y < InputImage->width - 1; y++) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 6, 1); + *valLBP = 0; + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp)) + (*(BinaryValue + 2))*(*(CarreExp + 2)) + (*(BinaryValue + 3))*(*(CarreExp + 3)) + (*(BinaryValue + 4))*(*(CarreExp + 4)) + (*(BinaryValue + 5))*(*(CarreExp + 5))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + } + + //le calcul de LBP pour la première colonne : C(0) + if ((x != 0 && x != InputImage->height) && y == 0) + { + for (int x = 1; x < InputImage->height - 1; x++) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 6, 2); + *valLBP = 0; + *valLBP = *valLBP + ((*(BinaryValue))*(*(CarreExp + 5)) + (*(BinaryValue + 1))*(*(CarreExp + 6)) + (*(BinaryValue + 3))*(*(CarreExp + 3)) + (*(BinaryValue + 4))*(*(CarreExp)) + (*(BinaryValue + 5))*(*(CarreExp + 1))) / 255.0; + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + } + + //pour le reste des elements d'image + for (int y = 1; y < InputImage->height - 1; y++) + { + for (int x = 1; x < InputImage->width - 1; x++) + { + p.getNeighberhoodGrayPixel(InputImage, x, y, neighberPixel); + getBinValue(neighberPixel, BinaryValue, 9, 4); + //le calcul de la valeur du LBP pour chaque elem. d'im. + *valLBP = 0; + for (int l = 0; l < 9; l++) + *valLBP = *valLBP + ((*(BinaryValue + l)) * (*(CarreExp + l))) / 255.0; + //printf("\nvalLBP(%d,%d)=%f",x,y,*valLBP); + p.PutGrayPixel(LBPimage, x, y, *valLBP); + } + } + + free(neighberPixel); + free(BinaryValue); + free(CarreExp); + free(valLBP); +} + +void FuzzyUtils::getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n) +{ + // la comparaison entre la valeur d'elem d'image central et les valeurs des elem. d'im. voisins + // m = le numero des elements (4, 6 ou 9); + // n = la position de l'element central; + + int h = 0; + for (int k = 0; k < m; k++) + { + if (*(neighberGrayPixel + k) >= *(neighberGrayPixel + n)) + { + *(BinaryValue + h) = 1; + h++; + } + else + { + *(BinaryValue + h) = 0; + h++; + } + } +} + +void FuzzyUtils::SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space) +{ + PixelUtils p; + int i, j; + + if (n == 1) + { + float* CurrentGrayPixel = (float*)malloc(1 * (sizeof(float))); + float* BGGrayPixel = (float*)malloc(1 * (sizeof(float))); + float* DeltaGrayPixel = (float*)malloc(1 * (sizeof(float))); + + for (i = 0; i < CurrentImage->width; i++) + { + for (j = 0; j < CurrentImage->height; j++) + { + p.GetGrayPixel(CurrentImage, i, j, CurrentGrayPixel); + p.GetGrayPixel(BGImage, i, j, BGGrayPixel); + RatioPixels(CurrentGrayPixel, BGGrayPixel, DeltaGrayPixel, 1); + p.PutGrayPixel(DeltaImage, i, j, *DeltaGrayPixel); + } + } + + free(CurrentGrayPixel); + free(BGGrayPixel); + free(DeltaGrayPixel); + } + + if (n != 1) + { + IplImage* ConvertedCurrentImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3); + IplImage* ConvertedBGImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3); + + float* ConvertedCurrentPixel = (float*)malloc(3 * (sizeof(float))); + float* ConvertedBGPixel = (float*)malloc(3 * (sizeof(float))); + float* DeltaConvertedPixel = (float*)malloc(3 * (sizeof(float))); + + p.ColorConversion(CurrentImage, ConvertedCurrentImage, color_space); + p.ColorConversion(BGImage, ConvertedBGImage, color_space); + + for (i = 0; i < CurrentImage->width; i++) + { + for (j = 0; j < CurrentImage->height; j++) + { + p.GetPixel(ConvertedCurrentImage, i, j, ConvertedCurrentPixel); + p.GetPixel(ConvertedBGImage, i, j, ConvertedBGPixel); + RatioPixels(ConvertedCurrentPixel, ConvertedBGPixel, DeltaConvertedPixel, 3); + p.PutPixel(DeltaImage, i, j, DeltaConvertedPixel); + } + } + + free(ConvertedCurrentPixel); + free(ConvertedBGPixel); + free(DeltaConvertedPixel); + + cvReleaseImage(&ConvertedCurrentImage); + cvReleaseImage(&ConvertedBGImage); + } +} + +void FuzzyUtils::RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n) +{ + if (n == 1) + { + if (*CurrentPixel < *BGPixel) + *DeltaPixel = *CurrentPixel / *BGPixel; + + if (*CurrentPixel > *BGPixel) + *DeltaPixel = *BGPixel / *CurrentPixel; + + if (*CurrentPixel == *BGPixel) + *DeltaPixel = 1.0; + } + + if (n == 3) + for (int i = 0; i < 3; i++) + { + if (*(CurrentPixel + i) < *(BGPixel + i)) + *(DeltaPixel + i) = *(CurrentPixel + i) / *(BGPixel + i); + + if (*(CurrentPixel + i) > *(BGPixel + i)) + *(DeltaPixel + i) = *(BGPixel + i) / *(CurrentPixel + i); + + if (*(CurrentPixel + i) == *(BGPixel + i)) + *(DeltaPixel + i) = 1.0; + } +} + +void FuzzyUtils::getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage) +{ + // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1 + // n : =2 cad aggreger les 2 images "H" et "Delta" + // =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta" + + PixelUtils p; + + float* HTexturePixel = (float*)malloc(1 * sizeof(float)); + float* DeltaOhtaPixel = (float*)malloc(3 * (sizeof(float))); + int *Indice = (int*)malloc(3 * (sizeof(int))); + float *HI = (float*)malloc(3 * (sizeof(float))); + float *Integral = (float*)malloc(3 * (sizeof(float))); + float* X = (float*)malloc(1 * sizeof(float)); + float* XiXj = (float*)malloc(1 * sizeof(float)); + float IntegralFlou; + + *Indice = 0; + *(Indice + 1) = 1; + *(Indice + 2) = 2; + *X = 1.0; + + for (int i = 0; i < H->width; i++) + { + for (int j = 0; j < H->height; j++) + { + p.GetGrayPixel(H, i, j, HTexturePixel); + p.GetPixel(Delta, i, j, DeltaOhtaPixel); + + *(HI + 0) = *(HTexturePixel + 0); + *(HI + 1) = *(DeltaOhtaPixel + 0); + *(HI + 2) = *(DeltaOhtaPixel + 1); + + Trier(HI, 3, Indice); + + *XiXj = *(MeasureG + (*(Indice + 1))) + (*(MeasureG + (*(Indice + 2)))); + + *(Integral + 0) = min((HI + (*(Indice + 0))), X); + *(Integral + 1) = min((HI + (*(Indice + 1))), XiXj); + *(Integral + 2) = min((HI + (*(Indice + 2))), ((MeasureG + (*(Indice + 2))))); + + IntegralFlou = max(Integral, 3); + p.PutGrayPixel(OutputImage, i, j, IntegralFlou); + } + } + + free(HTexturePixel); + free(DeltaOhtaPixel); + free(Indice); + free(HI); + free(X); + free(XiXj); + free(Integral); +} + +void FuzzyUtils::getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage) +{ + // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1 + // n : =2 cad aggreger les 2 images "H" et "Delta" + // =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta" + + PixelUtils p; + + float* HTexturePixel = (float*)malloc(1 * sizeof(float)); + float* DeltaOhtaPixel = (float*)malloc(3 * (sizeof(float))); + int *Indice = (int*)malloc(3 * (sizeof(int))); + float *HI = (float*)malloc(3 * (sizeof(float))); + float *Integral = (float*)malloc(3 * (sizeof(float))); + float* X = (float*)malloc(1 * sizeof(float)); + float* XiXj = (float*)malloc(1 * sizeof(float)); + float IntegralFlou; + + *Indice = 0; + *(Indice + 1) = 1; + *(Indice + 2) = 2; + *X = 1.0; + + for (int i = 0; i < Delta->width; i++) + { + for (int j = 0; j < Delta->height; j++) + { + if (n == 2) + { + p.GetGrayPixel(H, i, j, HTexturePixel); + p.GetPixel(Delta, i, j, DeltaOhtaPixel); + + *(HI + 0) = *(HTexturePixel + 0); + *(HI + 1) = *(DeltaOhtaPixel + 0); + *(HI + 2) = *(DeltaOhtaPixel + 1); + } + + if (n == 1) + { + //remplir HI par les valeurs des 3 composantes couleurs uniquement + p.GetPixel(Delta, i, j, DeltaOhtaPixel); + + *(HI + 0) = *(DeltaOhtaPixel + 0); + //*(HI+0) = *(DeltaOhtaPixel+2); + *(HI + 1) = *(DeltaOhtaPixel + 1); + *(HI + 2) = *(DeltaOhtaPixel + 2); + } + + Trier(HI, 3, Indice); + *XiXj = *(MeasureG + (*(Indice + 1))) + (*(MeasureG + (*(Indice + 2)))); + + *(Integral + 0) = *(HI + (*(Indice + 0)))* (*X - *XiXj); + *(Integral + 1) = *(HI + (*(Indice + 1)))* (*XiXj - *(MeasureG + (*(Indice + 2)))); + *(Integral + 2) = *(HI + (*(Indice + 2)))* (*(MeasureG + (*(Indice + 2)))); + + IntegralFlou = *(Integral + 0) + *(Integral + 1) + *(Integral + 2); + p.PutGrayPixel(OutputImage, i, j, IntegralFlou); + } + } + + free(HTexturePixel); + free(DeltaOhtaPixel); + free(Indice); + free(HI); + free(X); + free(XiXj); + free(Integral); +} + +void FuzzyUtils::FuzzyMeasureG(float g1, float g2, float g3, float *G) +{ + *(G + 0) = g1; + *(G + 1) = g2; + *(G + 2) = g3; +} + +void FuzzyUtils::Trier(float* g, int n, int* index) +{ + // Cette fonction trie un vecteur g par ordre croissant et + // sort egalement l'indice des elements selon le trie dans le vecteur "index" supposé initialisé par des valeurs de 1 a n + + float t; + int r, a, b; + + for (a = 1; a <= n; a++) + { + for (b = n - 1; b >= a; b--) + if (*(g + b - 1) < (*(g + b))) + { + // ordre croissant des élements + t = *(g + b - 1); + *(g + b - 1) = *(g + b); + *(g + b) = t; + + // ordre des indices des élements du vecteur g + r = *(index + b - 1); + *(index + b - 1) = *(index + b); + *(index + b) = r; + } + } +} + +float FuzzyUtils::min(float *a, float *b) +{ + float min = 0; + + if (*a >= (*b)) + min = *b; + else + min = *a; + + return min; +} + +float FuzzyUtils::max(float* g, int n) +{ + float max = 0; + + for (int i = 0; i < n; i++) + { + if (*(g + i) >= max) + max = *(g + i); + } + + return max; +} + +void FuzzyUtils::gDeDeux(float* a, float* b, float* lambda) +{ + float* c = (float*)malloc(1 * sizeof(float)); + *c = *a + (*b) + (*lambda) * (*a) * (*b); +} + +void FuzzyUtils::getLambda(float* g) +{ + float a, b; + float* lambda = (float*)malloc(1 * sizeof(float)); + + a = (*(g + 0) * (*(g + 1)) + (*(g + 1)) * (*(g + 2)) + (*(g + 0)) * (*(g + 2))); + *lambda = -(*(g + 0) * (*(g + 1)) + (*(g + 1)) * (*(g + 2)) + (*(g + 0)) * (*(g + 2))) / (*(g + 0) * (*(g + 1)) * (*(g + 2))); + b = (*(g + 0) * (*(g + 1)) * (*(g + 2))); + + //printf("\na:%f",a); + //printf("\nb:%f",b); + //printf("\nlambda:%f", *lambda); + + free(lambda); +} + +void FuzzyUtils::AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha) +{ + PixelUtils p; + + float beta = 0.0; + float* CurentImagePixel = (float*)malloc(3 * sizeof(float)); + float* BGImagePixel = (float*)malloc(3 * sizeof(float)); + float* OutputImagePixel = (float*)malloc(3 * sizeof(float)); + float* IntegralImagePixel = (float*)malloc(1 * sizeof(float)); + float *Maximum = (float*)malloc(1 * sizeof(float)); + float *Minimum = (float*)malloc(1 * sizeof(float)); + + p.ForegroundMaximum(Integral, Maximum, 1); + p.ForegroundMinimum(Integral, Minimum, 1); + + for (int i = 0; i < CurrentImage->width; i++) + { + for (int j = 0; j < CurrentImage->height; j++) + { + p.GetPixel(CurrentImage, i, j, CurentImagePixel); + p.GetPixel(BGImage, i, j, BGImagePixel); + p.GetGrayPixel(Integral, i, j, IntegralImagePixel); + + beta = 1 - ((*IntegralImagePixel) - ((*Minimum / (*Minimum - *Maximum)) * (*IntegralImagePixel) - (*Minimum * (*Maximum) / (*Minimum - *Maximum)))); + + for (int k = 0; k < 3; k++) + *(OutputImagePixel + k) = beta * (*(BGImagePixel + k)) + (1 - beta) * (alpha * (*(CurentImagePixel + k)) + (1 - alpha) * (*(BGImagePixel + k))); + + p.PutPixel(OutputImage, i, j, OutputImagePixel); + } + } + + free(CurentImagePixel); + free(BGImagePixel); + free(OutputImagePixel); + free(IntegralImagePixel); + free(Maximum); + free(Minimum); +} diff --git a/package_bgs/tb/FuzzyUtils.h b/package_bgs/T2F/FuzzyUtils.h similarity index 86% rename from package_bgs/tb/FuzzyUtils.h rename to package_bgs/T2F/FuzzyUtils.h index 43fc9ad..9a53a83 100644 --- a/package_bgs/tb/FuzzyUtils.h +++ b/package_bgs/T2F/FuzzyUtils.h @@ -15,19 +15,8 @@ You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -/* -Code provided by Thierry BOUWMANS - -Maitre de Conf�rences -Laboratoire MIA -Universit� de La Rochelle -17000 La Rochelle -France -tbouwman@univ-lr.fr -http://sites.google.com/site/thierrybouwmans/ -*/ -#include "PixelUtils.h" +#include "../../package_analysis/PixelUtils.h" class FuzzyUtils { @@ -44,7 +33,7 @@ public: void getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); void getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage); void FuzzyMeasureG(float g1, float g2, float g3, float *G); - void Trier(float* g, int n, int* index); + void Trier(float* g, int n, int* index); float min(float *a, float *b); float max(float *g, int n); void gDeDeux(float* a, float* b, float* lambda); diff --git a/package_bgs/tb/MRF.cpp b/package_bgs/T2F/MRF.cpp similarity index 58% rename from package_bgs/tb/MRF.cpp rename to package_bgs/T2F/MRF.cpp index cfde8af..291a846 100644 --- a/package_bgs/tb/MRF.cpp +++ b/package_bgs/T2F/MRF.cpp @@ -58,68 +58,68 @@ MRF_TC::MRF_TC() MRF_TC::~MRF_TC() { - delete []classes; - delete []old_labeling; - delete []in_image_data; - delete []local_evidence; + delete[]classes; + delete[]old_labeling; + delete[]in_image_data; + delete[]local_evidence; } double MRF_TC::TimeEnergy2(int i, int j, int label) { double energy = 0.0; - - if(old_labeling[i][j] == (label*255)) + + if (old_labeling[i][j] == (label * 255)) energy -= beta_time; else energy += beta_time; - if(i != height-1) // south + if (i != height - 1) // south { - if(label*255 == old_labeling[i+1][j]) + if (label * 255 == old_labeling[i + 1][j]) energy -= beta_time; else energy += beta_time; - if((j != width-1) && (label*255 == old_labeling[i+1][j+1])) + if ((j != width - 1) && (label * 255 == old_labeling[i + 1][j + 1])) energy -= beta_time; else energy += beta_time; - - if((j != 0) && (label*255 == old_labeling[i+1][j-1])) + + if ((j != 0) && (label * 255 == old_labeling[i + 1][j - 1])) energy -= beta_time; else energy += beta_time; } - if(j != width-1) // east + if (j != width - 1) // east { - if(label*255 == old_labeling[i][j+1]) + if (label * 255 == old_labeling[i][j + 1]) energy -= beta_time; else energy += beta_time; } - if(i != 0) // nord + if (i != 0) // nord { - if(label*255 == old_labeling[i-1][j]) + if (label * 255 == old_labeling[i - 1][j]) energy -= beta_time; else energy += beta_time; - if((j != width-1) && (label*255 == old_labeling[i-1][j+1])) + if ((j != width - 1) && (label * 255 == old_labeling[i - 1][j + 1])) energy -= beta_time; else energy += beta_time; - - if((j != 0) && (label*255 == old_labeling[i-1][j-1])) + + if ((j != 0) && (label * 255 == old_labeling[i - 1][j - 1])) energy -= beta_time; else energy += beta_time; } - if(j != 0) // west + if (j != 0) // west { - if(label*255 == old_labeling[i][j-1]) + if (label * 255 == old_labeling[i][j - 1]) energy -= beta_time; else energy += beta_time; @@ -132,53 +132,53 @@ double MRF_TC::Doubleton2(int i, int j, int label) { double energy = 0.0; - if(i != height-1) // south + if (i != height - 1) // south { - if(label == classes[i+1][j]) + if (label == classes[i + 1][j]) energy -= beta; else energy += beta; - if((j != width-1) && (label == classes[i+1][j+1])) + if ((j != width - 1) && (label == classes[i + 1][j + 1])) energy -= beta; else energy += beta; - - if((j != 0) && (label == classes[i+1][j-1])) + + if ((j != 0) && (label == classes[i + 1][j - 1])) energy -= beta; else energy += beta; } - if(j != width-1) // east + if (j != width - 1) // east { - if(label == classes[i][j+1]) + if (label == classes[i][j + 1]) energy -= beta; else energy += beta; } - if(i != 0) // nord + if (i != 0) // nord { - if(label == classes[i-1][j]) + if (label == classes[i - 1][j]) energy -= beta; else energy += beta; - if((j != width-1) && (label == classes[i-1][j+1])) + if ((j != width - 1) && (label == classes[i - 1][j + 1])) energy -= beta; else energy += beta; - if((j != 0) && (label == classes[i-1][j-1])) + if ((j != 0) && (label == classes[i - 1][j - 1])) energy -= beta; else energy += beta; } - if(j != 0) // west + if (j != 0) // west { - if(label == classes[i][j-1]) + if (label == classes[i][j - 1]) energy -= beta; else energy += beta; @@ -196,17 +196,17 @@ void MRF_TC::OnIterationOver2(void) void MRF_TC::Build_Classes_OldLabeling_InImage_LocalEnergy() { int i; - classes = new int* [height]; + classes = new int*[height]; old_labeling = new int *[height]; - in_image_data = new int* [height]; - local_evidence = new float* [height]; + in_image_data = new int*[height]; + local_evidence = new float*[height]; - for(i = 0; i < height; ++i) + for (i = 0; i < height; ++i) { classes[i] = new int[width]; old_labeling[i] = new int[width]; in_image_data[i] = new int[width]; - local_evidence[i] = new float[width*2]; + local_evidence[i] = new float[width * 2]; } } @@ -215,19 +215,19 @@ void MRF_TC::InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling) int i, j; background = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); - cvCopy(background2,background.Ptr()); + cvCopy(background2, background.Ptr()); unsigned char *in_data = (unsigned char *)(in_image->imageData); unsigned char *labeling_data = (unsigned char *)(labeling->imageData); - for(i = 0; i < height; ++i) + for (i = 0; i < height; ++i) { - for(j = 0; j < width; ++j) + for (j = 0; j < width; ++j) { - in_image_data[i][j] = in_data[(i*in_image->widthStep)+j]; - old_labeling[i][j] = labeling_data[i*width+j]; - - if(in_image_data[i][j] == 255) + in_image_data[i][j] = in_data[(i*in_image->widthStep) + j]; + old_labeling[i][j] = labeling_data[i*width + j]; + + if (in_image_data[i][j] == 255) classes[i][j] = 1; else classes[i][j] = 0; @@ -241,29 +241,29 @@ void MRF_TC::InitEvidence2(GMM *gmm, HMM *hmm, IplImage *labeling) float pixel; int modes = 3; - float mu; + float mu; - for(i = 0; i < height; ++i) + for (i = 0; i < height; ++i) { - for(j = 0; j < width; ++j) + for (j = 0; j < width; ++j) { - variance = gmm[(i*width+j) * modes+0].variance; - muR = gmm[(i*width+j) * modes+0].muR; - muG = gmm[(i*width+j) * modes+0].muG; - muB = gmm[(i*width+j) * modes+0].muB; + variance = gmm[(i*width + j) * modes + 0].variance; + muR = gmm[(i*width + j) * modes + 0].muR; + muG = gmm[(i*width + j) * modes + 0].muG; + muB = gmm[(i*width + j) * modes + 0].muB; - mu = (muR + muG + muB)/3; + mu = (muR + muG + muB) / 3; - pixel = (background(i,j,0) + background(i,j,1) + background(i,j,2))/3; + pixel = (background(i, j, 0) + background(i, j, 1) + background(i, j, 2)) / 3; - if(variance == 0) variance = 1; + if (variance == 0) variance = 1; - local_evidence[i][j*2+0] = pow((pixel-mu),2)/2/variance; + local_evidence[i][j * 2 + 0] = pow((pixel - mu), 2) / 2 / variance; - if(pixel >= mu) - local_evidence[i][j*2+1] = pow((pixel - mu - 2.5*sqrt(variance)),2)/2/variance; + if (pixel >= mu) + local_evidence[i][j * 2 + 1] = pow((pixel - mu - 2.5*sqrt(variance)), 2) / 2 / variance; else - local_evidence[i][j*2+1] = pow((pixel - mu + 2.5*sqrt(variance)),2)/2/variance; + local_evidence[i][j * 2 + 1] = pow((pixel - mu + 2.5*sqrt(variance)), 2) / 2 / variance; } } } @@ -274,12 +274,12 @@ void MRF_TC::CreateOutput2() int i, j; unsigned char *out_data; - out_data = (unsigned char *) out_image->imageData; + out_data = (unsigned char *)out_image->imageData; // create output image for (i = 0; i < height; ++i) - for(j = 0; j < width; ++j) - out_data[(i*width) + j] = (unsigned char)((classes[i][j])*255); + for (j = 0; j < width; ++j) + out_data[(i*width) + j] = (unsigned char)((classes[i][j]) * 255); } //calculate the whole energy @@ -288,12 +288,12 @@ double MRF_TC::CalculateEnergy2() double sum = 0.0; int i, j, k; // !FAIL! - for(i = 0; i < height; ++i) + for (i = 0; i < height; ++i) { - for(j = 0; j < width; ++j) + for (j = 0; j < width; ++j) { k = classes[i][j]; - sum = sum + local_evidence[i][j*2+k] + Doubleton2(i,j,k) + TimeEnergy2(i, j, k);//min the value + sum = sum + local_evidence[i][j * 2 + k] + Doubleton2(i, j, k) + TimeEnergy2(i, j, k);//min the value } } //sum = 0.1; @@ -303,7 +303,7 @@ double MRF_TC::CalculateEnergy2() // local energy double MRF_TC::LocalEnergy2(int i, int j, int label) { - return local_evidence[i][j*2+label] + Doubleton2(i,j,label) + TimeEnergy2(i,j,label); + return local_evidence[i][j * 2 + label] + Doubleton2(i, j, label) + TimeEnergy2(i, j, label); } void MRF_TC::ICM2() @@ -317,22 +317,22 @@ void MRF_TC::ICM2() do { - for(i = 0; i < height; ++i) - for(j = 0; j < width; ++j) + for (i = 0; i < height; ++i) + for (j = 0; j < width; ++j) { - localenergy0 = LocalEnergy2(i,j,0); - localenergy1 = LocalEnergy2(i,j,1); - - if(localenergy0 < localenergy1) + localenergy0 = LocalEnergy2(i, j, 0); + localenergy1 = LocalEnergy2(i, j, 1); + + if (localenergy0 < localenergy1) classes[i][j] = 0; else classes[i][j] = 1; } - //E = CalculateEnergy2(); - //summa_deltaE = fabs(E_old-E); - //E_old = E; - ++K; - OnIterationOver2(); - }while(K < 2); + //E = CalculateEnergy2(); + //summa_deltaE = fabs(E_old-E); + //E_old = E; + ++K; + OnIterationOver2(); + } while (K < 2); } diff --git a/package_bgs/tb/MRF.h b/package_bgs/T2F/MRF.h similarity index 95% rename from package_bgs/tb/MRF.h rename to package_bgs/T2F/MRF.h index c745899..1276a30 100644 --- a/package_bgs/tb/MRF.h +++ b/package_bgs/T2F/MRF.h @@ -14,8 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef MRF_H -#define MRF_H +#pragma once #include "T2FMRF.h" @@ -53,7 +52,7 @@ namespace Algorithms ////////////////////////////////////////////////////////////////////////// // alpha value for MMD - double alpha; + double alpha; ////////////////////////////////////////////////////////////////////////// //current global energy @@ -64,7 +63,7 @@ namespace Algorithms int K; ////////////////////////////////////////////////////////////////////////// - //labeling image + //labeling image int **classes; //input image int **in_image_data; @@ -75,7 +74,7 @@ namespace Algorithms /************************************************************************/ /* the Markov Random Field with time constraints for T2FGMM */ /************************************************************************/ - class MRF_TC: public MRF + class MRF_TC : public MRF { private: double beta_time; @@ -103,5 +102,3 @@ namespace Algorithms }; } } - -#endif diff --git a/package_bgs/tb/T2FGMM.cpp b/package_bgs/T2F/T2FGMM.cpp similarity index 69% rename from package_bgs/tb/T2FGMM.cpp rename to package_bgs/T2F/T2FGMM.cpp index a49407b..6ff9997 100644 --- a/package_bgs/tb/T2FGMM.cpp +++ b/package_bgs/T2F/T2FGMM.cpp @@ -17,8 +17,8 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. /**************************************************************************** * * T2FGMM.cpp -* -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) +* +* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) * "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" * Author: Fida El Baf, Thierry Bouwmans, September 2008. @@ -33,9 +33,9 @@ int compareT2FGMM(const void* _gmm1, const void* _gmm2) GMM gmm1 = *(GMM*)_gmm1; GMM gmm2 = *(GMM*)_gmm2; - if(gmm1.significants < gmm2.significants) + if (gmm1.significants < gmm2.significants) return 1; - else if(gmm1.significants == gmm2.significants) + else if (gmm1.significants == gmm2.significants) return 0; else return -1; @@ -53,10 +53,10 @@ T2FGMM::~T2FGMM() void T2FGMM::Initalize(const BgsParams& param) { - m_params = (T2FGMMParams&) param; + m_params = (T2FGMMParams&)param; // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper + m_bg_threshold = 0.75f; // 1-cf from the paper // Tgenerate - the threshold m_variance = 36.0f; // sigma for the new mode @@ -71,11 +71,11 @@ void T2FGMM::Initalize(const BgsParams& param) // Factor control for the T2FGMM-UM [0,3] //km = (float) 1.5; - km = (float) m_params.KM(); + km = (float)m_params.KM(); // Factor control for the T2FGMM-UV [0.3,1] //kv = (float) 0.6; - kv = (float) m_params.KV(); + kv = (float)m_params.KV(); } RgbImage* T2FGMM::Background() @@ -87,7 +87,7 @@ void T2FGMM::InitModel(const RgbImage& data) { m_modes_per_pixel.Clear(); - for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) { m_modes[i].weight = 0; m_modes[i].variance = 0; @@ -98,13 +98,13 @@ void T2FGMM::InitModel(const RgbImage& data) } } -void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void T2FGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { // it doesn't make sense to have conditional updates in the GMM framework } -void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) +void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) { // calculate distances to the modes (+ sort???) // here we need to go in descending order!!! @@ -119,19 +119,19 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& // calculate number of Gaussians to include in the background model int backgroundGaussians = 0; double sum = 0.0; - for(int i = 0; i < numModes; ++i) + for (int i = 0; i < numModes; ++i) { - if(sum < m_bg_threshold) + if (sum < m_bg_threshold) { backgroundGaussians++; - sum += m_modes[posPixel+i].weight; + sum += m_modes[posPixel + i].weight; } else break; } // update all distributions and check for match with current pixel - for(int iModes = 0; iModes < numModes; iModes++) + for (int iModes = 0; iModes < numModes; iModes++) { pos = posPixel + iModes; float weight = m_modes[pos].weight; @@ -159,45 +159,45 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& float HB; // T2FGMM-UM - if(m_params.Type() == TYPE_T2FGMM_UM) + if (m_params.Type() == TYPE_T2FGMM_UM) { - if((pixel(0)<muR-km*var)|| (pixel(0)>muR+km*var)) - HR=2*km*dR/var; + if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) + HR = 2 * km*dR / var; else - HR=dR*dR/(2*var*var)+km*dR/var+km*km/2; + HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; - if((pixel(1)<muG-km*var)|| (pixel(1)>muG+km*var)) - HG=2*km*dG/var; + if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) + HG = 2 * km*dG / var; else - HG=dG*dG/(2*var*var)+km*dG/var+km*km/2; + HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; - if((pixel(2)<muB-km*var)|| (pixel(2)>muB+km*var)) - HB=2*km*dB/var; + if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) + HB = 2 * km*dB / var; else - HB=dB*dB/(2*var*var)+km*dB/var+km*km/2; + HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; } // T2FGMM-UV - if(m_params.Type() == TYPE_T2FGMM_UV) + if (m_params.Type() == TYPE_T2FGMM_UV) { - HR = (1/(kv*kv)-kv*kv) * (pixel(0)-muR) * (pixel(0)-muR)/(2*var); - HG = (1/(kv*kv)-kv*kv) * (pixel(1)-muG) * (pixel(1)-muG)/(2*var); - HB = (1/(kv*kv)-kv*kv) * (pixel(2)-muB) * (pixel(2)-muB)/(2*var); + HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); + HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); + HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); } - + // calculate the squared distance float dist = (HR*HR + HG*HG + HB*HB); - if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) bBackgroundHigh = true; // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if(dist < m_params.LowThreshold()*var) + if (dist < m_params.LowThreshold()*var) { bFitsPDF = true; // check if this Gaussian is part of the background model - if(iModes < backgroundGaussians) + if (iModes < backgroundGaussians) bBackgroundLow = true; //update distribution @@ -209,16 +209,16 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& m_modes[pos].muB = muB - k*(dB); //limit the variance - float sigmanew = var + k*(dist-var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew; + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); } else { weight = fOneMinAlpha*weight; - if(weight < 0.0) + if (weight < 0.0) { - weight=0.0; + weight = 0.0; numModes--; } @@ -229,9 +229,9 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& else { weight = fOneMinAlpha*weight; - if(weight < 0.0) + if (weight < 0.0) { - weight=0.0; + weight = 0.0; numModes--; } m_modes[pos].weight = weight; @@ -243,25 +243,25 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& // renormalize weights so they add to one double invTotalWeight = 1.0 / totalWeight; - for(int iLocal = 0; iLocal < numModes; iLocal++) + for (int iLocal = 0; iLocal < numModes; iLocal++) { m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance); } - // Sort significance values so they are in desending order. - qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM); + // Sort significance values so they are in desending order. + qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareT2FGMM); // make new mode if needed and exit - if(!bFitsPDF) + if (!bFitsPDF) { - if(numModes < m_params.MaxModes()) + if (numModes < m_params.MaxModes()) numModes++; //else - // the weakest mode will be replaced - - pos = posPixel + numModes-1; + // the weakest mode will be replaced + + pos = posPixel + numModes - 1; m_modes[pos].muR = pixel.ch[0]; m_modes[pos].muG = pixel.ch[1]; @@ -277,26 +277,26 @@ void T2FGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& //renormalize weights int iLocal; float sum = 0.0; - for(iLocal = 0; iLocal < numModes; iLocal++) - sum += m_modes[posPixel+ iLocal].weight; - - double invSum = 1.0/sum; - for(iLocal = 0; iLocal < numModes; iLocal++) + for (iLocal = 0; iLocal < numModes; iLocal++) + sum += m_modes[posPixel + iLocal].weight; + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) { m_modes[posPixel + iLocal].weight *= (float)invSum; m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posPixel + iLocal].variance); } } - // Sort significance values so they are in desending order. + // Sort significance values so they are in desending order. qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareT2FGMM); - if(bBackgroundLow) + if (bBackgroundLow) low_threshold = BACKGROUND; else low_threshold = FOREGROUND; - - if(bBackgroundHigh) + + if (bBackgroundHigh) high_threshold = BACKGROUND; else high_threshold = FOREGROUND; @@ -316,21 +316,21 @@ void T2FGMM::Subtract(int frame_num, const RgbImage& data, BwImage& low_threshol long posPixel; // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) + for (unsigned int r = 0; r < m_params.Height(); ++r) { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { // update model + background subtract posPixel = (r*m_params.Width() + c) * m_params.MaxModes(); - SubtractPixel(posPixel, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold); + SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; - m_background(r,c,0) = (unsigned char) m_modes[posPixel].muR; - m_background(r,c,1) = (unsigned char) m_modes[posPixel].muG; - m_background(r,c,2) = (unsigned char) m_modes[posPixel].muB; + m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; } } } diff --git a/package_bgs/tb/T2FGMM.h b/package_bgs/T2F/T2FGMM.h similarity index 92% rename from package_bgs/tb/T2FGMM.h rename to package_bgs/T2F/T2FGMM.h index 7d966db..203c350 100644 --- a/package_bgs/tb/T2FGMM.h +++ b/package_bgs/T2F/T2FGMM.h @@ -18,18 +18,16 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * T2FGMM.h * -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) +* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) * "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" * Author: Fida El Baf, Thierry Bouwmans, September 2008 * * This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: +* background subtraction algorithm: * * Zivkovic's code can be obtained at: www.zoranz.net ******************************************************************************/ - -#ifndef T2F_GMM_ -#define T2F_GMM_ +#pragma once #include "../dp/Bgs.h" #include "../dp/GrimsonGMM.h" @@ -55,9 +53,9 @@ namespace Algorithms float &KV() { return m_kv; } private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values // lead to a small number of components but they can grow too large. // // It is usual easiest to think of these thresholds as being the number of variances away @@ -66,7 +64,7 @@ namespace Algorithms float m_high_threshold; // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. + // set alpha=1/T. float m_alpha; // Maximum number of modes (Gaussian components) that will be used per pixel @@ -92,12 +90,12 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background(); - private: + private: void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); // User adjustable parameters @@ -109,8 +107,8 @@ namespace Algorithms // it is considered foreground float m_bg_threshold; //1-cf from the paper - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. // A simple way is to estimate the typical standard deviation from the images. float m_variance; @@ -131,5 +129,3 @@ namespace Algorithms }; } } - -#endif diff --git a/package_bgs/tb/T2FMRF.cpp b/package_bgs/T2F/T2FMRF.cpp similarity index 70% rename from package_bgs/tb/T2FMRF.cpp rename to package_bgs/T2F/T2FMRF.cpp index 372f564..e722d02 100644 --- a/package_bgs/tb/T2FMRF.cpp +++ b/package_bgs/T2F/T2FMRF.cpp @@ -18,12 +18,12 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * T2FMRF.cpp * -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) +* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) * "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" * Author: Fida El Baf, Thierry Bouwmans, September 2008 * * This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: +* background subtraction algorithm: * * Zivkovic's code can be obtained at: www.zoranz.net ******************************************************************************/ @@ -37,9 +37,9 @@ int compareT2FMRF(const void* _gmm1, const void* _gmm2) GMM gmm1 = *(GMM*)_gmm1; GMM gmm2 = *(GMM*)_gmm2; - if(gmm1.significants < gmm2.significants) + if (gmm1.significants < gmm2.significants) return 1; - else if(gmm1.significants == gmm2.significants) + else if (gmm1.significants == gmm2.significants) return 0; else return -1; @@ -66,10 +66,10 @@ T2FMRF::~T2FMRF() void T2FMRF::Initalize(const BgsParams& param) { - m_params = (T2FMRFParams&) param; + m_params = (T2FMRFParams&)param; // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper + m_bg_threshold = 0.75f; // 1-cf from the paper // Tgenerate - the threshold m_variance = 36.0f; // sigma for the new mode @@ -87,11 +87,11 @@ void T2FMRF::Initalize(const BgsParams& param) // Factor control for the T2FGMM-UM [0,3] // km = (float) 2; //1.5; - km = (float) m_params.KM(); + km = (float)m_params.KM(); // Factor control for the T2FGMM-UV [0.3,1] // kv = (float) 0.9; //0.6; - kv = (float) m_params.KV(); + kv = (float)m_params.KV(); } RgbImage* T2FMRF::Background() @@ -103,7 +103,7 @@ void T2FMRF::InitModel(const RgbImage& data) { m_modes_per_pixel.Clear(); - for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) { m_modes[i].weight = 0; m_modes[i].variance = 0; @@ -124,13 +124,13 @@ void T2FMRF::InitModel(const RgbImage& data) } } -void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void T2FMRF::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { // it doesn't make sense to have conditional updates in the GMM framework } -void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) +void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) { // calculate distances to the modes (+ sort???) // here we need to go in descending order!!! @@ -144,7 +144,7 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, float Ab2f = m_state[posPixel].Ab2f; float Af2b = m_state[posPixel].Af2b; float Af2f = m_state[posPixel].Af2f; - float T = m_state[posPixel].T; + //float T = m_state[posPixel].T; float fOneMinAlpha = 1 - m_params.Alpha(); float totalWeight = 0.0f; @@ -152,12 +152,12 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, // calculate number of Gaussians to include in the background model int backgroundGaussians = 0; double sum = 0.0; - for(int i = 0; i < numModes; ++i) + for (int i = 0; i < numModes; ++i) { - if(sum < m_bg_threshold) + if (sum < m_bg_threshold) { backgroundGaussians++; - sum += m_modes[posGMode+i].weight; + sum += m_modes[posGMode + i].weight; } else break; @@ -192,57 +192,57 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, float HB; // T2FMRF-UM - if(m_params.Type() == TYPE_T2FMRF_UM) + if (m_params.Type() == TYPE_T2FMRF_UM) { - if((pixel(0) < muR-km*var) || (pixel(0) > muR+km*var)) - HR = 2*km*dR/var; + if ((pixel(0) < muR - km*var) || (pixel(0) > muR + km*var)) + HR = 2 * km*dR / var; else - HR = dR*dR/(2*var*var)+km*dR/var+km*km/2; + HR = dR*dR / (2 * var*var) + km*dR / var + km*km / 2; - if((pixel(1) < muG-km*var) || (pixel(1) > muG+km*var)) - HG = 2*km*dG/var; + if ((pixel(1) < muG - km*var) || (pixel(1) > muG + km*var)) + HG = 2 * km*dG / var; else - HG = dG*dG/(2*var*var)+km*dG/var+km*km/2; + HG = dG*dG / (2 * var*var) + km*dG / var + km*km / 2; - if((pixel(2) < muB-km*var) || (pixel(2) > muB+km*var)) - HB = 2*km*dB/var; + if ((pixel(2) < muB - km*var) || (pixel(2) > muB + km*var)) + HB = 2 * km*dB / var; else - HB = dB*dB/(2*var*var)+km*dB/var+km*km/2; + HB = dB*dB / (2 * var*var) + km*dB / var + km*km / 2; } // T2FGMM-UV - if(m_params.Type() == TYPE_T2FMRF_UV) + if (m_params.Type() == TYPE_T2FMRF_UV) { - HR = (1/(kv*kv)-kv*kv) * (pixel(0)-muR) * (pixel(0)-muR)/(2*var); - HG = (1/(kv*kv)-kv*kv) * (pixel(1)-muG) * (pixel(1)-muG)/(2*var); - HB = (1/(kv*kv)-kv*kv) * (pixel(2)-muB) * (pixel(2)-muB)/(2*var); + HR = (1 / (kv*kv) - kv*kv) * (pixel(0) - muR) * (pixel(0) - muR) / (2 * var); + HG = (1 / (kv*kv) - kv*kv) * (pixel(1) - muG) * (pixel(1) - muG) / (2 * var); + HB = (1 / (kv*kv) - kv*kv) * (pixel(2) - muB) * (pixel(2) - muB) / (2 * var); } float ro; if (CurrentState == background) { - if (Ab2b!=0) ro = (Ab2f/Ab2b); + if (Ab2b != 0) ro = (Ab2f / Ab2b); else ro = 10; } else { - if(Af2b!=0) ro = (Af2f/Af2b); + if (Af2b != 0) ro = (Af2f / Af2b); else ro = 10; } - + // calculate the squared distance float dist = (HR*HR + HG*HG + HB*HB); - if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) bBackgroundHigh = true; // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if(dist < m_params.LowThreshold()*var) + if (dist < m_params.LowThreshold()*var) { bFitsPDF = true; // check if this Gaussian is part of the background model - if(iModes < backgroundGaussians) + if (iModes < backgroundGaussians) bBackgroundLow = true; //update distribution @@ -254,8 +254,8 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, m_modes[pos].muB = muB - k*(dB); //limit the variance - float sigmanew = var + k*(dist-var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew; + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); } else @@ -263,7 +263,7 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, weight = fOneMinAlpha*weight; if (weight < 0.0) { - weight=0.0; + weight = 0.0; numModes--; } @@ -276,7 +276,7 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, weight = fOneMinAlpha*weight; if (weight < 0.0) { - weight=0.0; + weight = 0.0; numModes--; } m_modes[pos].weight = weight; @@ -294,18 +294,18 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, m_modes[posGMode + iLocal].significants = m_modes[posGMode + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); } - // Sort significance values so they are in desending order. - qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF); + // Sort significance values so they are in desending order. + qsort(&m_modes[posGMode], numModes, sizeof(GMM), compareT2FMRF); // make new mode if needed and exit - if(!bFitsPDF) + if (!bFitsPDF) { - if(numModes < m_params.MaxModes()) + if (numModes < m_params.MaxModes()) numModes++; //else - // the weakest mode will be replaced - - pos = posGMode + numModes-1; + // the weakest mode will be replaced + + pos = posGMode + numModes - 1; m_modes[pos].muR = pixel.ch[0]; m_modes[pos].muG = pixel.ch[1]; @@ -313,7 +313,7 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, m_modes[pos].variance = m_variance; m_modes[pos].significants = 0; // will be set below - if(numModes == 1) + if (numModes == 1) m_modes[pos].weight = 1; else m_modes[pos].weight = m_params.Alpha(); @@ -321,33 +321,33 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, //renormalize weights int iLocal; float sum = 0.0; - for(iLocal = 0; iLocal < numModes; iLocal++) - sum += m_modes[posGMode+ iLocal].weight; - - double invSum = 1.0/sum; - for(iLocal = 0; iLocal < numModes; iLocal++) + for (iLocal = 0; iLocal < numModes; iLocal++) + sum += m_modes[posGMode + iLocal].weight; + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) { m_modes[posGMode + iLocal].weight *= (float)invSum; m_modes[posGMode + iLocal].significants = m_modes[posPixel + iLocal].weight / sqrt(m_modes[posGMode + iLocal].variance); } } - // Sort significance values so they are in desending order. + // Sort significance values so they are in desending order. qsort(&(m_modes[posGMode]), numModes, sizeof(GMM), compareT2FMRF); - if(bBackgroundLow) + if (bBackgroundLow) { low_threshold = BACKGROUND; m_state[posPixel].State = background; - if(CurrentState == background) + if (CurrentState == background) { float b2b = fOneMinAlpha*Ab2b + m_params.Alpha(); float b2f = fOneMinAlpha*Ab2f; float b = b2b + b2f; - m_state[posPixel].Ab2b = b2b/b; - m_state[posPixel].Ab2f = b2f/b; + m_state[posPixel].Ab2b = b2b / b; + m_state[posPixel].Ab2f = b2f / b; m_state[posPixel].T = m_state[posPixel].Ab2b; } else @@ -356,8 +356,8 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, float f2f = fOneMinAlpha*Af2f; float f = f2b + f2f; - m_state[posPixel].Af2b = f2b/f; - m_state[posPixel].Af2f = f2f/f; + m_state[posPixel].Af2b = f2b / f; + m_state[posPixel].Af2f = f2f / f; m_state[posPixel].T = m_state[posPixel].Af2b; } } @@ -366,14 +366,14 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, low_threshold = FOREGROUND; m_state[posPixel].State = foreground; - if(CurrentState == background) + if (CurrentState == background) { float b2b = fOneMinAlpha*Ab2b; float b2f = fOneMinAlpha*Ab2f + m_params.Alpha(); float b = b2b + b2f; - m_state[posPixel].Ab2b = b2b/b; - m_state[posPixel].Ab2f = b2f/b; + m_state[posPixel].Ab2b = b2b / b; + m_state[posPixel].Ab2f = b2f / b; m_state[posPixel].T = m_state[posPixel].Ab2b; } else @@ -382,13 +382,13 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, float f2f = fOneMinAlpha*Af2f + m_params.Alpha(); float f = f2b + f2f; - m_state[posPixel].Af2b = f2b/f; - m_state[posPixel].Af2f = f2f/f; + m_state[posPixel].Af2b = f2b / f; + m_state[posPixel].Af2f = f2f / f; m_state[posPixel].T = m_state[posPixel].Af2b; } } - if(bBackgroundHigh) + if (bBackgroundHigh) high_threshold = BACKGROUND; else high_threshold = FOREGROUND; @@ -402,30 +402,30 @@ void T2FMRF::SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, // (the memory should already be reserved) // values: 255-foreground, 125-shadow, 0-background /////////////////////////////////////////////////////////////////////////////// -void T2FMRF::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void T2FMRF::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { unsigned char low_threshold, high_threshold; long posPixel; long posGMode; // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) + for (unsigned int r = 0; r < m_params.Height(); ++r) { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { // update model + background subtract posPixel = r*m_params.Width() + c; posGMode = (r*m_params.Width() + c) * m_params.MaxModes(); - SubtractPixel(posPixel, posGMode, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold); + SubtractPixel(posPixel, posGMode, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; - m_background(r,c,0) = (unsigned char) m_modes[posGMode].muR; - m_background(r,c,1) = (unsigned char) m_modes[posGMode].muG; - m_background(r,c,2) = (unsigned char) m_modes[posGMode].muB; + m_background(r, c, 0) = (unsigned char)m_modes[posGMode].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posGMode].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posGMode].muB; } } } diff --git a/package_bgs/tb/T2FMRF.h b/package_bgs/T2F/T2FMRF.h similarity index 91% rename from package_bgs/tb/T2FMRF.h rename to package_bgs/T2F/T2FMRF.h index 00e464c..1015426 100644 --- a/package_bgs/tb/T2FMRF.h +++ b/package_bgs/T2F/T2FMRF.h @@ -18,18 +18,16 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * T2FMRF.h * -* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) +* Purpose: Implementation of the T2 Fuzzy Gaussian Mixture Models (T2GMMs) * "Modeling of Dynamic Backgrounds by Type-2 Fuzzy Gaussians Mixture Models" * Author: Fida El Baf, Thierry Bouwmans, September 2008 * * This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: +* background subtraction algorithm: * * Zivkovic's code can be obtained at: www.zoranz.net ******************************************************************************/ - -#ifndef T2F_MRF_ -#define T2F_MRF_ +#pragma once #include "../dp/Bgs.h" #include "../dp/GrimsonGMM.h" @@ -41,9 +39,9 @@ namespace Algorithms const int TYPE_T2FMRF_UM = 0; const int TYPE_T2FMRF_UV = 1; - enum HiddenState {background, foreground}; + enum HiddenState { background, foreground }; - typedef struct HMMState + typedef struct HMMState { float T; //Hidden State @@ -80,9 +78,9 @@ namespace Algorithms float &KV() { return m_kv; } private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values // lead to a small number of components but they can grow too large. // // It is usual easiest to think of these thresholds as being the number of variances away @@ -91,7 +89,7 @@ namespace Algorithms float m_high_threshold; // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. + // set alpha=1/T. float m_alpha; // Maximum number of modes (Gaussian components) that will be used per pixel @@ -116,7 +114,7 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Subtract(int frame_num, const RgbImage& data, BwImage& low_threshold_mask, BwImage& high_threshold_mask); void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background(); @@ -124,7 +122,7 @@ namespace Algorithms GMM *gmm(void); HMM *hmm(void); - private: + private: void SubtractPixel(long posPixel, long posGMode, const RgbPixel& pixel, unsigned char& numModes, unsigned char& lowThreshold, unsigned char& highThreshold); // User adjustable parameters @@ -136,8 +134,8 @@ namespace Algorithms // it is considered foreground float m_bg_threshold; //1-cf from the paper - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. // A simple way is to estimate the typical standard deviation from the images. float m_variance; @@ -160,5 +158,3 @@ namespace Algorithms }; } } - -#endif diff --git a/package_bgs/tb/T2FGMM_UM.cpp b/package_bgs/T2FGMM_UM.cpp similarity index 64% rename from package_bgs/tb/T2FGMM_UM.cpp rename to package_bgs/T2FGMM_UM.cpp index 31a5338..ad1b40e 100644 --- a/package_bgs/tb/T2FGMM_UM.cpp +++ b/package_bgs/T2FGMM_UM.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "T2FGMM_UM.h" -T2FGMM_UM::T2FGMM_UM() : firstTime(true), frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +T2FGMM_UM::T2FGMM_UM() : + frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3) { std::cout << "T2FGMM_UM()" << std::endl; + setup("./config/T2FGMM_UM.xml"); } T2FGMM_UM::~T2FGMM_UM() @@ -28,23 +32,16 @@ T2FGMM_UM::~T2FGMM_UM() void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +52,7 @@ void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.SetFrameSize(width, height); params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); + params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; params.Type() = TYPE_T2FGMM_UM; @@ -69,13 +66,18 @@ void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("T2FGMM-UM", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("T2FGMM-UM", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; @@ -84,7 +86,7 @@ void T2FGMM_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & void T2FGMM_UM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UM.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -98,14 +100,14 @@ void T2FGMM_UM::saveConfig() void T2FGMM_UM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UM.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 9.0); - alpha = cvReadRealByName(fs, 0, "alpha", 0.01); - km = cvReadRealByName(fs, 0, "km", 1.5); - kv = cvReadRealByName(fs, 0, "kv", 0.6); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); + km = cvReadRealByName(fs, nullptr, "km", 1.5); + kv = cvReadRealByName(fs, nullptr, "kv", 0.6); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/tb/T2FGMM_UM.h b/package_bgs/T2FGMM_UM.h similarity index 52% rename from package_bgs/tb/T2FGMM_UM.h rename to package_bgs/T2FGMM_UM.h index ae6e29f..c58aeb7 100644 --- a/package_bgs/tb/T2FGMM_UM.h +++ b/package_bgs/T2FGMM_UM.h @@ -16,43 +16,42 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "T2FGMM.h" +#include "IBGS.h" +#include "T2F/T2FGMM.h" using namespace Algorithms::BackgroundSubtraction; -class T2FGMM_UM : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - T2FGMMParams params; - T2FGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - bool showOutput; - -public: - T2FGMM_UM(); - ~T2FGMM_UM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class T2FGMM_UM : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + T2FGMMParams params; + T2FGMM bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + float km; + float kv; + int gaussians; + + public: + T2FGMM_UM(); + ~T2FGMM_UM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/tb/T2FGMM_UV.cpp b/package_bgs/T2FGMM_UV.cpp similarity index 64% rename from package_bgs/tb/T2FGMM_UV.cpp rename to package_bgs/T2FGMM_UV.cpp index c6f99f1..4e9708f 100644 --- a/package_bgs/tb/T2FGMM_UV.cpp +++ b/package_bgs/T2FGMM_UV.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "T2FGMM_UV.h" -T2FGMM_UV::T2FGMM_UV() : firstTime(true), frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +T2FGMM_UV::T2FGMM_UV() : + frameNumber(0), threshold(9.0), alpha(0.01), km(1.5f), kv(0.6f), gaussians(3) { std::cout << "T2FGMM_UV()" << std::endl; + setup("./config/T2FGMM_UV.xml"); } T2FGMM_UV::~T2FGMM_UV() @@ -28,23 +32,16 @@ T2FGMM_UV::~T2FGMM_UV() void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -55,7 +52,7 @@ void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.SetFrameSize(width, height); params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); + params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; params.Type() = TYPE_T2FGMM_UV; @@ -69,13 +66,18 @@ void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("T2FGMM-UV", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("T2FGMM-UV", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; firstTime = false; @@ -84,7 +86,7 @@ void T2FGMM_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & void T2FGMM_UV::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UV.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -98,14 +100,14 @@ void T2FGMM_UV::saveConfig() void T2FGMM_UV::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FGMM_UV.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 9.0); - alpha = cvReadRealByName(fs, 0, "alpha", 0.01); - km = cvReadRealByName(fs, 0, "km", 1.5); - kv = cvReadRealByName(fs, 0, "kv", 0.6); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); + km = cvReadRealByName(fs, nullptr, "km", 1.5); + kv = cvReadRealByName(fs, nullptr, "kv", 0.6); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/tb/T2FGMM_UV.h b/package_bgs/T2FGMM_UV.h similarity index 52% rename from package_bgs/tb/T2FGMM_UV.h rename to package_bgs/T2FGMM_UV.h index 79edcc2..6102f3a 100644 --- a/package_bgs/tb/T2FGMM_UV.h +++ b/package_bgs/T2FGMM_UV.h @@ -16,43 +16,42 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "T2FGMM.h" +#include "IBGS.h" +#include "T2F/T2FGMM.h" using namespace Algorithms::BackgroundSubtraction; -class T2FGMM_UV : public IBGS +namespace bgslibrary { -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - T2FGMMParams params; - T2FGMM bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - bool showOutput; - -public: - T2FGMM_UV(); - ~T2FGMM_UV(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - + namespace algorithms + { + class T2FGMM_UV : public IBGS + { + private: + long frameNumber; + IplImage* frame; + RgbImage frame_data; + + T2FGMMParams params; + T2FGMM bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + float km; + float kv; + int gaussians; + + public: + T2FGMM_UV(); + ~T2FGMM_UV(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/tb/T2FMRF_UM.cpp b/package_bgs/T2FMRF_UM.cpp similarity index 59% rename from package_bgs/tb/T2FMRF_UM.cpp rename to package_bgs/T2FMRF_UM.cpp index 5b41d8a..e0e6dae 100644 --- a/package_bgs/tb/T2FMRF_UM.cpp +++ b/package_bgs/T2FMRF_UM.cpp @@ -16,10 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "T2FMRF_UM.h" -T2FMRF_UM::T2FMRF_UM() : firstTime(true), frameNumber(0), threshold(9.0), alpha(0.01), -km(2.f), kv(0.9f), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +T2FMRF_UM::T2FMRF_UM() : + frameNumber(0), threshold(9.0), alpha(0.01), km(2.f), kv(0.9f), gaussians(3) { std::cout << "T2FMRF_UM()" << std::endl; + setup("./config/DPMean.xml"); } T2FMRF_UM::~T2FMRF_UM() @@ -29,23 +32,16 @@ T2FMRF_UM::~T2FMRF_UM() void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -56,7 +52,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.SetFrameSize(width, height); params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); + params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; params.Type() = TYPE_T2FMRF_UM; @@ -70,7 +66,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & old = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); mrf.height = height; - mrf.width = width; + mrf.width = width; mrf.Build_Classes_OldLabeling_InImage_LocalEnergy(); firstTime = false; @@ -80,32 +76,37 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & cvCopy(lowThresholdMask.Ptr(), old); /************************************************************************/ - /* the code for MRF, it can be noted when using other methods */ - /************************************************************************/ - //the optimization process is done when the foreground detection is stable, - if(frameNumber >= 10) - { - gmm = bgs.gmm(); - hmm = bgs.hmm(); - mrf.background2 = frame_data.Ptr(); - mrf.in_image = lowThresholdMask.Ptr(); - mrf.out_image = lowThresholdMask.Ptr(); - mrf.InitEvidence2(gmm,hmm,old_labeling); - mrf.ICM2(); - cvCopy(mrf.out_image, lowThresholdMask.Ptr()); - } + /* the code for MRF, it can be noted when using other methods */ + /************************************************************************/ + //the optimization process is done when the foreground detection is stable, + if (frameNumber >= 10) + { + gmm = bgs.gmm(); + hmm = bgs.hmm(); + mrf.background2 = frame_data.Ptr(); + mrf.in_image = lowThresholdMask.Ptr(); + mrf.out_image = lowThresholdMask.Ptr(); + mrf.InitEvidence2(gmm, hmm, old_labeling); + mrf.ICM2(); + cvCopy(mrf.out_image, lowThresholdMask.Ptr()); + } cvCopy(old, old_labeling); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("T2FMRF-UM", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("T2FMRF-UM", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; frameNumber++; @@ -113,7 +114,7 @@ void T2FMRF_UM::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & void T2FMRF_UM::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UM.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -127,14 +128,14 @@ void T2FMRF_UM::saveConfig() void T2FMRF_UM::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UM.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 9.0); - alpha = cvReadRealByName(fs, 0, "alpha", 0.01); - km = cvReadRealByName(fs, 0, "km", 2); - kv = cvReadRealByName(fs, 0, "kv", 0.9); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); + km = cvReadRealByName(fs, nullptr, "km", 2); + kv = cvReadRealByName(fs, nullptr, "kv", 0.9); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/T2FMRF_UM.h b/package_bgs/T2FMRF_UM.h new file mode 100644 index 0000000..01f6014 --- /dev/null +++ b/package_bgs/T2FMRF_UM.h @@ -0,0 +1,64 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "T2F/MRF.h" + +using namespace Algorithms::BackgroundSubtraction; + +namespace bgslibrary +{ + namespace algorithms + { + class T2FMRF_UM : public IBGS + { + private: + long frameNumber; + IplImage *frame; + RgbImage frame_data; + + IplImage *old_labeling; + IplImage *old; + + T2FMRFParams params; + T2FMRF bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + float km; + float kv; + int gaussians; + + MRF_TC mrf; + GMM *gmm; + HMM *hmm; + + public: + T2FMRF_UM(); + ~T2FMRF_UM(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/tb/T2FMRF_UV.cpp b/package_bgs/T2FMRF_UV.cpp similarity index 59% rename from package_bgs/tb/T2FMRF_UV.cpp rename to package_bgs/T2FMRF_UV.cpp index 03f2595..7f43c02 100644 --- a/package_bgs/tb/T2FMRF_UV.cpp +++ b/package_bgs/T2FMRF_UV.cpp @@ -16,10 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "T2FMRF_UV.h" -T2FMRF_UV::T2FMRF_UV() : firstTime(true), frameNumber(0), threshold(9.0), alpha(0.01), -km(2.f), kv(0.9f), gaussians(3), showOutput(true) +using namespace bgslibrary::algorithms; + +T2FMRF_UV::T2FMRF_UV() : + frameNumber(0), threshold(9.0), alpha(0.01), km(2.f), kv(0.9f), gaussians(3) { std::cout << "T2FMRF_UV()" << std::endl; + setup("./config/T2FMRF_UV.xml"); } T2FMRF_UV::~T2FMRF_UV() @@ -29,23 +32,16 @@ T2FMRF_UV::~T2FMRF_UV() void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - + init(img_input, img_output, img_bgmodel); frame = new IplImage(img_input); - - if(firstTime) + + if (firstTime) frame_data.ReleaseMemory(false); frame_data = frame; - if(firstTime) + if (firstTime) { - int width = img_input.size().width; + int width = img_input.size().width; int height = img_input.size().height; lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); @@ -56,7 +52,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & params.SetFrameSize(width, height); params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); + params.HighThreshold() = 2 * params.LowThreshold(); params.Alpha() = alpha; params.MaxModes() = gaussians; params.Type() = TYPE_T2FMRF_UV; @@ -70,7 +66,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & old = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); mrf.height = height; - mrf.width = width; + mrf.width = width; mrf.Build_Classes_OldLabeling_InImage_LocalEnergy(); firstTime = false; @@ -80,32 +76,37 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & cvCopy(lowThresholdMask.Ptr(), old); /************************************************************************/ - /* the code for MRF, it can be noted when using other methods */ - /************************************************************************/ - //the optimization process is done when the foreground detection is stable, - if(frameNumber >= 10) - { - gmm = bgs.gmm(); - hmm = bgs.hmm(); - mrf.background2 = frame_data.Ptr(); - mrf.in_image = lowThresholdMask.Ptr(); - mrf.out_image = lowThresholdMask.Ptr(); - mrf.InitEvidence2(gmm,hmm,old_labeling); - mrf.ICM2(); - cvCopy(mrf.out_image, lowThresholdMask.Ptr()); - } + /* the code for MRF, it can be noted when using other methods */ + /************************************************************************/ + //the optimization process is done when the foreground detection is stable, + if (frameNumber >= 10) + { + gmm = bgs.gmm(); + hmm = bgs.hmm(); + mrf.background2 = frame_data.Ptr(); + mrf.in_image = lowThresholdMask.Ptr(); + mrf.out_image = lowThresholdMask.Ptr(); + mrf.InitEvidence2(gmm, hmm, old_labeling); + mrf.ICM2(); + cvCopy(mrf.out_image, lowThresholdMask.Ptr()); + } cvCopy(old, old_labeling); lowThresholdMask.Clear(); bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - if(showOutput) - cv::imshow("T2FMRF-UV", foreground); - - foreground.copyTo(img_output); + img_foreground = cv::cvarrToMat(highThresholdMask.Ptr()); + img_background = cv::cvarrToMat(bgs.Background()->Ptr()); + //img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + cv::imshow("T2FMRF-UV", img_foreground); +#endif + + img_foreground.copyTo(img_output); + img_background.copyTo(img_bgmodel); delete frame; frameNumber++; @@ -113,7 +114,7 @@ void T2FMRF_UV::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat & void T2FMRF_UV::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UV.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteReal(fs, "threshold", threshold); cvWriteReal(fs, "alpha", alpha); @@ -127,14 +128,14 @@ void T2FMRF_UV::saveConfig() void T2FMRF_UV::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/T2FMRF_UV.xml", 0, CV_STORAGE_READ); - - threshold = cvReadRealByName(fs, 0, "threshold", 9.0); - alpha = cvReadRealByName(fs, 0, "alpha", 0.01); - km = cvReadRealByName(fs, 0, "km", 2); - kv = cvReadRealByName(fs, 0, "kv", 0.9); - gaussians = cvReadIntByName(fs, 0, "gaussians", 3); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + threshold = cvReadRealByName(fs, nullptr, "threshold", 9.0); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.01); + km = cvReadRealByName(fs, nullptr, "km", 2); + kv = cvReadRealByName(fs, nullptr, "kv", 0.9); + gaussians = cvReadIntByName(fs, nullptr, "gaussians", 3); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/T2FMRF_UV.h b/package_bgs/T2FMRF_UV.h new file mode 100644 index 0000000..1c69171 --- /dev/null +++ b/package_bgs/T2FMRF_UV.h @@ -0,0 +1,64 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "T2F/MRF.h" + +using namespace Algorithms::BackgroundSubtraction; + +namespace bgslibrary +{ + namespace algorithms + { + class T2FMRF_UV : public IBGS + { + private: + long frameNumber; + IplImage *frame; + RgbImage frame_data; + + IplImage *old_labeling; + IplImage *old; + + T2FMRFParams params; + T2FMRF bgs; + BwImage lowThresholdMask; + BwImage highThresholdMask; + + double threshold; + double alpha; + float km; + float kv; + int gaussians; + + MRF_TC mrf; + GMM *gmm; + HMM *hmm; + + public: + T2FMRF_UV(); + ~T2FMRF_UV(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/TwoPoints.cpp b/package_bgs/TwoPoints.cpp new file mode 100644 index 0000000..aee4684 --- /dev/null +++ b/package_bgs/TwoPoints.cpp @@ -0,0 +1,112 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "TwoPoints.h" + +using namespace bgslibrary::algorithms; + +TwoPoints::TwoPoints() : + matchingThreshold(DEFAULT_MATCH_THRESH), + updateFactor(DEFAULT_UPDATE_FACTOR), model(nullptr) +{ + std::cout << "TwoPoints()" << std::endl; + //model = static_cast<twopointsModel_t*>(libtwopointsModel_New()); + model = libtwopointsModel_New(); + setup("./config/TwoPoints.xml"); +} + +TwoPoints::~TwoPoints() +{ + std::cout << "~TwoPoints()" << std::endl; + libtwopointsModel_Free(model); +} + +void TwoPoints::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_input.empty()) + return; + + cv::Mat updatingMask; + cv::Mat img_input_grayscale; + + // Convert input image to a grayscale image + cvtColor(img_input, img_input_grayscale, CV_BGR2GRAY); + + if (firstTime) + { + // Create a buffer for the output image. + //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1); + + // Initialization of the ViBe model. + libtwopointsModel_AllocInit_8u_C1R(model, img_input_grayscale.data, img_input.cols, img_input.rows); + + // Sets default model values. + // libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); + // libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); + } + + libtwopointsModel_Segmentation_8u_C1R(model, img_input_grayscale.data, img_output.data); + + updatingMask = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); + // Work on the output and define the updating mask + for (int i = 0; i < img_input.cols * img_input.rows; i++) + { + if (img_output.data[i] == 0) // Foreground pixel + { + updatingMask.data[i] = 0; + img_output.data[i] = 255; + } + else // Background + { + updatingMask.data[i] = 255; + img_output.data[i] = 0; + } + } + + libtwopointsModel_Update_8u_C1R(model, img_input_grayscale.data, updatingMask.data); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + imshow("Two points", img_output); +#endif + + firstTime = false; +} + +void TwoPoints::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "matchingThreshold", matchingThreshold); + cvWriteInt(fs, "updateFactor", updateFactor); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void TwoPoints::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + matchingThreshold = cvReadRealByName(fs, nullptr, "matchingThreshold", DEFAULT_MATCH_THRESH); + updateFactor = cvReadRealByName(fs, nullptr, "updateFactor", DEFAULT_UPDATE_FACTOR); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/TwoPoints.h b/package_bgs/TwoPoints.h new file mode 100644 index 0000000..b42c231 --- /dev/null +++ b/package_bgs/TwoPoints.h @@ -0,0 +1,46 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "TwoPoints/two_points.h" + +namespace bgslibrary +{ + namespace algorithms + { + class TwoPoints : public IBGS + { + private: + static const int DEFAULT_MATCH_THRESH = 20; + static const int DEFAULT_UPDATE_FACTOR = 16; + int matchingThreshold; + int updateFactor; + twopointsModel_t* model; + + public: + TwoPoints(); + ~TwoPoints(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/TwoPoints/two_points.cpp b/package_bgs/TwoPoints/two_points.cpp new file mode 100644 index 0000000..d8ee86b --- /dev/null +++ b/package_bgs/TwoPoints/two_points.cpp @@ -0,0 +1,394 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <assert.h> + +#include "two_points.h" + +static unsigned int abs_uint(const int i) +{ + return (i >= 0) ? i : -i; +} + +struct twopointsModel +{ + /* Parameters. */ + uint32_t width; + uint32_t height; + uint32_t numberOfSamples; + uint32_t matchingThreshold; + uint32_t matchingNumber; + uint32_t updateFactor; + + /* Storage for the history. */ + uint8_t *historyImage1; + uint8_t *historyImage2; + + /* Buffers with random values. */ + uint32_t *jump; + int *neighbor; +}; + +// ----------------------------------------------------------------------------- +// Creates the data structure +// ----------------------------------------------------------------------------- +twopointsModel_t *libtwopointsModel_New() +{ + /* Model structure alloc. */ + twopointsModel_t *model = NULL; + model = (twopointsModel_t*)calloc(1, sizeof(*model)); + assert(model != NULL); + + /* Default parameters values. */ + model->matchingThreshold = 20; + model->updateFactor = 16; + + /* Storage for the history. */ + model->historyImage1 = NULL; + model->historyImage2 = NULL; + + /* Buffers with random values. */ + model->jump = NULL; + model->neighbor = NULL; + + return(model); +} + +// ---------------------------------------------------------------------------- +// Frees the structure +// ---------------------------------------------------------------------------- +int32_t libtwopointsModel_Free(twopointsModel_t *model) +{ + if (model == NULL) + return(-1); + + if (model->historyImage1 != NULL) { + free(model->historyImage1); + model->historyImage1 = NULL; + } + if (model->historyImage2 != NULL) { + free(model->historyImage2); + model->historyImage2 = NULL; + } + if (model->jump != NULL) { + free(model->jump); + model->jump = NULL; + } + if (model->neighbor != NULL) { + free(model->neighbor); + model->neighbor = NULL; + } + free(model); + + return(0); +} + +// ----------------------------------------------------------------------------- +// Allocates and initializes a C1R model structure +// ----------------------------------------------------------------------------- +int32_t libtwopointsModel_AllocInit_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +) +{ + // Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage1 = NULL; + model->historyImage1 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); + model->historyImage2 = NULL; + model->historyImage2 = (uint8_t*)malloc(width * height * sizeof(uint8_t)); + + assert(model->historyImage1 != NULL); + assert(model->historyImage2 != NULL); + + for (int index = width * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + int value_plus_noise = value - 10; + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + model->historyImage1[index] = value_plus_noise; + + value_plus_noise = value + 10; + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + model->historyImage2[index] = value_plus_noise; + + // Swaps the two values if needed + if (model->historyImage1[index] > model->historyImage2[index]) { + uint8_t val = model->historyImage1[index]; + model->historyImage1[index] = model->historyImage2[index]; + model->historyImage2[index] = val; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. + } + + return(0); +} + +// ----------------------------------------------------------------------------- +// Segmentation of a C1R model +// ----------------------------------------------------------------------------- +int32_t libtwopointsModel_Segmentation_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +) +{ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert((model->jump != NULL) && (model->neighbor != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage1 = model->historyImage1; + uint8_t *historyImage2 = model->historyImage2; + + /* Segmentation. */ + memset(segmentation_map, 0, width * height); + + uint8_t *first = historyImage1; + for (int index = width * height - 1; index >= 0; --index) { + // We adapt the threshold + matchingThreshold = model->matchingThreshold; + if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { + matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); + } + if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) + segmentation_map[index]++; + } + + first = historyImage2; + for (int index = width * height - 1; index >= 0; --index) { + // We adapt the threshold + matchingThreshold = model->matchingThreshold; + if (matchingThreshold < abs_uint(historyImage2[index] - historyImage1[index])) { + matchingThreshold = abs_uint(historyImage2[index] - historyImage1[index]); + } + if (abs_uint(image_data[index] - first[index]) <= matchingThreshold) + segmentation_map[index]++; + } + + return(0); +} + +// ---------------------------------------------------------------------------- +// Update a C1R model +// ---------------------------------------------------------------------------- +int doUpdate(const uint8_t value) +{ + if (value == 0) return 0; + else return 1; +} + + +int32_t libtwopointsModel_Update_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +) +{ + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert((model->jump != NULL) && (model->neighbor != NULL)); + + // Some variables. + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage1 = model->historyImage1; + uint8_t *historyImage2 = model->historyImage2; + + // Updating. + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + + // All the frame, except the border. + uint32_t shift, indX, indY; + unsigned int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + + // Propagation + int index_neighbor = index + neighbor[shift]; + if (2 * value < (historyImage1[index_neighbor] + historyImage2[index_neighbor])) { + // if (rand()%2 == 0 ) { + historyImage1[index_neighbor] = value; + } + else { + historyImage2[index_neighbor] = value; + } + } + + ++shift; + indX += jump[shift]; + } + } + + // First row. + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indX += jump[shift]; + } + + // Last row. + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indX += jump[shift]; + } + + // First column. + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indY += jump[shift]; + } + + // Last column. + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (doUpdate(updating_mask[index])) { + uint8_t value = image_data[index]; + // In-place substitution. + // if (2*value < (historyImage1[index]+historyImage2[index]) ) { + if (rand() % 2 == 0) { + historyImage1[index] = value; + } + else { + historyImage2[index] = value; + } + } + + ++shift; + indY += jump[shift]; + } + + // The first pixel! + if (rand() % model->updateFactor == 0) { + if (doUpdate(updating_mask[0])) { + uint8_t value = image_data[0]; + // In-place substitution. + if (rand() % 2 == 0) { + historyImage1[0] = value; + } + else { + historyImage2[0] = value; + } + } + } + + return(0); +} diff --git a/package_bgs/TwoPoints/two_points.h b/package_bgs/TwoPoints/two_points.h new file mode 100644 index 0000000..a64152a --- /dev/null +++ b/package_bgs/TwoPoints/two_points.h @@ -0,0 +1,50 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#define COLOR_BACKGROUND 0 /*!< Default label for background pixels */ +#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */ + +typedef struct twopointsModel twopointsModel_t; + +twopointsModel_t *libtwopointsModel_New(); + +int32_t libtwopointsModel_Free(twopointsModel_t *model); + +int32_t libtwopointsModel_AllocInit_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +); + +int32_t libtwopointsModel_Segmentation_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +); + +int32_t libtwopointsModel_Update_8u_C1R( + twopointsModel_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +); diff --git a/package_bgs/ViBe.cpp b/package_bgs/ViBe.cpp new file mode 100644 index 0000000..0d3125f --- /dev/null +++ b/package_bgs/ViBe.cpp @@ -0,0 +1,98 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "ViBe.h" + +using namespace bgslibrary::algorithms; + +ViBe::ViBe() : + //numberOfSamples(DEFAULT_NUM_SAMPLES), + matchingThreshold(DEFAULT_MATCH_THRESH), + matchingNumber(DEFAULT_MATCH_NUM), + updateFactor(DEFAULT_UPDATE_FACTOR), + model(nullptr) +{ + std::cout << "ViBe()" << std::endl; + model = libvibeModel_Sequential_New(); + setup("./config/ViBe.xml"); +} + +ViBe::~ViBe() +{ + std::cout << "~ViBe()" << std::endl; + libvibeModel_Sequential_Free(model); +} + +void ViBe::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_input.empty()) + return; + + if (firstTime) + { + /* Create a buffer for the output image. */ + //img_output = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); + + /* Initialization of the ViBe model. */ + libvibeModel_Sequential_AllocInit_8u_C3R(model, img_input.data, img_input.cols, img_input.rows); + + /* Sets default model values. */ + //libvibeModel_Sequential_SetNumberOfSamples(model, numberOfSamples); + libvibeModel_Sequential_SetMatchingThreshold(model, matchingThreshold); + libvibeModel_Sequential_SetMatchingNumber(model, matchingNumber); + libvibeModel_Sequential_SetUpdateFactor(model, updateFactor); + } + + libvibeModel_Sequential_Segmentation_8u_C3R(model, img_input.data, img_output.data); + //libvibeModel_Sequential_Update_8u_C3R(model, model_img_input.data, img_output.data); + libvibeModel_Sequential_Update_8u_C3R(model, img_input.data, img_output.data); + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + imshow("ViBe", img_output); +#endif + + firstTime = false; +} + +void ViBe::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + //cvWriteInt(fs, "numberOfSamples", numberOfSamples); + cvWriteInt(fs, "matchingThreshold", matchingThreshold); + cvWriteInt(fs, "matchingNumber", matchingNumber); + cvWriteInt(fs, "updateFactor", updateFactor); + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void ViBe::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + //numberOfSamples = cvReadIntByName(fs, nullptr, "numberOfSamples", DEFAULT_NUM_SAMPLES); + matchingThreshold = cvReadRealByName(fs, nullptr, "matchingThreshold", DEFAULT_MATCH_THRESH); + matchingNumber = cvReadRealByName(fs, nullptr, "matchingNumber", DEFAULT_MATCH_NUM); + updateFactor = cvReadRealByName(fs, nullptr, "updateFactor", DEFAULT_UPDATE_FACTOR); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/ViBe.h b/package_bgs/ViBe.h new file mode 100644 index 0000000..c8014cb --- /dev/null +++ b/package_bgs/ViBe.h @@ -0,0 +1,52 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "ViBe/vibe-background-sequential.h" + +namespace bgslibrary +{ + namespace algorithms + { + class ViBe : public IBGS + { + private: + static const int DEFAULT_NUM_SAMPLES = 20; + static const int DEFAULT_MATCH_THRESH = 20; + static const int DEFAULT_MATCH_NUM = 2; + static const int DEFAULT_UPDATE_FACTOR = 16; + + private: + //int numberOfSamples; + int matchingThreshold; + int matchingNumber; + int updateFactor; + vibeModel_Sequential_t* model; + + public: + ViBe(); + ~ViBe(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/ViBe/LICENSE b/package_bgs/ViBe/LICENSE new file mode 100644 index 0000000..7f22a77 --- /dev/null +++ b/package_bgs/ViBe/LICENSE @@ -0,0 +1,44 @@ + Authors: + -------- + Olivier Barnich and + Marc Van Droogenbroeck <m.vandroogenbroeck@ulg.ac.be> + + Licence: + -------- + ViBe is covered by a patent (see http://www.ulg.ac.be/telecom/research/vibe). + We do not provide the source code but provide an object file and an interface. + + Permission to use ViBe without payment of fee is granted + for nonprofit educational and research purposes only. + + This work may not be copied or reproduced in whole or in part for any + purpose. + + Copying, reproduction, or republishing for any purpose shall require + a license. Please contact the author in such cases. + All the code is provided without any guarantee. + + + How to refer to us: + ------------------- + + If you want to refer to this work, please cite the following publications: + + Barnich and M. Van Droogenbroeck. ViBe: A universal background subtraction algorithm for video sequences. In IEEE Transactions on Image Processing, 20(6):1709-1724, June 2011. + +@article{Barnich2011ViBe, + title = {{ViBe}: A universal background subtraction algorithm for video sequences}, + author = {O. Barnich and M. {Van Droogenbroeck}}, + journal = {IEEE Transactions on Image Processing}, + volume = {20}, + number = {6}, + pages = {1709-1724}, + month = {June}, + year = {2011}, + keywords = {ViBe, Background, Background subtraction, Segmentation, Motion, Motion detection}, + pdf = {http://orbi.ulg.ac.be/bitstream/2268/81248/1/Barnich2011ViBe.pdf}, + doi = {10.1109/TIP.2010.2101613}, + url = {http://hdl.handle.net/2268/81248} +} + + diff --git a/package_bgs/ViBe/vibe-background-sequential.cpp b/package_bgs/ViBe/vibe-background-sequential.cpp new file mode 100644 index 0000000..c4b9178 --- /dev/null +++ b/package_bgs/ViBe/vibe-background-sequential.cpp @@ -0,0 +1,929 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/** +@file vibe-background-sequential.c +@brief Implementation of vibe-background-sequential.h +@author Marc Van Droogenbroeck +@date May 2014 +*/ +#include <assert.h> +#include <time.h> + +#include "vibe-background-sequential.h" + +#define NUMBER_OF_HISTORY_IMAGES 2 + +uint32_t distance_Han2014Improved(uint8_t pixel, uint8_t bg) +{ + uint8_t min, max; + + // Computes R = 0.13 min{ max[bg,26], 230} + max = 26; + if (bg > max) { max = bg; } + + min = 230; + if (min > max) { min = max; } + + return (uint32_t)(0.13*min); +} + +static int abs_uint(const int i) +{ + return (i >= 0) ? i : -i; +} + +static int32_t distance_is_close_8u_C3R(uint8_t r1, uint8_t g1, uint8_t b1, uint8_t r2, uint8_t g2, uint8_t b2, uint32_t threshold) +{ + return (abs_uint(r1 - r2) + abs_uint(g1 - g2) + abs_uint(b1 - b2) <= 4.5 * threshold); +} + +struct vibeModel_Sequential +{ + /* Parameters. */ + uint32_t width; + uint32_t height; + uint32_t numberOfSamples; + uint32_t matchingThreshold; + uint32_t matchingNumber; + uint32_t updateFactor; + + /* Storage for the history. */ + uint8_t *historyImage; + uint8_t *historyBuffer; + uint32_t lastHistoryImageSwapped; + + /* Buffers with random values. */ + uint32_t *jump; + int *neighbor; + uint32_t *position; +}; + +// ----------------------------------------------------------------------------- +// Print parameters +// ----------------------------------------------------------------------------- +uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model) +{ + printf( + "Using ViBe background subtraction algorithm\n" + " - Number of samples per pixel: %03d\n" + " - Number of matches needed: %03d\n" + " - Matching threshold: %03d\n" + " - Model update subsampling factor: %03d\n", + libvibeModel_Sequential_GetNumberOfSamples(model), + libvibeModel_Sequential_GetMatchingNumber(model), + libvibeModel_Sequential_GetMatchingThreshold(model), + libvibeModel_Sequential_GetUpdateFactor(model) + ); + + return(0); +} + +// ----------------------------------------------------------------------------- +// Creates the data structure +// ----------------------------------------------------------------------------- +vibeModel_Sequential_t *libvibeModel_Sequential_New() +{ + /* Model structure alloc. */ + vibeModel_Sequential_t *model = NULL; + model = (vibeModel_Sequential_t*)calloc(1, sizeof(*model)); + assert(model != NULL); + + /* Default parameters values. */ + model->numberOfSamples = 20; + model->matchingThreshold = 20; + model->matchingNumber = 2; + model->updateFactor = 16; + + /* Storage for the history. */ + model->historyImage = NULL; + model->historyBuffer = NULL; + model->lastHistoryImageSwapped = 0; + + /* Buffers with random values. */ + model->jump = NULL; + model->neighbor = NULL; + model->position = NULL; + + return(model); +} + +// ----------------------------------------------------------------------------- +// Some "Get-ers" +// ----------------------------------------------------------------------------- +uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model) +{ + assert(model != NULL); return(model->numberOfSamples); +} + +uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model) +{ + assert(model != NULL); return(model->matchingNumber); +} + +uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model) +{ + assert(model != NULL); return(model->matchingThreshold); +} + +uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model) +{ + assert(model != NULL); return(model->updateFactor); +} + +// ----------------------------------------------------------------------------- +// Some "Set-ers" +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_SetMatchingThreshold( + vibeModel_Sequential_t *model, + const uint32_t matchingThreshold +) { + assert(model != NULL); + assert(matchingThreshold > 0); + + model->matchingThreshold = matchingThreshold; + + return(0); +} + +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_SetMatchingNumber( + vibeModel_Sequential_t *model, + const uint32_t matchingNumber +) { + assert(model != NULL); + assert(matchingNumber > 0); + + model->matchingNumber = matchingNumber; + + return(0); +} + +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_SetUpdateFactor( + vibeModel_Sequential_t *model, + const uint32_t updateFactor +) { + assert(model != NULL); + assert(updateFactor > 0); + + model->updateFactor = updateFactor; + + /* We also need to change the values of the jump buffer ! */ + assert(model->jump != NULL); + + /* Shifts. */ + int size = (model->width > model->height) ? 2 * model->width + 1 : 2 * model->height + 1; + + for (int i = 0; i < size; ++i) + model->jump[i] = (updateFactor == 1) ? 1 : (rand() % (2 * model->updateFactor)) + 1; // 1 or values between 1 and 2 * updateFactor. + + return(0); +} + +// ---------------------------------------------------------------------------- +// Frees the structure +// ---------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model) +{ + if (model == NULL) + return(-1); + + if (model->historyBuffer == NULL) { + free(model); + return(0); + } + + free(model->historyImage); + free(model->historyBuffer); + free(model->jump); + free(model->neighbor); + free(model->position); + free(model); + + return(0); +} + +// ----------------------------------------------------------------------------- +// Allocates and initializes a C1R model structure +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_AllocInit_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +) { + // Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage = NULL; + model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * width * height * sizeof(*(model->historyImage))); + + assert(model->historyImage != NULL); + + for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + for (int index = width * height - 1; index >= 0; --index) + model->historyImage[i * width * height + index] = image_data[index]; + } + + /* Now creates and fills the history buffer. */ + model->historyBuffer = (uint8_t*)malloc(width * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); + assert(model->historyBuffer != NULL); + + for (int index = width * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { + int value_plus_noise = value + rand() % 20 - 10; + + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + + model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); + assert(model->position != NULL); + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { -width - 1, ... , width + 1 }. + model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. + } + + return(0); +} + +// ----------------------------------------------------------------------------- +// Segmentation of a C1R model +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_Segmentation_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingNumber = model->matchingNumber; + uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Segmentation. */ + memset(segmentation_map, matchingNumber - 1, width * height); + + /* First history Image structure. */ + for (int index = width * height - 1; index >= 0; --index) { + //if (abs_uint(image_data[index] - historyImage[index]) > matchingThreshold) + if (abs_uint(image_data[index] - historyImage[index]) > distance_Han2014Improved(image_data[index], historyImage[index])) + segmentation_map[index] = matchingNumber; + } + + /* Next historyImages. */ + for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + uint8_t *pels = historyImage + i * width * height; + + for (int index = width * height - 1; index >= 0; --index) { + // if (abs_uint(image_data[index] - pels[index]) <= matchingThreshold) + if (abs_uint(image_data[index] - pels[index]) <= distance_Han2014Improved(image_data[index], pels[index])) + --segmentation_map[index]; + } + } + + /* For swapping. */ + model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; + uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * width * height; + + /* Now, we move in the buffer and leave the historyImages. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + for (int index = width * height - 1; index >= 0; --index) { + if (segmentation_map[index] > 0) { + /* We need to check the full border and swap values with the first or second historyImage. + * We still need to find a match before we can stop our search. + */ + uint32_t indexHistoryBuffer = index * numberOfTests; + uint8_t currentValue = image_data[index]; + + for (int i = numberOfTests; i > 0; --i, ++indexHistoryBuffer) { + // if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= matchingThreshold) { + if (abs_uint(currentValue - historyBuffer[indexHistoryBuffer]) <= distance_Han2014Improved(currentValue, historyBuffer[indexHistoryBuffer])) { + --segmentation_map[index]; + + /* Swaping: Putting found value in history image buffer. */ + uint8_t temp = swappingImageBuffer[index]; + swappingImageBuffer[index] = historyBuffer[indexHistoryBuffer]; + historyBuffer[indexHistoryBuffer] = temp; + + /* Exit inner loop. */ + if (segmentation_map[index] <= 0) break; + } + } // for + } // if + } // for + + /* Produces the output. Note that this step is application-dependent. */ + for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) + if (*mask > 0) *mask = COLOR_FOREGROUND; + + return(0); +} + +// ---------------------------------------------------------------------------- +// Update a C1R model +// ---------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_Update_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +) { + /* Basic checks . */ + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Some utility variable. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + /* Updating. */ + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + uint32_t *position = model->position; + + /* All the frame, except the border. */ + uint32_t shift, indX, indY; + int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + /* In-place substitution. */ + uint8_t value = image_data[index]; + int index_neighbor = index + neighbor[shift]; + + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[index + position[shift] * width * height] = value; + historyImage[index_neighbor + position[shift] * width * height] = value; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = value; + historyBuffer[index_neighbor * numberOfTests + pos] = value; + } + } + + ++shift; + indX += jump[shift]; + } + } + + /* First row. */ + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indX += jump[shift]; + } + + /* Last row. */ + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indX += jump[shift]; + } + + /* First column. */ + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indY += jump[shift]; + } + + /* Last column. */ + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) + historyImage[index + position[shift] * width * height] = image_data[index]; + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[index * numberOfTests + pos] = image_data[index]; + } + } + + ++shift; + indY += jump[shift]; + } + + /* The first pixel! */ + if (rand() % model->updateFactor == 0) { + if (updating_mask[0] == 0) { + int position = rand() % model->numberOfSamples; + + if (position < NUMBER_OF_HISTORY_IMAGES) + historyImage[position * width * height] = image_data[0]; + else { + int pos = position - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[pos] = image_data[0]; + } + } + } + + return(0); +} + +// ---------------------------------------------------------------------------- +// -------------------------- The same for C3R models ------------------------- +// ---------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// Allocates and initializes a C3R model structure +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_AllocInit_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +) { + /* Some basic checks. */ + assert((image_data != NULL) && (model != NULL)); + assert((width > 0) && (height > 0)); + + /* Finish model alloc - parameters values cannot be changed anymore. */ + model->width = width; + model->height = height; + + /* Creates the historyImage structure. */ + model->historyImage = NULL; + model->historyImage = (uint8_t*)malloc(NUMBER_OF_HISTORY_IMAGES * (3 * width) * height * sizeof(uint8_t)); + assert(model->historyImage != NULL); + + for (int i = 0; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + for (int index = (3 * width) * height - 1; index >= 0; --index) + model->historyImage[i * (3 * width) * height + index] = image_data[index]; + } + + assert(model->historyImage != NULL); + + /* Now creates and fills the history buffer. */ + model->historyBuffer = (uint8_t *)malloc((3 * width) * height * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) * sizeof(uint8_t)); + assert(model->historyBuffer != NULL); + + for (int index = (3 * width) * height - 1; index >= 0; --index) { + uint8_t value = image_data[index]; + + for (int x = 0; x < model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES; ++x) { + int value_plus_noise = value + rand() % 20 - 10; + + if (value_plus_noise < 0) { value_plus_noise = 0; } + if (value_plus_noise > 255) { value_plus_noise = 255; } + + model->historyBuffer[index * (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES) + x] = value_plus_noise; + } + } + + /* Fills the buffers with random values. */ + int size = (width > height) ? 2 * width + 1 : 2 * height + 1; + + model->jump = (uint32_t*)malloc(size * sizeof(*(model->jump))); + assert(model->jump != NULL); + + model->neighbor = (int*)malloc(size * sizeof(*(model->neighbor))); + assert(model->neighbor != NULL); + + model->position = (uint32_t*)malloc(size * sizeof(*(model->position))); + assert(model->position != NULL); + + for (int i = 0; i < size; ++i) { + model->jump[i] = (rand() % (2 * model->updateFactor)) + 1; // Values between 1 and 2 * updateFactor. + model->neighbor[i] = ((rand() % 3) - 1) + ((rand() % 3) - 1) * width; // Values between { width - 1, ... , width + 1 }. + model->position[i] = rand() % (model->numberOfSamples); // Values between 0 and numberOfSamples - 1. + } + + return(0); +} + +// ----------------------------------------------------------------------------- +// Segmentation of a C3R model +// ----------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_Segmentation_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + uint32_t matchingNumber = model->matchingNumber; + uint32_t matchingThreshold = model->matchingThreshold; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Segmentation. */ + memset(segmentation_map, matchingNumber - 1, width * height); + + /* First history Image structure. */ + uint8_t *first = historyImage; + + for (int index = width * height - 1; index >= 0; --index) { + if ( + !distance_is_close_8u_C3R( + image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], + first[3 * index], first[3 * index + 1], first[3 * index + 2], matchingThreshold + ) + ) + segmentation_map[index] = matchingNumber; + } + + /* Next historyImages. */ + for (int i = 1; i < NUMBER_OF_HISTORY_IMAGES; ++i) { + uint8_t *pels = historyImage + i * (3 * width) * height; + + for (int index = width * height - 1; index >= 0; --index) { + if ( + distance_is_close_8u_C3R( + image_data[3 * index], image_data[3 * index + 1], image_data[3 * index + 2], + pels[3 * index], pels[3 * index + 1], pels[3 * index + 2], matchingThreshold + ) + ) + --segmentation_map[index]; + } + } + + // For swapping + model->lastHistoryImageSwapped = (model->lastHistoryImageSwapped + 1) % NUMBER_OF_HISTORY_IMAGES; + uint8_t *swappingImageBuffer = historyImage + (model->lastHistoryImageSwapped) * (3 * width) * height; + + // Now, we move in the buffer and leave the historyImages + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + for (int index = width * height - 1; index >= 0; --index) { + if (segmentation_map[index] > 0) { + /* We need to check the full border and swap values with the first or second historyImage. + * We still need to find a match before we can stop our search. + */ + uint32_t indexHistoryBuffer = (3 * index) * numberOfTests; + + for (int i = numberOfTests; i > 0; --i, indexHistoryBuffer += 3) { + if ( + distance_is_close_8u_C3R( + image_data[(3 * index)], image_data[(3 * index) + 1], image_data[(3 * index) + 2], + historyBuffer[indexHistoryBuffer], historyBuffer[indexHistoryBuffer + 1], historyBuffer[indexHistoryBuffer + 2], + matchingThreshold + ) + ) + --segmentation_map[index]; + + /* Swaping: Putting found value in history image buffer. */ + uint8_t temp_r = swappingImageBuffer[(3 * index)]; + uint8_t temp_g = swappingImageBuffer[(3 * index) + 1]; + uint8_t temp_b = swappingImageBuffer[(3 * index) + 2]; + + swappingImageBuffer[(3 * index)] = historyBuffer[indexHistoryBuffer]; + swappingImageBuffer[(3 * index) + 1] = historyBuffer[indexHistoryBuffer + 1]; + swappingImageBuffer[(3 * index) + 2] = historyBuffer[indexHistoryBuffer + 2]; + + historyBuffer[indexHistoryBuffer] = temp_r; + historyBuffer[indexHistoryBuffer + 1] = temp_g; + historyBuffer[indexHistoryBuffer + 2] = temp_b; + + /* Exit inner loop. */ + if (segmentation_map[index] <= 0) break; + } // for + } // if + } // for + + /* Produces the output. Note that this step is application-dependent. */ + for (uint8_t *mask = segmentation_map; mask < segmentation_map + (width * height); ++mask) + if (*mask > 0) *mask = COLOR_FOREGROUND; + + return(0); +} + +// ---------------------------------------------------------------------------- +// Update a C3R model +// ---------------------------------------------------------------------------- +int32_t libvibeModel_Sequential_Update_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +) { + /* Basic checks. */ + assert((image_data != NULL) && (model != NULL) && (updating_mask != NULL)); + assert((model->width > 0) && (model->height > 0)); + assert(model->historyBuffer != NULL); + assert((model->jump != NULL) && (model->neighbor != NULL) && (model->position != NULL)); + + /* Some variables. */ + uint32_t width = model->width; + uint32_t height = model->height; + + uint8_t *historyImage = model->historyImage; + uint8_t *historyBuffer = model->historyBuffer; + + /* Some utility variable. */ + int numberOfTests = (model->numberOfSamples - NUMBER_OF_HISTORY_IMAGES); + + /* Updating. */ + uint32_t *jump = model->jump; + int *neighbor = model->neighbor; + uint32_t *position = model->position; + + /* All the frame, except the border. */ + uint32_t shift, indX, indY; + int x, y; + + for (y = 1; y < height - 1; ++y) { + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX < width - 1) { + int index = indX + y * width; + + if (updating_mask[index] == COLOR_BACKGROUND) { + /* In-place substitution. */ + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + int index_neighbor = 3 * (index + neighbor[shift]); + + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + + historyImage[index_neighbor + position[shift] * (3 * width) * height] = r; + historyImage[index_neighbor + position[shift] * (3 * width) * height + 1] = g; + historyImage[index_neighbor + position[shift] * (3 * width) * height + 2] = r; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + + historyBuffer[index_neighbor * numberOfTests + 3 * pos] = r; + historyBuffer[index_neighbor * numberOfTests + 3 * pos + 1] = g; + historyBuffer[index_neighbor * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + } + + /* First row. */ + y = 0; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + + /* Last row. */ + y = height - 1; + shift = rand() % width; + indX = jump[shift]; // index_jump should never be zero (> 1). + + while (indX <= width - 1) { + int index = indX + y * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indX += jump[shift]; + } + + /* First column. */ + x = 0; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indY += jump[shift]; + } + + /* Last column. */ + x = width - 1; + shift = rand() % height; + indY = jump[shift]; // index_jump should never be zero (> 1). + + while (indY <= height - 1) { + int index = x + indY * width; + + uint8_t r = image_data[3 * index]; + uint8_t g = image_data[3 * index + 1]; + uint8_t b = image_data[3 * index + 2]; + + if (updating_mask[index] == COLOR_BACKGROUND) { + if (position[shift] < NUMBER_OF_HISTORY_IMAGES) { + historyImage[3 * index + position[shift] * (3 * width) * height] = r; + historyImage[3 * index + position[shift] * (3 * width) * height + 1] = g; + historyImage[3 * index + position[shift] * (3 * width) * height + 2] = b; + } + else { + int pos = position[shift] - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[(3 * index) * numberOfTests + 3 * pos] = r; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 1] = g; + historyBuffer[(3 * index) * numberOfTests + 3 * pos + 2] = b; + } + } + + ++shift; + indY += jump[shift]; + } + + /* The first pixel! */ + if (rand() % model->updateFactor == 0) { + if (updating_mask[0] == 0) { + int position = rand() % model->numberOfSamples; + + uint8_t r = image_data[0]; + uint8_t g = image_data[1]; + uint8_t b = image_data[2]; + + if (position < NUMBER_OF_HISTORY_IMAGES) { + historyImage[position * (3 * width) * height] = r; + historyImage[position * (3 * width) * height + 1] = g; + historyImage[position * (3 * width) * height + 2] = b; + } + else { + int pos = position - NUMBER_OF_HISTORY_IMAGES; + + historyBuffer[3 * pos] = r; + historyBuffer[3 * pos + 1] = g; + historyBuffer[3 * pos + 2] = b; + } + } + } + + return(0); +} diff --git a/package_bgs/ViBe/vibe-background-sequential.h b/package_bgs/ViBe/vibe-background-sequential.h new file mode 100644 index 0000000..068c7d1 --- /dev/null +++ b/package_bgs/ViBe/vibe-background-sequential.h @@ -0,0 +1,293 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + @file vibe-background-sequential.h + @brief Interface for the ViBe library + @author Marc Van Droogenbroeck + @date July 2014 + @details + + Full documentation is available online at: + http://www.ulg.ac.be/telecom/research/vibe/doc + + All technical details are available in the following paper: +<em>O. Barnich and M. Van Droogenbroeck. ViBe: A universal background subtraction algorithm for video sequences. IEEE Transactions on Image Processing, 20(6):1709-1724, June 2011.</em> + +\verbatim +BiBTeX information + + @article{Barnich2011ViBe, + title = {{ViBe}: A universal background subtraction algorithm for video sequences}, + author = {O. Barnich and M. {Van Droogenbroeck}}, + journal = {IEEE Transactions on Image Processing}, + volume = {20}, + number = {6}, + pages = {1709-1724}, + month = {June}, + year = {2011}, + keywords = {ViBe, Background, Background subtraction, Segmentation, Motion, Motion detection}, + pdf = {http://orbi.ulg.ac.be/bitstream/2268/145853/1/Barnich2011ViBe.pdf}, + doi = {10.1109/TIP.2010.2101613}, + url = {http://hdl.handle.net/2268/145853} + } +\endverbatim +See +\cite Barnich2011ViBe +*/ +#pragma once + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#define COLOR_BACKGROUND 0 /*!< Default label for background pixels */ +#define COLOR_FOREGROUND 255 /*!< Default label for foreground pixels. Note that some authors chose any value different from 0 instead */ + +/** + * \typedef struct vibeModel_Sequential_t + * \brief Data structure for the background subtraction model. + * + * This data structure contains the background model as well as some paramaters value. + * The code is designed to hide all the implementation details to the user to ease its use. + */ +typedef struct vibeModel_Sequential vibeModel_Sequential_t; + +/** + * Allocation of a new data structure where the background model will be stored. + * Please note that this function only creates the structure to host the data. + * This data structures will only be filled with a call to \ref libvibeModel_Sequential_AllocInit_8u_C1R. + * + * \result A pointer to a newly allocated \ref vibeModel_Sequential_t + * structure, or <tt>NULL</tt> in the case of an error. + */ +vibeModel_Sequential_t *libvibeModel_Sequential_New(); + +/** + * ViBe uses several parameters. + * You can print and change some of them if you want. However, default + * value should meet your needs for most videos. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +uint32_t libvibeModel_Sequential_PrintParameters(const vibeModel_Sequential_t *model); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param numberOfSamples + * @return + */ +int32_t libvibeModel_Sequential_SetNumberOfSamples( + vibeModel_Sequential_t *model, + const uint32_t numberOfSamples +); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +uint32_t libvibeModel_Sequential_GetNumberOfSamples(const vibeModel_Sequential_t *model); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param matchingThreshold + * @return + */ +int32_t libvibeModel_Sequential_SetMatchingThreshold( + vibeModel_Sequential_t *model, + const uint32_t matchingThreshold +); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +uint32_t libvibeModel_Sequential_GetMatchingThreshold(const vibeModel_Sequential_t *model); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param matchingNumber + * @return + */ +int32_t libvibeModel_Sequential_SetMatchingNumber( + vibeModel_Sequential_t *model, + const uint32_t matchingNumber +); + +/** + * Setter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param updateFactor New value for the update factor. Please note that the update factor is to be understood as a probability of updating. More specifically, an update factor of 16 means that 1 out of every 16 background pixels is updated. Likewise, an update factor of 1 means that every background pixel is updated. + * @return + */ +int32_t libvibeModel_Sequential_SetUpdateFactor( + vibeModel_Sequential_t *model, + const uint32_t updateFactor +); + +/** + * Getter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +uint32_t libvibeModel_Sequential_GetMatchingNumber(const vibeModel_Sequential_t *model); + + +/** + * Getter. + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +uint32_t libvibeModel_Sequential_GetUpdateFactor(const vibeModel_Sequential_t *model); + +/** + * \brief Frees all the memory used by the <tt>model</tt> and deallocates the structure. + * + * This function frees all the memory allocated by \ref libvibeModel_SequentialNew and + * \ref libvibeModel_Sequential_AllocInit_8u_C1R or \ref libvibeModel_Sequential_AllocInit_8u_C3R. + * @param model The data structure with ViBe's background subtraction model and parameters. + * @return + */ +int32_t libvibeModel_Sequential_Free(vibeModel_Sequential_t *model); + +/** + * The two following functions allocate the required memory according to the + * model parameters and the dimensions of the input images. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + * These 2 functions also initialize the background model using the content + * of *image_data which is the pixel buffer of the first image of your stream. + */ + // ------------------------- Single channel images ---------------------------- + /** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param width + * @param height + * @return + */ +int32_t libvibeModel_Sequential_AllocInit_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +); + +/* These 2 functions perform 2 operations: + * - they classify the pixels *image_data using the provided model and store + * the results in *segmentation_map. + * - they update *model according to these results and the content of + * *image_data. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + */ + /** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param segmentation_map + * @return + */ +int32_t libvibeModel_Sequential_Segmentation_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +); + +/** + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param updating_mask + * @return + */ +int32_t libvibeModel_Sequential_Update_8u_C1R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +); + +// ------------------------- Three channel images ----------------------------- +/** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param width + * @param height + * @return + */ +int32_t libvibeModel_Sequential_AllocInit_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height +); + +/* These 2 functions perform 2 operations: + * - they classify the pixels *image_data using the provided model and store + * the results in *segmentation_map. + * - they update *model according to these results and the content of + * *image_data. + * You must use the "C1R" function for grayscale images and the "C3R" for color + * images. + */ + /** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param segmentation_map + * @return + */ +int32_t libvibeModel_Sequential_Segmentation_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *segmentation_map +); + +/** + * The pixel values of color images are arranged in the following order + * RGBRGBRGB... (or HSVHSVHSVHSVHSVHSV...) + * + * @param model The data structure with ViBe's background subtraction model and parameters. + * @param image_data + * @param updating_mask + * @return + */ +int32_t libvibeModel_Sequential_Update_8u_C3R( + vibeModel_Sequential_t *model, + const uint8_t *image_data, + uint8_t *updating_mask +); diff --git a/package_bgs/av/VuMeter.cpp b/package_bgs/VuMeter.cpp similarity index 52% rename from package_bgs/av/VuMeter.cpp rename to package_bgs/VuMeter.cpp index 29a1477..99baee9 100644 --- a/package_bgs/av/VuMeter.cpp +++ b/package_bgs/VuMeter.cpp @@ -16,9 +16,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "VuMeter.h" -VuMeter::VuMeter() : firstTime(true), showOutput(true), enableFilter(true), binSize(8), alpha(0.995), threshold(0.03) +using namespace bgslibrary::algorithms; + +VuMeter::VuMeter() : + enableFilter(true), binSize(8), alpha(0.995), threshold(0.03) { std::cout << "VuMeter()" << std::endl; + setup("./config/VuMeter.xml"); } VuMeter::~VuMeter() @@ -32,69 +36,62 @@ VuMeter::~VuMeter() void VuMeter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - else - frame = new IplImage(img_input); - - loadConfig(); + init(img_input, img_output, img_bgmodel); + frame = new IplImage(img_input); - if(firstTime) + if (firstTime) { bgs.SetAlpha(alpha); bgs.SetBinSize(binSize); bgs.SetThreshold(threshold); - gray = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1); - cvCvtColor(frame,gray,CV_RGB2GRAY); + gray = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1); + cvCvtColor(frame, gray, CV_RGB2GRAY); - background = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1); + background = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); cvCopy(gray, background); - mask = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1); + mask = cvCreateImage(cvGetSize(gray), IPL_DEPTH_8U, 1); cvZero(mask); - - saveConfig(); } else - cvCvtColor(frame,gray,CV_RGB2GRAY); - - bgs.UpdateBackground(gray,background,mask); - cv::Mat img_foreground(mask); - cv::Mat img_bkg(background); + cvCvtColor(frame, gray, CV_RGB2GRAY); + + bgs.UpdateBackground(gray, background, mask); + img_foreground = cv::cvarrToMat(mask); + img_background = cv::cvarrToMat(background); - if(enableFilter) + if (enableFilter) { - cv::erode(img_foreground,img_foreground,cv::Mat()); + cv::erode(img_foreground, img_foreground, cv::Mat()); cv::medianBlur(img_foreground, img_foreground, 5); } - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) { - if(!img_foreground.empty()) - cv::imshow("VuMeter", img_foreground); - - if(!img_bkg.empty()) - cv::imshow("VuMeter Bkg Model", img_bkg); + cv::imshow("VuMeter", img_foreground); + cv::imshow("VuMeter Bkg Model", img_background); } +#endif img_foreground.copyTo(img_output); - img_bkg.copyTo(img_bgmodel); - + img_background.copyTo(img_bgmodel); + delete frame; firstTime = false; } void VuMeter::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/VuMeter.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "enableFilter", enableFilter); - + cvWriteInt(fs, "binSize", binSize); cvWriteReal(fs, "alpha", alpha); cvWriteReal(fs, "threshold", threshold); - + cvWriteInt(fs, "showOutput", showOutput); cvReleaseFileStorage(&fs); @@ -102,15 +99,15 @@ void VuMeter::saveConfig() void VuMeter::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/VuMeter.xml", 0, CV_STORAGE_READ); - - enableFilter = cvReadIntByName(fs, 0, "enableFilter", true); - - binSize = cvReadIntByName(fs, 0, "binSize", 8); - alpha = cvReadRealByName(fs, 0, "alpha", 0.995); - threshold = cvReadRealByName(fs, 0, "threshold", 0.03); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableFilter = cvReadIntByName(fs, nullptr, "enableFilter", true); + + binSize = cvReadIntByName(fs, nullptr, "binSize", 8); + alpha = cvReadRealByName(fs, nullptr, "alpha", 0.995); + threshold = cvReadRealByName(fs, nullptr, "threshold", 0.03); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); } diff --git a/package_bgs/VuMeter.h b/package_bgs/VuMeter.h new file mode 100644 index 0000000..fefd3ec --- /dev/null +++ b/package_bgs/VuMeter.h @@ -0,0 +1,52 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" +#include "VuMeter/TBackgroundVuMeter.h" + +namespace bgslibrary +{ + namespace algorithms + { + class VuMeter : public IBGS + { + private: + TBackgroundVuMeter bgs; + + IplImage *frame; + IplImage *gray; + IplImage *background; + IplImage *mask; + + bool enableFilter; + int binSize; + double alpha; + double threshold; + + public: + VuMeter(); + ~VuMeter(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/av/TBackground.cpp b/package_bgs/VuMeter/TBackground.cpp similarity index 77% rename from package_bgs/av/TBackground.cpp rename to package_bgs/VuMeter/TBackground.cpp index d05bbd2..4e93729 100644 --- a/package_bgs/av/TBackground.cpp +++ b/package_bgs/VuMeter/TBackground.cpp @@ -72,19 +72,19 @@ bool TBackground::isInitOk(IplImage * pSource, IplImage *pBackground, IplImage * { bool bResult = true; - if(pSource == NULL || pSource->nChannels != 1 || pSource->depth != IPL_DEPTH_8U) + if (pSource == NULL || pSource->nChannels != 1 || pSource->depth != IPL_DEPTH_8U) bResult = false; - if(bResult) + if (bResult) { int nbl, nbc; nbl = pSource->height; nbc = pSource->width; - - if(pBackground == NULL || pBackground->width != nbc || pBackground->height != nbl || pBackground->imageSize != pSource->imageSize) + + if (pBackground == NULL || pBackground->width != nbc || pBackground->height != nbl || pBackground->imageSize != pSource->imageSize) bResult = false; - - if(pMotionMask == NULL || pMotionMask->width != nbc || pMotionMask->height != nbl || pMotionMask->imageSize != pSource->imageSize) + + if (pMotionMask == NULL || pMotionMask->width != nbc || pMotionMask->height != nbl || pMotionMask->imageSize != pSource->imageSize) bResult = false; } @@ -100,7 +100,7 @@ IplImage *TBackground::CreateTestImg() { IplImage *pImage = cvCreateImage(cvSize(256, 256), IPL_DEPTH_8U, 3); - if(pImage != NULL) + if (pImage != NULL) cvSetZero(pImage); return pImage; @@ -112,33 +112,33 @@ int TBackground::UpdateTest(IplImage *pSource, IplImage *pBackground, IplImage * CvScalar Color; unsigned char *ptr; - if(pTest == NULL || !isInitOk(pSource, pBackground, pSource)) + if (pTest == NULL || !isInitOk(pSource, pBackground, pSource)) nErr = 1; - if(!nErr) + if (!nErr) { - if(pTest->width != 256 || pTest->height != 256 || pTest->nChannels != 3) + if (pTest->width != 256 || pTest->height != 256 || pTest->nChannels != 3) nErr = 1; - if(nX < 0 || nX > pSource->width || nY < 0 || nY > pSource->height) + if (nX < 0 || nX > pSource->width || nY < 0 || nY > pSource->height) nErr = 1; - switch(nInd) + switch (nInd) { - case 0 : Color = cvScalar(128, 0, 0); break; - case 1 : Color = cvScalar(0, 128, 0); break; - case 2 : Color = cvScalar(0, 0, 128); break; - default : nErr = 1; + case 0: Color = cvScalar(128, 0, 0); break; + case 1: Color = cvScalar(0, 128, 0); break; + case 2: Color = cvScalar(0, 0, 128); break; + default: nErr = 1; } } - if(!nErr) + if (!nErr) { int l, c; // recupere l'indice de la colonne ptr = (unsigned char *)(pTest->imageData); c = *ptr; - + // efface la colonne cvLine(pTest, cvPoint(c, 0), cvPoint(c, 255), cvScalar(0)); *ptr += 1; diff --git a/package_bgs/av/TBackground.h b/package_bgs/VuMeter/TBackground.h similarity index 99% rename from package_bgs/av/TBackground.h rename to package_bgs/VuMeter/TBackground.h index 463063f..dbaaa6c 100644 --- a/package_bgs/av/TBackground.h +++ b/package_bgs/VuMeter/TBackground.h @@ -26,7 +26,6 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. #include <iostream> #include <opencv2/opencv.hpp> - class TBackground { public: diff --git a/package_bgs/av/TBackgroundVuMeter.cpp b/package_bgs/VuMeter/TBackgroundVuMeter.cpp similarity index 74% rename from package_bgs/av/TBackgroundVuMeter.cpp rename to package_bgs/VuMeter/TBackgroundVuMeter.cpp index 7fade7a..c4fd7a7 100644 --- a/package_bgs/av/TBackgroundVuMeter.cpp +++ b/package_bgs/VuMeter/TBackgroundVuMeter.cpp @@ -46,11 +46,11 @@ void TBackgroundVuMeter::Clear(void) { TBackground::Clear(); - if(m_pHist != NULL) + if (m_pHist != NULL) { - for(int i = 0; i < m_nBinCount; ++i) + for (int i = 0; i < m_nBinCount; ++i) { - if(m_pHist[i] != NULL) + if (m_pHist[i] != NULL) cvReleaseImage(&m_pHist[i]); } @@ -68,14 +68,14 @@ void TBackgroundVuMeter::Reset(void) TBackground::Reset(); - if(m_pHist != NULL) + if (m_pHist != NULL) { // fVal = (m_nBinCount != 0) ? (float)(1.0 / (double)m_nBinCount) : (float)0.0; fVal = 0.0; - for(int i = 0; i < m_nBinCount; ++i) + for (int i = 0; i < m_nBinCount; ++i) { - if(m_pHist[i] != NULL) + if (m_pHist[i] != NULL) { cvSetZero(m_pHist[i]); cvAddS(m_pHist[i], cvScalar(fVal), m_pHist[i]); @@ -98,18 +98,18 @@ std::string TBackgroundVuMeter::GetParameterName(int nInd) nNb = TBackground::GetParameterCount(); - if(nInd >= nNb) + if (nInd >= nNb) { nInd -= nNb; - switch(nInd) + switch (nInd) { - case 0 : csResult = "Bin size"; break; - case 1 : csResult = "Alpha"; break; - case 2 : csResult = "Threshold"; break; + case 0: csResult = "Bin size"; break; + case 1: csResult = "Alpha"; break; + case 2: csResult = "Threshold"; break; } } - else + else csResult = TBackground::GetParameterName(nInd); return csResult; @@ -122,22 +122,22 @@ std::string TBackgroundVuMeter::GetParameterValue(int nInd) nNb = TBackground::GetParameterCount(); - if(nInd >= nNb) + if (nInd >= nNb) { nInd -= nNb; char buff[100]; - - switch(nInd) + + switch (nInd) { - case 0 : sprintf(buff, "%d", m_nBinSize); break; - case 1 : sprintf(buff, "%.3f", m_fAlpha); break; - case 2 : sprintf(buff, "%.2f", m_fThreshold); break; + case 0: sprintf(buff, "%d", m_nBinSize); break; + case 1: sprintf(buff, "%.3f", m_fAlpha); break; + case 2: sprintf(buff, "%.2f", m_fThreshold); break; } csResult = buff; } - else + else csResult = TBackground::GetParameterValue(nInd); return csResult; @@ -151,19 +151,19 @@ int TBackgroundVuMeter::SetParameterValue(int nInd, std::string csNew) nNb = TBackground::GetParameterCount(); - if(nInd >= nNb) + if (nInd >= nNb) { nInd -= nNb; - switch(nInd) + switch (nInd) { - case 0 : SetBinSize(atoi(csNew.c_str())); break; - case 1 : SetAlpha(atof(csNew.c_str())); break; - case 2 : SetThreshold(atof(csNew.c_str())); break; - default : nErr = 1; + case 0: SetBinSize(atoi(csNew.c_str())); break; + case 1: SetAlpha(atof(csNew.c_str())); break; + case 2: SetThreshold(atof(csNew.c_str())); break; + default: nErr = 1; } } - else + else nErr = TBackground::SetParameterValue(nInd, csNew); return nErr; @@ -178,42 +178,42 @@ int TBackgroundVuMeter::Init(IplImage * pSource) nErr = TBackground::Init(pSource); - if(pSource == NULL) + if (pSource == NULL) nErr = 1; // calcul le nb de bin - if(!nErr) + if (!nErr) { nbl = pSource->height; nbc = pSource->width; m_nBinCount = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; - if(m_nBinCount <= 0 || m_nBinCount > 256) + if (m_nBinCount <= 0 || m_nBinCount > 256) nErr = 1; } // creation du tableau de pointeur - if(!nErr) + if (!nErr) { m_pHist = new IplImage *[m_nBinCount]; - if(m_pHist == NULL) + if (m_pHist == NULL) nErr = 1; } // creation des images - if(!nErr) + if (!nErr) { - for(int i = 0; i < m_nBinCount; ++i) + for (int i = 0; i < m_nBinCount; ++i) { m_pHist[i] = cvCreateImage(cvSize(nbc, nbl), IPL_DEPTH_32F, 1); - if(m_pHist[i] == NULL) + if (m_pHist[i] == NULL) nErr = 1; } } - if(!nErr) + if (!nErr) Reset(); else Clear(); @@ -228,28 +228,28 @@ bool TBackgroundVuMeter::isInitOk(IplImage * pSource, IplImage *pBackground, Ipl bResult = TBackground::isInitOk(pSource, pBackground, pMotionMask); - if(pSource == NULL) + if (pSource == NULL) bResult = false; - if(m_nBinSize == 0) + if (m_nBinSize == 0) bResult = false; - if(bResult) + if (bResult) { i = (m_nBinSize != 0) ? 256 / m_nBinSize : 0; - if(i != m_nBinCount || m_pHist == NULL) + if (i != m_nBinCount || m_pHist == NULL) bResult = false; } - if(bResult) + if (bResult) { int nbl = pSource->height; int nbc = pSource->width; - for(i = 0; i < m_nBinCount; ++i) + for (i = 0; i < m_nBinCount; ++i) { - if(m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl) + if (m_pHist[i] == NULL || m_pHist[i]->width != nbc || m_pHist[i]->height != nbl) bResult = false; } } @@ -263,10 +263,10 @@ int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackgroun unsigned char *ptrs, *ptrb, *ptrm; float *ptr1, *ptr2; - if(!isInitOk(pSource, pBackground, pMotionMask)) + if (!isInitOk(pSource, pBackground, pMotionMask)) nErr = Init(pSource); - - if(!nErr) + + if (!nErr) { m_nCount++; int nbc = pSource->width; @@ -274,23 +274,23 @@ int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackgroun unsigned char v = m_nBinSize; // multiplie tout par alpha - for(int i = 0; i < m_nBinCount; ++i) + for (int i = 0; i < m_nBinCount; ++i) cvConvertScale(m_pHist[i], m_pHist[i], m_fAlpha, 0.0); - for(int l = 0; l < nbl; ++l) + for (int l = 0; l < nbl; ++l) { ptrs = (unsigned char *)(pSource->imageData + pSource->widthStep * l); ptrm = (unsigned char *)(pMotionMask->imageData + pMotionMask->widthStep * l); ptrb = (unsigned char *)(pBackground->imageData + pBackground->widthStep * l); - for(int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++) + for (int c = 0; c < nbc; ++c, ptrs++, ptrb++, ptrm++) { - // recherche le bin � augmenter + // recherche le bin à augmenter int i = *ptrs / v; - - if(i < 0 || i >= m_nBinCount) + + if (i < 0 || i >= m_nBinCount) i = 0; - + ptr1 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); ptr1 += c; @@ -299,19 +299,19 @@ int TBackgroundVuMeter::UpdateBackground(IplImage *pSource, IplImage *pBackgroun // recherche le bin du fond actuel i = *ptrb / v; - - if(i < 0 || i >= m_nBinCount) + + if (i < 0 || i >= m_nBinCount) i = 0; - + ptr2 = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * l); ptr2 += c; - if(*ptr2 < *ptr1) + if (*ptr2 < *ptr1) *ptrb = *ptrs; } } - if(m_nCount < 5) + if (m_nCount < 5) cvSetZero(pMotionMask); } @@ -322,10 +322,10 @@ IplImage *TBackgroundVuMeter::CreateTestImg() { IplImage *pImage = NULL; - if(m_nBinCount > 0) + if (m_nBinCount > 0) pImage = cvCreateImage(cvSize(m_nBinCount, 100), IPL_DEPTH_8U, 3); - if(pImage != NULL) + if (pImage != NULL) cvSetZero(pImage); return pImage; @@ -336,31 +336,31 @@ int TBackgroundVuMeter::UpdateTest(IplImage *pSource, IplImage *pBackground, Ipl int nErr = 0; float *ptrf; - if(pTest == NULL || !isInitOk(pSource, pBackground, pSource)) + if (pTest == NULL || !isInitOk(pSource, pBackground, pSource)) nErr = 1; - if(!nErr) + if (!nErr) { int nbl = pTest->height; int nbc = pTest->width; - if(nbl != 100 || nbc != m_nBinCount) + if (nbl != 100 || nbc != m_nBinCount) nErr = 1; - if(nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height) + if (nX < 0 || nX >= pSource->width || nY < 0 || nY >= pSource->height) nErr = 1; } - if(!nErr) + if (!nErr) { cvSetZero(pTest); - for(int i = 0; i < m_nBinCount; ++i) + for (int i = 0; i < m_nBinCount; ++i) { ptrf = (float *)(m_pHist[i]->imageData + m_pHist[i]->widthStep * nY); ptrf += nX; - if(*ptrf >= 0 || *ptrf <= 1.0) { + if (*ptrf >= 0 || *ptrf <= 1.0) { cvLine(pTest, cvPoint(i, 100), cvPoint(i, (int)(100.0 * (1.0 - *ptrf))), cvScalar(0, 255, 0)); } } diff --git a/package_bgs/av/TBackgroundVuMeter.h b/package_bgs/VuMeter/TBackgroundVuMeter.h similarity index 95% rename from package_bgs/av/TBackgroundVuMeter.h rename to package_bgs/VuMeter/TBackgroundVuMeter.h index 1a19324..36fe0d0 100644 --- a/package_bgs/av/TBackgroundVuMeter.h +++ b/package_bgs/VuMeter/TBackgroundVuMeter.h @@ -44,13 +44,13 @@ public: virtual std::string GetParameterValue(int nInd); virtual int SetParameterValue(int nInd, std::string csNew); - inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; } + inline void SetBinSize(int nNew) { m_nBinSize = (nNew > 0 && nNew < 255) ? nNew : 8; } inline double GetBinSize() { return m_nBinSize; } - inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; } + inline void SetAlpha(double fNew) { m_fAlpha = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.995; } inline double GetAlpha() { return m_fAlpha; } - inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; } + inline void SetThreshold(double fNew) { m_fThreshold = (fNew > 0.0 && fNew < 1.0) ? fNew : 0.03; } inline double GetThreshold() { return m_fThreshold; } protected: diff --git a/package_bgs/WeightedMovingMeanBGS.cpp b/package_bgs/WeightedMovingMean.cpp similarity index 51% rename from package_bgs/WeightedMovingMeanBGS.cpp rename to package_bgs/WeightedMovingMean.cpp index 841c467..3a427fc 100644 --- a/package_bgs/WeightedMovingMeanBGS.cpp +++ b/package_bgs/WeightedMovingMean.cpp @@ -14,77 +14,72 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "WeightedMovingMeanBGS.h" +#include "WeightedMovingMean.h" -WeightedMovingMeanBGS::WeightedMovingMeanBGS() : firstTime(true), enableWeight(true), enableThreshold(true), threshold(15), showOutput(true), showBackground(false) +using namespace bgslibrary::algorithms; + +WeightedMovingMean::WeightedMovingMean() : + enableWeight(true), enableThreshold(true), threshold(15) { - std::cout << "WeightedMovingMeanBGS()" << std::endl; + std::cout << "WeightedMovingMean()" << std::endl; + setup("./config/WeightedMovingMean.xml"); } -WeightedMovingMeanBGS::~WeightedMovingMeanBGS() +WeightedMovingMean::~WeightedMovingMean() { - std::cout << "~WeightedMovingMeanBGS()" << std::endl; + std::cout << "~WeightedMovingMean()" << std::endl; } -void WeightedMovingMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void WeightedMovingMean::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); + init(img_input, img_output, img_bgmodel); - if(img_input_prev_1.empty()) - { + if (img_input_prev_1.empty()) { img_input.copyTo(img_input_prev_1); return; } - if(img_input_prev_2.empty()) - { + if (img_input_prev_2.empty()) { img_input_prev_1.copyTo(img_input_prev_2); img_input.copyTo(img_input_prev_1); return; } - + cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1./255.); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); cv::Mat img_input_prev_1_f(img_input.size(), CV_32F); - img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1./255.); + img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1. / 255.); cv::Mat img_input_prev_2_f(img_input.size(), CV_32F); - img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1./255.); + img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1. / 255.); cv::Mat img_background_f(img_input.size(), CV_32F); - - if(enableWeight) + + if (enableWeight) img_background_f = ((img_input_f * 0.5) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.2)); else - img_background_f = ((img_input_f) + (img_input_prev_1_f) + (img_input_prev_2_f)) / 3.0; - - cv::Mat img_background(img_background_f.size(), CV_8U); + img_background_f = ((img_input_f)+(img_input_prev_1_f)+(img_input_prev_2_f)) / 3.0; double minVal, maxVal; minVal = 0.; maxVal = 1.; - img_background_f.convertTo(img_background, CV_8U, 255.0/(maxVal - minVal), -minVal); - - if(showBackground) - cv::imshow("W Moving Mean BG Model", img_background); + img_background_f.convertTo(img_background, CV_8U, 255.0 / (maxVal - minVal), -minVal); - cv::Mat img_foreground; cv::absdiff(img_input, img_background, img_foreground); - if(img_foreground.channels() == 3) + if (img_foreground.channels() == 3) cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) + { cv::imshow("W Moving Mean FG Mask", img_foreground); + cv::imshow("W Moving Mean BG Model", img_background); + } +#endif img_foreground.copyTo(img_output); img_background.copyTo(img_bgmodel); @@ -95,28 +90,26 @@ void WeightedMovingMeanBGS::process(const cv::Mat &img_input, cv::Mat &img_outpu firstTime = false; } -void WeightedMovingMeanBGS::saveConfig() +void WeightedMovingMean::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingMeanBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "enableWeight", enableWeight); cvWriteInt(fs, "enableThreshold", enableThreshold); cvWriteInt(fs, "threshold", threshold); cvWriteInt(fs, "showOutput", showOutput); - cvWriteInt(fs, "showBackground", showBackground); cvReleaseFileStorage(&fs); } -void WeightedMovingMeanBGS::loadConfig() +void WeightedMovingMean::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingMeanBGS.xml", 0, CV_STORAGE_READ); - - enableWeight = cvReadIntByName(fs, 0, "enableWeight", true); - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - showBackground = cvReadIntByName(fs, 0, "showBackground", false); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableWeight = cvReadIntByName(fs, nullptr, "enableWeight", true); + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); cvReleaseFileStorage(&fs); -} \ No newline at end of file +} diff --git a/package_bgs/WeightedMovingMean.h b/package_bgs/WeightedMovingMean.h new file mode 100644 index 0000000..4a1a3c5 --- /dev/null +++ b/package_bgs/WeightedMovingMean.h @@ -0,0 +1,45 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class WeightedMovingMean : public IBGS + { + private: + cv::Mat img_input_prev_1; + cv::Mat img_input_prev_2; + bool enableWeight; + bool enableThreshold; + int threshold; + + public: + WeightedMovingMean(); + ~WeightedMovingMean(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/WeightedMovingVarianceBGS.cpp b/package_bgs/WeightedMovingVariance.cpp similarity index 62% rename from package_bgs/WeightedMovingVarianceBGS.cpp rename to package_bgs/WeightedMovingVariance.cpp index 0317a3c..2855a92 100644 --- a/package_bgs/WeightedMovingVarianceBGS.cpp +++ b/package_bgs/WeightedMovingVariance.cpp @@ -14,68 +14,61 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -#include "WeightedMovingVarianceBGS.h" +#include "WeightedMovingVariance.h" -WeightedMovingVarianceBGS::WeightedMovingVarianceBGS() : firstTime(true), enableWeight(true), - enableThreshold(true), threshold(15), showOutput(true) +using namespace bgslibrary::algorithms; + +WeightedMovingVariance::WeightedMovingVariance() : + enableWeight(true), enableThreshold(true), threshold(15) { - std::cout << "WeightedMovingVarianceBGS()" << std::endl; + std::cout << "WeightedMovingVariance()" << std::endl; + setup("./config/WeightedMovingVariance.xml"); } -WeightedMovingVarianceBGS::~WeightedMovingVarianceBGS() +WeightedMovingVariance::~WeightedMovingVariance() { - std::cout << "~WeightedMovingVarianceBGS()" << std::endl; + std::cout << "~WeightedMovingVariance()" << std::endl; } -void WeightedMovingVarianceBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +void WeightedMovingVariance::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) { - if(img_input.empty()) - return; - - loadConfig(); + init(img_input, img_output, img_bgmodel); - if(firstTime) - saveConfig(); - - if(img_input_prev_1.empty()) - { + if (img_input_prev_1.empty()) { img_input.copyTo(img_input_prev_1); return; } - if(img_input_prev_2.empty()) - { + if (img_input_prev_2.empty()) { img_input_prev_1.copyTo(img_input_prev_2); img_input.copyTo(img_input_prev_1); return; } cv::Mat img_input_f(img_input.size(), CV_32F); - img_input.convertTo(img_input_f, CV_32F, 1./255.); + img_input.convertTo(img_input_f, CV_32F, 1. / 255.); cv::Mat img_input_prev_1_f(img_input.size(), CV_32F); - img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1./255.); + img_input_prev_1.convertTo(img_input_prev_1_f, CV_32F, 1. / 255.); cv::Mat img_input_prev_2_f(img_input.size(), CV_32F); - img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1./255.); - - cv::Mat img_foreground; + img_input_prev_2.convertTo(img_input_prev_2_f, CV_32F, 1. / 255.); // Weighted mean cv::Mat img_mean_f(img_input.size(), CV_32F); - - if(enableWeight) + + if (enableWeight) img_mean_f = ((img_input_f * 0.5) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.2)); else img_mean_f = ((img_input_f * 0.3) + (img_input_prev_1_f * 0.3) + (img_input_prev_2_f * 0.3)); - + // Weighted variance cv::Mat img_1_f(img_input.size(), CV_32F); cv::Mat img_2_f(img_input.size(), CV_32F); cv::Mat img_3_f(img_input.size(), CV_32F); cv::Mat img_4_f(img_input.size(), CV_32F); - if(enableWeight) + if (enableWeight) { img_1_f = computeWeightedVariance(img_input_f, img_mean_f, 0.5); img_2_f = computeWeightedVariance(img_input_prev_1_f, img_mean_f, 0.3); @@ -89,73 +82,71 @@ void WeightedMovingVarianceBGS::process(const cv::Mat &img_input, cv::Mat &img_o img_3_f = computeWeightedVariance(img_input_prev_2_f, img_mean_f, 0.3); img_4_f = (img_1_f + img_2_f + img_3_f); } - + // Standard deviation cv::Mat img_sqrt_f(img_input.size(), CV_32F); cv::sqrt(img_4_f, img_sqrt_f); cv::Mat img_sqrt(img_input.size(), CV_8U); double minVal, maxVal; minVal = 0.; maxVal = 1.; - img_sqrt_f.convertTo(img_sqrt, CV_8U, 255.0/(maxVal - minVal), -minVal); + img_sqrt_f.convertTo(img_sqrt, CV_8U, 255.0 / (maxVal - minVal), -minVal); img_sqrt.copyTo(img_foreground); - if(img_foreground.channels() == 3) + if (img_foreground.channels() == 3) cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - if(enableThreshold) + if (enableThreshold) cv::threshold(img_foreground, img_foreground, threshold, 255, cv::THRESH_BINARY); - if(showOutput) +#ifndef MEX_COMPILE_FLAG + if (showOutput) cv::imshow("W Moving Variance", img_foreground); +#endif img_foreground.copyTo(img_output); + img_background = cv::Mat::zeros(img_input.size(), img_input.type()); + img_background.copyTo(img_bgmodel); + img_input_prev_1.copyTo(img_input_prev_2); img_input.copyTo(img_input_prev_1); - - firstTime = false; -} -//unused -cv::Mat WeightedMovingVarianceBGS::computeWeightedMean(const std::vector<cv::Mat> &v_img_input_f, const std::vector<double> &weights) -{ - cv::Mat img; - return img; + firstTime = false; } -cv::Mat WeightedMovingVarianceBGS::computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight) +cv::Mat WeightedMovingVariance::computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight) { //ERROR in return (weight * ((cv::abs(img_input_f - img_mean_f))^2.)); - + cv::Mat img_f_absdiff(img_input_f.size(), CV_32F); cv::absdiff(img_input_f, img_mean_f, img_f_absdiff); cv::Mat img_f_pow(img_input_f.size(), CV_32F); cv::pow(img_f_absdiff, 2.0, img_f_pow); cv::Mat img_f = weight * img_f_pow; - + return img_f; } -void WeightedMovingVarianceBGS::saveConfig() +void WeightedMovingVariance::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingVarianceBGS.xml", 0, CV_STORAGE_WRITE); + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); cvWriteInt(fs, "enableWeight", enableWeight); cvWriteInt(fs, "enableThreshold", enableThreshold); cvWriteInt(fs, "threshold", threshold); cvWriteInt(fs, "showOutput", showOutput); - + cvReleaseFileStorage(&fs); } -void WeightedMovingVarianceBGS::loadConfig() +void WeightedMovingVariance::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/WeightedMovingVarianceBGS.xml", 0, CV_STORAGE_READ); - - enableWeight = cvReadIntByName(fs, 0, "enableWeight", true); - enableThreshold = cvReadIntByName(fs, 0, "enableThreshold", true); - threshold = cvReadIntByName(fs, 0, "threshold", 15); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + enableWeight = cvReadIntByName(fs, nullptr, "enableWeight", true); + enableThreshold = cvReadIntByName(fs, nullptr, "enableThreshold", true); + threshold = cvReadIntByName(fs, nullptr, "threshold", 15); + showOutput = cvReadIntByName(fs, nullptr, "showOutput", true); + cvReleaseFileStorage(&fs); } diff --git a/package_bgs/WeightedMovingVariance.h b/package_bgs/WeightedMovingVariance.h new file mode 100644 index 0000000..79198b4 --- /dev/null +++ b/package_bgs/WeightedMovingVariance.h @@ -0,0 +1,46 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "IBGS.h" + +namespace bgslibrary +{ + namespace algorithms + { + class WeightedMovingVariance : public IBGS + { + private: + cv::Mat img_input_prev_1; + cv::Mat img_input_prev_2; + bool enableWeight; + bool enableThreshold; + int threshold; + + public: + WeightedMovingVariance(); + ~WeightedMovingVariance(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + cv::Mat computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/WeightedMovingVarianceBGS.h b/package_bgs/WeightedMovingVarianceBGS.h deleted file mode 100644 index 88c2ec8..0000000 --- a/package_bgs/WeightedMovingVarianceBGS.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "IBGS.h" - -class WeightedMovingVarianceBGS : public IBGS -{ -private: - bool firstTime; - cv::Mat img_input_prev_1; - cv::Mat img_input_prev_2; - bool enableWeight; - bool enableThreshold; - int threshold; - bool showOutput; - -public: - WeightedMovingVarianceBGS(); - ~WeightedMovingVarianceBGS(); - - cv::Mat computeWeightedMean(const std::vector<cv::Mat> &v_img_input_f, const std::vector<double> &weights); - cv::Mat computeWeightedVariance(const cv::Mat &img_input_f, const cv::Mat &img_mean_f, const double weight); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/_template_/Amber.cpp b/package_bgs/_template_/Amber.cpp new file mode 100644 index 0000000..2e29ac0 --- /dev/null +++ b/package_bgs/_template_/Amber.cpp @@ -0,0 +1,112 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "Amber.h" + +using namespace bgslibrary::algorithms; + +Amber::Amber() : model(nullptr) +{ + std::cout << "Amber()" << std::endl; + /* Initialization of the Amber model */ + model = libamberModelNew(); + setup("./config/Amber.xml"); +} + +Amber::~Amber() +{ + std::cout << "~Amber()" << std::endl; + libamberModelFree(model); +} + +void Amber::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + init(img_input, img_output, img_bgmodel); + + if (img_input.empty()) + return; + + // Start the initialization + unsigned int width = img_input.cols; + unsigned int height = img_input.rows; + + if (img_input.channels() != 3) + { + std::cout << "Only works for 3 channels images. Sorry for that" << std::endl; + return; + } + + unsigned int stride = width * 3; + unsigned char* image = static_cast<unsigned char*>(img_input.data); + + if (firstTime) + { + /* Create a buffer for the output image */ + //img_output = Mat(img_input.rows, img_input.cols, CV_8UC1); + + /* Sets default model values */ + // libamberModelSetNumberOfSamples(model, nbSamples); + // libamberModelSetMatchingThreshold(model, matchingThreshold); + // libamberModelSetMatchingNumber(model, matchingNumber); + // libamberModelSetUpdateFactor(model, init_subsamplingFactor); + // libamberModelPrintParameters(model); + + /* Initiliazes the Amber model */ + libamberModelAllocInit_8u_C3R(model, image, width, height); + } + + /* Create temporary buffers */ + unsigned char* output_segmentationMap = static_cast<unsigned char*>(calloc(width * height, sizeof(unsigned char))); + libamberGetSegmentation_8u_C3R(model, image, output_segmentationMap); + + unsigned char* oBuffer = static_cast<unsigned char*>(img_output.data); + unsigned char* tmpSegmentationMap = output_segmentationMap; + + for (int i = 0; i < width * height; i++) + { + *oBuffer = *tmpSegmentationMap; + + ++oBuffer; + ++tmpSegmentationMap; + } + +#ifndef MEX_COMPILE_FLAG + if (showOutput) + imshow("Amber", img_output); +#endif + + firstTime = false; + free(output_segmentationMap); +} + +void Amber::saveConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_WRITE); + + cvWriteInt(fs, "showOutput", showOutput); + + cvReleaseFileStorage(&fs); +} + +void Amber::loadConfig() +{ + CvFileStorage* fs = cvOpenFileStorage(config_xml.c_str(), nullptr, CV_STORAGE_READ); + + showOutput = cvReadIntByName(fs, nullptr, "showOutput", false); + + cvReleaseFileStorage(&fs); +} diff --git a/package_bgs/_template_/Amber.h b/package_bgs/_template_/Amber.h new file mode 100644 index 0000000..37f0f8d --- /dev/null +++ b/package_bgs/_template_/Amber.h @@ -0,0 +1,45 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <math.h> +#include <sys/types.h> + +#include "../IBGS.h" +#include "amber/amber.h" + +namespace bgslibrary +{ + namespace algorithms + { + class Amber : public IBGS + { + private: + amberModel* model; + + public: + Amber(); + ~Amber(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + }; + } +} diff --git a/package_bgs/_template_/MyBGS.cpp b/package_bgs/_template_/MyBGS.cpp new file mode 100644 index 0000000..10d5588 --- /dev/null +++ b/package_bgs/_template_/MyBGS.cpp @@ -0,0 +1,44 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "MyBGS.h" + +using namespace bgslibrary::algorithms; + +MyBGS::MyBGS() {} +MyBGS::~MyBGS() {} + +void MyBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + if (img_input.empty()) + return; + + if (img_previous.empty()) + img_input.copyTo(img_previous); + + cv::Mat img_foreground; + cv::absdiff(img_previous, img_input, img_foreground); + + if (img_foreground.channels() == 3) + cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); + + cv::threshold(img_foreground, img_foreground, 15, 255, cv::THRESH_BINARY); + + img_foreground.copyTo(img_output); + img_previous.copyTo(img_bgmodel); + + img_input.copyTo(img_previous); +} diff --git a/package_bgs/ck/LbpMrf.h b/package_bgs/_template_/MyBGS.h similarity index 65% rename from package_bgs/ck/LbpMrf.h rename to package_bgs/_template_/MyBGS.h index 6fd7267..dea2a2f 100644 --- a/package_bgs/ck/LbpMrf.h +++ b/package_bgs/_template_/MyBGS.h @@ -16,29 +16,28 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #pragma once -#include <iostream> #include <opencv2/opencv.hpp> #include "../IBGS.h" -class MotionDetection; - -class LbpMrf : public IBGS +namespace bgslibrary { -private: - bool firstTime; - MotionDetection* Detector; - cv::Mat img_foreground; - cv::Mat img_segmentation; - bool showOutput; - -public: - LbpMrf(); - ~LbpMrf(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; + namespace algorithms + { + class MyBGS : public IBGS + { + private: + cv::Mat img_previous; + + public: + MyBGS(); + ~MyBGS(); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig() {} + void loadConfig() {} + }; + } +} diff --git a/package_bgs/_template_/amber/amber.c b/package_bgs/_template_/amber/amber.c new file mode 100644 index 0000000..00bdfb1 --- /dev/null +++ b/package_bgs/_template_/amber/amber.c @@ -0,0 +1,80 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "amber.h" + +#define COLOR_BACKGROUND 0 +#define COLOR_FOREGROUND 255 + +amberModel* libamberModelNew() +{ + /* model structure alloc */ + amberModel* model = NULL; + model = (amberModel*)calloc(1, sizeof(amberModel)); + assert(model != NULL); + + /* default parameters values */ + model->height = 0; + + return(model); +} + +// -------------------------------------------------- +int32_t libamberModelAllocInit_8u_C3R(amberModel* model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height) +{ + + /* basic checks */ + assert((image_data != NULL) && (model != NULL)); + assert((model->width > 0) && (model->height > 0)); + + /* finish model alloc - parameters values cannot be changed anymore */ + model->width = width; + model->height = height; + + return(0); +} + +// -------------------------------------------------- +int32_t libamberGetSegmentation_8u_C3R(amberModel* model, + const uint8_t *image_data, + uint8_t *segmentation_map) +{ + /* basic checks */ + assert((image_data != NULL) && (model != NULL) && (segmentation_map != NULL)); + assert((model->width > 0) && (model->height > 0)); + + return(0); +} + +// -------------------------------------------------- +int32_t libamberModelFree(amberModel* model) +{ + if (model == NULL) + return(-1); + + free(model); + + return(0); +} + +/* For compilation with g++ */ +#ifdef __cplusplus +} +#endif diff --git a/package_bgs/_template_/amber/amber.h b/package_bgs/_template_/amber/amber.h new file mode 100644 index 0000000..0206179 --- /dev/null +++ b/package_bgs/_template_/amber/amber.h @@ -0,0 +1,64 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +#define COLOR_BACKGROUND 0 +#define COLOR_FOREGROUND 255 + +/* For compilation with g++ */ +#ifdef __cplusplus +extern "C" +{ +#endif + /* end of addition for compilation with g++ */ + +#ifndef _STDINT_H +// This is used to make it compatible for cross-compilation + typedef unsigned char uint8_t; + typedef int int32_t; + typedef unsigned int uint32_t; +#endif // _STDINT_H + + typedef struct { + uint32_t width; + uint32_t height; + } amberModel; + + /** Allocation of a new data structure where the background model + will be stored */ + amberModel* libamberModelNew(); + + int32_t libamberModelAllocInit_8u_C3R(amberModel* model, + const uint8_t *image_data, + const uint32_t width, + const uint32_t height); + + int32_t libamberGetSegmentation_8u_C3R(amberModel* model, + const uint8_t *image_data, + uint8_t *segmentation_map); + + + int32_t libamberModelFree(amberModel* model); + + /* For compilation with g++ */ +#ifdef __cplusplus +} +#endif diff --git a/package_bgs/ae/KDE.h b/package_bgs/ae/KDE.h deleted file mode 100644 index adcc659..0000000 --- a/package_bgs/ae/KDE.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "NPBGSubtractor.h" -#include "../IBGS.h" - -class KDE : public IBGS -{ -private: - NPBGSubtractor *p; - int rows; - int cols; - int color_channels; - int SequenceLength; - int TimeWindowSize; - int SDEstimationFlag; - int lUseColorRatiosFlag; - double th; - double alpha; - int framesToLearn; - int frameNumber; - bool firstTime; - bool showOutput; - - cv::Mat img_foreground; - unsigned char *FGImage; - unsigned char *FilteredFGImage; - unsigned char **DisplayBuffers; - -public: - KDE(); - ~KDE(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/ae/NPBGSubtractor.cpp b/package_bgs/ae/NPBGSubtractor.cpp deleted file mode 100644 index 3f0620f..0000000 --- a/package_bgs/ae/NPBGSubtractor.cpp +++ /dev/null @@ -1,1160 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -/* -* -* Copyright 2001 by Ahmed Elgammal All rights reserved. -* -* Permission to use, copy, or modify this software and its documentation -* for educational and research purposes only and without fee is hereby -* granted, provided that this copyright notice and the original authors's -* name appear on all copies and supporting documentation. If individual -* files are separated from this distribution directory structure, this -* copyright notice must be included. For any other uses of this software, -* in original or modified form, including but not limited to distribution -* in whole or in part, specific prior permission must be obtained from -* Author or UMIACS. These programs shall not be used, rewritten, or -* adapted as the basis of a commercial software or hardware product -* without first obtaining appropriate licenses from Author. -* Other than these cases, no part of this software may be used or -* distributed without written permission of the author. -* -* Neither the author nor UMIACS make any representations about the -* suitability of this software for any purpose. It is provided -* "as is" without express or implied warranty. -* -* Ahmed Elgammal -* -* University of Maryland at College Park -* UMIACS -* A.V. Williams Bldg. -* CollegePark, MD 20742 -* E-mail: elgammal@umiacs.umd.edu -* -**/ - -// NPBGSubtractor.cpp: implementation of the NPBGSubtractor class. -// -////////////////////////////////////////////////////////////////////// - -#include "NPBGSubtractor.h" -#include <assert.h> -#include <math.h> -#include <string.h> - -//#ifdef _DEBUG -//#undef THIS_FILE -//static char THIS_FILE[]=__FILE__; -//#define new DEBUG_NEW -//#endif - -void BGR2SnGnRn(unsigned char * in_image, - unsigned char * out_image, - unsigned int rows, - unsigned int cols) -{ - unsigned int i; - unsigned int r2,r3; - unsigned int r,g,b; - double s; - - for(i = 0; i < rows*cols*3; i += 3) - { - b=in_image[i]; - g=in_image[i+1]; - r=in_image[i+2]; - - // calculate color ratios - s = (double) 255 / (double) (b+g+r+30); - - r2 =(unsigned int) ((g+10) * s ); - r3 =(unsigned int) ((r+10) * s ); - - out_image[i] = (unsigned char) (((unsigned int) b+g+r) / 3); - out_image[i+1] = (unsigned char) (r2 > 255 ? 255 : r2) ; - out_image[i+2] = (unsigned char) (r3 > 255 ? 255 : r3) ; - } -} - -void UpdateDiffHist(unsigned char * image1, unsigned char * image2, DynamicMedianHistogram * pHist) -{ - unsigned int j; - int bin,diff; - - unsigned int imagesize = pHist->imagesize; - unsigned char histbins = pHist->histbins; - unsigned char *pAbsDiffHist = pHist->Hist; - - int histbins_1 = histbins-1; - - for(j = 0; j < imagesize; j++) - { - diff = (int) image1[j] - (int) image2[j]; - diff = abs(diff); - // update histogram - bin = (diff < histbins ? diff : histbins_1); - pAbsDiffHist[j*histbins+bin]++; - } -} - -void FindHistMedians(DynamicMedianHistogram * pAbsDiffHist) -{ - unsigned char * Hist = pAbsDiffHist->Hist; - unsigned char * MedianBins = pAbsDiffHist->MedianBins; - unsigned char * AccSum = pAbsDiffHist->AccSum; - unsigned char histsum = pAbsDiffHist->histsum; - unsigned char histbins = pAbsDiffHist->histbins; - unsigned int imagesize = pAbsDiffHist->imagesize; - - int sum; - int bin; - unsigned int histindex; - unsigned char medianCount=histsum/2; - unsigned int j; - - // find medians - for(j = 0; j < imagesize; j++) - { - // find the median - bin=0; - sum=0; - - histindex=j*histbins; - - while(sum < medianCount) - { - sum+=Hist[histindex+bin]; - bin++; - } - - bin--; - - MedianBins[j]=bin; - AccSum[j]=sum; - } -} - -DynamicMedianHistogram BuildAbsDiffHist(unsigned char * pSequence, - unsigned int rows, - unsigned int cols, - unsigned int color_channels, - unsigned int SequenceLength, - unsigned int histbins) -{ - - unsigned int imagesize=rows*cols*color_channels; - unsigned int i; - - DynamicMedianHistogram Hist; - - unsigned char *pAbsDiffHist = new unsigned char[rows*cols*color_channels*histbins]; - unsigned char *pMedianBins = new unsigned char[rows*cols*color_channels]; - unsigned char *pMedianFreq = new unsigned char[rows*cols*color_channels]; - unsigned char *pAccSum = new unsigned char[rows*cols*color_channels]; - - memset(pAbsDiffHist,0,rows*cols*color_channels*histbins); - - Hist.Hist = pAbsDiffHist; - Hist.MedianBins = pMedianBins; - Hist.MedianFreq = pMedianFreq; - Hist.AccSum = pAccSum; - Hist.histbins = histbins; - Hist.imagesize = rows*cols*color_channels; - Hist.histsum = SequenceLength-1; - - unsigned char *image1, *image2; - for(i = 1; i < SequenceLength; i++) - { - // find diff between frame i,i-1; - image1 = pSequence+(i-1)*imagesize; - image2 = pSequence+(i)*imagesize; - - UpdateDiffHist(image1,image2,&Hist); - } - - FindHistMedians(&Hist); - - return Hist; -} - -void EstimateSDsFromAbsDiffHist(DynamicMedianHistogram * pAbsDiffHist, - unsigned char * pSDs, - unsigned int imagesize, - double MinSD, - double MaxSD, - unsigned int kernelbins) -{ - double v; - double kernelbinfactor=(kernelbins-1)/(MaxSD-MinSD); - int medianCount; - int sum; - int bin; - unsigned int histindex; - unsigned int j; - unsigned int x1,x2; - - unsigned char *Hist =pAbsDiffHist->Hist; - unsigned char *MedianBins =pAbsDiffHist->MedianBins; - unsigned char *AccSum =pAbsDiffHist->AccSum; - unsigned char histsum =pAbsDiffHist->histsum; - unsigned char histbins =pAbsDiffHist->histbins; - - medianCount=(histsum)/2 ; - - for(j = 0; j < imagesize; j++) - { - histindex=j*histbins; - - bin=MedianBins[j]; - sum=AccSum[j]; - - x1=sum-Hist[histindex+bin]; - x2=sum; - - // interpolate to get the median - // x1 < 50 % < x2 - - v =1.04 * ((double) bin-(double) (x2-medianCount)/ (double) (x2-x1)); - v=( v <= MinSD ? MinSD : v); - - // convert sd to kernel table bin - - bin=(int) (v>=MaxSD ? kernelbins-1 : floor((v-MinSD)*kernelbinfactor+.5)); - - assert(bin>=0 && bin < kernelbins ); - - pSDs[j]=bin; - } -} - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -NPBGSubtractor::NPBGSubtractor(){} - -NPBGSubtractor::~NPBGSubtractor() -{ - delete AbsDiffHist.Hist; - delete AbsDiffHist.MedianBins; - delete AbsDiffHist.MedianFreq; - delete AbsDiffHist.AccSum; - delete KernelTable; - delete BGModel->SDbinsImage; - delete BGModel; - delete Pimage1; - delete Pimage2; - delete tempFrame; - delete imageindex->List; - delete imageindex; -} - -int NPBGSubtractor::Intialize(unsigned int prows, - unsigned int pcols, - unsigned int pcolor_channels, - unsigned int SequenceLength, - unsigned int pTimeWindowSize, - unsigned char pSDEstimationFlag, - unsigned char pUseColorRatiosFlag) -{ - - rows=prows; - cols=pcols; - color_channels=pcolor_channels; - imagesize=rows*cols*color_channels; - SdEstimateFlag = pSDEstimationFlag; - UseColorRatiosFlag=pUseColorRatiosFlag; - //SampleSize = SequenceLength; - - AdaptBGFlag = FALSE; - // - SubsetFlag = TRUE; - - UpdateSDRate = 0; - - BGModel = new NPBGmodel(rows,cols,color_channels,SequenceLength,pTimeWindowSize,500); - - Pimage1= new double[rows*cols]; - Pimage2= new double[rows*cols]; - - tempFrame= new unsigned char[rows*cols*3]; - - imageindex = new ImageIndex; - imageindex->List= new unsigned int [rows*cols]; - - // error checking - if (BGModel==NULL) - return 0; - - return 1; -} - -void NPBGSubtractor::AddFrame(unsigned char *ImageBuffer) -{ - if(UseColorRatiosFlag && color_channels==3) - BGR2SnGnRn(ImageBuffer,ImageBuffer,rows,cols); - - BGModel->AddFrame(ImageBuffer); -} - -void NPBGSubtractor::Estimation() -{ - int SampleSize=BGModel->SampleSize; - - memset(BGModel->TemporalMask,0,rows*cols*BGModel->TemporalBufferLength); - - //BGModel->AccMask= new unsigned int [rows*cols]; - memset(BGModel->AccMask,0,rows*cols*sizeof(unsigned int)); - - unsigned char *pSDs = new unsigned char[rows*cols*color_channels]; - - //DynamicMedianHistogram AbsDiffHist; - - int Abshistbins = 20; - - TimeIndex=0; - - // estimate standard deviations - - if(SdEstimateFlag) - { - AbsDiffHist = BuildAbsDiffHist(BGModel->Sequence,rows,cols,color_channels,SampleSize,Abshistbins); - EstimateSDsFromAbsDiffHist(&AbsDiffHist,pSDs,imagesize,SEGMAMIN,SEGMAMAX,SEGMABINS); - } - else - { - unsigned int bin; - bin = (unsigned int) floor(((DEFAULTSEGMA-SEGMAMIN)*SEGMABINS)/(SEGMAMAX-SEGMAMIN)); - memset(pSDs,bin,rows*cols*color_channels*sizeof(unsigned char)); - } - - BGModel->SDbinsImage=pSDs; - - // Generate the Kernel - KernelTable = new KernelLUTable(KERNELHALFWIDTH,SEGMAMIN,SEGMAMAX,SEGMABINS); -} - -/*********************************************************************/ - -void BuildImageIndex(unsigned char * Image, - ImageIndex * imageIndex, - unsigned int rows, - unsigned int cols) -{ - unsigned int i,j; - unsigned int r,c; - unsigned int * image_list; - - j=cols+1; - i=0; - image_list=imageIndex->List; - - for(r = 1; r < rows-1; r++) - { - for(c = 1; c < cols-1; c++) - { - if(Image[j]) - image_list[i++]=j; - - j++; - } - j+=2; - } - - imageIndex->cnt = i; -} - -/*********************************************************************/ - -void HystExpandOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - double * Pimage, - double hyst_th, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows,cols; - - int Nbr[9]; - unsigned int i,j; - unsigned int k; - unsigned int idx; - - rows=(int) urows; - cols=(int) ucols; - - in_cnt=inIndex->cnt; - in_list=inIndex->List; - - Nbr[0]=-cols-1; - Nbr[1]=-cols; - Nbr[2]=-cols+1; - Nbr[3]=-1; - Nbr[4]=0; - Nbr[5]=1; - Nbr[6]=cols-1; - Nbr[7]=cols; - Nbr[8]=cols+1; - - memset(outImage,0,rows*cols); - - out_list=outIndex->List; - k=0; - - for(i = 0; i < in_cnt; i++) - { - for(j = 0; j < 9; j++) - { - idx = in_list[i] + Nbr[j]; - - if(Pimage[idx] < hyst_th) - outImage[idx] = 255; - } - } - - // build index for out image - BuildImageIndex(outImage,outIndex,urows,ucols); -} - -/*********************************************************************/ - -void HystShrinkOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - double * Pimage, - double hyst_th, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows,cols; - - int Nbr[9]; - unsigned int i,j; - unsigned int k,idx; - - rows=(int) urows; - cols=(int) ucols; - - in_cnt=inIndex->cnt; - in_list=inIndex->List; - - Nbr[0]=-cols-1; - Nbr[1]=-cols; - Nbr[2]=-cols+1; - Nbr[3]=-1; - Nbr[4]=0; - Nbr[5]=1; - Nbr[6]=cols-1; - Nbr[7]=cols; - Nbr[8]=cols+1; - - memset(outImage,0,rows*cols); - - out_list=outIndex->List; - k=0; - - for(i = 0; i < in_cnt; i++) - { - idx = in_list[i]; - j = 0; - - while(j < 9 && inImage[idx+Nbr[j]]) - j++; - - if(j >= 9 || Pimage[idx] <= hyst_th) - outImage[idx]=255; - } - - BuildImageIndex(outImage,outIndex,rows,cols); -} - -/*********************************************************************/ - -void ExpandOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows,cols; - - int Nbr[9]; - unsigned int i,j; - unsigned int k; - unsigned int idx; - - rows=(int) urows; - cols=(int) ucols; - - in_cnt=inIndex->cnt; - in_list=inIndex->List; - - Nbr[0]=-cols-1; - Nbr[1]=-cols; - Nbr[2]=-cols+1; - Nbr[3]=-1; - Nbr[4]=0; - Nbr[5]=1; - Nbr[6]=cols-1; - Nbr[7]=cols; - Nbr[8]=cols+1; - - - memset(outImage,0,rows*cols); - - - out_list=outIndex->List; - k=0; - for (i=0; i<in_cnt;i++) - for (j=0;j<9;j++) { - idx=in_list[i]+Nbr[j]; - outImage[idx]=255; - } - - - // build index for out image - - BuildImageIndex(outImage,outIndex,rows,cols); - -} - -/*********************************************************************/ - -void ShrinkOperatorIndexed(unsigned char * inImage, - ImageIndex * inIndex, - unsigned char * outImage, - ImageIndex * outIndex, - unsigned int urows, - unsigned int ucols) -{ - - unsigned int * in_list; - unsigned int in_cnt; - unsigned int * out_list; - - int rows,cols; - - int Nbr[9]; - unsigned int i,j; - unsigned int k,idx; - - rows=(int) urows; - cols=(int) ucols; - - in_cnt=inIndex->cnt; - in_list=inIndex->List; - - Nbr[0]=-cols-1; - Nbr[1]=-cols; - Nbr[2]=-cols+1; - Nbr[3]=-1; - Nbr[4]=0; - Nbr[5]=1; - Nbr[6]=cols-1; - Nbr[7]=cols; - Nbr[8]=cols+1; - - - memset(outImage,0,rows*cols); - - out_list=outIndex->List; - k=0; - for (i=0; i<in_cnt;i++) { - idx=in_list[i]; - j=0; - - while ( j<9 && inImage[idx+Nbr[j]]){ - j++; - } - - if (j>=9) { - outImage[idx]=255; - } - } - - BuildImageIndex(outImage,outIndex,rows,cols); -} - -/*********************************************************************/ - -void NoiseFilter_o(unsigned char * Image, - unsigned char * ResultIm, - int rows, - int cols, - unsigned char th) -{ - /* assuming input is 1 for on, 0 for off */ - - - int r,c; - unsigned char *p,*n,*nw,*ne,*e,*w,*s,*sw,*se; - unsigned int v; - unsigned int TH; - - unsigned char * ResultPtr; - - TH=255*th; - - memset(ResultIm,0,rows*cols); - - p=Image+cols+1; - ResultPtr=ResultIm+cols+1; - - for(r=1;r<rows-1;r++) - { - for(c=1;c<cols-1;c++) - { - if (*p) - { - n=p-cols; - ne=n+1; - nw=n-1; - e=p+1; - w=p-1; - s=p+cols; - se=s+1; - sw=s-1; - - v=(unsigned int) *nw+*n+*ne+*w+*e+*sw+*s+*se; - - if (v>=TH) - *ResultPtr=255; - else - *ResultPtr=0; - } - p++; - ResultPtr++; - } - p+=2; - ResultPtr+=2; - } -} - -/*********************************************************************/ - -void NPBGSubtractor::SequenceBGUpdate_Pairs(unsigned char * image, - unsigned char * Mask) -{ - unsigned int i,ic; - unsigned char * pSequence =BGModel->Sequence; - unsigned char * PixelQTop =BGModel->PixelQTop; - unsigned int Top =BGModel->Top; - unsigned int rate; - - int TemporalBufferTop =(int) BGModel->TemporalBufferTop; - unsigned char * pTemporalBuffer = BGModel->TemporalBuffer; - unsigned char * pTemporalMask = BGModel->TemporalMask; - int TemporalBufferLength = BGModel->TemporalBufferLength; - - unsigned int * AccMask = BGModel->AccMask; - unsigned int ResetMaskTh = BGModel->ResetMaskTh; - - unsigned char *pAbsDiffHist = AbsDiffHist.Hist; - unsigned char histbins = AbsDiffHist.histbins; - int histbins_1=histbins-1; - - int TimeWindowSize = BGModel->TimeWindowSize; - int SampleSize = BGModel->SampleSize; - - int TemporalBufferNext; - - unsigned int imagebuffersize=rows*cols*color_channels; - unsigned int imagespatialsize=rows*cols; - - unsigned char mask; - - unsigned int histindex; - unsigned char diff; - unsigned char bin; - - static int TBCount=0; - - unsigned char * pTBbase1, * pTBbase2; - unsigned char * pModelbase1, * pModelbase2; - - rate=TimeWindowSize/SampleSize; - rate=(rate > 2) ? rate : 2; - - - TemporalBufferNext=(TemporalBufferTop+1) - % TemporalBufferLength; - - // pointers to Masks : Top and Next - unsigned char * pTMaskTop=pTemporalMask+TemporalBufferTop*imagespatialsize; - unsigned char * pTMaskNext=pTemporalMask+TemporalBufferNext*imagespatialsize; - - // pointers to TB frames: Top and Next - unsigned char * pTBTop=pTemporalBuffer+TemporalBufferTop*imagebuffersize; - unsigned char * pTBNext=pTemporalBuffer+TemporalBufferNext*imagebuffersize; - - if ( ((TimeIndex) % rate == 0) && TBCount >= TemporalBufferLength ) - { - for(i=0,ic=0;i<imagespatialsize;i++,ic+=color_channels) - { - mask= * (pTMaskTop+i) || * (pTMaskNext+i); - - if(!mask) - { - // pointer to TB pixels to be added to the model - pTBbase1=pTBTop+ic; - pTBbase2=pTBNext+ic; - - // pointers to Model pixels to be replaced - pModelbase1=pSequence+PixelQTop[i]*imagebuffersize+ic; - pModelbase2=pSequence+((PixelQTop[i]+1)% SampleSize)*imagebuffersize+ic; - - // update Deviation Histogram - if(SdEstimateFlag) - { - if(color_channels==1) - { - histindex=i*histbins; - - // add new pair from temporal buffer - diff=(unsigned char) abs((int) *pTBbase1 - (int) *pTBbase2); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]++; - - - // remove old pair from the model - diff=(unsigned char) abs((int) *pModelbase1-(int) *pModelbase2); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]--; - } - else - { - // color - - // add new pair from temporal buffer - histindex=ic*histbins; - diff=abs(*pTBbase1 - - *pTBbase2); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]++; - - histindex+=histbins; - diff=abs(*(pTBbase1+1) - - *(pTBbase2+1)); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]++; - - histindex+=histbins; - diff=abs(*(pTBbase1+2) - - *(pTBbase2+2)); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]++; - - // remove old pair from the model - histindex=ic*histbins; - - diff=abs(*pModelbase1- - *pModelbase2); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]--; - - histindex+=histbins; - diff=abs(*(pModelbase1+1)- - *(pModelbase2+1)); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]--; - - histindex+=histbins; - diff=abs(*(pModelbase1+2)- - *(pModelbase2+2)); - bin=(diff < histbins ? diff : histbins_1); - pAbsDiffHist[histindex+bin]--; - } - } - - // add new pair into the model - memcpy(pModelbase1,pTBbase1, color_channels*sizeof(unsigned char)); - - memcpy(pModelbase2,pTBbase2, color_channels*sizeof(unsigned char)); - - PixelQTop[i]=(PixelQTop[i]+2) % SampleSize; - } - } - } // end if (sampling event) - - // update temporal buffer - // add new frame to Temporal buffer. - memcpy(pTBTop,image,imagebuffersize); - - // update AccMask - // update new Mask with information in AccMask - - for (i=0;i<rows*cols;i++) - { - if (Mask[i]) - AccMask[i]++; - else - AccMask[i]=0; - - if (AccMask[i] > ResetMaskTh) - Mask[i]=0; - } - - // add new mask - memcpy(pTMaskTop,Mask,imagespatialsize); - - // advance Temporal buffer pointer - TemporalBufferTop=(TemporalBufferTop+1) % TemporalBufferLength; - - BGModel->TemporalBufferTop=TemporalBufferTop; - - TBCount++; - - // estimate SDs - - if (SdEstimateFlag && UpdateSDRate && ((TimeIndex) % UpdateSDRate == 0)) - { - double MaxSD = KernelTable->maxsegma; - double MinSD = KernelTable->minsegma; - int KernelBins = KernelTable->segmabins; - - unsigned char * pSDs= BGModel->SDbinsImage; - - FindHistMedians(&(AbsDiffHist)); - EstimateSDsFromAbsDiffHist(&(AbsDiffHist),pSDs,imagebuffersize,MinSD,MaxSD,KernelBins); - } - - TimeIndex++; -} - -/*********************************************************************/ - -void DisplayPropabilityImageWithThresholding(double * Pimage, - unsigned char * DisplayImage, - double Threshold, - unsigned int rows, - unsigned int cols) -{ - double p; - - for(unsigned int i=0;i<rows*cols;i++) - { - p = Pimage[i]; - - DisplayImage[i]=(p > Threshold) ? 0 : 255; - } -} - -/*********************************************************************/ - -void NPBGSubtractor::NPBGSubtraction_Subset_Kernel( - unsigned char * image, - unsigned char * FGImage, - unsigned char * FilteredFGImage) -{ - unsigned int i,j; - unsigned char *pSequence =BGModel->Sequence; - - unsigned int SampleSize = BGModel->SampleSize; - - double *kerneltable = KernelTable->kerneltable; - int KernelHalfWidth = KernelTable->tablehalfwidth; - double *KernelSum = KernelTable->kernelsums; - double KernelMaxSigma = KernelTable->maxsegma; - double KernelMinSigma = KernelTable->minsegma; - int KernelBins = KernelTable->segmabins; - unsigned char * SDbins= BGModel->SDbinsImage; - - unsigned char * SaturationImage=FilteredFGImage; - - // default sigmas .. to be removed. - double sigma1; - double sigma2; - double sigma3; - - sigma1=2.25; - sigma2=2.25; - sigma3=2.25; - - double p; - double th; - - double alpha; - - alpha= AlphaValue; - - /* intialize FG image */ - - memset(FGImage,0,rows*cols); - - //Threshold=1; - th = Threshold * SampleSize; - - double sum=0,kernel1,kernel2,kernel3; - int k,g; - - - if (color_channels==1) - { - // gray scale - - int kernelbase; - - for (i=0;i<rows*cols;i++) - { - kernelbase=SDbins[i]*(2*KernelHalfWidth+1); - sum=0; - j=0; - - while (j<SampleSize && sum < th) - { - g=pSequence[j*imagesize+i]; - k= g- image[i] +KernelHalfWidth; - sum+=kerneltable[kernelbase+k]; - j++; - } - - p=sum/j; - Pimage1[i]=p; - } - } - else if (UseColorRatiosFlag && SubsetFlag) - { - // color ratios - - unsigned int ig; - int base; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - - unsigned int kerneltablewidth=2*KernelHalfWidth+1; - - double beta=3.0; // minimum bound on the range. - double betau=100.0; - - double beta_over_alpha = beta / alpha; - double betau_over_alpha = betau / alpha; - - - double brightness_lowerbound = 1-alpha; - double brightness_upperbound = 1+alpha; - int x1,x2; - unsigned int SubsampleCount; - - for (i=0,ig=0;i<imagesize;i+=3,ig++) - { - kernelbase1=SDbins[i]*kerneltablewidth; - kernelbase2=SDbins[i+1]*kerneltablewidth; - kernelbase3=SDbins[i+2]*kerneltablewidth; - - sum=0; - j=0; - SubsampleCount=0; - - while (j<SampleSize && sum < th) - { - base=j*imagesize+i; - g=pSequence[base]; - - if (g < beta_over_alpha) - { - x1=(int) (g-beta); - x2=(int) (g+beta); - } - else if (g > betau_over_alpha) - { - x1=(int) (g-betau); - x2=(int) (g+betau); - } - else - { - x1=(int) (g*brightness_lowerbound+0.5); - x2=(int) (g*brightness_upperbound+0.5); - } - - if(x1<image[i] && image[i] <x2) - { - g=pSequence[base+1]; - k= (g- image[i+1]) +KernelHalfWidth; - kernel2=kerneltable[kernelbase2+k]; - - g=pSequence[base+2]; - k= (g- image[i+2]) +KernelHalfWidth; - kernel3=kerneltable[kernelbase3+k]; - - sum+=kernel2*kernel3; - - SubsampleCount++; - } - j++; - } - - p=sum / j; - Pimage1[ig]=p; - } - } - else if (UseColorRatiosFlag && ! SubsetFlag) - { - // color ratios - - unsigned int ig; - int base; - int bin; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - - unsigned int kerneltablewidth=2*KernelHalfWidth+1; - - int gmin,gmax; - double gfactor; - - gmax=200; - gmin=10; - - gfactor = (KernelMaxSigma-KernelMinSigma) / (double) (gmax - gmin); - - for (i=0,ig=0;i<imagesize;i+=3,ig++) - { - - bin=(int) floor(((alpha*16-KernelMinSigma)*KernelBins)/(KernelMaxSigma-KernelMinSigma)); - - kernelbase1=bin*kerneltablewidth; - kernelbase2=SDbins[i+1]*kerneltablewidth; - kernelbase3=SDbins[i+2]*kerneltablewidth; - - sum=0; - j=0; - - while (j<SampleSize && sum < th) - { - base=j*imagesize+i; - g=pSequence[base]; - - if (g < gmin ) - bin=0; - else if (g > gmax) - bin = KernelBins -1 ; - else - bin= (int) ((g-gmin) * gfactor + 0.5); - - kernelbase1=bin*kerneltablewidth; - - k= (g- image[i]) +KernelHalfWidth; - kernel1=kerneltable[kernelbase1+k]; - - g=pSequence[base+1]; - k= (g- image[i+1]) +KernelHalfWidth; - kernel2=kerneltable[kernelbase2+k]; - - g=pSequence[base+2]; - k= (g- image[i+2]) +KernelHalfWidth; - kernel3=kerneltable[kernelbase3+k]; - - sum+=kernel1*kernel2*kernel3; - j++; - } - - p=sum / j; - Pimage1[ig]=p; - } - } - else // RGB color - { - unsigned int ig; - int base; - - int kernelbase1; - int kernelbase2; - int kernelbase3; - unsigned int kerneltablewidth=2*KernelHalfWidth+1; - - for (i=0,ig=0;i<imagesize;i+=3,ig++) - { - // used extimated kernel width to access the right kernel - kernelbase1=SDbins[i]*kerneltablewidth; - kernelbase2=SDbins[i+1]*kerneltablewidth; - kernelbase3=SDbins[i+2]*kerneltablewidth; - - sum=0; - j=0; - while (j<SampleSize && sum < th) - { - base=j*imagesize+i; - g=pSequence[base]; - k= (g- image[i]) +KernelHalfWidth; - kernel1=kerneltable[kernelbase1+k]; - - g=pSequence[base+1]; - k= (g- image[i+1]) +KernelHalfWidth; - kernel2=kerneltable[kernelbase2+k]; - - g=pSequence[base+2]; - k= (g- image[i+2]) +KernelHalfWidth; - kernel3=kerneltable[kernelbase3+k]; - - sum+=kernel1*kernel2*kernel3; - j++; - } - - p=sum/j; - Pimage1[ig]=p; - } - } - - DisplayPropabilityImageWithThresholding(Pimage1,FGImage,Threshold,rows,cols); -} - -/*********************************************************************/ - -void NPBGSubtractor::NBBGSubtraction(unsigned char * Frame, - unsigned char * FGImage, - unsigned char * FilteredFGImage, - unsigned char ** DisplayBuffers) -{ - if(UseColorRatiosFlag) - BGR2SnGnRn(Frame,tempFrame,rows,cols); - else - memcpy(tempFrame,Frame,rows*cols*color_channels); - - NPBGSubtraction_Subset_Kernel(tempFrame,FGImage,FilteredFGImage); - /*NoiseFilter_o(FGImage,DisplayBuffers[3],rows,cols,4); - BuildImageIndex(DisplayBuffers[3],imageindex,rows,cols); - - ExpandOperatorIndexed(DisplayBuffers[3],imageindex,DisplayBuffers[4],imageindex,rows,cols); - ShrinkOperatorIndexed(DisplayBuffers[4],imageindex,FilteredFGImage,imageindex,rows,cols); - - memset(DisplayBuffers[3],0,rows*cols);*/ -} - -void NPBGSubtractor::Update(unsigned char * FGMask) -{ - if(UpdateBGFlag) - SequenceBGUpdate_Pairs(tempFrame,FGMask); -} diff --git a/package_bgs/av/VuMeter.h b/package_bgs/av/VuMeter.h deleted file mode 100644 index a2334ca..0000000 --- a/package_bgs/av/VuMeter.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "TBackgroundVuMeter.h" -#include "../IBGS.h" - -class VuMeter : public IBGS -{ -private: - TBackgroundVuMeter bgs; - - IplImage *frame; - IplImage *gray; - IplImage *background; - IplImage *mask; - - bool firstTime; - bool showOutput; - bool enableFilter; - - int binSize; - double alpha; - double threshold; - -public: - VuMeter(); - ~VuMeter(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/bgslibrary.h b/package_bgs/bgslibrary.h new file mode 100644 index 0000000..3895ba8 --- /dev/null +++ b/package_bgs/bgslibrary.h @@ -0,0 +1,65 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include "FrameDifference.h" +#include "StaticFrameDifference.h" +#include "WeightedMovingMean.h" +#include "WeightedMovingVariance.h" +#include "MixtureOfGaussianV1.h" // Only for OpenCV >= 2 +#include "MixtureOfGaussianV2.h" +#include "AdaptiveBackgroundLearning.h" +#include "AdaptiveSelectiveBackgroundLearning.h" +#include "KNN.h" // Only for OpenCV >= 3 +#include "GMG.h" // Only for OpenCV >= 2.4.3 +#include "DPAdaptiveMedian.h" +#include "DPGrimsonGMM.h" +#include "DPZivkovicAGMM.h" +#include "DPMean.h" +#include "DPWrenGA.h" +#include "DPPratiMediod.h" +#include "DPEigenbackground.h" +#include "DPTexture.h" +#include "T2FGMM_UM.h" +#include "T2FGMM_UV.h" +#include "T2FMRF_UM.h" +#include "T2FMRF_UV.h" +#include "FuzzySugenoIntegral.h" +#include "FuzzyChoquetIntegral.h" +#include "LBSimpleGaussian.h" +#include "LBFuzzyGaussian.h" +#include "LBMixtureOfGaussians.h" +#include "LBAdaptiveSOM.h" +#include "LBFuzzyAdaptiveSOM.h" +#include "LBP_MRF.h" +#include "MultiLayer.h" +#include "PixelBasedAdaptiveSegmenter.h" +#include "VuMeter.h" +#include "KDE.h" +#include "IndependentMultimodal.h" +#include "MultiCue.h" +#include "SigmaDelta.h" +#include "SuBSENSE.h" +#include "LOBSTER.h" +#include "PAWCS.h" +#include "TwoPoints.h" +#include "ViBe.h" + +//#include "_template_/MyBGS.h" +//#include "_template_/Amber.h" + +using namespace bgslibrary::algorithms; diff --git a/package_bgs/bl/SigmaDeltaBGS.cpp b/package_bgs/bl/SigmaDeltaBGS.cpp deleted file mode 100644 index a9c7914..0000000 --- a/package_bgs/bl/SigmaDeltaBGS.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "SigmaDeltaBGS.h" - -SigmaDeltaBGS::SigmaDeltaBGS() : -firstTime(true), -ampFactor(1), -minVar(15), -maxVar(255), -algorithm(sdLaMa091New()), -showOutput(true) { - - applyParams(); - std::cout << "SigmaDeltaBGS()" << std::endl; -} - -SigmaDeltaBGS::~SigmaDeltaBGS() { - sdLaMa091Free(algorithm); - std::cout << "~SigmaDeltaBGS()" << std::endl; -} - -void SigmaDeltaBGS::process( - const cv::Mat &img_input, - cv::Mat &img_output, - cv::Mat &img_bgmodel - ) { - if (img_input.empty()) - return; - - loadConfig(); - - if (firstTime) { - saveConfig(); - sdLaMa091AllocInit_8u_C3R(algorithm, img_input.data, img_input.cols, img_input.rows, img_input.step); - - firstTime = false; - return; - } - - img_output = cv::Mat(img_input.rows, img_input.cols, CV_8UC1); - cv::Mat img_output_tmp(img_input.rows, img_input.cols, CV_8UC3); - - sdLaMa091Update_8u_C3R(algorithm, img_input.data, img_output_tmp.data); - - unsigned char* tmpBuffer = (unsigned char*)img_output_tmp.data; - unsigned char* outBuffer = (unsigned char*)img_output.data; - - for (size_t i = 0; i < img_output.total(); ++i) { - *outBuffer = *tmpBuffer; - - ++outBuffer; - tmpBuffer += img_output_tmp.channels(); - } - - if (showOutput) - cv::imshow("Sigma-Delta", img_output); -} - -void SigmaDeltaBGS::saveConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/SigmaDeltaBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "ampFactor", ampFactor); - cvWriteInt(fs, "minVar", minVar); - cvWriteInt(fs, "maxVar", maxVar); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void SigmaDeltaBGS::loadConfig() { - CvFileStorage* fs = cvOpenFileStorage("./config/SigmaDeltaBGS.xml", 0, CV_STORAGE_READ); - - ampFactor = cvReadIntByName(fs, 0, "ampFactor", 1); - minVar = cvReadIntByName(fs, 0, "minVar", 15); - maxVar = cvReadIntByName(fs, 0, "maxVar", 255); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - applyParams(); - - cvReleaseFileStorage(&fs); -} - -void SigmaDeltaBGS::applyParams() { - sdLaMa091SetAmplificationFactor(algorithm, ampFactor); - sdLaMa091SetMinimalVariance(algorithm, minVar); - sdLaMa091SetMaximalVariance(algorithm, maxVar); -} diff --git a/package_bgs/bl/SigmaDeltaBGS.h b/package_bgs/bl/SigmaDeltaBGS.h deleted file mode 100644 index a4be271..0000000 --- a/package_bgs/bl/SigmaDeltaBGS.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -//extern "C" { -#include "sdLaMa091.h" -//} - -class SigmaDeltaBGS : public IBGS { -private: - - bool firstTime; - unsigned int ampFactor; - unsigned int minVar; - unsigned int maxVar; - sdLaMa091_t* algorithm; - bool showOutput; - -public: - - SigmaDeltaBGS(); - - ~SigmaDeltaBGS(); - - void process( - const cv::Mat &img_input, - cv::Mat &img_output, - cv::Mat &img_bgmodel - ); - -private: - - void saveConfig(); - - void loadConfig(); - - void applyParams(); -}; diff --git a/package_bgs/bl/stdbool.h b/package_bgs/bl/stdbool.h deleted file mode 100644 index abeb3b8..0000000 --- a/package_bgs/bl/stdbool.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -//#ifndef false -// #define false 0 -//#endif - -//#ifndef true -// #define true 1 -//#endif - -//#ifndef bool -// #define bool int -//#endif - -// #ifdef _WIN32 -// #endif diff --git a/package_bgs/ck/MEDefs.cpp b/package_bgs/ck/MEDefs.cpp deleted file mode 100644 index 9347353..0000000 --- a/package_bgs/ck/MEDefs.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of the AiBO+ project - * - * Copyright (C) 2005-2013 Csaba Kertész (csaba.kertesz@gmail.com) - * - * AiBO+ is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * AiBO+ is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#include "MEDefs.hpp" - -#include <math.h> - -float MERound(float number) -{ - double FracPart = 0.0; - double IntPart = 0.0; - float Ret = 0.0; - - FracPart = modf((double)number, &IntPart); - if (number >= 0) - { - Ret = (float)(FracPart >= 0.5 ? IntPart+1 : IntPart); - } else { - Ret = (float)(FracPart <= -0.5 ? IntPart-1 : IntPart); - } - return Ret; -} diff --git a/package_bgs/ck/README.TXT b/package_bgs/ck/README.TXT deleted file mode 100644 index d76c6a3..0000000 --- a/package_bgs/ck/README.TXT +++ /dev/null @@ -1,135 +0,0 @@ -################################################################### -# # -# MAXFLOW - software for computing mincut/maxflow in a graph # -# Version 2.2 # -# http://www.cs.cornell.edu/People/vnk/software.html # -# # -# Yuri Boykov (yuri@csd.uwo.ca) # -# Vladimir Kolmogorov (vnk@cs.cornell.edu) # -# 2001 # -# # -################################################################### - -1. Introduction. - -This software library implements the maxflow algorithm -described in - - An Experimental Comparison of Min-Cut/Max-Flow Algorithms - for Energy Minimization in Vision. - Yuri Boykov and Vladimir Kolmogorov. - In IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI), - September 2004 - -This algorithm was developed by Yuri Boykov and Vladimir Kolmogorov -at Siemens Corporate Research. To make it available for public use, -it was later reimplemented by Vladimir Kolmogorov based on open publications. - -If you use this software for research purposes, you should cite -the aforementioned paper in any resulting publication. - -Tested under windows, Visual C++ 6.0 compiler and unix (SunOS 5.8 -and RedHat Linux 7.0, GNU c++ compiler). - -################################################################## - -2. License. - - Copyright 2001 Vladimir Kolmogorov (vnk@cs.cornell.edu), Yuri Boykov (yuri@csd.uwo.ca). - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -################################################################## - -3. Graph representation. - -There are two versions of the algorithm using different -graph representations (adjacency list and forward star). -The former one uses more than twice as much memory as the -latter one but is 10-20% faster. - -Memory allocation (assuming that all capacities are 'short' - 2 bytes): - - | Nodes | Arcs ------------------------------------------- -Adjacency list | *24 bytes | *14 bytes -Forward star | *28 bytes | 6 bytes - -(* means that often it should be rounded up to be a multiple of 4 -- some compilers (e.g. Visual C++) seem to round up elements -of arrays unless the are structures containing only char[].) - -Note that arcs are always added in pairs - in forward and reverse directions. -Arcs between nodes and terminals (the source and the sink) are -not stored as arcs, but rather as a part of nodes. - -The assumption for the forward star representation is that -the maximum number of arcs per node (except the source -and the sink) is much less than ARC_BLOCK_SIZE (1024 by default). - -Both versions have the same interface. - -################################################################## - -4. Example usage. - -This section shows how to use the library to compute -a minimum cut on the following graph: - - SOURCE - / \ - 1/ \2 - / 3 \ - node0 -----> node1 - | <----- | - | 4 | - \ / - 5\ /6 - \ / - SINK - -/////////////////////////////////////////////////// - -#include <stdio.h> -#include "graph.h" - -void main() -{ - Graph::node_id nodes[2]; - Graph *g = new Graph(); - - nodes[0] = g -> add_node(); - nodes[1] = g -> add_node(); - g -> set_tweights(nodes[0], 1, 5); - g -> set_tweights(nodes[1], 2, 6); - g -> add_edge(nodes[0], nodes[1], 3, 4); - - Graph::flowtype flow = g -> maxflow(); - - printf("Flow = %d\n", flow); - printf("Minimum cut:\n"); - if (g->what_segment(nodes[0]) == Graph::SOURCE) - printf("node0 is in the SOURCE set\n"); - else - printf("node0 is in the SINK set\n"); - if (g->what_segment(nodes[1]) == Graph::SOURCE) - printf("node1 is in the SOURCE set\n"); - else - printf("node1 is in the SINK set\n"); - - delete g; -} - -/////////////////////////////////////////////////// diff --git a/package_bgs/db/IndependentMultimodalBGS.cpp b/package_bgs/db/IndependentMultimodalBGS.cpp deleted file mode 100644 index 5312075..0000000 --- a/package_bgs/db/IndependentMultimodalBGS.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "IndependentMultimodalBGS.h" - -IndependentMultimodalBGS::IndependentMultimodalBGS() : fps(10), firstTime(true), showOutput(true){ - pIMBS = new BackgroundSubtractorIMBS(fps); -} -IndependentMultimodalBGS::~IndependentMultimodalBGS(){ - delete pIMBS; -} - -void IndependentMultimodalBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - loadConfig(); - - if (firstTime) - saveConfig(); - - //get the fgmask and update the background model - pIMBS->apply(img_input, img_foreground); - - //get background image - pIMBS->getBackgroundImage(img_background); - - img_foreground.copyTo(img_output); - img_background.copyTo(img_bgmodel); - - if (showOutput) - { - cv::imshow("IMBS FG", img_foreground); - cv::imshow("IMBS BG", img_background); - } - - firstTime = false; -} - -void IndependentMultimodalBGS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/IndependentMultimodalBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void IndependentMultimodalBGS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/IndependentMultimodalBGS.xml", 0, CV_STORAGE_READ); - - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/db/IndependentMultimodalBGS.h b/package_bgs/db/IndependentMultimodalBGS.h deleted file mode 100644 index 64b83bd..0000000 --- a/package_bgs/db/IndependentMultimodalBGS.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include <opencv2/opencv.hpp> - - -#include "imbs.hpp" - -#include "../IBGS.h" - -class IndependentMultimodalBGS : public IBGS -{ -private: - BackgroundSubtractorIMBS* pIMBS; - int fps; - bool firstTime; - cv::Mat img_foreground; - cv::Mat img_background; - bool showOutput; - -public: - IndependentMultimodalBGS(); - ~IndependentMultimodalBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file diff --git a/package_bgs/dp/AdaptiveMedianBGS.cpp b/package_bgs/dp/AdaptiveMedianBGS.cpp index 16b3988..da1add9 100644 --- a/package_bgs/dp/AdaptiveMedianBGS.cpp +++ b/package_bgs/dp/AdaptiveMedianBGS.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * AdaptiveMedianBGS.cpp * -* Purpose: Implementation of the simple adaptive median background +* Purpose: Implementation of the simple adaptive median background * subtraction algorithm described in: * "Segmentation and tracking of piglets in images" * by McFarlane and Schofield @@ -37,77 +37,77 @@ using namespace Algorithms::BackgroundSubtraction; void AdaptiveMedianBGS::Initalize(const BgsParams& param) { - m_params = (AdaptiveMedianParams&)param; + m_params = (AdaptiveMedianParams&)param; - m_median = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - cvSet(m_median.Ptr(), CV_RGB(BACKGROUND,BACKGROUND,BACKGROUND)); + m_median = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + cvSet(m_median.Ptr(), CV_RGB(BACKGROUND, BACKGROUND, BACKGROUND)); } RgbImage* AdaptiveMedianBGS::Background() { - return &m_median; + return &m_median; } void AdaptiveMedianBGS::InitModel(const RgbImage& data) { - // initialize the background model - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - m_median(r,c) = data(r,c); - } - } + // initialize the background model + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + m_median(r, c) = data(r, c); + } + } } -void AdaptiveMedianBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void AdaptiveMedianBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - if(frame_num % m_params.SamplingRate() == 1) - { - // update background model - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // perform conditional updating only if we are passed the learning phase - if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames()) - { - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - if(data(r,c,ch) > m_median(r,c,ch)) - { - m_median(r,c,ch)++; - } - else if(data(r,c,ch) < m_median(r,c,ch)) - { - m_median(r,c,ch)--; - } - } - } - } - } - } + if (frame_num % m_params.SamplingRate() == 1) + { + // update background model + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // perform conditional updating only if we are passed the learning phase + if (update_mask(r, c) == BACKGROUND || frame_num < m_params.LearningFrames()) + { + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + if (data(r, c, ch) > m_median(r, c, ch)) + { + m_median(r, c, ch)++; + } + else if (data(r, c, ch) < m_median(r, c, ch)) + { + m_median(r, c, ch)--; + } + } + } + } + } + } } -void AdaptiveMedianBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& low_threshold, unsigned char& high_threshold) +void AdaptiveMedianBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& low_threshold, unsigned char& high_threshold) { - // perform background subtraction - low_threshold = high_threshold = FOREGROUND; - - int diffR = abs(pixel(0) - m_median(r,c,0)); - int diffG = abs(pixel(1) - m_median(r,c,1)); - int diffB = abs(pixel(2) - m_median(r,c,2)); - - if(diffR <= m_params.LowThreshold() && diffG <= m_params.LowThreshold() && diffB <= m_params.LowThreshold()) - { - low_threshold = BACKGROUND; - } - - if(diffR <= m_params.HighThreshold() && diffG <= m_params.HighThreshold() && diffB <= m_params.HighThreshold()) - { - high_threshold = BACKGROUND; - } + // perform background subtraction + low_threshold = high_threshold = FOREGROUND; + + int diffR = abs(pixel(0) - m_median(r, c, 0)); + int diffG = abs(pixel(1) - m_median(r, c, 1)); + int diffB = abs(pixel(2) - m_median(r, c, 2)); + + if (diffR <= m_params.LowThreshold() && diffG <= m_params.LowThreshold() && diffB <= m_params.LowThreshold()) + { + low_threshold = BACKGROUND; + } + + if (diffR <= m_params.HighThreshold() && diffG <= m_params.HighThreshold() && diffB <= m_params.HighThreshold()) + { + high_threshold = BACKGROUND; + } } /////////////////////////////////////////////////////////////////////////////// @@ -118,23 +118,23 @@ void AdaptiveMedianBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, // (the memory should already be reserved) // values: 255-foreground, 0-background /////////////////////////////////////////////////////////////////////////////// -void AdaptiveMedianBGS::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void AdaptiveMedianBGS::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - unsigned char low_threshold, high_threshold; - - // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // perform background subtraction - SubtractPixel(r, c, data(r,c), low_threshold, high_threshold); - - // setup silhouette mask - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; - } - } + unsigned char low_threshold, high_threshold; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // perform background subtraction + SubtractPixel(r, c, data(r, c), low_threshold, high_threshold); + + // setup silhouette mask + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + } + } } diff --git a/package_bgs/dp/AdaptiveMedianBGS.h b/package_bgs/dp/AdaptiveMedianBGS.h index d199b81..79a04b3 100644 --- a/package_bgs/dp/AdaptiveMedianBGS.h +++ b/package_bgs/dp/AdaptiveMedianBGS.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * AdaptiveMedianBGS.hpp * -* Purpose: Implementation of the simple adaptive median background +* Purpose: Implementation of the simple adaptive median background * subtraction algorithm described in: * "Segmentation and tracking of piglets in images" * by McFarlane and Schofield @@ -26,64 +26,65 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, September 2007 Example: - Algorithms::BackgroundSubtraction::AdaptiveMedianParams params; - params.SetFrameSize(width, height); - params.LowThreshold() = 40; - params.HighThreshold() = 2*params.LowThreshold(); - params.SamplingRate() = 7; - params.LearningFrames() = 30; - - Algorithms::BackgroundSubtraction::AdaptiveMedianBGS bgs; - bgs.Initalize(params); + Algorithms::BackgroundSubtraction::AdaptiveMedianParams params; + params.SetFrameSize(width, height); + params.LowThreshold() = 40; + params.HighThreshold() = 2*params.LowThreshold(); + params.SamplingRate() = 7; + params.LearningFrames() = 30; + + Algorithms::BackgroundSubtraction::AdaptiveMedianBGS bgs; + bgs.Initalize(params); ******************************************************************************/ +#pragma once #include "Bgs.h" namespace Algorithms { - namespace BackgroundSubtraction - { - // --- Parameters used by the Adaptive Median BGS algorithm --- - class AdaptiveMedianParams : public BgsParams - { - public: - unsigned char &LowThreshold() { return m_low_threshold; } - unsigned char &HighThreshold() { return m_high_threshold; } + namespace BackgroundSubtraction + { + // --- Parameters used by the Adaptive Median BGS algorithm --- + class AdaptiveMedianParams : public BgsParams + { + public: + unsigned char &LowThreshold() { return m_low_threshold; } + unsigned char &HighThreshold() { return m_high_threshold; } - int &SamplingRate() { return m_samplingRate; } - int &LearningFrames() { return m_learning_frames; } + int &SamplingRate() { return m_samplingRate; } + int &LearningFrames() { return m_learning_frames; } - private: - unsigned char m_low_threshold; - unsigned char m_high_threshold; + private: + unsigned char m_low_threshold; + unsigned char m_high_threshold; - int m_samplingRate; - int m_learning_frames; - }; + int m_samplingRate; + int m_learning_frames; + }; - // --- Adaptive Median BGS algorithm --- - class AdaptiveMedianBGS : public Bgs - { - public: - virtual ~AdaptiveMedianBGS() {} + // --- Adaptive Median BGS algorithm --- + class AdaptiveMedianBGS : public Bgs + { + public: + virtual ~AdaptiveMedianBGS() {} - void Initalize(const BgsParams& param); + void Initalize(const BgsParams& param); - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - RgbImage* Background(); + RgbImage* Background(); - private: - void SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& low_threshold, unsigned char& high_threshold); + private: + void SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& low_threshold, unsigned char& high_threshold); - AdaptiveMedianParams m_params; + AdaptiveMedianParams m_params; - RgbImage m_median; - }; - } + RgbImage m_median; + }; + } } diff --git a/package_bgs/dp/Bgs.h b/package_bgs/dp/Bgs.h index 5f91246..26fff70 100644 --- a/package_bgs/dp/Bgs.h +++ b/package_bgs/dp/Bgs.h @@ -23,45 +23,41 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, October 2007 * ******************************************************************************/ - -#ifndef BGS_H_ -#define BGS_H_ +#pragma once #include "Image.h" #include "BgsParams.h" namespace Algorithms { - namespace BackgroundSubtraction - { - class Bgs - { - public: - static const int BACKGROUND = 0; - static const int FOREGROUND = 255; +namespace BackgroundSubtraction +{ +class Bgs +{ +public: + static const int BACKGROUND = 0; + static const int FOREGROUND = 255; - virtual ~Bgs() {} + virtual ~Bgs() {} - // Initialize any data required by the BGS algorithm. Should be called once before calling - // any of the following functions. - virtual void Initalize(const BgsParams& param) = 0; + // Initialize any data required by the BGS algorithm. Should be called once before calling + // any of the following functions. + virtual void Initalize(const BgsParams& param) = 0; - // Initialize the background model. Typically, the background model is initialized using the first - // frame of the incoming video stream, but alternatives are possible. - virtual void InitModel(const RgbImage& data) = 0; + // Initialize the background model. Typically, the background model is initialized using the first + // frame of the incoming video stream, but alternatives are possible. + virtual void InitModel(const RgbImage& data) = 0; - // Subtract the current frame from the background model and produce a binary foreground mask using - // both a low and high threshold value. - virtual void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) = 0; + // Subtract the current frame from the background model and produce a binary foreground mask using + // both a low and high threshold value. + virtual void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) = 0; - // Update the background model. Only pixels set to background in update_mask are updated. - virtual void Update(int frame_num, const RgbImage& data, const BwImage& update_mask) = 0; + // Update the background model. Only pixels set to background in update_mask are updated. + virtual void Update(int frame_num, const RgbImage& data, const BwImage& update_mask) = 0; - // Return the current background model. - virtual RgbImage *Background() = 0; - }; - } + // Return the current background model. + virtual RgbImage *Background() = 0; +}; +} } - -#endif diff --git a/package_bgs/dp/BgsParams.h b/package_bgs/dp/BgsParams.h index a63b1ac..d2e7d29 100644 --- a/package_bgs/dp/BgsParams.h +++ b/package_bgs/dp/BgsParams.h @@ -24,36 +24,32 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, May 2008 * ******************************************************************************/ - -#ifndef BGS_PARAMS_H_ -#define BGS_PARAMS_H_ +#pragma once namespace Algorithms { - namespace BackgroundSubtraction - { - class BgsParams - { - public: - virtual ~BgsParams() {} - - virtual void SetFrameSize(unsigned int width, unsigned int height) - { - m_width = width; - m_height = height; - m_size = width*height; - } - - unsigned int &Width() { return m_width; } - unsigned int &Height() { return m_height; } - unsigned int &Size() { return m_size; } - - protected: - unsigned int m_width; - unsigned int m_height; - unsigned int m_size; - }; - } +namespace BackgroundSubtraction +{ +class BgsParams +{ +public: + virtual ~BgsParams() {} + + virtual void SetFrameSize(unsigned int width, unsigned int height) + { + m_width = width; + m_height = height; + m_size = width*height; + } + + unsigned int &Width() { return m_width; } + unsigned int &Height() { return m_height; } + unsigned int &Size() { return m_size; } + +protected: + unsigned int m_width; + unsigned int m_height; + unsigned int m_size; +}; +} } - -#endif diff --git a/package_bgs/dp/DPAdaptiveMedianBGS.cpp b/package_bgs/dp/DPAdaptiveMedianBGS.cpp deleted file mode 100644 index 0ae68fe..0000000 --- a/package_bgs/dp/DPAdaptiveMedianBGS.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "DPAdaptiveMedianBGS.h" - -DPAdaptiveMedianBGS::DPAdaptiveMedianBGS() : firstTime(true), frameNumber(0), threshold(40), samplingRate(7), learningFrames(30), showOutput(true) -{ - std::cout << "DPAdaptiveMedianBGS()" << std::endl; -} - -DPAdaptiveMedianBGS::~DPAdaptiveMedianBGS() -{ - std::cout << "~DPAdaptiveMedianBGS()" << std::endl; -} - -void DPAdaptiveMedianBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - loadConfig(); - - if(firstTime) - saveConfig(); - - frame = new IplImage(img_input); - - if(firstTime) - frame_data.ReleaseMemory(false); - frame_data = frame; - - if(firstTime) - { - int width = img_input.size().width; - int height = img_input.size().height; - - lowThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - lowThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - highThresholdMask = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); - highThresholdMask.Ptr()->origin = IPL_ORIGIN_BL; - - params.SetFrameSize(width, height); - params.LowThreshold() = threshold; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing - params.SamplingRate() = samplingRate; - params.LearningFrames() = learningFrames; - - bgs.Initalize(params); - bgs.InitModel(frame_data); - - std::cout << "threshold: " << threshold << std::endl; - std::cout << "samplingRate: " << samplingRate << std::endl; - std::cout << "learningFrames: " << learningFrames << std::endl; - std::cout << "showOutput: " << showOutput << std::endl; - } - - bgs.Subtract(frameNumber, frame_data, lowThresholdMask, highThresholdMask); - lowThresholdMask.Clear(); - bgs.Update(frameNumber, frame_data, lowThresholdMask); - - cv::Mat foreground(highThresholdMask.Ptr()); - cv::Mat background(bgs.Background()->Ptr()); - - if(showOutput){ - cv::imshow("Adaptive Median FG (McFarlane&Schofield)", foreground); - cv::imshow("Adaptive Median BG (McFarlane&Schofield)", background); - } - - foreground.copyTo(img_output); - background.copyTo(img_bgmodel); - - delete frame; - firstTime = false; - frameNumber++; -} - -void DPAdaptiveMedianBGS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/DPAdaptiveMedianBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteInt(fs, "threshold", threshold); - cvWriteInt(fs, "samplingRate", samplingRate); - cvWriteInt(fs, "learningFrames", learningFrames); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void DPAdaptiveMedianBGS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/DPAdaptiveMedianBGS.xml", 0, CV_STORAGE_READ); - - threshold = cvReadIntByName(fs, 0, "threshold", 40); - samplingRate = cvReadIntByName(fs, 0, "samplingRate", 7); - learningFrames = cvReadIntByName(fs, 0, "learningFrames", 30); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/dp/DPAdaptiveMedianBGS.h b/package_bgs/dp/DPAdaptiveMedianBGS.h deleted file mode 100644 index a5dd387..0000000 --- a/package_bgs/dp/DPAdaptiveMedianBGS.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "AdaptiveMedianBGS.h" - -using namespace Algorithms::BackgroundSubtraction; - -class DPAdaptiveMedianBGS : public IBGS -{ -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - AdaptiveMedianParams params; - AdaptiveMedianBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - int samplingRate; - int learningFrames; - bool showOutput; - -public: - DPAdaptiveMedianBGS(); - ~DPAdaptiveMedianBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - diff --git a/package_bgs/dp/DPPratiMediodBGS.h b/package_bgs/dp/DPPratiMediodBGS.h deleted file mode 100644 index 8aa6416..0000000 --- a/package_bgs/dp/DPPratiMediodBGS.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "PratiMediodBGS.h" - -using namespace Algorithms::BackgroundSubtraction; - -class DPPratiMediodBGS : public IBGS -{ -private: - bool firstTime; - long frameNumber; - IplImage* frame; - RgbImage frame_data; - - PratiParams params; - PratiMediodBGS bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - int threshold; - int samplingRate; - int historySize; - int weight; - bool showOutput; - -public: - DPPratiMediodBGS(); - ~DPPratiMediodBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - diff --git a/package_bgs/dp/DPTextureBGS.h b/package_bgs/dp/DPTextureBGS.h deleted file mode 100644 index c29e7e9..0000000 --- a/package_bgs/dp/DPTextureBGS.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "TextureBGS.h" -//#include "ConnectedComponents.h" - -class DPTextureBGS : public IBGS -{ -private: - bool firstTime; - bool showOutput; - - int width; - int height; - int size; - TextureBGS bgs; - IplImage* frame; - RgbImage image; - BwImage fgMask; - BwImage tempMask; - TextureArray* bgModel; - RgbImage texture; - unsigned char* modeArray; - TextureHistogram* curTextureHist; - //ConnectedComponents cc; - //CBlobResult largeBlobs; - //IplConvKernel* dilateElement; - //IplConvKernel* erodeElement; - //bool enableFiltering; - -public: - DPTextureBGS(); - ~DPTextureBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/dp/Eigenbackground.cpp b/package_bgs/dp/Eigenbackground.cpp index 2d2c3ef..dceb4cd 100644 --- a/package_bgs/dp/Eigenbackground.cpp +++ b/package_bgs/dp/Eigenbackground.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Eigenbackground.cpp * -* Purpose: Implementation of the Eigenbackground background subtraction +* Purpose: Implementation of the Eigenbackground background subtraction * algorithm developed by Oliver et al. * * Author: Donovan Parks, September 2007 @@ -34,157 +34,157 @@ using namespace Algorithms::BackgroundSubtraction; Eigenbackground::Eigenbackground() { - m_pcaData = NULL; - m_pcaAvg = NULL; - m_eigenValues = NULL; - m_eigenVectors = NULL; + m_pcaData = NULL; + m_pcaAvg = NULL; + m_eigenValues = NULL; + m_eigenVectors = NULL; } Eigenbackground::~Eigenbackground() { - if(m_pcaData != NULL) cvReleaseMat(&m_pcaData); - if(m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg); - if(m_eigenValues != NULL) cvReleaseMat(&m_eigenValues); - if(m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors); + if (m_pcaData != NULL) cvReleaseMat(&m_pcaData); + if (m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg); + if (m_eigenValues != NULL) cvReleaseMat(&m_eigenValues); + if (m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors); } void Eigenbackground::Initalize(const BgsParams& param) { - m_params = (EigenbackgroundParams&)param; - - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - m_background.Clear(); + m_params = (EigenbackgroundParams&)param; + + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_background.Clear(); } void Eigenbackground::InitModel(const RgbImage& data) { - if(m_pcaData != NULL) cvReleaseMat(&m_pcaData); - if(m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg); - if(m_eigenValues != NULL) cvReleaseMat(&m_eigenValues); - if(m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors); + if (m_pcaData != NULL) cvReleaseMat(&m_pcaData); + if (m_pcaAvg != NULL) cvReleaseMat(&m_pcaAvg); + if (m_eigenValues != NULL) cvReleaseMat(&m_eigenValues); + if (m_eigenVectors != NULL) cvReleaseMat(&m_eigenVectors); - m_pcaData = cvCreateMat(m_params.HistorySize(), m_params.Size()*3, CV_8UC1); + m_pcaData = cvCreateMat(m_params.HistorySize(), m_params.Size() * 3, CV_8UC1); - m_background.Clear(); + m_background.Clear(); } -void Eigenbackground::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void Eigenbackground::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - // the eigenbackground model is not updated (serious limitation!) + // the eigenbackground model is not updated (serious limitation!) } -void Eigenbackground::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void Eigenbackground::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - // create eigenbackground - if(frame_num == m_params.HistorySize()) - { - // create the eigenspace - m_pcaAvg = cvCreateMat( 1, m_pcaData->cols, CV_32F ); - m_eigenValues = cvCreateMat( m_pcaData->rows, 1, CV_32F ); - m_eigenVectors = cvCreateMat( m_pcaData->rows, m_pcaData->cols, CV_32F ); - cvCalcPCA(m_pcaData, m_pcaAvg, m_eigenValues, m_eigenVectors, CV_PCA_DATA_AS_ROW); - - int index = 0; - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - for(int ch = 0; ch < m_background.Ptr()->nChannels; ++ch) - { - m_background(r,c,0) = static_cast<unsigned char>(cvmGet(m_pcaAvg,0,index)+0.5); - index++; - } - } - } - } - - if(frame_num >= m_params.HistorySize()) - { - // project new image into the eigenspace - int w = data.Ptr()->width; - int h = data.Ptr()->height; - int ch = data.Ptr()->nChannels; - CvMat* dataPt = cvCreateMat(1, w*h*ch, CV_8UC1); - CvMat data_row; - cvGetRow(dataPt, &data_row, 0); - cvReshape(&data_row, &data_row, 3, data.Ptr()->height); - cvCopy(data.Ptr(), &data_row); - - CvMat* proj = cvCreateMat(1, m_params.EmbeddedDim(), CV_32F); - cvProjectPCA(dataPt, m_pcaAvg, m_eigenVectors, proj); - - // reconstruct point - CvMat* result = cvCreateMat(1, m_pcaData->cols, CV_32F); - cvBackProjectPCA(proj, m_pcaAvg, m_eigenVectors, result); - - // calculate Euclidean distance between new image and its eigenspace projection - int index = 0; - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - double dist = 0; - bool bgLow = true; - bool bgHigh = true; - for(int ch = 0; ch < 3; ++ch) - { - dist = (data(r,c,ch) - cvmGet(result,0,index))*(data(r,c,ch) - cvmGet(result,0,index)); - if(dist > m_params.LowThreshold()) - bgLow = false; - if(dist > m_params.HighThreshold()) - bgHigh = false; - index++; - } - - if(!bgLow) - { - low_threshold_mask(r,c) = FOREGROUND; - } - else - { - low_threshold_mask(r,c) = BACKGROUND; - } - - if(!bgHigh) - { - high_threshold_mask(r,c) = FOREGROUND; - } - else - { - high_threshold_mask(r,c) = BACKGROUND; - } - } - } - - cvReleaseMat(&result); - cvReleaseMat(&proj); - cvReleaseMat(&dataPt); - } - else - { - // set entire image to background since there is not enough information yet - // to start performing background subtraction - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - low_threshold_mask(r,c) = BACKGROUND; - high_threshold_mask(r,c) = BACKGROUND; - } - } - } - - UpdateHistory(frame_num, data); + // create eigenbackground + if (frame_num == m_params.HistorySize()) + { + // create the eigenspace + m_pcaAvg = cvCreateMat(1, m_pcaData->cols, CV_32F); + m_eigenValues = cvCreateMat(m_pcaData->rows, 1, CV_32F); + m_eigenVectors = cvCreateMat(m_pcaData->rows, m_pcaData->cols, CV_32F); + cvCalcPCA(m_pcaData, m_pcaAvg, m_eigenValues, m_eigenVectors, CV_PCA_DATA_AS_ROW); + + int index = 0; + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + for (int ch = 0; ch < m_background.Ptr()->nChannels; ++ch) + { + m_background(r, c, 0) = static_cast<unsigned char>(cvmGet(m_pcaAvg, 0, index) + 0.5); + index++; + } + } + } + } + + if (frame_num >= m_params.HistorySize()) + { + // project new image into the eigenspace + int w = data.Ptr()->width; + int h = data.Ptr()->height; + int ch = data.Ptr()->nChannels; + CvMat* dataPt = cvCreateMat(1, w*h*ch, CV_8UC1); + CvMat data_row; + cvGetRow(dataPt, &data_row, 0); + cvReshape(&data_row, &data_row, 3, data.Ptr()->height); + cvCopy(data.Ptr(), &data_row); + + CvMat* proj = cvCreateMat(1, m_params.EmbeddedDim(), CV_32F); + cvProjectPCA(dataPt, m_pcaAvg, m_eigenVectors, proj); + + // reconstruct point + CvMat* result = cvCreateMat(1, m_pcaData->cols, CV_32F); + cvBackProjectPCA(proj, m_pcaAvg, m_eigenVectors, result); + + // calculate Euclidean distance between new image and its eigenspace projection + int index = 0; + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + double dist = 0; + bool bgLow = true; + bool bgHigh = true; + for (int ch = 0; ch < 3; ++ch) + { + dist = (data(r, c, ch) - cvmGet(result, 0, index))*(data(r, c, ch) - cvmGet(result, 0, index)); + if (dist > m_params.LowThreshold()) + bgLow = false; + if (dist > m_params.HighThreshold()) + bgHigh = false; + index++; + } + + if (!bgLow) + { + low_threshold_mask(r, c) = FOREGROUND; + } + else + { + low_threshold_mask(r, c) = BACKGROUND; + } + + if (!bgHigh) + { + high_threshold_mask(r, c) = FOREGROUND; + } + else + { + high_threshold_mask(r, c) = BACKGROUND; + } + } + } + + cvReleaseMat(&result); + cvReleaseMat(&proj); + cvReleaseMat(&dataPt); + } + else + { + // set entire image to background since there is not enough information yet + // to start performing background subtraction + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + low_threshold_mask(r, c) = BACKGROUND; + high_threshold_mask(r, c) = BACKGROUND; + } + } + } + + UpdateHistory(frame_num, data); } void Eigenbackground::UpdateHistory(int frame_num, const RgbImage& new_frame) { - if(frame_num < m_params.HistorySize()) - { - CvMat src_row; - cvGetRow(m_pcaData, &src_row, frame_num); - cvReshape(&src_row, &src_row, 3, new_frame.Ptr()->height); - cvCopy(new_frame.Ptr(), &src_row); - } + if (frame_num < m_params.HistorySize()) + { + CvMat src_row; + cvGetRow(m_pcaData, &src_row, frame_num); + cvReshape(&src_row, &src_row, 3, new_frame.Ptr()->height); + cvCopy(new_frame.Ptr(), &src_row); + } } diff --git a/package_bgs/dp/Eigenbackground.h b/package_bgs/dp/Eigenbackground.h index 721b735..10ed189 100644 --- a/package_bgs/dp/Eigenbackground.h +++ b/package_bgs/dp/Eigenbackground.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Eigenbackground.hpp * -* Purpose: Implementation of the Eigenbackground background subtraction +* Purpose: Implementation of the Eigenbackground background subtraction * algorithm developed by Oliver et al. * * Author: Donovan Parks, September 2007 @@ -30,16 +30,14 @@ Example: Algorithms::BackgroundSubtraction::EigenbackgroundParams params; params.SetFrameSize(width, height); params.LowThreshold() = 15*15; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing +params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing params.HistorySize() = 100; params.EmbeddedDim() = 20; Algorithms::BackgroundSubtraction::Eigenbackground bgs; bgs.Initalize(params); ******************************************************************************/ - -#ifndef _ELGAMMAL_H_ -#define _ELGAMMAL_H_ +#pragma once #include "Bgs.h" @@ -77,9 +75,9 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background() { return &m_background; } @@ -90,12 +88,10 @@ namespace Algorithms CvMat* m_pcaData; CvMat* m_pcaAvg; - CvMat* m_eigenValues; + CvMat* m_eigenValues; CvMat* m_eigenVectors; RgbImage m_background; }; } } - -#endif diff --git a/package_bgs/dp/Error.h b/package_bgs/dp/Error.h index cdbb222..81cbbeb 100644 --- a/package_bgs/dp/Error.h +++ b/package_bgs/dp/Error.h @@ -23,14 +23,9 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, July 2007 * ******************************************************************************/ - -#ifndef ERROR_H -#define ERROR_H +#pragma once bool Error(const char* msg, const char* code, int data); - bool TraceInit(const char* filename); void Trace(const char* msg); void TraceClose(); - -#endif diff --git a/package_bgs/dp/GrimsonGMM.cpp b/package_bgs/dp/GrimsonGMM.cpp index ff9c262..4cf6f35 100644 --- a/package_bgs/dp/GrimsonGMM.cpp +++ b/package_bgs/dp/GrimsonGMM.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * GrimsonGMM.cpp * -* Purpose: Implementation of the Gaussian mixture model (GMM) background +* Purpose: Implementation of the Gaussian mixture model (GMM) background * subtraction described in: * "Adaptive background mixture models for real-time tracking" * by Chris Stauffer and W.E.L Grimson @@ -26,16 +26,16 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, September 2007 * * This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: +* background subtraction algorithm: * * "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic +* Z.Zivkovic * International Conference Pattern Recognition, UK, August, 2004 * * -* "Efficient Adaptive Density Estimapion per Image Pixel for the +* "Efficient Adaptive Density Estimapion per Image Pixel for the * Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden +* Z.Zivkovic, F. van der Heijden * Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. * * Zivkovic's code can be obtained at: www.zoranz.net @@ -47,252 +47,252 @@ using namespace Algorithms::BackgroundSubtraction; int compareGMM(const void* _gmm1, const void* _gmm2) { - GMM gmm1 = *(GMM*)_gmm1; - GMM gmm2 = *(GMM*)_gmm2; - - if(gmm1.significants < gmm2.significants) - return 1; - else if(gmm1.significants == gmm2.significants) - return 0; - else - return -1; + GMM gmm1 = *(GMM*)_gmm1; + GMM gmm2 = *(GMM*)_gmm2; + + if (gmm1.significants < gmm2.significants) + return 1; + else if (gmm1.significants == gmm2.significants) + return 0; + else + return -1; } GrimsonGMM::GrimsonGMM() { - m_modes = NULL; + m_modes = NULL; } GrimsonGMM::~GrimsonGMM() { - delete[] m_modes; + delete[] m_modes; } void GrimsonGMM::Initalize(const BgsParams& param) { - m_params = (GrimsonParams&)param; + m_params = (GrimsonParams&)param; - // Tbf - the threshold - m_bg_threshold = 0.75f; // 1-cf from the paper + // Tbf - the threshold + m_bg_threshold = 0.75f; // 1-cf from the paper - // Tgenerate - the threshold - m_variance = 36.0f; // sigma for the new mode + // Tgenerate - the threshold + m_variance = 36.0f; // sigma for the new mode - // GMM for each pixel - m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; + // GMM for each pixel + m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; - // used modes per pixel - m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + // used modes per pixel + m_modes_per_pixel = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); } RgbImage* GrimsonGMM::Background() { - return &m_background; + return &m_background; } void GrimsonGMM::InitModel(const RgbImage& data) { - m_modes_per_pixel.Clear(); - - for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) - { - m_modes[i].weight = 0; - m_modes[i].variance = 0; - m_modes[i].muR = 0; - m_modes[i].muG = 0; - m_modes[i].muB = 0; - m_modes[i].significants = 0; - } + m_modes_per_pixel.Clear(); + + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + { + m_modes[i].weight = 0; + m_modes[i].variance = 0; + m_modes[i].muR = 0; + m_modes[i].muG = 0; + m_modes[i].muB = 0; + m_modes[i].significants = 0; + } } -void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void GrimsonGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - // it doesn't make sense to have conditional updates in the GMM framework + // it doesn't make sense to have conditional updates in the GMM framework } -void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& low_threshold, unsigned char& high_threshold) +void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& low_threshold, unsigned char& high_threshold) { - // calculate distances to the modes (+ sort???) - // here we need to go in descending order!!! - long pos; - bool bFitsPDF=false; - bool bBackgroundLow=false; - bool bBackgroundHigh=false; - - float fOneMinAlpha = 1-m_params.Alpha(); - - float totalWeight = 0.0f; - - // calculate number of Gaussians to include in the background model - int backgroundGaussians = 0; - double sum = 0.0; - for(int i = 0; i < numModes; ++i) - { - if(sum < m_bg_threshold) - { - backgroundGaussians++; - sum += m_modes[posPixel+i].weight; - } - else - { - break; - } - } - - // update all distributions and check for match with current pixel - for (int iModes=0; iModes < numModes; iModes++) - { - pos=posPixel+iModes; - float weight = m_modes[pos].weight; - - // fit not found yet - if (!bFitsPDF) - { - //check if it belongs to some of the modes - //calculate distance - float var = m_modes[pos].variance; - float muR = m_modes[pos].muR; - float muG = m_modes[pos].muG; - float muB = m_modes[pos].muB; - - float dR=muR - pixel(0); - float dG=muG - pixel(1); - float dB=muB - pixel(2); - - // calculate the squared distance - float dist = (dR*dR + dG*dG + dB*dB); - - if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) - bBackgroundHigh = true; - - // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution - if(dist < m_params.LowThreshold()*var) - { - bFitsPDF=true; - - // check if this Gaussian is part of the background model - if(iModes < backgroundGaussians) - bBackgroundLow = true; - - //update distribution - float k = m_params.Alpha()/weight; - weight = fOneMinAlpha*weight + m_params.Alpha(); - m_modes[pos].weight = weight; - m_modes[pos].muR = muR - k*(dR); - m_modes[pos].muG = muG - k*(dG); - m_modes[pos].muB = muB - k*(dB); - - //limit the variance - float sigmanew = var + k*(dist-var); - m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight=0.0; - numModes--; - } - - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - } - else - { - weight = fOneMinAlpha*weight; - if (weight < 0.0) - { - weight=0.0; - numModes--; - } - m_modes[pos].weight = weight; - m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); - } - - totalWeight += weight; - } - - // renormalize weights so they add to one - double invTotalWeight = 1.0 / totalWeight; - for (int iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight - / sqrt(m_modes[posPixel + iLocal].variance); - } - - // Sort significance values so they are in desending order. - qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM); - - // make new mode if needed and exit - if (!bFitsPDF) - { - if (numModes < m_params.MaxModes()) - { - numModes++; - } - else - { - // the weakest mode will be replaced - } - - pos = posPixel + numModes-1; - - m_modes[pos].muR = pixel.ch[0]; - m_modes[pos].muG = pixel.ch[1]; - m_modes[pos].muB = pixel.ch[2]; - m_modes[pos].variance = m_variance; - m_modes[pos].significants = 0; // will be set below - - if (numModes==1) - m_modes[pos].weight = 1; - else - m_modes[pos].weight = m_params.Alpha(); - - //renormalize weights - int iLocal; - float sum = 0.0; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - sum += m_modes[posPixel+ iLocal].weight; - } - - double invSum = 1.0/sum; - for (iLocal = 0; iLocal < numModes; iLocal++) - { - m_modes[posPixel + iLocal].weight *= (float)invSum; - m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight - / sqrt(m_modes[posPixel + iLocal].variance); - - } - } - - // Sort significance values so they are in desending order. - qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM); - - if(bBackgroundLow) - { - low_threshold = BACKGROUND; - } - else - { - low_threshold = FOREGROUND; - } - - if(bBackgroundHigh) - { - high_threshold = BACKGROUND; - } - else - { - high_threshold = FOREGROUND; - } + // calculate distances to the modes (+ sort???) + // here we need to go in descending order!!! + long pos; + bool bFitsPDF = false; + bool bBackgroundLow = false; + bool bBackgroundHigh = false; + + float fOneMinAlpha = 1 - m_params.Alpha(); + + float totalWeight = 0.0f; + + // calculate number of Gaussians to include in the background model + int backgroundGaussians = 0; + double sum = 0.0; + for (int i = 0; i < numModes; ++i) + { + if (sum < m_bg_threshold) + { + backgroundGaussians++; + sum += m_modes[posPixel + i].weight; + } + else + { + break; + } + } + + // update all distributions and check for match with current pixel + for (int iModes = 0; iModes < numModes; iModes++) + { + pos = posPixel + iModes; + float weight = m_modes[pos].weight; + + // fit not found yet + if (!bFitsPDF) + { + //check if it belongs to some of the modes + //calculate distance + float var = m_modes[pos].variance; + float muR = m_modes[pos].muR; + float muG = m_modes[pos].muG; + float muB = m_modes[pos].muB; + + float dR = muR - pixel(0); + float dG = muG - pixel(1); + float dB = muB - pixel(2); + + // calculate the squared distance + float dist = (dR*dR + dG*dG + dB*dB); + + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + bBackgroundHigh = true; + + // a match occurs when the pixel is within sqrt(fTg) standard deviations of the distribution + if (dist < m_params.LowThreshold()*var) + { + bFitsPDF = true; + + // check if this Gaussian is part of the background model + if (iModes < backgroundGaussians) + bBackgroundLow = true; + + //update distribution + float k = m_params.Alpha() / weight; + weight = fOneMinAlpha*weight + m_params.Alpha(); + m_modes[pos].weight = weight; + m_modes[pos].muR = muR - k*(dR); + m_modes[pos].muG = muG - k*(dG); + m_modes[pos].muB = muB - k*(dB); + + //limit the variance + float sigmanew = var + k*(dist - var); + m_modes[pos].variance = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + } + else + { + weight = fOneMinAlpha*weight; + if (weight < 0.0) + { + weight = 0.0; + numModes--; + } + m_modes[pos].weight = weight; + m_modes[pos].significants = m_modes[pos].weight / sqrt(m_modes[pos].variance); + } + + totalWeight += weight; + } + + // renormalize weights so they add to one + double invTotalWeight = 1.0 / totalWeight; + for (int iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invTotalWeight; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + / sqrt(m_modes[posPixel + iLocal].variance); + } + + // Sort significance values so they are in desending order. + qsort(&m_modes[posPixel], numModes, sizeof(GMM), compareGMM); + + // make new mode if needed and exit + if (!bFitsPDF) + { + if (numModes < m_params.MaxModes()) + { + numModes++; + } + else + { + // the weakest mode will be replaced + } + + pos = posPixel + numModes - 1; + + m_modes[pos].muR = pixel.ch[0]; + m_modes[pos].muG = pixel.ch[1]; + m_modes[pos].muB = pixel.ch[2]; + m_modes[pos].variance = m_variance; + m_modes[pos].significants = 0; // will be set below + + if (numModes == 1) + m_modes[pos].weight = 1; + else + m_modes[pos].weight = m_params.Alpha(); + + //renormalize weights + int iLocal; + float sum = 0.0; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + sum += m_modes[posPixel + iLocal].weight; + } + + double invSum = 1.0 / sum; + for (iLocal = 0; iLocal < numModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= (float)invSum; + m_modes[posPixel + iLocal].significants = m_modes[posPixel + iLocal].weight + / sqrt(m_modes[posPixel + iLocal].variance); + + } + } + + // Sort significance values so they are in desending order. + qsort(&(m_modes[posPixel]), numModes, sizeof(GMM), compareGMM); + + if (bBackgroundLow) + { + low_threshold = BACKGROUND; + } + else + { + low_threshold = FOREGROUND; + } + + if (bBackgroundHigh) + { + high_threshold = BACKGROUND; + } + else + { + high_threshold = FOREGROUND; + } } /////////////////////////////////////////////////////////////////////////////// @@ -303,29 +303,29 @@ void GrimsonGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned ch // (the memory should already be reserved) // values: 255-foreground, 125-shadow, 0-background /////////////////////////////////////////////////////////////////////////////// -void GrimsonGMM::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void GrimsonGMM::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - unsigned char low_threshold, high_threshold; - long posPixel; - - // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // update model + background subtract - posPixel=(r*m_params.Width()+c)*m_params.MaxModes(); - - SubtractPixel(posPixel, data(r,c), m_modes_per_pixel(r,c), low_threshold, high_threshold); - - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; - - m_background(r,c,0) = (unsigned char)m_modes[posPixel].muR; - m_background(r,c,1) = (unsigned char)m_modes[posPixel].muG; - m_background(r,c,2) = (unsigned char)m_modes[posPixel].muB; - } - } + unsigned char low_threshold, high_threshold; + long posPixel; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // update model + background subtract + posPixel = (r*m_params.Width() + c)*m_params.MaxModes(); + + SubtractPixel(posPixel, data(r, c), m_modes_per_pixel(r, c), low_threshold, high_threshold); + + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + + m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; + } + } } diff --git a/package_bgs/dp/GrimsonGMM.h b/package_bgs/dp/GrimsonGMM.h index a177a80..2c0f772 100644 --- a/package_bgs/dp/GrimsonGMM.h +++ b/package_bgs/dp/GrimsonGMM.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * GrimsonGMM.cpp * -* Purpose: Implementation of the Gaussian mixture model (GMM) background +* Purpose: Implementation of the Gaussian mixture model (GMM) background * subtraction described in: * "Adaptive background mixture models for real-time tracking" * by Chris Stauffer and W.E.L Grimson @@ -26,125 +26,121 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * Author: Donovan Parks, September 2007 * * This code is based on code by Z. Zivkovic's written for his enhanced GMM -* background subtraction algorithm: +* background subtraction algorithm: * * "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic +* Z.Zivkovic * International Conference Pattern Recognition, UK, August, 2004 * * -* "Efficient Adaptive Density Estimapion per Image Pixel for the +* "Efficient Adaptive Density Estimapion per Image Pixel for the * Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden +* Z.Zivkovic, F. van der Heijden * Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. * * Zivkovic's code can be obtained at: www.zoranz.net Example: - Algorithms::BackgroundSubtraction::GrimsonParams params; - params.SetFrameSize(width, height); - params.LowThreshold() = 3.0f*3.0f; - params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing - params.Alpha() = 0.001f; - params.MaxModes() = 3; - - Algorithms::BackgroundSubtraction::GrimsonGMM bgs; - bgs.Initalize(params); + Algorithms::BackgroundSubtraction::GrimsonParams params; + params.SetFrameSize(width, height); + params.LowThreshold() = 3.0f*3.0f; + params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing + params.Alpha() = 0.001f; + params.MaxModes() = 3; + + Algorithms::BackgroundSubtraction::GrimsonGMM bgs; + bgs.Initalize(params); ******************************************************************************/ - -#ifndef GRIMSON_GMM_ -#define GRIMSON_GMM_ +#pragma once #include "Bgs.h" namespace Algorithms { - namespace BackgroundSubtraction - { - typedef struct GMMGaussian - { - float variance; - float muR; - float muG; - float muB; - float weight; - float significants; // this is equal to weight / standard deviation and is used to - // determine which Gaussians should be part of the background model - } GMM; - - // --- User adjustable parameters used by the Grimson GMM BGS algorithm --- - class GrimsonParams : public BgsParams - { - public: - float &LowThreshold() { return m_low_threshold; } - float &HighThreshold() { return m_high_threshold; } - - float &Alpha() { return m_alpha; } - int &MaxModes() { return m_max_modes; } - - private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values - // lead to a small number of components but they can grow too large. - // - // It is usual easiest to think of these thresholds as being the number of variances away - // from the mean of a pixel before it is considered to be from the foreground. - float m_low_threshold; - float m_high_threshold; - - // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. - float m_alpha; - - // Maximum number of modes (Gaussian components) that will be used per pixel - int m_max_modes; - }; - - // --- Grimson GMM BGS algorithm --- - class GrimsonGMM : public Bgs - { - public: - GrimsonGMM(); - ~GrimsonGMM(); - - void Initalize(const BgsParams& param); - - void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); - - RgbImage* Background(); - - private: - void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, - unsigned char& lowThreshold, unsigned char& highThreshold); - - // User adjustable parameters - GrimsonParams m_params; - - // Threshold when the component becomes significant enough to be included into - // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 - // For alpha=0.001 it means that the mode should exist for approximately 105 frames before - // it is considered foreground - float m_bg_threshold; //1-cf from the paper - - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. - // A simple way is to estimate the typical standard deviation from the images. - float m_variance; - - // Dynamic array for the mixture of Gaussians - GMM* m_modes; - - // Number of Gaussian components per pixel - BwImage m_modes_per_pixel; - - // Current background model - RgbImage m_background; - }; - } + namespace BackgroundSubtraction + { + typedef struct GMMGaussian + { + float variance; + float muR; + float muG; + float muB; + float weight; + float significants; // this is equal to weight / standard deviation and is used to + // determine which Gaussians should be part of the background model + } GMM; + + // --- User adjustable parameters used by the Grimson GMM BGS algorithm --- + class GrimsonParams : public BgsParams + { + public: + float &LowThreshold() { return m_low_threshold; } + float &HighThreshold() { return m_high_threshold; } + + float &Alpha() { return m_alpha; } + int &MaxModes() { return m_max_modes; } + + private: + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values + // lead to a small number of components but they can grow too large. + // + // It is usual easiest to think of these thresholds as being the number of variances away + // from the mean of a pixel before it is considered to be from the foreground. + float m_low_threshold; + float m_high_threshold; + + // alpha - speed of update - if the time interval you want to average over is T + // set alpha=1/T. + float m_alpha; + + // Maximum number of modes (Gaussian components) that will be used per pixel + int m_max_modes; + }; + + // --- Grimson GMM BGS algorithm --- + class GrimsonGMM : public Bgs + { + public: + GrimsonGMM(); + ~GrimsonGMM(); + + void Initalize(const BgsParams& param); + + void InitModel(const RgbImage& data); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + + RgbImage* Background(); + + private: + void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char& numModes, + unsigned char& lowThreshold, unsigned char& highThreshold); + + // User adjustable parameters + GrimsonParams m_params; + + // Threshold when the component becomes significant enough to be included into + // the background model. It is the TB = 1-cf from the paper. So I use cf=0.1 => TB=0.9 + // For alpha=0.001 it means that the mode should exist for approximately 105 frames before + // it is considered foreground + float m_bg_threshold; //1-cf from the paper + + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. + // A simple way is to estimate the typical standard deviation from the images. + float m_variance; + + // Dynamic array for the mixture of Gaussians + GMM* m_modes; + + // Number of Gaussian components per pixel + BwImage m_modes_per_pixel; + + // Current background model + RgbImage m_background; + }; + } } - -#endif diff --git a/package_bgs/dp/Image.cpp b/package_bgs/dp/Image.cpp index f00febd..92119c2 100644 --- a/package_bgs/dp/Image.cpp +++ b/package_bgs/dp/Image.cpp @@ -18,59 +18,59 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Image.hpp * -* Purpose: C++ wrapper for OpenCV IplImage which supports simple and +* Purpose: C++ wrapper for OpenCV IplImage which supports simple and * efficient access to the image data * * Author: Donovan Parks, September 2007 * -* Based on code from: +* Based on code from: * http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.hpptml ******************************************************************************/ #include "Image.h" ImageBase::~ImageBase() -{ - if(imgp != NULL && m_bReleaseMemory) +{ + if (imgp != NULL && m_bReleaseMemory) cvReleaseImage(&imgp); - imgp = NULL; + imgp = NULL; } void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue) { - for(int r = 1; r < image.Ptr()->height-1; ++r) + for (int r = 1; r < image.Ptr()->height - 1; ++r) { - for(int c = 1; c < image.Ptr()->width-1; ++c) + for (int c = 1; c < image.Ptr()->width - 1; ++c) { int count = 0; - if(image(r,c) == fgValue) + if (image(r, c) == fgValue) { - if(image(r-1,c-1) == fgValue) + if (image(r - 1, c - 1) == fgValue) count++; - if(image(r-1,c) == fgValue) + if (image(r - 1, c) == fgValue) count++; - if(image(r-1,c+1) == fgValue) + if (image(r - 1, c + 1) == fgValue) count++; - if(image(r,c-1) == fgValue) + if (image(r, c - 1) == fgValue) count++; - if(image(r,c+1) == fgValue) + if (image(r, c + 1) == fgValue) count++; - if(image(r+1,c-1) == fgValue) + if (image(r + 1, c - 1) == fgValue) count++; - if(image(r+1,c) == fgValue) + if (image(r + 1, c) == fgValue) count++; - if(image(r+1,c+1) == fgValue) + if (image(r + 1, c + 1) == fgValue) count++; - if(count < minDensity) - filtered(r,c) = 0; + if (count < minDensity) + filtered(r, c) = 0; else - filtered(r,c) = fgValue; + filtered(r, c) = fgValue; } else { - filtered(r,c) = 0; + filtered(r, c) = 0; } } } -} \ No newline at end of file +} diff --git a/package_bgs/dp/Image.h b/package_bgs/dp/Image.h index 58fe50d..6c0b5b3 100644 --- a/package_bgs/dp/Image.h +++ b/package_bgs/dp/Image.h @@ -18,17 +18,15 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Image.h * -* Purpose: C++ wrapper for OpenCV IplImage which supports simple and +* Purpose: C++ wrapper for OpenCV IplImage which supports simple and * efficient access to the image data * * Author: Donovan Parks, September 2007 * -* Based on code from: +* Based on code from: * http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/opencv-intro.html ******************************************************************************/ - -#ifndef _IMAGE_H_ -#define _IMAGE_H_ +#pragma once #include <opencv2/opencv.hpp> //#include <cxcore.h> @@ -36,30 +34,30 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. // --- Image Iterator --------------------------------------------------------- template <class T> -class ImageIterator +class ImageIterator { -public: - ImageIterator(IplImage* image, int x=0, int y=0, int dx= 0, int dy=0) : - i(x), j(y), i0(0) - { +public: + ImageIterator(IplImage* image, int x = 0, int y = 0, int dx = 0, int dy = 0) : + i(x), j(y), i0(0) + { data = reinterpret_cast<T*>(image->imageData); step = image->widthStep / sizeof(T); - nl= image->height; - if ((y+dy)>0 && (y+dy) < nl) - nl= y+dy; + nl = image->height; + if ((y + dy) > 0 && (y + dy) < nl) + nl = y + dy; - if (y<0) - j=0; + if (y < 0) + j = 0; data += step*j; nc = image->width; - if ((x+dx) > 0 && (x+dx) < nc) - nc = x+dx; + if ((x + dx) > 0 && (x + dx) < nc) + nc = x + dx; nc *= image->nChannels; - if (x>0) + if (x > 0) i0 = x*image->nChannels; i = i0; @@ -71,26 +69,26 @@ public: bool operator!() const { return j < nl; } /* next pixel */ - ImageIterator& operator++() + ImageIterator& operator++() { i++; - if (i >= nc) - { - i=i0; - j++; - data += step; + if (i >= nc) + { + i = i0; + j++; + data += step; } return *this; } - ImageIterator& operator+=(int s) + ImageIterator& operator+=(int s) { - i+=s; - if (i >= nc) - { - i=i0; - j++; - data += step; + i += s; + if (i >= nc) + { + i = i0; + j++; + data += step; } return *this; } @@ -101,18 +99,18 @@ public: const T operator*() const { return data[i]; } const T neighbor(int dx, int dy) const - { - return *(data+dy*step+i+dx); + { + return *(data + dy*step + i + dx); } - T* operator&() const { return data+i; } + T* operator&() const { return data + i; } /* current pixel coordinates */ - int column() const { return i/nch; } + int column() const { return i / nch; } int line() const { return j; } private: - int i, i0,j; + int i, i0, j; T* data; int step; int nl, nc; @@ -128,7 +126,7 @@ const unsigned char NUM_CHANNELS = 3; class RgbPixel { public: - RgbPixel() {;} + RgbPixel() { ; } RgbPixel(unsigned char _r, unsigned char _g, unsigned char _b) { ch[0] = _r; ch[1] = _g; ch[2] = _b; @@ -156,7 +154,7 @@ public: class RgbPixelFloat { public: - RgbPixelFloat() {;} + RgbPixelFloat() { ; } RgbPixelFloat(float _r, float _g, float _b) { ch[0] = _r; ch[1] = _g; ch[2] = _b; @@ -199,14 +197,14 @@ public: cvReleaseImage(&imgp); } - void operator=(IplImage* img) - { + void operator=(IplImage* img) + { imgp = img; } // copy-constructor ImageBase(const ImageBase& rhs) - { + { // it is very inefficent if this copy-constructor is called assert(false); } @@ -237,31 +235,31 @@ public: cvZero(imgp); } - void operator=(IplImage* img) - { + void operator=(IplImage* img) + { imgp = img; } // channel-level access using image(row, col, channel) inline unsigned char& operator()(const int r, const int c, const int ch) { - return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch]; + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; } inline const unsigned char& operator()(const int r, const int c, const int ch) const { - return (unsigned char &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels+ch]; + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels + ch]; } // RGB pixel-level access using image(row, col) - inline RgbPixel& operator()(const int r, const int c) + inline RgbPixel& operator()(const int r, const int c) { - return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels]; + return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; } inline const RgbPixel& operator()(const int r, const int c) const { - return (RgbPixel &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels]; + return (RgbPixel &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels]; } }; @@ -275,31 +273,31 @@ public: cvZero(imgp); } - void operator=(IplImage* img) - { + void operator=(IplImage* img) + { imgp = img; } // channel-level access using image(row, col, channel) inline float& operator()(const int r, const int c, const int ch) { - return (float &)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)]; + return (float &)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; } inline float operator()(const int r, const int c, const int ch) const { - return (float)imgp->imageData[r*imgp->widthStep+(c*imgp->nChannels+ch)*sizeof(float)]; + return (float)imgp->imageData[r*imgp->widthStep + (c*imgp->nChannels + ch) * sizeof(float)]; } // RGB pixel-level access using image(row, col) - inline RgbPixelFloat& operator()(const int r, const int c) + inline RgbPixelFloat& operator()(const int r, const int c) { - return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)]; + return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; } inline const RgbPixelFloat& operator()(const int r, const int c) const { - return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep+c*imgp->nChannels*sizeof(float)]; + return (RgbPixelFloat &)imgp->imageData[r*imgp->widthStep + c*imgp->nChannels * sizeof(float)]; } }; @@ -313,20 +311,20 @@ public: cvZero(imgp); } - void operator=(IplImage* img) - { + void operator=(IplImage* img) + { imgp = img; } // pixel-level access using image(row, col) inline unsigned char& operator()(const int r, const int c) { - return (unsigned char &)imgp->imageData[r*imgp->widthStep+c]; + return (unsigned char &)imgp->imageData[r*imgp->widthStep + c]; } inline unsigned char operator()(const int r, const int c) const { - return (unsigned char)imgp->imageData[r*imgp->widthStep+c]; + return (unsigned char)imgp->imageData[r*imgp->widthStep + c]; } }; @@ -340,25 +338,23 @@ public: cvZero(imgp); } - void operator=(IplImage* img) - { + void operator=(IplImage* img) + { imgp = img; } // pixel-level access using image(row, col) inline float& operator()(const int r, const int c) { - return (float &)imgp->imageData[r*imgp->widthStep+c*sizeof(float)]; + return (float &)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; } inline float operator()(const int r, const int c) const { - return (float)imgp->imageData[r*imgp->widthStep+c*sizeof(float)]; + return (float)imgp->imageData[r*imgp->widthStep + c * sizeof(float)]; } }; // --- Image Functions -------------------------------------------------------- void DensityFilter(BwImage& image, BwImage& filtered, int minDensity, unsigned char fgValue); - -#endif diff --git a/package_bgs/dp/MeanBGS.cpp b/package_bgs/dp/MeanBGS.cpp index b8df895..5178158 100644 --- a/package_bgs/dp/MeanBGS.cpp +++ b/package_bgs/dp/MeanBGS.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * MeanBGS.h * -* Purpose: Implementation of a simple temporal mean background +* Purpose: Implementation of a simple temporal mean background * subtraction algorithm. * * Author: Donovan Parks, September 2007 @@ -31,72 +31,72 @@ using namespace Algorithms::BackgroundSubtraction; void MeanBGS::Initalize(const BgsParams& param) { - m_params = (MeanParams&)param; + m_params = (MeanParams&)param; - m_mean = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_32F, 3); - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_mean = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_32F, 3); + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); } void MeanBGS::InitModel(const RgbImage& data) { - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - m_mean(r,c,ch) = (float)data(r,c,ch); - } - } - } + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + m_mean(r, c, ch) = (float)data(r, c, ch); + } + } + } } -void MeanBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void MeanBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - // update background model - for (unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // perform conditional updating only if we are passed the learning phase - if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames()) - { - // update B/G model - float mean; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - mean = m_params.Alpha() * m_mean(r,c,ch) + (1.0f-m_params.Alpha()) * data(r,c,ch); - m_mean(r,c,ch) = mean; - m_background(r,c,ch) = (unsigned char)(mean + 0.5); - } - } - } - } + // update background model + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // perform conditional updating only if we are passed the learning phase + if (update_mask(r, c) == BACKGROUND || frame_num < m_params.LearningFrames()) + { + // update B/G model + float mean; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + mean = m_params.Alpha() * m_mean(r, c, ch) + (1.0f - m_params.Alpha()) * data(r, c, ch); + m_mean(r, c, ch) = mean; + m_background(r, c, ch) = (unsigned char)(mean + 0.5); + } + } + } + } } -void MeanBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& low_threshold, - unsigned char& high_threshold) +void MeanBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& low_threshold, + unsigned char& high_threshold) { - // calculate distance to sample point - float dist = 0; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - dist += (pixel(ch)-m_mean(r,c,ch))*(pixel(ch)-m_mean(r,c,ch)); - } - - // determine if sample point is F/G or B/G pixel - low_threshold = BACKGROUND; - if(dist > m_params.LowThreshold()) - { - low_threshold = FOREGROUND; - } - - high_threshold = BACKGROUND; - if(dist > m_params.HighThreshold()) - { - high_threshold = FOREGROUND; - } + // calculate distance to sample point + float dist = 0; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + dist += (pixel(ch) - m_mean(r, c, ch))*(pixel(ch) - m_mean(r, c, ch)); + } + + // determine if sample point is F/G or B/G pixel + low_threshold = BACKGROUND; + if (dist > m_params.LowThreshold()) + { + low_threshold = FOREGROUND; + } + + high_threshold = BACKGROUND; + if (dist > m_params.HighThreshold()) + { + high_threshold = FOREGROUND; + } } /////////////////////////////////////////////////////////////////////////////// @@ -106,26 +106,22 @@ void MeanBGS::SubtractPixel(int r, int c, const RgbPixel& pixel, // output - a pointer to the data of a gray value image of the same size // values: 255-foreground, 0-background /////////////////////////////////////////////////////////////////////////////// -void MeanBGS::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void MeanBGS::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - unsigned char low_threshold, high_threshold; - - // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // perform background subtraction + update background model - SubtractPixel(r, c, data(r,c), low_threshold, high_threshold); - - // setup silhouette mask - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; - } - } + unsigned char low_threshold, high_threshold; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // perform background subtraction + update background model + SubtractPixel(r, c, data(r, c), low_threshold, high_threshold); + + // setup silhouette mask + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + } + } } - - - - diff --git a/package_bgs/dp/MeanBGS.h b/package_bgs/dp/MeanBGS.h index 247e094..306af1a 100644 --- a/package_bgs/dp/MeanBGS.h +++ b/package_bgs/dp/MeanBGS.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * MeanBGS.hpp * -* Purpose: Implementation of a simple temporal mean background +* Purpose: Implementation of a simple temporal mean background * subtraction algorithm. * * Author: Donovan Parks, September 2007 @@ -28,13 +28,14 @@ Example: Algorithms::BackgroundSubtraction::MeanParams params; params.SetFrameSize(width, height); params.LowThreshold() = 3*30*30; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing +params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing params.Alpha() = 1e-6f; params.LearningFrames() = 30; Algorithms::BackgroundSubtraction::MeanBGS bgs; bgs.Initalize(params); ******************************************************************************/ +#pragma once #include "Bgs.h" @@ -54,7 +55,7 @@ namespace Algorithms int &LearningFrames() { return m_learning_frames; } private: - // A pixel is considered to be from the background if the squared distance between + // A pixel is considered to be from the background if the squared distance between // it and the background model is less than the threshold. unsigned int m_low_threshold; unsigned int m_high_threshold; @@ -73,14 +74,14 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background() { return &m_background; } - private: - void SubtractPixel(int r, int c, const RgbPixel& pixel, + private: + void SubtractPixel(int r, int c, const RgbPixel& pixel, unsigned char& lowThreshold, unsigned char& highThreshold); MeanParams m_params; @@ -91,8 +92,3 @@ namespace Algorithms } } - - - - - diff --git a/package_bgs/dp/PratiMediodBGS.cpp b/package_bgs/dp/PratiMediodBGS.cpp index 2256ceb..5a15cec 100644 --- a/package_bgs/dp/PratiMediodBGS.cpp +++ b/package_bgs/dp/PratiMediodBGS.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * PratiMediodBGS.h * -* Purpose: Implementation of the temporal median background +* Purpose: Implementation of the temporal median background * subtraction algorithm described in: * * [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream" @@ -29,7 +29,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Author: Donovan Parks, September 2007 * -* Please note that this is not an implementation of the complete system +* Please note that this is not an implementation of the complete system * given in the above papers. It simply implements the temporal media background * subtraction algorithm. ******************************************************************************/ @@ -40,202 +40,202 @@ using namespace Algorithms::BackgroundSubtraction; PratiMediodBGS::PratiMediodBGS() { - m_median_buffer = NULL; + m_median_buffer = NULL; } PratiMediodBGS::~PratiMediodBGS() { - delete[] m_median_buffer; + delete[] m_median_buffer; } void PratiMediodBGS::Initalize(const BgsParams& param) { - m_params = (PratiParams&)param; + m_params = (PratiParams&)param; - m_mask_low_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - m_mask_high_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + m_mask_low_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); + m_mask_high_threshold = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 1); - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); - m_median_buffer = new MEDIAN_BUFFER[m_params.Size()]; + m_median_buffer = new MEDIAN_BUFFER[m_params.Size()]; } void PratiMediodBGS::InitModel(const RgbImage& data) { - // there is no need to initialize the mode since it needs a buffer of frames - // before it can performing background subtraction + // there is no need to initialize the mode since it needs a buffer of frames + // before it can performing background subtraction } -void PratiMediodBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void PratiMediodBGS::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - // update the image buffer with the new frame and calculate new median values - if(frame_num % m_params.SamplingRate() == 0) - { - if(m_median_buffer[0].dist.size() == m_params.HistorySize()) - { - // subtract distance to sample being removed from all distances - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - int i = r*m_params.Width()+c; - - if(update_mask(r,c) == BACKGROUND) - { - int oldPos = m_median_buffer[i].pos; - for(unsigned int s = 0; s < m_median_buffer[i].pixels.size(); ++s) - { - int maxDist = 0; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - int tempDist = abs(m_median_buffer[i].pixels.at(oldPos)(ch) - - m_median_buffer[i].pixels.at(s)(ch)); - if(tempDist > maxDist) - maxDist = tempDist; - } - - m_median_buffer[i].dist.at(s) -= maxDist; - } - - int dist; - UpdateMediod(r, c, data, dist); - m_median_buffer[i].dist.at(oldPos) = dist; - m_median_buffer[i].pixels.at(oldPos) = data(r,c); - m_median_buffer[i].pos++; - if(m_median_buffer[i].pos >= m_params.HistorySize()) - m_median_buffer[i].pos = 0; - } - } - } - } - else - { - // calculate sum of L-inf distances for new point and - // add distance from each sample point to this point to their L-inf sum - int dist; - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - int index = r*m_params.Width()+c; - UpdateMediod(r, c, data, dist); - m_median_buffer[index].dist.push_back(dist); - m_median_buffer[index].pos = 0; - m_median_buffer[index].pixels.push_back(data(r,c)); - } - } - } - } + // update the image buffer with the new frame and calculate new median values + if (frame_num % m_params.SamplingRate() == 0) + { + if (m_median_buffer[0].dist.size() == m_params.HistorySize()) + { + // subtract distance to sample being removed from all distances + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + int i = r*m_params.Width() + c; + + if (update_mask(r, c) == BACKGROUND) + { + int oldPos = m_median_buffer[i].pos; + for (unsigned int s = 0; s < m_median_buffer[i].pixels.size(); ++s) + { + int maxDist = 0; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + int tempDist = abs(m_median_buffer[i].pixels.at(oldPos)(ch) + - m_median_buffer[i].pixels.at(s)(ch)); + if (tempDist > maxDist) + maxDist = tempDist; + } + + m_median_buffer[i].dist.at(s) -= maxDist; + } + + int dist; + UpdateMediod(r, c, data, dist); + m_median_buffer[i].dist.at(oldPos) = dist; + m_median_buffer[i].pixels.at(oldPos) = data(r, c); + m_median_buffer[i].pos++; + if (m_median_buffer[i].pos >= m_params.HistorySize()) + m_median_buffer[i].pos = 0; + } + } + } + } + else + { + // calculate sum of L-inf distances for new point and + // add distance from each sample point to this point to their L-inf sum + int dist; + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + int index = r*m_params.Width() + c; + UpdateMediod(r, c, data, dist); + m_median_buffer[index].dist.push_back(dist); + m_median_buffer[index].pos = 0; + m_median_buffer[index].pixels.push_back(data(r, c)); + } + } + } + } } void PratiMediodBGS::UpdateMediod(int r, int c, const RgbImage& new_frame, int& dist) { - // calculate sum of L-inf distances for new point and - // add distance from each sample point to this point to their L-inf sum - unsigned int i = (r*m_params.Width()+c); - - m_median_buffer[i].medianDist = INT_MAX; - - int L_inf_dist = 0; - for(unsigned int s = 0; s < m_median_buffer[i].dist.size(); ++s) - { - int maxDist = 0; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - int tempDist = abs(m_median_buffer[i].pixels.at(s)(ch) - new_frame(r,c,ch)); - if(tempDist > maxDist) - maxDist = tempDist; - } - - // check if point from this frame in the image buffer is the median - m_median_buffer[i].dist.at(s) += maxDist; - if(m_median_buffer[i].dist.at(s) < m_median_buffer[i].medianDist) - { - m_median_buffer[i].medianDist = m_median_buffer[i].dist.at(s); - m_median_buffer[i].median = m_median_buffer[i].pixels.at(s); - } - - L_inf_dist += maxDist; - } - - dist = L_inf_dist; - - // check if the new point is the median - if(L_inf_dist < m_median_buffer[i].medianDist) - { - m_median_buffer[i].medianDist = L_inf_dist; - m_median_buffer[i].median = new_frame(r,c); - } + // calculate sum of L-inf distances for new point and + // add distance from each sample point to this point to their L-inf sum + unsigned int i = (r*m_params.Width() + c); + + m_median_buffer[i].medianDist = INT_MAX; + + int L_inf_dist = 0; + for (unsigned int s = 0; s < m_median_buffer[i].dist.size(); ++s) + { + int maxDist = 0; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + int tempDist = abs(m_median_buffer[i].pixels.at(s)(ch) - new_frame(r, c, ch)); + if (tempDist > maxDist) + maxDist = tempDist; + } + + // check if point from this frame in the image buffer is the median + m_median_buffer[i].dist.at(s) += maxDist; + if (m_median_buffer[i].dist.at(s) < m_median_buffer[i].medianDist) + { + m_median_buffer[i].medianDist = m_median_buffer[i].dist.at(s); + m_median_buffer[i].median = m_median_buffer[i].pixels.at(s); + } + + L_inf_dist += maxDist; + } + + dist = L_inf_dist; + + // check if the new point is the median + if (L_inf_dist < m_median_buffer[i].medianDist) + { + m_median_buffer[i].medianDist = L_inf_dist; + m_median_buffer[i].median = new_frame(r, c); + } } void PratiMediodBGS::Combine(const BwImage& low_mask, const BwImage& high_mask, BwImage& output) { - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - output(r,c) = BACKGROUND; - - if(r == 0 || c == 0 || r == m_params.Height()-1 || c == m_params.Width()-1) - continue; - - if(high_mask(r,c) == FOREGROUND) - { - output(r,c) = FOREGROUND; - } - else if(low_mask(r,c) == FOREGROUND) - { - // consider the pixel to be a F/G pixel if it is 8-connected to - // a F/G pixel in the high mask - // check if there is an 8-connected foreground pixel - if(high_mask(r-1,c-1)) - output(r,c) = FOREGROUND; - else if(high_mask(r-1,c)) - output(r,c) = FOREGROUND; - else if(high_mask(r-1,c+1)) - output(r,c) = FOREGROUND; - else if(high_mask(r,c-1)) - output(r,c) = FOREGROUND; - else if(high_mask(r,c+1)) - output(r,c) = FOREGROUND; - else if(high_mask(r+1,c-1)) - output(r,c) = FOREGROUND; - else if(high_mask(r+1,c)) - output(r,c) = FOREGROUND; - else if(high_mask(r+1,c+1)) - output(r,c) = FOREGROUND; - } - } - } + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + output(r, c) = BACKGROUND; + + if (r == 0 || c == 0 || r == m_params.Height() - 1 || c == m_params.Width() - 1) + continue; + + if (high_mask(r, c) == FOREGROUND) + { + output(r, c) = FOREGROUND; + } + else if (low_mask(r, c) == FOREGROUND) + { + // consider the pixel to be a F/G pixel if it is 8-connected to + // a F/G pixel in the high mask + // check if there is an 8-connected foreground pixel + if (high_mask(r - 1, c - 1)) + output(r, c) = FOREGROUND; + else if (high_mask(r - 1, c)) + output(r, c) = FOREGROUND; + else if (high_mask(r - 1, c + 1)) + output(r, c) = FOREGROUND; + else if (high_mask(r, c - 1)) + output(r, c) = FOREGROUND; + else if (high_mask(r, c + 1)) + output(r, c) = FOREGROUND; + else if (high_mask(r + 1, c - 1)) + output(r, c) = FOREGROUND; + else if (high_mask(r + 1, c)) + output(r, c) = FOREGROUND; + else if (high_mask(r + 1, c + 1)) + output(r, c) = FOREGROUND; + } + } + } } void PratiMediodBGS::CalculateMasks(int r, int c, const RgbPixel& pixel) { - int pos = r*m_params.Width()+c; - - // calculate l-inf distance between current value and median value - unsigned char dist = 0; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - int tempDist = abs(pixel(ch) - m_median_buffer[pos].median(ch)); - if(tempDist > dist) - dist = tempDist; - } - m_background(r,c) = m_median_buffer[pos].median; - - // check if pixel is a B/G or F/G pixel according to the low threshold B/G model - m_mask_low_threshold(r,c) = BACKGROUND; - if(dist > m_params.LowThreshold()) - { - m_mask_low_threshold(r,c) = FOREGROUND; - } - - // check if pixel is a B/G or F/G pixel according to the high threshold B/G model - m_mask_high_threshold(r,c)= BACKGROUND; - if(dist > m_params.HighThreshold()) - { - m_mask_high_threshold(r,c) = FOREGROUND; - } + int pos = r*m_params.Width() + c; + + // calculate l-inf distance between current value and median value + unsigned char dist = 0; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + int tempDist = abs(pixel(ch) - m_median_buffer[pos].median(ch)); + if (tempDist > dist) + dist = tempDist; + } + m_background(r, c) = m_median_buffer[pos].median; + + // check if pixel is a B/G or F/G pixel according to the low threshold B/G model + m_mask_low_threshold(r, c) = BACKGROUND; + if (dist > m_params.LowThreshold()) + { + m_mask_low_threshold(r, c) = FOREGROUND; + } + + // check if pixel is a B/G or F/G pixel according to the high threshold B/G model + m_mask_high_threshold(r, c) = BACKGROUND; + if (dist > m_params.HighThreshold()) + { + m_mask_high_threshold(r, c) = FOREGROUND; + } } /////////////////////////////////////////////////////////////////////////////// @@ -245,29 +245,29 @@ void PratiMediodBGS::CalculateMasks(int r, int c, const RgbPixel& pixel) // output - a pointer to the data of a gray value image of the same size // values: 255-foreground, 0-background /////////////////////////////////////////////////////////////////////////////// -void PratiMediodBGS::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mark, BwImage& high_threshold_mark) +void PratiMediodBGS::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mark, BwImage& high_threshold_mark) { - if(frame_num < m_params.HistorySize()) - { - low_threshold_mark.Clear(); - high_threshold_mark.Clear(); - return; - } - - // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // need at least one frame of data before we can start calculating the masks - CalculateMasks(r, c, data(r,c)); - } - } - - // combine low and high threshold masks - Combine(m_mask_low_threshold, m_mask_high_threshold, low_threshold_mark); - Combine(m_mask_low_threshold, m_mask_high_threshold, high_threshold_mark); + if (frame_num < m_params.HistorySize()) + { + low_threshold_mark.Clear(); + high_threshold_mark.Clear(); + return; + } + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // need at least one frame of data before we can start calculating the masks + CalculateMasks(r, c, data(r, c)); + } + } + + // combine low and high threshold masks + Combine(m_mask_low_threshold, m_mask_high_threshold, low_threshold_mark); + Combine(m_mask_low_threshold, m_mask_high_threshold, high_threshold_mark); } diff --git a/package_bgs/dp/PratiMediodBGS.h b/package_bgs/dp/PratiMediodBGS.h index bc8cb7f..6bc8f92 100644 --- a/package_bgs/dp/PratiMediodBGS.h +++ b/package_bgs/dp/PratiMediodBGS.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * PratiMediodBGS.hpp * -* Purpose: Implementation of the temporal median background +* Purpose: Implementation of the temporal median background * subtraction algorithm described in: * * [1] "Detecting Moving Objects, Shosts, and Shadows in Video Stream" @@ -29,7 +29,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * Author: Donovan Parks, September 2007 * -* Please note that this is not an implementation of the complete system +* Please note that this is not an implementation of the complete system * given in the above papers. It simply implements the temporal media background * subtraction algorithm. @@ -37,7 +37,7 @@ Example: Algorithms::BackgroundSubtraction::PratiParams params; params.SetFrameSize(width, height); params.LowThreshold() = 30; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing +params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing params.SamplingRate() = 5; params.HistorySize() = 16; params.Weight() = 5; @@ -45,9 +45,7 @@ params.Weight() = 5; Algorithms::BackgroundSubtraction::PratiMediodBGS bgs; bgs.Initalize(params); ******************************************************************************/ - -#ifndef PRATI_MEDIA_BGS_H -#define PRATI_MEDIA_BGS_H +#pragma once #include <vector> #include "Bgs.h" @@ -68,9 +66,9 @@ namespace Algorithms int &HistorySize() { return m_history_size; } private: - // The low threshold is used to supress noise. The high thresohld is used - // to find pixels highly likely to be foreground. This implementation uses an L-inf - // distance measure and a pixel p is considered F/G if D(I(p), B(p)) > threshold. + // The low threshold is used to supress noise. The high thresohld is used + // to find pixels highly likely to be foreground. This implementation uses an L-inf + // distance measure and a pixel p is considered F/G if D(I(p), B(p)) > threshold. // The two threshold maps are combined as in [2]. unsigned int m_low_threshold; unsigned int m_high_threshold; @@ -88,9 +86,9 @@ namespace Algorithms }; // --- Prati Mediod BGS algorithm --- - class PratiMediodBGS : public Bgs + class PratiMediodBGS : public Bgs { - private: + private: // sum of L-inf distances from a sample point to all other sample points struct MEDIAN_BUFFER { @@ -109,13 +107,13 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background() { return &m_background; } - private: + private: MEDIAN_BUFFER* m_median_buffer; void CalculateMasks(int r, int c, const RgbPixel& pixel); @@ -132,11 +130,3 @@ namespace Algorithms } } - -#endif - - - - - - diff --git a/package_bgs/dp/TextureBGS.cpp b/package_bgs/dp/TextureBGS.cpp index 62684f8..920f140 100644 --- a/package_bgs/dp/TextureBGS.cpp +++ b/package_bgs/dp/TextureBGS.cpp @@ -16,40 +16,40 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ #include "TextureBGS.h" -TextureBGS::TextureBGS(){} -TextureBGS::~TextureBGS(){} +TextureBGS::TextureBGS() {} +TextureBGS::~TextureBGS() {} void TextureBGS::LBP(RgbImage& image, RgbImage& texture) { - for(int y = TEXTURE_R; y < image.Ptr()->height-TEXTURE_R; ++y) + for (int y = TEXTURE_R; y < image.Ptr()->height - TEXTURE_R; ++y) { - for(int x = TEXTURE_R; x < image.Ptr()->width-TEXTURE_R; ++x) - { - for(int ch = 0; ch < NUM_CHANNELS; ++ch) + for (int x = TEXTURE_R; x < image.Ptr()->width - TEXTURE_R; ++x) + { + for (int ch = 0; ch < NUM_CHANNELS; ++ch) { unsigned char textureCode = 0; int centerValue = (int)image(y, x, ch); // this only works for a texture radius of 2 - if(centerValue - (int)image(y-2, x, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y - 2, x, ch) + HYSTERSIS >= 0) textureCode += 1; - if(centerValue - (int)image(y-1, x-2, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y - 1, x - 2, ch) + HYSTERSIS >= 0) textureCode += 2; - if(centerValue - (int)image(y-1, x+2, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y - 1, x + 2, ch) + HYSTERSIS >= 0) textureCode += 4; - if(centerValue - (int)image(y+1, x-2, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y + 1, x - 2, ch) + HYSTERSIS >= 0) textureCode += 8; - if(centerValue - (int)image(y+1, x+2, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y + 1, x + 2, ch) + HYSTERSIS >= 0) textureCode += 16; - if(centerValue - (int)image(y+2, x, ch) + HYSTERSIS >= 0) + if (centerValue - (int)image(y + 2, x, ch) + HYSTERSIS >= 0) textureCode += 32; - texture(y,x,ch) = textureCode; + texture(y, x, ch) = textureCode; } } } @@ -58,14 +58,14 @@ void TextureBGS::LBP(RgbImage& image, RgbImage& texture) void TextureBGS::Histogram(RgbImage& texture, TextureHistogram* curTextureHist) { // calculate histogram within a 2*REGION_R square - for(int y = REGION_R+TEXTURE_R; y < texture.Ptr()->height-REGION_R-TEXTURE_R; ++y) + for (int y = REGION_R + TEXTURE_R; y < texture.Ptr()->height - REGION_R - TEXTURE_R; ++y) { - for(int x = REGION_R+TEXTURE_R; x < texture.Ptr()->width-REGION_R-TEXTURE_R; ++x) - { - int index = x+y*(texture.Ptr()->width); + for (int x = REGION_R + TEXTURE_R; x < texture.Ptr()->width - REGION_R - TEXTURE_R; ++x) + { + int index = x + y*(texture.Ptr()->width); // clear histogram - for(int i = 0; i < NUM_BINS; ++i) + for (int i = 0; i < NUM_BINS; ++i) { curTextureHist[index].r[i] = 0; curTextureHist[index].g[i] = 0; @@ -73,13 +73,13 @@ void TextureBGS::Histogram(RgbImage& texture, TextureHistogram* curTextureHist) } // calculate histogram - for(int j = -REGION_R; j <= REGION_R; ++j) + for (int j = -REGION_R; j <= REGION_R; ++j) { - for(int i = -REGION_R; i <= REGION_R; ++i) + for (int i = -REGION_R; i <= REGION_R; ++i) { - curTextureHist[index].r[texture(y+j,x+i,2)]++; - curTextureHist[index].g[texture(y+j,x+i,1)]++; - curTextureHist[index].b[texture(y+j,x+i,0)]++; + curTextureHist[index].r[texture(y + j, x + i, 2)]++; + curTextureHist[index].g[texture(y + j, x + i, 1)]++; + curTextureHist[index].b[texture(y + j, x + i, 0)]++; } } } @@ -88,66 +88,66 @@ void TextureBGS::Histogram(RgbImage& texture, TextureHistogram* curTextureHist) int TextureBGS::ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist) { - int proximity = 0; - for(int i = 0; i < NUM_BINS; ++i) + int proximity = 0; + for (int i = 0; i < NUM_BINS; ++i) { proximity += std::min(bgTexture.r[i], curTextureHist.r[i]); proximity += std::min(bgTexture.g[i], curTextureHist.g[i]); proximity += std::min(bgTexture.b[i], curTextureHist.b[i]); } - return proximity; + return proximity; } -void TextureBGS::BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, - unsigned char* modeArray, float threshold, BwImage& fgMask) +void TextureBGS::BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, + unsigned char* modeArray, float threshold, BwImage& fgMask) { cvZero(fgMask.Ptr()); - for(int y = REGION_R+TEXTURE_R; y < fgMask.Ptr()->height-REGION_R-TEXTURE_R; ++y) + for (int y = REGION_R + TEXTURE_R; y < fgMask.Ptr()->height - REGION_R - TEXTURE_R; ++y) { - for(int x = REGION_R+TEXTURE_R; x < fgMask.Ptr()->width-REGION_R-TEXTURE_R; ++x) - { - int index = x+y*(fgMask.Ptr()->width); + for (int x = REGION_R + TEXTURE_R; x < fgMask.Ptr()->width - REGION_R - TEXTURE_R; ++x) + { + int index = x + y*(fgMask.Ptr()->width); // find closest matching texture in background model int maxProximity = -1; - for(int m = 0; m < NUM_MODES; ++m) + for (int m = 0; m < NUM_MODES; ++m) { int proximity = ProximityMeasure(bgModel[index].mode[m], curTextureHist[index]); - if(proximity > maxProximity) + if (proximity > maxProximity) { maxProximity = proximity; modeArray[index] = m; } } - if(maxProximity < threshold) - fgMask(y,x) = 255; + if (maxProximity < threshold) + fgMask(y, x) = 255; } } } -void TextureBGS::UpdateModel(BwImage& fgMask, TextureArray* bgModel, - TextureHistogram* curTextureHist, unsigned char* modeArray) +void TextureBGS::UpdateModel(BwImage& fgMask, TextureArray* bgModel, + TextureHistogram* curTextureHist, unsigned char* modeArray) { - for(int y = REGION_R+TEXTURE_R; y < fgMask.Ptr()->height-REGION_R-TEXTURE_R; ++y) + for (int y = REGION_R + TEXTURE_R; y < fgMask.Ptr()->height - REGION_R - TEXTURE_R; ++y) { - for(int x = REGION_R+TEXTURE_R; x < fgMask.Ptr()->width-REGION_R-TEXTURE_R; ++x) - { - int index = x+y*(fgMask.Ptr()->width); + for (int x = REGION_R + TEXTURE_R; x < fgMask.Ptr()->width - REGION_R - TEXTURE_R; ++x) + { + int index = x + y*(fgMask.Ptr()->width); - if(fgMask(y,x) == 0) + if (fgMask(y, x) == 0) { - for(int i = 0; i < NUM_BINS; ++i) + for (int i = 0; i < NUM_BINS; ++i) { bgModel[index].mode[modeArray[index]].r[i] - = (unsigned char)(ALPHA*curTextureHist[index].r[i] - + (1-ALPHA)*bgModel[index].mode[modeArray[index]].r[i] + 0.5); + = (unsigned char)(ALPHA*curTextureHist[index].r[i] + + (1 - ALPHA)*bgModel[index].mode[modeArray[index]].r[i] + 0.5); } - } + } } - } + } } diff --git a/package_bgs/dp/TextureBGS.h b/package_bgs/dp/TextureBGS.h index 573e6f9..2650f04 100644 --- a/package_bgs/dp/TextureBGS.h +++ b/package_bgs/dp/TextureBGS.h @@ -14,6 +14,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ +#pragma once + #include <math.h> #include "Image.h" @@ -23,7 +25,7 @@ const int TEXTURE_R = 2; // Note: the code currently assumes this value is 2 const int NUM_BINS = 64; // 2^TEXTURE_POINTS const int HYSTERSIS = 3; const double ALPHA = 0.05f; -const double THRESHOLD = 0.5*(REGION_R+REGION_R+1)*(REGION_R+REGION_R+1)*NUM_CHANNELS; +const double THRESHOLD = 0.5*(REGION_R + REGION_R + 1)*(REGION_R + REGION_R + 1)*NUM_CHANNELS; const int NUM_MODES = 1; // The paper describes how multiple modes can be maintained, // but this implementation does not fully support more than one @@ -48,8 +50,8 @@ public: void LBP(RgbImage& image, RgbImage& texture); void Histogram(RgbImage& texture, TextureHistogram* curTextureHist); int ProximityMeasure(TextureHistogram& bgTexture, TextureHistogram& curTextureHist); - void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, - unsigned char* modeArray, float threshold, BwImage& fgMask); - void UpdateModel(BwImage& fgMask, TextureArray* bgModel, - TextureHistogram* curTextureHist, unsigned char* modeArray); + void BgsCompare(TextureArray* bgModel, TextureHistogram* curTextureHist, + unsigned char* modeArray, float threshold, BwImage& fgMask); + void UpdateModel(BwImage& fgMask, TextureArray* bgModel, + TextureHistogram* curTextureHist, unsigned char* modeArray); }; diff --git a/package_bgs/dp/WrenGA.cpp b/package_bgs/dp/WrenGA.cpp index 16e2640..80a9e27 100644 --- a/package_bgs/dp/WrenGA.cpp +++ b/package_bgs/dp/WrenGA.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * WrenGA.h * -* Purpose: Implementation of the running Gaussian average background +* Purpose: Implementation of the running Gaussian average background * subtraction algorithm described in: * "Pfinder: real-time tracking of the human body" * by C. Wren et al (1997) @@ -36,114 +36,114 @@ using namespace Algorithms::BackgroundSubtraction; WrenGA::WrenGA() { - m_gaussian = NULL; + m_gaussian = NULL; } WrenGA::~WrenGA() { - delete[] m_gaussian; + delete[] m_gaussian; } void WrenGA::Initalize(const BgsParams& param) { - m_params = (WrenParams&)param; - - m_variance = 36.0f; - - // GMM for each pixel - m_gaussian = new GAUSSIAN[m_params.Size()]; - for(unsigned int i = 0; i < m_params.Size(); ++i) - { - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - m_gaussian[i].mu[ch] = 0; - m_gaussian[i].var[ch] = 0; - } - } - - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_params = (WrenParams&)param; + + m_variance = 36.0f; + + // GMM for each pixel + m_gaussian = new GAUSSIAN[m_params.Size()]; + for (unsigned int i = 0; i < m_params.Size(); ++i) + { + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + m_gaussian[i].mu[ch] = 0; + m_gaussian[i].var[ch] = 0; + } + } + + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); } void WrenGA::InitModel(const RgbImage& data) { - int pos = 0; - - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - m_gaussian[pos].mu[ch] = data(r,c,ch); - m_gaussian[pos].var[ch] = m_variance; - } - - pos++; - } - } + int pos = 0; + + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + m_gaussian[pos].mu[ch] = data(r, c, ch); + m_gaussian[pos].var[ch] = m_variance; + } + + pos++; + } + } } -void WrenGA::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void WrenGA::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - int pos = 0; - - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - // perform conditional updating only if we are passed the learning phase - if(update_mask(r,c) == BACKGROUND || frame_num < m_params.LearningFrames()) - { - float dR = m_gaussian[pos].mu[0] - data(r,c,0); - float dG = m_gaussian[pos].mu[1] - data(r,c,1); - float dB = m_gaussian[pos].mu[2] - data(r,c,2); - - float dist = (dR*dR + dG*dG + dB*dB); - - m_gaussian[pos].mu[0] -= m_params.Alpha()*(dR); - m_gaussian[pos].mu[1] -= m_params.Alpha()*(dG); - m_gaussian[pos].mu[2] -= m_params.Alpha()*(dB); - - float sigmanew = m_gaussian[pos].var[0] + m_params.Alpha()*(dist-m_gaussian[pos].var[0]); - m_gaussian[pos].var[0] = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew; - - m_background(r, c, 0) = (unsigned char)(m_gaussian[pos].mu[0] + 0.5); - m_background(r, c, 1) = (unsigned char)(m_gaussian[pos].mu[1] + 0.5); - m_background(r, c, 2) = (unsigned char)(m_gaussian[pos].mu[2] + 0.5); - } - - pos++; - } - } + int pos = 0; + + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + // perform conditional updating only if we are passed the learning phase + if (update_mask(r, c) == BACKGROUND || frame_num < m_params.LearningFrames()) + { + float dR = m_gaussian[pos].mu[0] - data(r, c, 0); + float dG = m_gaussian[pos].mu[1] - data(r, c, 1); + float dB = m_gaussian[pos].mu[2] - data(r, c, 2); + + float dist = (dR*dR + dG*dG + dB*dB); + + m_gaussian[pos].mu[0] -= m_params.Alpha()*(dR); + m_gaussian[pos].mu[1] -= m_params.Alpha()*(dG); + m_gaussian[pos].mu[2] -= m_params.Alpha()*(dB); + + float sigmanew = m_gaussian[pos].var[0] + m_params.Alpha()*(dist - m_gaussian[pos].var[0]); + m_gaussian[pos].var[0] = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + + m_background(r, c, 0) = (unsigned char)(m_gaussian[pos].mu[0] + 0.5); + m_background(r, c, 1) = (unsigned char)(m_gaussian[pos].mu[1] + 0.5); + m_background(r, c, 2) = (unsigned char)(m_gaussian[pos].mu[2] + 0.5); + } + + pos++; + } + } } -void WrenGA::SubtractPixel(int r, int c, const RgbPixel& pixel, - unsigned char& low_threshold, - unsigned char& high_threshold) +void WrenGA::SubtractPixel(int r, int c, const RgbPixel& pixel, + unsigned char& low_threshold, + unsigned char& high_threshold) { - unsigned int pos = r*m_params.Width()+c; - - // calculate distance between model and pixel - float mu[NUM_CHANNELS]; - float var[1]; - float delta[NUM_CHANNELS]; - float dist = 0; - for(int ch = 0; ch < NUM_CHANNELS; ++ch) - { - mu[ch] = m_gaussian[pos].mu[ch]; - var[0] = m_gaussian[pos].var[0]; - delta[ch] = mu[ch] - pixel(ch); - dist += delta[ch]*delta[ch]; - } - - // calculate the squared distance and see if pixel fits the B/G model - low_threshold = BACKGROUND; - high_threshold = BACKGROUND; - - if(dist > m_params.LowThreshold()*var[0]) - low_threshold = FOREGROUND; - if(dist > m_params.HighThreshold()*var[0]) - high_threshold = FOREGROUND; + unsigned int pos = r*m_params.Width() + c; + + // calculate distance between model and pixel + float mu[NUM_CHANNELS]; + float var[1]; + float delta[NUM_CHANNELS]; + float dist = 0; + for (int ch = 0; ch < NUM_CHANNELS; ++ch) + { + mu[ch] = m_gaussian[pos].mu[ch]; + var[0] = m_gaussian[pos].var[0]; + delta[ch] = mu[ch] - pixel(ch); + dist += delta[ch] * delta[ch]; + } + + // calculate the squared distance and see if pixel fits the B/G model + low_threshold = BACKGROUND; + high_threshold = BACKGROUND; + + if (dist > m_params.LowThreshold()*var[0]) + low_threshold = FOREGROUND; + if (dist > m_params.HighThreshold()*var[0]) + high_threshold = FOREGROUND; } /////////////////////////////////////////////////////////////////////////////// @@ -154,20 +154,20 @@ void WrenGA::SubtractPixel(int r, int c, const RgbPixel& pixel, // (the memory should already be reserved) // values: 255-foreground, 125-shadow, 0-background /////////////////////////////////////////////////////////////////////////////// -void WrenGA::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void WrenGA::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - unsigned char low_threshold, high_threshold; - - // update each pixel of the image - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - SubtractPixel(r, c, data(r,c), low_threshold, high_threshold); - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; - } - } + unsigned char low_threshold, high_threshold; + + // update each pixel of the image + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + SubtractPixel(r, c, data(r, c), low_threshold, high_threshold); + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + } + } } diff --git a/package_bgs/dp/WrenGA.h b/package_bgs/dp/WrenGA.h index 116c292..97e97ee 100644 --- a/package_bgs/dp/WrenGA.h +++ b/package_bgs/dp/WrenGA.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * WrenGA.hpp * -* Purpose: Implementation of the running Gaussian average background +* Purpose: Implementation of the running Gaussian average background * subtraction algorithm described in: * "Pfinder: real-time tracking of the human body" * by C. Wren et al (1997) @@ -33,16 +33,14 @@ Example: Algorithms::BackgroundSubtraction::WrenParams params; params.SetFrameSize(width, height); params.LowThreshold() = 3.5f*3.5f; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing +params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing params.Alpha() = 0.005f; params.LearningFrames() = 30; Algorithms::BackgroundSubtraction::WrenGA bgs; bgs.Initalize(params); ******************************************************************************/ - -#ifndef WREN_GA_H -#define WREN_GA_H +#pragma once #include "Bgs.h" @@ -74,7 +72,7 @@ namespace Algorithms // --- Mean BGS algorithm --- class WrenGA : public Bgs { - private: + private: struct GAUSSIAN { float mu[NUM_CHANNELS]; @@ -88,19 +86,19 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background() { return &m_background; } - private: - void SubtractPixel(int r, int c, const RgbPixel& pixel, + private: + void SubtractPixel(int r, int c, const RgbPixel& pixel, unsigned char& lowThreshold, unsigned char& highThreshold); WrenParams m_params; - // Initial variance for the newly generated components. + // Initial variance for the newly generated components. float m_variance; // dynamic array for the mixture of Gaussians @@ -110,11 +108,3 @@ namespace Algorithms }; } } - -#endif - - - - - - diff --git a/package_bgs/dp/ZivkovicAGMM.cpp b/package_bgs/dp/ZivkovicAGMM.cpp index 041ffc4..f73d5a1 100644 --- a/package_bgs/dp/ZivkovicAGMM.cpp +++ b/package_bgs/dp/ZivkovicAGMM.cpp @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * ZivkovicAGMM.cpp * -* Purpose: Implementation of the Gaussian mixture model (GMM) background +* Purpose: Implementation of the Gaussian mixture model (GMM) background * subtraction algorithm developed by Z. Zivkovic. * * Author: Donovan Parks, September 2007 @@ -28,13 +28,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * following papers: * * "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic +* Z.Zivkovic * International Conference Pattern Recognition, UK, August, 2004 * * -* "Efficient Adaptive Density Estimapion per Image Pixel for the +* "Efficient Adaptive Density Estimapion per Image Pixel for the * Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden +* Z.Zivkovic, F. van der Heijden * Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. * * Zivkovic's code can be obtained at: www.zoranz.net @@ -46,328 +46,328 @@ using namespace Algorithms::BackgroundSubtraction; ZivkovicAGMM::ZivkovicAGMM() { - m_modes = NULL; - m_modes_per_pixel = NULL; + m_modes = NULL; + m_modes_per_pixel = NULL; } ZivkovicAGMM::~ZivkovicAGMM() { - delete[] m_modes; - delete[] m_modes_per_pixel; + delete[] m_modes; + delete[] m_modes_per_pixel; } void ZivkovicAGMM::Initalize(const BgsParams& param) { - m_params = (ZivkovicParams&)param; + m_params = (ZivkovicParams&)param; - m_num_bands = 3; //always 3 - not implemented for other values! - m_bg_threshold = 0.75f; //1-cf from the paper - m_variance = 36.0f; // variance for the new mode - m_complexity_prior = 0.05f; // complexity reduction prior constant + m_num_bands = 3; //always 3 - not implemented for other values! + m_bg_threshold = 0.75f; //1-cf from the paper + m_variance = 36.0f; // variance for the new mode + m_complexity_prior = 0.05f; // complexity reduction prior constant - // GMM for each pixel - m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; + // GMM for each pixel + m_modes = new GMM[m_params.Size()*m_params.MaxModes()]; - // used modes per pixel - m_modes_per_pixel = new unsigned char[m_params.Size()]; + // used modes per pixel + m_modes_per_pixel = new unsigned char[m_params.Size()]; - m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); + m_background = cvCreateImage(cvSize(m_params.Width(), m_params.Height()), IPL_DEPTH_8U, 3); } void ZivkovicAGMM::InitModel(const RgbImage& data) { - for(unsigned int i = 0; i < m_params.Size(); ++i) - { - m_modes_per_pixel[i] = 0; - } - - for(unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) - { - m_modes[i].weight = 0; - m_modes[i].sigma = 0; - m_modes[i].muR = 0; - m_modes[i].muG = 0; - m_modes[i].muB = 0; - } + for (unsigned int i = 0; i < m_params.Size(); ++i) + { + m_modes_per_pixel[i] = 0; + } + + for (unsigned int i = 0; i < m_params.Size()*m_params.MaxModes(); ++i) + { + m_modes[i].weight = 0; + m_modes[i].sigma = 0; + m_modes[i].muR = 0; + m_modes[i].muG = 0; + m_modes[i].muB = 0; + } } -void ZivkovicAGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) +void ZivkovicAGMM::Update(int frame_num, const RgbImage& data, const BwImage& update_mask) { - // it doesn't make sense to have conditional updates in the GMM framework + // it doesn't make sense to have conditional updates in the GMM framework } -void ZivkovicAGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, - unsigned char& low_threshold, unsigned char& high_threshold) +void ZivkovicAGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, + unsigned char& low_threshold, unsigned char& high_threshold) { - //calculate distances to the modes (+ sort???) - //here we need to go in descending order!!! - long pos; - bool bFitsPDF=0; - bool bBackgroundLow=false; - bool bBackgroundHigh=false; - - float fOneMinAlpha = 1-m_params.Alpha(); - - float prune = -m_params.Alpha()*m_complexity_prior; - - int nModes =* pModesUsed; - float totalWeight = 0.0f; - - // calculate number of Gaussians to include in the background model - int backgroundGaussians = 0; - double sum = 0.0; - for(int i = 0; i < nModes; ++i) - { - if(sum < m_bg_threshold) - { - backgroundGaussians++; - sum += m_modes[posPixel+i].weight; - } - else - { - break; - } - } - - // update all distributions and check for match with current pixel - for (int iModes = 0; iModes < nModes; iModes++) - { - pos=posPixel+iModes; - float weight = m_modes[pos].weight; - - //fit not found yet - if (!bFitsPDF) - { - //check if it belongs to some of the modes - //calculate distance - float var = m_modes[pos].sigma; - float muR = m_modes[pos].muR; - float muG = m_modes[pos].muG; - float muB = m_modes[pos].muB; - - float dR=muR - pixel(0); - float dG=muG - pixel(1); - float dB=muB - pixel(2); - - // calculate the squared distance - float dist = (dR*dR + dG*dG + dB*dB); - - if(dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) - bBackgroundHigh = true; - - //check fit - if (dist < m_params.LowThreshold()*var) - { - ///// - //belongs to the mode - bFitsPDF = true; - - // check if this Gaussian is part of the background model - if(iModes < backgroundGaussians) - bBackgroundLow = true; - - //update distribution - float k = m_params.Alpha()/weight; - weight = fOneMinAlpha*weight+prune; - weight += m_params.Alpha(); - m_modes[pos].weight = weight; - m_modes[pos].muR = muR - k*(dR); - m_modes[pos].muG = muG - k*(dG); - m_modes[pos].muB = muB - k*(dB); - - //limit update speed for cov matrice - //not needed - //k=k>20*m_m_params.Alpha()?20*m_m_params.Alpha():k; - //float sigmanew = var + k*((0.33*(dR*dR+dG*dG+dB*dB))-var); - //float sigmanew = var + k*((dR*dR+dG*dG+dB*dB)-var); - //float sigmanew = var + k*((0.33*dist)-var); - float sigmanew = var + k*(dist-var); - - //limit the variance - m_modes[pos].sigma = sigmanew < 4 ? 4 : sigmanew > 5*m_variance ? 5*m_variance : sigmanew; - - // Sort weights so they are in desending order. Note that only the weight for this - // mode will increase and that the weight for all modes that were previously larger than - // this one have already been modified and will not be modified again. Thus, we just need to - // the correct position of this mode in the already sorted list. - - // Zivkovic implementation has been modified for clarity, but the results are equivalent - /* - for (int iLocal = iModes;iLocal>0;iLocal--) - { - long posLocal=posPixel + iLocal; - if (weight < (m_modes[posLocal-1].weight)) - { - break; - } - else - { - //swap - GMM temp = m_modes[posLocal]; - m_modes[posLocal] = m_modes[posLocal-1]; - m_modes[posLocal-1] = temp; - } - } - */ - - for (int iLocal = iModes; iLocal > 0; iLocal--) - { - long posLocal = posPixel + iLocal; - if (m_modes[posLocal].weight > m_modes[posLocal-1].weight) - { - //swap - GMM temp = m_modes[posLocal]; - m_modes[posLocal] = m_modes[posLocal-1]; - m_modes[posLocal-1] = temp; - } - else - { - break; - } - } - } - else - { - weight = fOneMinAlpha*weight+prune; - //check prune - if (weight < -prune) - { - weight=0.0; - nModes--; - } - m_modes[pos].weight = weight; - } - //check if it fits the current mode (2.5 sigma) - /////// - } - //fit not found yet - ///// - else - { - weight = fOneMinAlpha*weight + prune; - //check prune - if (weight < -prune) - { - weight=0.0; - nModes--; - } - m_modes[pos].weight = weight; - } - totalWeight += weight; - } - - //renormalize weights so they sum to 1 - for (int iLocal = 0; iLocal < nModes; iLocal++) - { - m_modes[posPixel+ iLocal].weight = m_modes[posPixel+ iLocal].weight/totalWeight; - } - - //make new mode if needed and exit - if (!bFitsPDF) - { - if (nModes == m_params.MaxModes()) - { - //replace the weakest - } - else - { - nModes++; - } - pos = posPixel + nModes-1; - - if (nModes==1) - m_modes[pos].weight=1; - else - m_modes[pos].weight=m_params.Alpha(); - - // Zivkovic implementation changes as this will not result in the - // weights adding to 1 - /* - int iLocal; - for (iLocal = 0; iLocal < m_params.MaxModes()odes-1; iLocal++) - { - m_modes[posPixel+ iLocal].weight *= fOneMinAlpha; - } - */ - - // Revised implementation: - //renormalize weights - int iLocal; - float sum = 0.0; - for (iLocal = 0; iLocal < nModes; iLocal++) - { - sum += m_modes[posPixel+ iLocal].weight; - } - - float invSum = 1.0f/sum; - for (iLocal = 0; iLocal < nModes; iLocal++) - { - m_modes[posPixel+ iLocal].weight *= invSum; - } - - m_modes[pos].muR=pixel(0); - m_modes[pos].muG=pixel(1); - m_modes[pos].muB=pixel(2); - m_modes[pos].sigma=m_variance; - - // Zivkovic implementation to sort GMM so they are sorted in descending order according to their weight. - // It has been revised for clarity, but the results are equivalent - /* - for (iLocal = m_params.MaxModes()odes-1; iLocal > 0; iLocal--) - { - long posLocal = posPixel + iLocal; - if (m_params.Alpha() < (m_modes[posLocal-1].weight)) - { - break; - } - else - { - //swap - GMM temp = m_modes[posLocal]; - m_modes[posLocal] = m_modes[posLocal-1]; - m_modes[posLocal-1] = temp; - } - } - */ - - // sort GMM so they are sorted in descending order according to their weight - for (iLocal = nModes-1; iLocal > 0; iLocal--) - { - long posLocal = posPixel + iLocal; - if (m_modes[posLocal].weight > m_modes[posLocal-1].weight) - { - //swap - GMM temp = m_modes[posLocal]; - m_modes[posLocal] = m_modes[posLocal-1]; - m_modes[posLocal-1] = temp; - } - else - { - break; - } - } - } - - //set the number of modes - *pModesUsed=nModes; - - if(bBackgroundLow) - { - low_threshold = BACKGROUND; - } - else - { - low_threshold = FOREGROUND; - } - - if(bBackgroundHigh) - { - high_threshold = BACKGROUND; - } - else - { - high_threshold = FOREGROUND; - } + //calculate distances to the modes (+ sort???) + //here we need to go in descending order!!! + long pos; + bool bFitsPDF = 0; + bool bBackgroundLow = false; + bool bBackgroundHigh = false; + + float fOneMinAlpha = 1 - m_params.Alpha(); + + float prune = -m_params.Alpha()*m_complexity_prior; + + int nModes = *pModesUsed; + float totalWeight = 0.0f; + + // calculate number of Gaussians to include in the background model + int backgroundGaussians = 0; + double sum = 0.0; + for (int i = 0; i < nModes; ++i) + { + if (sum < m_bg_threshold) + { + backgroundGaussians++; + sum += m_modes[posPixel + i].weight; + } + else + { + break; + } + } + + // update all distributions and check for match with current pixel + for (int iModes = 0; iModes < nModes; iModes++) + { + pos = posPixel + iModes; + float weight = m_modes[pos].weight; + + //fit not found yet + if (!bFitsPDF) + { + //check if it belongs to some of the modes + //calculate distance + float var = m_modes[pos].sigma; + float muR = m_modes[pos].muR; + float muG = m_modes[pos].muG; + float muB = m_modes[pos].muB; + + float dR = muR - pixel(0); + float dG = muG - pixel(1); + float dB = muB - pixel(2); + + // calculate the squared distance + float dist = (dR*dR + dG*dG + dB*dB); + + if (dist < m_params.HighThreshold()*var && iModes < backgroundGaussians) + bBackgroundHigh = true; + + //check fit + if (dist < m_params.LowThreshold()*var) + { + ///// + //belongs to the mode + bFitsPDF = true; + + // check if this Gaussian is part of the background model + if (iModes < backgroundGaussians) + bBackgroundLow = true; + + //update distribution + float k = m_params.Alpha() / weight; + weight = fOneMinAlpha*weight + prune; + weight += m_params.Alpha(); + m_modes[pos].weight = weight; + m_modes[pos].muR = muR - k*(dR); + m_modes[pos].muG = muG - k*(dG); + m_modes[pos].muB = muB - k*(dB); + + //limit update speed for cov matrice + //not needed + //k=k>20*m_m_params.Alpha()?20*m_m_params.Alpha():k; + //float sigmanew = var + k*((0.33*(dR*dR+dG*dG+dB*dB))-var); + //float sigmanew = var + k*((dR*dR+dG*dG+dB*dB)-var); + //float sigmanew = var + k*((0.33*dist)-var); + float sigmanew = var + k*(dist - var); + + //limit the variance + m_modes[pos].sigma = sigmanew < 4 ? 4 : sigmanew > 5 * m_variance ? 5 * m_variance : sigmanew; + + // Sort weights so they are in desending order. Note that only the weight for this + // mode will increase and that the weight for all modes that were previously larger than + // this one have already been modified and will not be modified again. Thus, we just need to + // the correct position of this mode in the already sorted list. + + // Zivkovic implementation has been modified for clarity, but the results are equivalent + /* + for (int iLocal = iModes;iLocal>0;iLocal--) + { + long posLocal=posPixel + iLocal; + if (weight < (m_modes[posLocal-1].weight)) + { + break; + } + else + { + //swap + GMM temp = m_modes[posLocal]; + m_modes[posLocal] = m_modes[posLocal-1]; + m_modes[posLocal-1] = temp; + } + } + */ + + for (int iLocal = iModes; iLocal > 0; iLocal--) + { + long posLocal = posPixel + iLocal; + if (m_modes[posLocal].weight > m_modes[posLocal - 1].weight) + { + //swap + GMM temp = m_modes[posLocal]; + m_modes[posLocal] = m_modes[posLocal - 1]; + m_modes[posLocal - 1] = temp; + } + else + { + break; + } + } + } + else + { + weight = fOneMinAlpha*weight + prune; + //check prune + if (weight < -prune) + { + weight = 0.0; + nModes--; + } + m_modes[pos].weight = weight; + } + //check if it fits the current mode (2.5 sigma) + /////// + } + //fit not found yet + ///// + else + { + weight = fOneMinAlpha*weight + prune; + //check prune + if (weight < -prune) + { + weight = 0.0; + nModes--; + } + m_modes[pos].weight = weight; + } + totalWeight += weight; + } + + //renormalize weights so they sum to 1 + for (int iLocal = 0; iLocal < nModes; iLocal++) + { + m_modes[posPixel + iLocal].weight = m_modes[posPixel + iLocal].weight / totalWeight; + } + + //make new mode if needed and exit + if (!bFitsPDF) + { + if (nModes == m_params.MaxModes()) + { + //replace the weakest + } + else + { + nModes++; + } + pos = posPixel + nModes - 1; + + if (nModes == 1) + m_modes[pos].weight = 1; + else + m_modes[pos].weight = m_params.Alpha(); + + // Zivkovic implementation changes as this will not result in the + // weights adding to 1 + /* + int iLocal; + for (iLocal = 0; iLocal < m_params.MaxModes()odes-1; iLocal++) + { + m_modes[posPixel+ iLocal].weight *= fOneMinAlpha; + } + */ + + // Revised implementation: + //renormalize weights + int iLocal; + float sum = 0.0; + for (iLocal = 0; iLocal < nModes; iLocal++) + { + sum += m_modes[posPixel + iLocal].weight; + } + + float invSum = 1.0f / sum; + for (iLocal = 0; iLocal < nModes; iLocal++) + { + m_modes[posPixel + iLocal].weight *= invSum; + } + + m_modes[pos].muR = pixel(0); + m_modes[pos].muG = pixel(1); + m_modes[pos].muB = pixel(2); + m_modes[pos].sigma = m_variance; + + // Zivkovic implementation to sort GMM so they are sorted in descending order according to their weight. + // It has been revised for clarity, but the results are equivalent + /* + for (iLocal = m_params.MaxModes()odes-1; iLocal > 0; iLocal--) + { + long posLocal = posPixel + iLocal; + if (m_params.Alpha() < (m_modes[posLocal-1].weight)) + { + break; + } + else + { + //swap + GMM temp = m_modes[posLocal]; + m_modes[posLocal] = m_modes[posLocal-1]; + m_modes[posLocal-1] = temp; + } + } + */ + + // sort GMM so they are sorted in descending order according to their weight + for (iLocal = nModes - 1; iLocal > 0; iLocal--) + { + long posLocal = posPixel + iLocal; + if (m_modes[posLocal].weight > m_modes[posLocal - 1].weight) + { + //swap + GMM temp = m_modes[posLocal]; + m_modes[posLocal] = m_modes[posLocal - 1]; + m_modes[posLocal - 1] = temp; + } + else + { + break; + } + } + } + + //set the number of modes + *pModesUsed = nModes; + + if (bBackgroundLow) + { + low_threshold = BACKGROUND; + } + else + { + low_threshold = FOREGROUND; + } + + if (bBackgroundHigh) + { + high_threshold = BACKGROUND; + } + else + { + high_threshold = FOREGROUND; + } } @@ -379,30 +379,30 @@ void ZivkovicAGMM::SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned // (the memory should already be reserved) // values: 255-foreground, 125-shadow, 0-background /////////////////////////////////////////////////////////////////////////////// -void ZivkovicAGMM::Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask) +void ZivkovicAGMM::Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask) { - unsigned char low_threshold, high_threshold; - - // update each pixel of the image - long posPixel; - unsigned char* pUsedModes=m_modes_per_pixel; - for(unsigned int r = 0; r < m_params.Height(); ++r) - { - for(unsigned int c = 0; c < m_params.Width(); ++c) - { - //update model+ background subtract - posPixel=(r*m_params.Width()+c)*m_params.MaxModes(); - SubtractPixel(posPixel, data(r,c), pUsedModes, low_threshold, high_threshold); - low_threshold_mask(r,c) = low_threshold; - high_threshold_mask(r,c) = high_threshold; - - m_background(r,c,0) = (unsigned char)m_modes[posPixel].muR; - m_background(r,c,1) = (unsigned char)m_modes[posPixel].muG; - m_background(r,c,2) = (unsigned char)m_modes[posPixel].muB; - - pUsedModes++; - } - } + unsigned char low_threshold, high_threshold; + + // update each pixel of the image + long posPixel; + unsigned char* pUsedModes = m_modes_per_pixel; + for (unsigned int r = 0; r < m_params.Height(); ++r) + { + for (unsigned int c = 0; c < m_params.Width(); ++c) + { + //update model+ background subtract + posPixel = (r*m_params.Width() + c)*m_params.MaxModes(); + SubtractPixel(posPixel, data(r, c), pUsedModes, low_threshold, high_threshold); + low_threshold_mask(r, c) = low_threshold; + high_threshold_mask(r, c) = high_threshold; + + m_background(r, c, 0) = (unsigned char)m_modes[posPixel].muR; + m_background(r, c, 1) = (unsigned char)m_modes[posPixel].muG; + m_background(r, c, 2) = (unsigned char)m_modes[posPixel].muB; + + pUsedModes++; + } + } } diff --git a/package_bgs/dp/ZivkovicAGMM.h b/package_bgs/dp/ZivkovicAGMM.h index 1cd99b0..07da9c3 100644 --- a/package_bgs/dp/ZivkovicAGMM.h +++ b/package_bgs/dp/ZivkovicAGMM.h @@ -18,7 +18,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * * ZivkovicAGMM.hpp * -* Purpose: Implementation of the Gaussian mixture model (GMM) background +* Purpose: Implementation of the Gaussian mixture model (GMM) background * subtraction algorithm developed by Z. Zivkovic. * * Author: Donovan Parks, September 2007 @@ -28,13 +28,13 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. * following papers: * * "Improved adaptive Gausian mixture model for background subtraction" -* Z.Zivkovic +* Z.Zivkovic * International Conference Pattern Recognition, UK, August, 2004 * * -* "Efficient Adaptive Density Estimapion per Image Pixel for the +* "Efficient Adaptive Density Estimapion per Image Pixel for the * Task of Background Subtraction" -* Z.Zivkovic, F. van der Heijden +* Z.Zivkovic, F. van der Heijden * Pattern Recognition Letters, vol. 27, no. 7, pages 773-780, 2006. * * Zivkovic's code can be obtained at: www.zoranz.net @@ -43,16 +43,14 @@ Example: Algorithms::BackgroundSubtraction::ZivkovicParams params; params.SetFrameSize(width, height); params.LowThreshold() = 5.0f*5.0f; -params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing +params.HighThreshold() = 2*params.LowThreshold(); // Note: high threshold is used by post-processing params.Alpha() = 0.001f; params.MaxModes() = 3; Algorithms::BackgroundSubtraction::ZivkovicAGMM bgs; bgs.Initalize(params); ******************************************************************************/ - -#ifndef ZIVKOVIC_AGMM_H -#define ZIVKOVIC_AGMM_H +#pragma once #include "Bgs.h" @@ -71,18 +69,18 @@ namespace Algorithms int &MaxModes() { return m_max_modes; } private: - // Threshold on the squared dist. to decide when a sample is close to an existing - // components. If it is not close to any a new component will be generated. - // Smaller threshold values lead to more generated components and higher threshold values + // Threshold on the squared dist. to decide when a sample is close to an existing + // components. If it is not close to any a new component will be generated. + // Smaller threshold values lead to more generated components and higher threshold values // lead to a small number of components but they can grow too large. // - // It is usual easiest to think of these thresholds as being the number of variances (not standard deviations) + // It is usual easiest to think of these thresholds as being the number of variances (not standard deviations) // away from the mean of a pixel before it is considered to be from the foreground. float m_low_threshold; float m_high_threshold; // alpha - speed of update - if the time interval you want to average over is T - // set alpha=1/T. + // set alpha=1/T. float m_alpha; // Maximum number of modes (Gaussian components) that will be used per pixel @@ -109,14 +107,14 @@ namespace Algorithms void Initalize(const BgsParams& param); void InitModel(const RgbImage& data); - void Subtract(int frame_num, const RgbImage& data, - BwImage& low_threshold_mask, BwImage& high_threshold_mask); - void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); + void Subtract(int frame_num, const RgbImage& data, + BwImage& low_threshold_mask, BwImage& high_threshold_mask); + void Update(int frame_num, const RgbImage& data, const BwImage& update_mask); RgbImage* Background() { return &m_background; } private: - void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, + void SubtractPixel(long posPixel, const RgbPixel& pixel, unsigned char* pModesUsed, unsigned char& lowThreshold, unsigned char& highThreshold); // User adjustable parameters @@ -128,13 +126,13 @@ namespace Algorithms // it is considered foreground float m_bg_threshold; //1-cf from the paper - // Initial variance for the newly generated components. - // It will will influence the speed of adaptation. A good guess should be made. + // Initial variance for the newly generated components. + // It will will influence the speed of adaptation. A good guess should be made. // A simple way is to estimate the typical standard deviation from the images. float m_variance; // This is related to the number of samples needed to accept that a component - // actually exists. + // actually exists. float m_complexity_prior; //data @@ -150,11 +148,3 @@ namespace Algorithms }; } } - -#endif - - - - - - diff --git a/package_bgs/jmo/BlobResult.cpp b/package_bgs/jmo/BlobResult.cpp deleted file mode 100644 index 1a047c7..0000000 --- a/package_bgs/jmo/BlobResult.cpp +++ /dev/null @@ -1,847 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -BlobResult.cpp - -FUNCIONALITAT: Implementaci� de la classe CBlobResult -AUTOR: Inspecta S.L. -MODIFICACIONS (Modificaci�, Autor, Data): - -**************************************************************************/ - -#include <limits.h> -#include <stdio.h> -#include <functional> -#include <algorithm> -#include "BlobResult.h" -#include "BlobExtraction.h" - -/************************************************************************** -Constructors / Destructors -**************************************************************************/ - -namespace Blob -{ - - /** - - FUNCI�: CBlobResult - - FUNCIONALITAT: Constructor estandard. - - PAR�METRES: - - RESULTAT: - - Crea un CBlobResult sense cap blob - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobResult - - FUNCTIONALITY: Standard constructor - - PARAMETERS: - - RESULT: - - creates an empty set of blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult() - { - m_blobs = blob_vector(); - } - - /** - - FUNCI�: CBlobResult - - FUNCIONALITAT: Constructor a partir d'una imatge. Inicialitza la seq��ncia de blobs - amb els blobs resultants de l'an�lisi de blobs de la imatge. - - PAR�METRES: - - source: imatge d'on s'extreuran els blobs - - mask: m�scara a aplicar. Nom�s es calcularan els blobs on la m�scara sigui - diferent de 0. Els blobs que toquin a un pixel 0 de la m�scara seran - considerats exteriors. - - threshold: llindar que s'aplicar� a la imatge source abans de calcular els blobs - - findmoments: indica si s'han de calcular els moments de cada blob - - RESULTAT: - - objecte CBlobResult amb els blobs de la imatge source - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Constructor from an image. Fills an object with all the blobs in - the image - - PARAMETERS: - - source: image to extract the blobs from - - mask: optional mask to apply. The blobs will be extracted where the mask is - not 0. All the neighbouring blobs where the mask is 0 will be extern blobs - - threshold: threshold level to apply to the image before computing blobs - - findmoments: true to calculate the blob moments (slower) - - RESULT: - - object with all the blobs in the image. It throws an EXCEPCIO_CALCUL_BLOBS - if some error appears in the BlobAnalysis function - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult(IplImage *source, IplImage *mask, int threshold, bool findmoments) - { - bool success; - - try - { - // cridem la funci� amb el marc a true=1=blanc (aix� no unir� els blobs externs) - success = BlobAnalysis(source, (uchar)threshold, mask, true, findmoments, m_blobs); - } - catch (...) - { - success = false; - } - - if (!success) throw EXCEPCIO_CALCUL_BLOBS; - } - - /** - - FUNCI�: CBlobResult - - FUNCIONALITAT: Constructor de c�pia. Inicialitza la seq��ncia de blobs - amb els blobs del par�metre. - - PAR�METRES: - - source: objecte que es copiar� - - RESULTAT: - - objecte CBlobResult amb els blobs de l'objecte source - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobResult - - FUNCTIONALITY: Copy constructor - - PARAMETERS: - - source: object to copy - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::CBlobResult(const CBlobResult &source) - { - m_blobs = blob_vector(source.GetNumBlobs()); - - // creem el nou a partir del passat com a par�metre - m_blobs = blob_vector(source.GetNumBlobs()); - // copiem els blobs de l'origen a l'actual - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = m_blobs.begin(); - - while (pBlobsSrc != source.m_blobs.end()) - { - // no podem cridar a l'operador = ja que blob_vector �s un - // vector de CBlob*. Per tant, creem un blob nou a partir del - // blob original - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - ++pBlobsDst; - } - } - - - - /** - - FUNCI�: ~CBlobResult - - FUNCIONALITAT: Destructor estandard. - - PAR�METRES: - - RESULTAT: - - Allibera la mem�ria reservada de cadascun dels blobs de la classe - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: ~CBlobResult - - FUNCTIONALITY: Destructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult::~CBlobResult() - { - ClearBlobs(); - } - - /************************************************************************** - Operadors / Operators - **************************************************************************/ - - - /** - - FUNCI�: operador = - - FUNCIONALITAT: Assigna un objecte source a l'actual - - PAR�METRES: - - source: objecte a assignar - - RESULTAT: - - Substitueix els blobs actuals per els de l'objecte source - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: Assigment operator - - FUNCTIONALITY: - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult& CBlobResult::operator=(const CBlobResult& source) - { - // si ja s�n el mateix, no cal fer res - if (this != &source) - { - // alliberem el conjunt de blobs antic - for (int i = 0; i < GetNumBlobs(); i++) - { - delete m_blobs[i]; - } - m_blobs.clear(); - // creem el nou a partir del passat com a par�metre - m_blobs = blob_vector(source.GetNumBlobs()); - // copiem els blobs de l'origen a l'actual - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = m_blobs.begin(); - - while (pBlobsSrc != source.m_blobs.end()) - { - // no podem cridar a l'operador = ja que blob_vector �s un - // vector de CBlob*. Per tant, creem un blob nou a partir del - // blob original - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - ++pBlobsDst; - } - } - return *this; - } - - - /** - - FUNCI�: operador + - - FUNCIONALITAT: Concatena els blobs de dos CBlobResult - - PAR�METRES: - - source: d'on s'agafaran els blobs afegits a l'actual - - RESULTAT: - - retorna un nou CBlobResult amb els dos CBlobResult concatenats - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - NOTA: per la implementaci�, els blobs del par�metre es posen en ordre invers - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: + operator - - FUNCTIONALITY: Joins the blobs in source with the current ones - - PARAMETERS: - - source: object to copy the blobs - - RESULT: - - object with the actual blobs and the source blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlobResult CBlobResult::operator+(const CBlobResult& source) - { - //creem el resultat a partir dels blobs actuals - CBlobResult resultat(*this); - - // reservem mem�ria per als nous blobs - resultat.m_blobs.resize(resultat.GetNumBlobs() + source.GetNumBlobs()); - - // declarem els iterador per rec�rrer els blobs d'origen i desti - blob_vector::const_iterator pBlobsSrc = source.m_blobs.begin(); - blob_vector::iterator pBlobsDst = resultat.m_blobs.end(); - - // insertem els blobs de l'origen a l'actual - while (pBlobsSrc != source.m_blobs.end()) - { - --pBlobsDst; - *pBlobsDst = new CBlob(**pBlobsSrc); - ++pBlobsSrc; - } - - return resultat; - } - - /************************************************************************** - Operacions / Operations - **************************************************************************/ - - /** - - FUNCI�: AddBlob - - FUNCIONALITAT: Afegeix un blob al conjunt - - PAR�METRES: - - blob: blob a afegir - - RESULTAT: - - modifica el conjunt de blobs actual - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 2006/03/01 - - MODIFICACI�: Data. Autor. Descripci�. - */ - void CBlobResult::AddBlob(CBlob *blob) - { - if (blob != NULL) - m_blobs.push_back(new CBlob(blob)); - } - - - /** - - FUNCI�: GetSTLResult - - FUNCIONALITAT: Calcula el resultat especificat sobre tots els blobs de la classe - - PAR�METRES: - - evaluador: Qualsevol objecte derivat de COperadorBlob - - RESULTAT: - - Retorna un array de double's STL amb el resultat per cada blob - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: GetResult - - FUNCTIONALITY: Computes the function evaluador on all the blobs of the class - and returns a vector with the result - - PARAMETERS: - - evaluador: function to apply to each blob (any object derived from the - COperadorBlob class ) - - RESULT: - - vector with all the results in the same order as the blobs - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double_stl_vector CBlobResult::GetSTLResult(funcio_calculBlob *evaluador) const - { - if (GetNumBlobs() <= 0) - { - return double_stl_vector(); - } - - // definim el resultat - double_stl_vector result = double_stl_vector(GetNumBlobs()); - // i iteradors sobre els blobs i el resultat - double_stl_vector::iterator itResult = result.begin(); - blob_vector::const_iterator itBlobs = m_blobs.begin(); - - // avaluem la funci� en tots els blobs - while (itBlobs != m_blobs.end()) - { - *itResult = (*evaluador)(**itBlobs); - ++itBlobs; - ++itResult; - } - return result; - } - - /** - - FUNCI�: GetNumber - - FUNCIONALITAT: Calcula el resultat especificat sobre un �nic blob de la classe - - PAR�METRES: - - evaluador: Qualsevol objecte derivat de COperadorBlob - - indexblob: n�mero de blob del que volem calcular el resultat. - - RESULTAT: - - Retorna un double amb el resultat - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: GetNumber - - FUNCTIONALITY: Computes the function evaluador on a blob of the class - - PARAMETERS: - - indexBlob: index of the blob to compute the function - - evaluador: function to apply to each blob (any object derived from the - COperadorBlob class ) - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobResult::GetNumber(int indexBlob, funcio_calculBlob *evaluador) const - { - if (indexBlob < 0 || indexBlob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - return (*evaluador)(*m_blobs[indexBlob]); - } - - /////////////////////////// FILTRAT DE BLOBS //////////////////////////////////// - - /** - - FUNCI�: Filter - - FUNCIONALITAT: Filtra els blobs de la classe i deixa el resultat amb nom�s - els blobs que han passat el filtre. - El filtrat es basa en especificar condicions sobre un resultat dels blobs - i seleccionar (o excloure) aquells blobs que no compleixen una determinada - condicio - - PAR�METRES: - - dst: variable per deixar els blobs filtrats - - filterAction: acci� de filtrat. Incloure els blobs trobats (B_INCLUDE), - o excloure els blobs trobats (B_EXCLUDE) - - evaluador: Funci� per evaluar els blobs (qualsevol objecte derivat de COperadorBlob - - Condition: tipus de condici� que ha de superar la mesura (FilterType) - sobre cada blob per a ser considerat. - B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, - B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - - LowLimit: valor num�ric per a la comparaci� (Condition) de la mesura (FilterType) - - HighLimit: valor num�ric per a la comparaci� (Condition) de la mesura (FilterType) - (nom�s t� sentit per a aquelles condicions que tenen dos valors - (B_INSIDE, per exemple). - - RESULTAT: - - Deixa els blobs resultants del filtrat a destination - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: Filter - - FUNCTIONALITY: Get some blobs from the class based on conditions on measures - of the blobs. - - PARAMETERS: - - dst: where to store the selected blobs - - filterAction: B_INCLUDE: include the blobs which pass the filter in the result - B_EXCLUDE: exclude the blobs which pass the filter in the result - - evaluador: Object to evaluate the blob - - Condition: How to decide if the result returned by evaluador on each blob - is included or not. It can be: - B_EQUAL,B_NOT_EQUAL,B_GREATER,B_LESS,B_GREATER_OR_EQUAL, - B_LESS_OR_EQUAL,B_INSIDE,B_OUTSIDE - - LowLimit: numerical value to evaluate the Condition on evaluador(blob) - - HighLimit: numerical value to evaluate the Condition on evaluador(blob). - Only useful for B_INSIDE and B_OUTSIDE - - RESULT: - - It returns on dst the blobs that accomplish (B_INCLUDE) or discards (B_EXCLUDE) - the Condition on the result returned by evaluador on each blob - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::Filter(CBlobResult &dst, - int filterAction, - funcio_calculBlob *evaluador, - int condition, - double lowLimit, double highLimit /*=0*/) - - { - int i, numBlobs; - bool resultavaluacio; - double_stl_vector avaluacioBlobs; - double_stl_vector::iterator itavaluacioBlobs; - - if (GetNumBlobs() <= 0) return; - if (!evaluador) return; - //avaluem els blobs amb la funci� pertinent - avaluacioBlobs = GetSTLResult(evaluador); - itavaluacioBlobs = avaluacioBlobs.begin(); - numBlobs = GetNumBlobs(); - switch (condition) - { - case B_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs == lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_NOT_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs != lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_GREATER: - for (i = 0; i<numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs > lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_LESS: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs < lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_GREATER_OR_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs >= lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_LESS_OR_EQUAL: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = *itavaluacioBlobs <= lowLimit; - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_INSIDE: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = (*itavaluacioBlobs >= lowLimit) && (*itavaluacioBlobs <= highLimit); - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - case B_OUTSIDE: - for (i = 0; i < numBlobs; i++, itavaluacioBlobs++) - { - resultavaluacio = (*itavaluacioBlobs < lowLimit) || (*itavaluacioBlobs > highLimit); - if ((resultavaluacio && filterAction == B_INCLUDE) || - (!resultavaluacio && filterAction == B_EXCLUDE)) - { - dst.m_blobs.push_back(new CBlob(GetBlob(i))); - } - } - break; - } - - - // en cas de voler filtrar un CBlobResult i deixar-ho en el mateix CBlobResult - // ( operacio inline ) - if (&dst == this) - { - // esborrem els primers blobs ( que s�n els originals ) - // ja que els tindrem replicats al final si passen el filtre - blob_vector::iterator itBlobs = m_blobs.begin(); - for (int i = 0; i < numBlobs; i++) - { - delete *itBlobs; - ++itBlobs; - } - m_blobs.erase(m_blobs.begin(), itBlobs); - } - } - - - /** - - FUNCI�: GetBlob - - FUNCIONALITAT: Retorna un blob si aquest existeix (index != -1) - - PAR�METRES: - - indexblob: index del blob a retornar - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /* - - FUNCTION: GetBlob - - FUNCTIONALITY: Gets the n-th blob (without ordering the blobs) - - PARAMETERS: - - indexblob: index in the blob array - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob CBlobResult::GetBlob(int indexblob) const - { - if (indexblob < 0 || indexblob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - - return *m_blobs[indexblob]; - } - CBlob *CBlobResult::GetBlob(int indexblob) - { - if (indexblob < 0 || indexblob >= GetNumBlobs()) - RaiseError(EXCEPTION_BLOB_OUT_OF_BOUNDS); - - return m_blobs[indexblob]; - } - - /** - - FUNCI�: GetNthBlob - - FUNCIONALITAT: Retorna l'en�ssim blob segons un determinat criteri - - PAR�METRES: - - criteri: criteri per ordenar els blobs (objectes derivats de COperadorBlob) - - nBlob: index del blob a retornar - - dst: on es retorna el resultat - - RESULTAT: - - retorna el blob nBlob a dst ordenant els blobs de la classe segons el criteri - en ordre DESCENDENT. Per exemple, per obtenir el blob major: - GetNthBlob( CBlobGetArea(), 0, blobMajor ); - GetNthBlob( CBlobGetArea(), 1, blobMajor ); (segon blob m�s gran) - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /* - - FUNCTION: GetNthBlob - - FUNCTIONALITY: Gets the n-th blob ordering first the blobs with some criteria - - PARAMETERS: - - criteri: criteria to order the blob array - - nBlob: index of the returned blob in the ordered blob array - - dst: where to store the result - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::GetNthBlob(funcio_calculBlob *criteri, int nBlob, CBlob &dst) const - { - // verifiquem que no estem accedint fora el vector de blobs - if (nBlob < 0 || nBlob >= GetNumBlobs()) - { - //RaiseError( EXCEPTION_BLOB_OUT_OF_BOUNDS ); - dst = CBlob(); - return; - } - - double_stl_vector avaluacioBlobs, avaluacioBlobsOrdenat; - double valorEnessim; - - //avaluem els blobs amb la funci� pertinent - avaluacioBlobs = GetSTLResult(criteri); - - avaluacioBlobsOrdenat = double_stl_vector(GetNumBlobs()); - - // obtenim els nBlob primers resultats (en ordre descendent) - std::partial_sort_copy(avaluacioBlobs.begin(), - avaluacioBlobs.end(), - avaluacioBlobsOrdenat.begin(), - avaluacioBlobsOrdenat.end(), - std::greater<double>()); - - valorEnessim = avaluacioBlobsOrdenat[nBlob]; - - // busquem el primer blob que t� el valor n-ssim - double_stl_vector::const_iterator itAvaluacio = avaluacioBlobs.begin(); - - bool trobatBlob = false; - int indexBlob = 0; - while (itAvaluacio != avaluacioBlobs.end() && !trobatBlob) - { - if (*itAvaluacio == valorEnessim) - { - trobatBlob = true; - dst = CBlob(GetBlob(indexBlob)); - } - ++itAvaluacio; - indexBlob++; - } - } - - /** - - FUNCI�: ClearBlobs - - FUNCIONALITAT: Elimina tots els blobs de l'objecte - - PAR�METRES: - - RESULTAT: - - Allibera tota la mem�ria dels blobs - - RESTRICCIONS: - - AUTOR: Ricard Borr�s Navarra - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /* - - FUNCTION: ClearBlobs - - FUNCTIONALITY: Clears all the blobs from the object and releases all its memory - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::ClearBlobs() - { - /*for( int i = 0; i < GetNumBlobs(); i++ ) - { - delete m_blobs[i]; - }*/ - blob_vector::iterator itBlobs = m_blobs.begin(); - while (itBlobs != m_blobs.end()) - { - delete *itBlobs; - ++itBlobs; - } - - m_blobs.clear(); - } - - /** - - FUNCI�: RaiseError - - FUNCIONALITAT: Funci� per a notificar errors al l'usuari (en debug) i llen�a - les excepcions - - PAR�METRES: - - errorCode: codi d'error - - RESULTAT: - - Ensenya un missatge a l'usuari (en debug) i llen�a una excepci� - - RESTRICCIONS: - - AUTOR: Ricard Borr�s Navarra - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /* - - FUNCTION: RaiseError - - FUNCTIONALITY: Error handling function - - PARAMETERS: - - errorCode: reason of the error - - RESULT: - - in _DEBUG version, shows a message box with the error. In release is silent. - In both cases throws an exception with the error. - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::RaiseError(const int errorCode) const - { - throw errorCode; - } - - - - /************************************************************************** - Auxiliars / Auxiliary functions - **************************************************************************/ - - - /** - - FUNCI�: PrintBlobs - - FUNCIONALITAT: Escriu els par�metres (�rea, per�metre, exterior, mitjana) - de tots els blobs a un fitxer. - - PAR�METRES: - - nom_fitxer: path complet del fitxer amb el resultat - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /* - - FUNCTION: PrintBlobs - - FUNCTIONALITY: Prints some blob features in an ASCII file - - PARAMETERS: - - nom_fitxer: full path + filename to generate - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlobResult::PrintBlobs(char *nom_fitxer) const - { - double_stl_vector area, /*perimetre,*/ exterior, mitjana, compacitat, longitud, - externPerimeter, perimetreConvex, perimetre; - int i; - FILE *fitxer_sortida; - - area = GetSTLResult(CBlobGetArea()); - perimetre = GetSTLResult(CBlobGetPerimeter()); - exterior = GetSTLResult(CBlobGetExterior()); - mitjana = GetSTLResult(CBlobGetMean()); - compacitat = GetSTLResult(CBlobGetCompactness()); - longitud = GetSTLResult(CBlobGetLength()); - externPerimeter = GetSTLResult(CBlobGetExternPerimeter()); - perimetreConvex = GetSTLResult(CBlobGetHullPerimeter()); - - fitxer_sortida = fopen(nom_fitxer, "w"); - - for (i = 0; i < GetNumBlobs(); i++) - { - fprintf(fitxer_sortida, "blob %d ->\t a=%7.0f\t p=%8.2f (%8.2f extern)\t pconvex=%8.2f\t ext=%.0f\t m=%7.2f\t c=%3.2f\t l=%8.2f\n", - i, area[i], perimetre[i], externPerimeter[i], perimetreConvex[i], exterior[i], mitjana[i], compacitat[i], longitud[i]); - } - fclose(fitxer_sortida); - - } - -} diff --git a/package_bgs/jmo/MultiLayerBGS.h b/package_bgs/jmo/MultiLayerBGS.h deleted file mode 100644 index 29db946..0000000 --- a/package_bgs/jmo/MultiLayerBGS.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "CMultiLayerBGS.h" - -class MultiLayerBGS : public IBGS -{ -public: - enum Status - { - MLBGS_NONE = -1, - MLBGS_LEARN = 0, - MLBGS_DETECT = 1 - }; - -private: - bool firstTime; - long long frameNumber; - cv::Mat img_foreground; - cv::Mat img_merged; - cv::Mat img_background; - bool showOutput; - bool saveModel; - bool disableDetectMode; - bool disableLearning; - int detectAfter; - CMultiLayerBGS* BGS; - Status status; - IplImage* img; - IplImage* org_img; - IplImage* fg_img; - IplImage* bg_img; - IplImage* fg_prob_img; - IplImage* fg_mask_img; - IplImage* fg_prob_img3; - IplImage* merged_img; - std::string bg_model_preload; - - bool loadDefaultParams; - - int max_mode_num; - float weight_updating_constant; - float texture_weight; - float bg_mode_percent; - int pattern_neig_half_size; - float pattern_neig_gaus_sigma; - float bg_prob_threshold; - float bg_prob_updating_threshold; - int robust_LBP_constant; - float min_noised_angle; - float shadow_rate; - float highlight_rate; - float bilater_filter_sigma_s; - float bilater_filter_sigma_r; - - float frame_duration; - - float mode_learn_rate_per_second; - float weight_learn_rate_per_second; - float init_mode_weight; - - float learn_mode_learn_rate_per_second; - float learn_weight_learn_rate_per_second; - float learn_init_mode_weight; - - float detect_mode_learn_rate_per_second; - float detect_weight_learn_rate_per_second; - float detect_init_mode_weight; - -public: - MultiLayerBGS(); - ~MultiLayerBGS(); - - void setStatus(Status status); - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void finish(void); - void saveConfig(); - void loadConfig(); -}; \ No newline at end of file diff --git a/package_bgs/jmo/blob.cpp b/package_bgs/jmo/blob.cpp deleted file mode 100644 index 3629714..0000000 --- a/package_bgs/jmo/blob.cpp +++ /dev/null @@ -1,1149 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -/* --- --- --- -* Copyright (C) 2008--2010 Idiap Research Institute (.....@idiap.ch) -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. The name of the author may not be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/************************************************************************ -Blob.cpp - -- FUNCIONALITAT: Implementaci� de la classe CBlob -- AUTOR: Inspecta S.L. -MODIFICACIONS (Modificaci�, Autor, Data): - - -FUNCTIONALITY: Implementation of the CBlob class and some helper classes to perform -some calculations on it -AUTHOR: Inspecta S.L. -MODIFICATIONS (Modification, Author, Date): - -**************************************************************************/ - - -#include <limits.h> -#include "blob.h" -#include <opencv2/opencv.hpp> - -namespace Blob -{ - - /** - - FUNCI�: CBlob - - FUNCIONALITAT: Constructor est�ndard - - PAR�METRES: - - RESULTAT: - - inicialitzaci� de totes les variables internes i de l'storage i la sequencia - per a les cantonades del blob - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Standard constructor - - PARAMETERS: - - RESULT: - - memory allocation for the blob edges and initialization of member variables - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::CBlob() - { - etiqueta = -1; // Flag indicates null region - exterior = 0; - area = 0.0f; - perimeter = 0.0f; - parent = -1; - minx = LONG_MAX; - maxx = 0; - miny = LONG_MAX; - maxy = 0; - sumx = 0; - sumy = 0; - sumxx = 0; - sumyy = 0; - sumxy = 0; - mean = 0; - stddev = 0; - externPerimeter = 0; - - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - } - - /** - - FUNCI�: CBlob - - FUNCIONALITAT: Constructor de c�pia - - PAR�METRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Copy constructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::CBlob(const CBlob &src) - { - // copiem les propietats del blob origen a l'actual - etiqueta = src.etiqueta; - exterior = src.exterior; - area = src.Area(); - perimeter = src.Perimeter(); - parent = src.parent; - minx = src.minx; - maxx = src.maxx; - miny = src.miny; - maxy = src.maxy; - sumx = src.sumx; - sumy = src.sumy; - sumxx = src.sumxx; - sumyy = src.sumyy; - sumxy = src.sumxy; - mean = src.mean; - stddev = src.stddev; - externPerimeter = src.externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - cvStartReadSeq(src.Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - CBlob::CBlob(const CBlob *src) - { - // copiem les propietats del blob origen a l'actual - etiqueta = src->etiqueta; - exterior = src->exterior; - area = src->Area(); - perimeter = src->Perimeter(); - parent = src->parent; - minx = src->minx; - maxx = src->maxx; - miny = src->miny; - maxy = src->maxy; - sumx = src->sumx; - sumy = src->sumy; - sumxx = src->sumxx; - sumyy = src->sumyy; - sumxy = src->sumxy; - mean = src->mean; - stddev = src->stddev; - externPerimeter = src->externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - cvStartReadSeq(src->Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src->Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - - /** - - FUNCI�: ~CBlob - - FUNCIONALITAT: Destructor est�ndard - - PAR�METRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlob - - FUNCTIONALITY: Standard destructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob::~CBlob() - { - // Eliminar v�rtexs del blob - cvClearSeq(edges); - // i la zona de mem�ria on s�n - cvReleaseMemStorage(&m_storage); - } - - /** - - FUNCI�: operator= - - FUNCIONALITAT: Operador d'assignaci� - - PAR�METRES: - - src: blob a assignar a l'actual - - RESULTAT: - - Substitueix el blob actual per el src - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: Assigment operator - - FUNCTIONALITY: Assigns a blob to the current - - PARAMETERS: - - src: blob to assign - - RESULT: - - the current blob is replaced by the src blob - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CBlob& CBlob::operator=(const CBlob &src) - { - // si ja s�n el mateix, no cal fer res - if (this != &src) - { - // Eliminar v�rtexs del blob - cvClearSeq(edges); - // i la zona de mem�ria on s�n - cvReleaseMemStorage(&m_storage); - - // creem una sequencia buida per als edges - m_storage = cvCreateMemStorage(0); - edges = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2, - sizeof(CvContour), - sizeof(CvPoint), m_storage); - - // copiem les propietats del blob origen a l'actual - etiqueta = src.etiqueta; - exterior = src.exterior; - area = src.Area(); - perimeter = src.Perimeter(); - parent = src.parent; - minx = src.minx; - maxx = src.maxx; - miny = src.miny; - maxy = src.maxy; - sumx = src.sumx; - sumy = src.sumy; - sumxx = src.sumxx; - sumyy = src.sumyy; - sumxy = src.sumxy; - mean = src.mean; - stddev = src.stddev; - externPerimeter = src.externPerimeter; - - // copiem els edges del blob origen a l'actual - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - cvStartReadSeq(src.Edges(), &reader); - cvStartAppendToSeq(edges, &writer); - - for (int i = 0; i < src.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - return *this; - } - - /** - - FUNCI�: FillBlob - - FUNCIONALITAT: Pinta l'interior d'un blob amb el color especificat - - PAR�METRES: - - imatge: imatge on es vol pintar el el blob - - color: color amb que es vol pintar el blob - - RESULTAT: - - retorna la imatge d'entrada amb el blob pintat - - RESTRICCIONS: - - AUTOR: - - Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: FillBlob - - FUNCTIONALITY: - - Fills the blob with a specified colour - - PARAMETERS: - - imatge: where to paint - - color: colour to paint the blob - - RESULT: - - modifies input image and returns the seed point used to fill the blob - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::FillBlob(IplImage *imatge, CvScalar color, int offsetX /*=0*/, int offsetY /*=0*/) const - { - - //verifiquem que existeixi el blob i que tingui cantonades - if (edges == NULL || edges->total == 0) return; - - CvPoint edgeactual, pt1, pt2; - CvSeqReader reader; - vectorPunts vectorEdges = vectorPunts(edges->total); - vectorPunts::iterator itEdges, itEdgesSeguent; - bool dinsBlob; - int yActual; - - // passem els punts del blob a un vector de punts de les STL - cvStartReadSeq(edges, &reader); - itEdges = vectorEdges.begin(); - while (itEdges != vectorEdges.end()) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - *itEdges = edgeactual; - ++itEdges; - } - // ordenem el vector per les Y's i les X's d'esquerra a dreta - std::sort(vectorEdges.begin(), vectorEdges.end(), comparaCvPoint()); - - // recorrem el vector ordenat i fem linies entre punts consecutius - itEdges = vectorEdges.begin(); - itEdgesSeguent = vectorEdges.begin() + 1; - dinsBlob = true; - while (itEdges != (vectorEdges.end() - 1)) - { - yActual = (*itEdges).y; - - if (((*itEdges).x != (*itEdgesSeguent).x) && - ((*itEdgesSeguent).y == yActual) - ) - { - if (dinsBlob) - { - pt1 = *itEdges; - pt1.x += offsetX; - pt1.y += offsetY; - - pt2 = *itEdgesSeguent; - pt2.x += offsetX; - pt2.y += offsetY; - - cvLine(imatge, pt1, pt2, color); - } - dinsBlob = !dinsBlob; - } - ++itEdges; - ++itEdgesSeguent; - if ((*itEdges).y != yActual) dinsBlob = true; - } - vectorEdges.clear(); - } - - /** - - FUNCI�: CopyEdges - - FUNCIONALITAT: Afegeix els v�rtexs del blob al blob destination - - PAR�METRES: - - destination: blob al que volem afegir els v�rtexs - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CopyEdges - - FUNCTIONALITY: Adds the blob edges to destination - - PARAMETERS: - - destination: where to add the edges - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::CopyEdges(CBlob &destination) const - { - CvSeqReader reader; - CvSeqWriter writer; - CvPoint edgeactual; - - cvStartReadSeq(edges, &reader); - cvStartAppendToSeq(destination.Edges(), &writer); - - for (int i = 0; i < edges->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - CV_WRITE_SEQ_ELEM(edgeactual, writer); - } - - cvEndWriteSeq(&writer); - } - - /** - - FUNCI�: ClearEdges - - FUNCIONALITAT: Elimina els v�rtexs del blob - - PAR�METRES: - - RESULTAT: - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: ClearEdges - - FUNCTIONALITY: Delete current blob edges - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - void CBlob::ClearEdges() - { - // Eliminar v�rtexs del blob eliminat - cvClearSeq(edges); - } - - /** - - FUNCI�: GetConvexHull - - FUNCIONALITAT: Retorna el poligon convex del blob - - PAR�METRES: - - dst: sequencia on desarem el resultat (no ha d'estar inicialitzada) - - RESULTAT: - - true si tot ha anat b� - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: GetConvexHull - - FUNCTIONALITY: Calculates the convex hull polygon of the blob - - PARAMETERS: - - dst: where to store the result - - RESULT: - - true if no error ocurred - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - bool CBlob::GetConvexHull(CvSeq **dst) const - { - if (edges != NULL && edges->total > 0) - { - *dst = cvConvexHull2(edges, 0, CV_CLOCKWISE, 0); - return true; - } - return false; - } - - /** - - FUNCI�: GetEllipse - - FUNCIONALITAT: Retorna l'ellipse que s'ajusta millor a les cantonades del blob - - PAR�METRES: - - RESULTAT: - - estructura amb l'ellipse - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 25-05-2005. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: GetEllipse - - FUNCTIONALITY: Calculates the ellipse that best fits the edges of the blob - - PARAMETERS: - - RESULT: - - CvBox2D struct with the calculated ellipse - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - CvBox2D CBlob::GetEllipse() const - { - CvBox2D elipse; - // necessitem 6 punts per calcular l'elipse - if (edges != NULL && edges->total > 6) - { - elipse = cvFitEllipse2(edges); - } - else - { - elipse.center.x = 0.0; - elipse.center.y = 0.0; - elipse.size.width = 0.0; - elipse.size.height = 0.0; - elipse.angle = 0.0; - } - return elipse; - } - - - - /*************************************************************************** - Implementaci� de les classes per al c�lcul de caracter�stiques sobre el blob - - Implementation of the helper classes to perform operations on blobs - **************************************************************************/ - - /** - - FUNCI�: Moment - - FUNCIONALITAT: Calcula el moment pq del blob - - RESULTAT: - - retorna el moment pq especificat o 0 si el moment no est� implementat - - RESTRICCIONS: - - Implementats els moments pq: 00, 01, 10, 20, 02 - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: Moment - - FUNCTIONALITY: Calculates the pq moment of the blob - - PARAMETERS: - - RESULT: - - returns the pq moment or 0 if the moment it is not implemented - - RESTRICTIONS: - - Currently, only implemented the 00, 01, 10, 20, 02 pq moments - - AUTHOR: Ricard Borr�s - - CREATION DATE: 20-07-2004. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMoment::operator()(const CBlob &blob) const - { - //Moment 00 - if ((m_p == 0) && (m_q == 0)) - return blob.Area(); - - //Moment 10 - if ((m_p == 1) && (m_q == 0)) - return blob.SumX(); - - //Moment 01 - if ((m_p == 0) && (m_q == 1)) - return blob.SumY(); - - //Moment 20 - if ((m_p == 2) && (m_q == 0)) - return blob.SumXX(); - - //Moment 02 - if ((m_p == 0) && (m_q == 2)) - return blob.SumYY(); - - return 0; - } - - /** - - FUNCI�: HullPerimeter - - FUNCIONALITAT: Calcula la longitud del perimetre convex del blob. - Fa servir la funci� d'OpenCV cvConvexHull2 per a - calcular el perimetre convex. - - - PAR�METRES: - - RESULTAT: - - retorna la longitud del per�metre convex del blob. Si el blob no t� coordenades - associades retorna el per�metre normal del blob. - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobGetHullPerimeter - - FUNCTIONALITY: Calculates the convex hull perimeter of the blob - - PARAMETERS: - - RESULT: - - returns the convex hull perimeter of the blob or the perimeter if the - blob edges could not be retrieved - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetHullPerimeter::operator()(const CBlob &blob) const - { - if (blob.Edges() != NULL && blob.Edges()->total > 0) - { - CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); - return fabs(cvArcLength(hull, CV_WHOLE_SEQ, 1)); - } - return blob.Perimeter(); - } - - double CBlobGetHullArea::operator()(const CBlob &blob) const - { - if (blob.Edges() != NULL && blob.Edges()->total > 0) - { - CvSeq *hull = cvConvexHull2(blob.Edges(), 0, CV_CLOCKWISE, 1); - return fabs(cvContourArea(hull)); - } - return blob.Perimeter(); - } - - /** - - FUNCI�: MinX_at_MinY - - FUNCIONALITAT: Calcula el valor MinX a MinY. - - PAR�METRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la X minima en la Y minima. - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobGetMinXatMinY - - FUNCTIONALITY: Calculates the minimum X on the minimum Y - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMinXatMinY::operator()(const CBlob &blob) const - { - double MinX_at_MinY = LONG_MAX; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.y == blob.MinY()) && (edgeactual.x < MinX_at_MinY)) - { - MinX_at_MinY = edgeactual.x; - } - } - - return MinX_at_MinY; - } - - /** - - FUNCI�: MinY_at_MaxX - - FUNCIONALITAT: Calcula el valor MinX a MaxX. - - PAR�METRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la Y minima en la X maxima. - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobGetMinXatMinY - - FUNCTIONALITY: Calculates the minimum Y on the maximum X - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMinYatMaxX::operator()(const CBlob &blob) const - { - double MinY_at_MaxX = LONG_MAX; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j < blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.x == blob.MaxX()) && (edgeactual.y < MinY_at_MaxX)) - { - MinY_at_MaxX = edgeactual.y; - } - } - - return MinY_at_MaxX; - } - - /** - - FUNCI�: MaxX_at_MaxY - - FUNCIONALITAT: Calcula el valor MaxX a MaxY. - - PAR�METRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la X maxima en la Y maxima. - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobGetMaxXatMaxY - - FUNCTIONALITY: Calculates the maximum X on the maximum Y - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMaxXatMaxY::operator()(const CBlob &blob) const - { - double MaxX_at_MaxY = LONG_MIN; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j<blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.y == blob.MaxY()) && (edgeactual.x > MaxX_at_MaxY)) - { - MaxX_at_MaxY = edgeactual.x; - } - } - - return MaxX_at_MaxY; - } - - /** - - FUNCI�: MaxY_at_MinX - - FUNCIONALITAT: Calcula el valor MaxY a MinX. - - PAR�METRES: - - blob: blob del que volem calcular el valor - - RESULTAT: - - retorna la Y maxima en la X minima. - - RESTRICCIONS: - - AUTOR: Ricard Borr�s - - DATA DE CREACI�: 20-07-2004. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: CBlobGetMaxYatMinX - - FUNCTIONALITY: Calculates the maximum Y on the minimum X - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetMaxYatMinX::operator()(const CBlob &blob) const - { - double MaxY_at_MinX = LONG_MIN; - - CvSeqReader reader; - CvPoint edgeactual; - - cvStartReadSeq(blob.Edges(), &reader); - - for (int j = 0; j<blob.Edges()->total; j++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if ((edgeactual.x == blob.MinY()) && (edgeactual.y > MaxY_at_MinX)) - { - MaxY_at_MinX = edgeactual.y; - } - } - - return MaxY_at_MinX; - } - - /** - Retorna l'elongaci� del blob (longitud/amplada) - */ - /** - - FUNCTION: CBlobGetElongation - - FUNCTIONALITY: Calculates the elongation of the blob ( length/breadth ) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - See below to see how the lenght and the breadth are aproximated - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetElongation::operator()(const CBlob &blob) const - { - double ampladaC, longitudC, amplada, longitud; - - ampladaC = (double)(blob.Perimeter() + sqrt(pow(blob.Perimeter(), 2) - 16 * blob.Area())) / 4; - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - longitud = MAX(longitudC, ampladaC); - amplada = MIN(longitudC, ampladaC); - - return (double)longitud / amplada; - } - - /** - Retorna la compacitat del blob - */ - /** - - FUNCTION: CBlobGetCompactness - - FUNCTIONALITY: Calculates the compactness of the blob - ( maximum for circle shaped blobs, minimum for the rest) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetCompactness::operator()(const CBlob &blob) const - { - if (blob.Area() != 0.0) - return (double)pow(blob.Perimeter(), 2) / (4 * CV_PI*blob.Area()); - else - return 0.0; - } - - /** - Retorna la rugositat del blob - */ - /** - - FUNCTION: CBlobGetRoughness - - FUNCTIONALITY: Calculates the roughness of the blob - ( ratio between perimeter and convex hull perimeter) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetRoughness::operator()(const CBlob &blob) const - { - CBlobGetHullPerimeter getHullPerimeter = CBlobGetHullPerimeter(); - - double hullPerimeter = getHullPerimeter(blob); - - if (hullPerimeter != 0.0) - return blob.Perimeter() / hullPerimeter;//HullPerimeter(); - - return 0.0; - } - - /** - Retorna la longitud del blob - */ - /** - - FUNCTION: CBlobGetLength - - FUNCTIONALITY: Calculates the lenght of the blob (the biggest axis of the blob) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - The lenght is an aproximation to the real lenght - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetLength::operator()(const CBlob &blob) const - { - double ampladaC, longitudC; - double tmp; - - tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); - - if (tmp > 0.0) - ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; - // error intr�nsec en els c�lculs de l'�rea i el per�metre - else - ampladaC = (double)(blob.Perimeter()) / 4; - - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - return MAX(longitudC, ampladaC); - } - - /** - Retorna l'amplada del blob - */ - /** - - FUNCTION: CBlobGetBreadth - - FUNCTIONALITY: Calculates the breadth of the blob (the smallest axis of the blob) - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - The breadth is an aproximation to the real breadth - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetBreadth::operator()(const CBlob &blob) const - { - double ampladaC, longitudC; - double tmp; - - tmp = blob.Perimeter()*blob.Perimeter() - 16 * blob.Area(); - - if (tmp > 0.0) - ampladaC = (double)(blob.Perimeter() + sqrt(tmp)) / 4; - // error intr�nsec en els c�lculs de l'�rea i el per�metre - else - ampladaC = (double)(blob.Perimeter()) / 4; - - if (ampladaC <= 0.0) return 0; - longitudC = (double)blob.Area() / ampladaC; - - return MIN(longitudC, ampladaC); - } - - /** - Calcula la dist�ncia entre un punt i el centre del blob - */ - /** - - FUNCTION: CBlobGetDistanceFromPoint - - FUNCTIONALITY: Calculates the euclidean distance between the blob center and - the point specified in the constructor - - PARAMETERS: - - RESULT: - - RESTRICTIONS: - - AUTHOR: Ricard Borr�s - - CREATION DATE: 25-05-2005. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetDistanceFromPoint::operator()(const CBlob &blob) const - { - double xmitjana, ymitjana; - CBlobGetXCenter getXCenter; - CBlobGetYCenter getYCenter; - - xmitjana = m_x - getXCenter(blob); - ymitjana = m_y - getYCenter(blob); - - return sqrt((xmitjana*xmitjana) + (ymitjana*ymitjana)); - } - - /** - - FUNCI�: BlobGetXYInside - - FUNCIONALITAT: Calcula si un punt cau dins de la capsa rectangular - del blob - - RESULTAT: - - retorna 1 si hi est�; 0 si no - - RESTRICCIONS: - - AUTOR: Francesc Pinyol Margalef - - DATA DE CREACI�: 16-01-2006. - - MODIFICACI�: Data. Autor. Descripci�. - */ - /** - - FUNCTION: BlobGetXYInside - - FUNCTIONALITY: Calculates whether a point is inside the - rectangular bounding box of a blob - - PARAMETERS: - - RESULT: - - returns 1 if it is inside; o if not - - RESTRICTIONS: - - AUTHOR: Francesc Pinyol Margalef - - CREATION DATE: 16-01-2006. - - MODIFICATION: Date. Author. Description. - */ - double CBlobGetXYInside::operator()(const CBlob &blob) const - { - if (blob.Edges() == NULL || blob.Edges()->total == 0) return 0.0; - - // passem els punts del blob a un vector de punts de les STL - CvSeqReader reader; - CBlob::vectorPunts vectorEdges; - CBlob::vectorPunts::iterator itEdges, itEdgesSeguent; - CvPoint edgeactual; - bool dinsBlob; - - // agafem tots els punts amb la mateixa y que l'actual - cvStartReadSeq(blob.Edges(), &reader); - - for (int i = 0; i < blob.Edges()->total; i++) - { - CV_READ_SEQ_ELEM(edgeactual, reader); - if (edgeactual.y == m_p.y) - vectorEdges.push_back(edgeactual); - } - - if (vectorEdges.empty()) return 0.0; - - // ordenem el vector per les Y's i les X's d'esquerra a dreta - std::sort(vectorEdges.begin(), vectorEdges.end(), CBlob::comparaCvPoint()); - - // recorrem el punts del blob de la mateixa fila que el punt d'entrada - // i mirem si la X del punt d'entrada est� entre dos coordenades "plenes" - // del blob - itEdges = vectorEdges.begin(); - itEdgesSeguent = vectorEdges.begin() + 1; - dinsBlob = true; - - while (itEdges != (vectorEdges.end() - 1)) - { - if ((*itEdges).x <= m_p.x && (*itEdgesSeguent).x >= m_p.x && dinsBlob) - { - vectorEdges.clear(); - return 1.0; - } - - ++itEdges; - ++itEdgesSeguent; - dinsBlob = !dinsBlob; - } - - vectorEdges.clear(); - return 0.0; - } - -#ifdef BLOB_OBJECT_FACTORY - - /** - - FUNCI�: RegistraTotsOperadors - - FUNCIONALITAT: Registrar tots els operadors definits a blob.h - - PAR�METRES: - - fabricaOperadorsBlob: f�brica on es registraran els operadors - - RESULTAT: - - Modifica l'objecte fabricaOperadorsBlob - - RESTRICCIONS: - - Nom�s es registraran els operadors de blob.h. Si se'n volen afegir, cal afegir-los amb - el m�tode Register de la f�brica. - - AUTOR: rborras - - DATA DE CREACI�: 2006/05/18 - - MODIFICACI�: Data. Autor. Descripci�. - */ - void RegistraTotsOperadors( t_OperadorBlobFactory &fabricaOperadorsBlob ) - { - // blob shape - fabricaOperadorsBlob.Register( CBlobGetArea().GetNom(), Type2Type<CBlobGetArea>()); - fabricaOperadorsBlob.Register( CBlobGetBreadth().GetNom(), Type2Type<CBlobGetBreadth>()); - fabricaOperadorsBlob.Register( CBlobGetCompactness().GetNom(), Type2Type<CBlobGetCompactness>()); - fabricaOperadorsBlob.Register( CBlobGetElongation().GetNom(), Type2Type<CBlobGetElongation>()); - fabricaOperadorsBlob.Register( CBlobGetExterior().GetNom(), Type2Type<CBlobGetExterior>()); - fabricaOperadorsBlob.Register( CBlobGetLength().GetNom(), Type2Type<CBlobGetLength>()); - fabricaOperadorsBlob.Register( CBlobGetPerimeter().GetNom(), Type2Type<CBlobGetPerimeter>()); - fabricaOperadorsBlob.Register( CBlobGetRoughness().GetNom(), Type2Type<CBlobGetRoughness>()); - - // extern pixels - fabricaOperadorsBlob.Register( CBlobGetExternPerimeterRatio().GetNom(), Type2Type<CBlobGetExternPerimeterRatio>()); - fabricaOperadorsBlob.Register( CBlobGetExternHullPerimeterRatio().GetNom(), Type2Type<CBlobGetExternHullPerimeterRatio>()); - fabricaOperadorsBlob.Register( CBlobGetExternPerimeter().GetNom(), Type2Type<CBlobGetExternPerimeter>()); - - - // hull - fabricaOperadorsBlob.Register( CBlobGetHullPerimeter().GetNom(), Type2Type<CBlobGetHullPerimeter>()); - fabricaOperadorsBlob.Register( CBlobGetHullArea().GetNom(), Type2Type<CBlobGetHullArea>()); - - - // elipse info - fabricaOperadorsBlob.Register( CBlobGetMajorAxisLength().GetNom(), Type2Type<CBlobGetMajorAxisLength>()); - fabricaOperadorsBlob.Register( CBlobGetMinorAxisLength().GetNom(), Type2Type<CBlobGetMinorAxisLength>()); - fabricaOperadorsBlob.Register( CBlobGetAxisRatio().GetNom(), Type2Type<CBlobGetAxisRatio>()); - fabricaOperadorsBlob.Register( CBlobGetOrientation().GetNom(), Type2Type<CBlobGetOrientation>()); - fabricaOperadorsBlob.Register( CBlobGetOrientationCos().GetNom(), Type2Type<CBlobGetOrientationCos>()); - fabricaOperadorsBlob.Register( CBlobGetAreaElipseRatio().GetNom(), Type2Type<CBlobGetAreaElipseRatio>()); - - // min an max - fabricaOperadorsBlob.Register( CBlobGetMaxX().GetNom(), Type2Type<CBlobGetMaxX>()); - fabricaOperadorsBlob.Register( CBlobGetMaxY().GetNom(), Type2Type<CBlobGetMaxY>()); - fabricaOperadorsBlob.Register( CBlobGetMinX().GetNom(), Type2Type<CBlobGetMinX>()); - fabricaOperadorsBlob.Register( CBlobGetMinY().GetNom(), Type2Type<CBlobGetMinY>()); - - fabricaOperadorsBlob.Register( CBlobGetMaxXatMaxY().GetNom(), Type2Type<CBlobGetMaxXatMaxY>()); - fabricaOperadorsBlob.Register( CBlobGetMaxYatMinX().GetNom(), Type2Type<CBlobGetMaxYatMinX>()); - fabricaOperadorsBlob.Register( CBlobGetMinXatMinY().GetNom(), Type2Type<CBlobGetMinXatMinY>()); - fabricaOperadorsBlob.Register( CBlobGetMinYatMaxX().GetNom(), Type2Type<CBlobGetMinYatMaxX>()); - - // grey level stats - fabricaOperadorsBlob.Register( CBlobGetMean().GetNom(), Type2Type<CBlobGetMean>()); - fabricaOperadorsBlob.Register( CBlobGetStdDev().GetNom(), Type2Type<CBlobGetStdDev>()); - - // coordinate info - fabricaOperadorsBlob.Register( CBlobGetXYInside().GetNom(), Type2Type<CBlobGetXYInside>()); - fabricaOperadorsBlob.Register( CBlobGetDiffY().GetNom(), Type2Type<CBlobGetDiffY>()); - fabricaOperadorsBlob.Register( CBlobGetDiffX().GetNom(), Type2Type<CBlobGetDiffX>()); - fabricaOperadorsBlob.Register( CBlobGetXCenter().GetNom(), Type2Type<CBlobGetXCenter>()); - fabricaOperadorsBlob.Register( CBlobGetYCenter().GetNom(), Type2Type<CBlobGetYCenter>()); - fabricaOperadorsBlob.Register( CBlobGetDistanceFromPoint().GetNom(), Type2Type<CBlobGetDistanceFromPoint>()); - - // moments - fabricaOperadorsBlob.Register( CBlobGetMoment().GetNom(), Type2Type<CBlobGetMoment>()); - - } - -#endif - -} - diff --git a/package_bgs/lb/BGModel.cpp b/package_bgs/lb/BGModel.cpp index c42bec7..3c73b53 100644 --- a/package_bgs/lb/BGModel.cpp +++ b/package_bgs/lb/BGModel.cpp @@ -14,9 +14,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModel.cpp - + Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> This program is free software; you can redistribute it and/or modify @@ -38,11 +38,11 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. namespace lb_library { - BGModel::BGModel(int width, int height): m_width(width), m_height(height) + BGModel::BGModel(int width, int height) : m_width(width), m_height(height) { - m_SrcImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3); - m_BGImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3); - m_FGImage = cvCreateImage(cvSize(m_width,m_height), IPL_DEPTH_8U, 3); + m_SrcImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); + m_BGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); + m_FGImage = cvCreateImage(cvSize(m_width, m_height), IPL_DEPTH_8U, 3); cvZero(m_SrcImage); cvZero(m_BGImage); @@ -51,9 +51,9 @@ namespace lb_library BGModel::~BGModel() { - if (m_SrcImage!=NULL) cvReleaseImage(&m_SrcImage); - if (m_BGImage!=NULL) cvReleaseImage(&m_BGImage); - if (m_FGImage!=NULL) cvReleaseImage(&m_FGImage); + if (m_SrcImage != NULL) cvReleaseImage(&m_SrcImage); + if (m_BGImage != NULL) cvReleaseImage(&m_BGImage); + if (m_FGImage != NULL) cvReleaseImage(&m_FGImage); } IplImage* BGModel::GetSrc() @@ -73,15 +73,15 @@ namespace lb_library void BGModel::InitModel(IplImage* image) { - cvCopy(image,m_SrcImage); + cvCopy(image, m_SrcImage); Init(); return; } void BGModel::UpdateModel(IplImage* image) { - cvCopy(image,m_SrcImage); + cvCopy(image, m_SrcImage); Update(); return; } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModel.h b/package_bgs/lb/BGModel.h index 77f0490..d47ad62 100644 --- a/package_bgs/lb/BGModel.h +++ b/package_bgs/lb/BGModel.h @@ -14,9 +14,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModel.h - + Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> This program is free software; you can redistribute it and/or modify @@ -33,9 +33,7 @@ along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODEL_H -#define BGMODEL_H +#pragma once #include <opencv2/opencv.hpp> #include <math.h> @@ -54,7 +52,7 @@ namespace lb_library void InitModel(IplImage* image); void UpdateModel(IplImage* image); - + virtual void setBGModelParameter(int id, int value) {}; virtual IplImage* GetSrc(); @@ -62,17 +60,15 @@ namespace lb_library virtual IplImage* GetBG(); protected: - + IplImage* m_SrcImage; IplImage* m_BGImage; IplImage* m_FGImage; const int m_width; const int m_height; - + virtual void Init() = 0; virtual void Update() = 0; }; } - -#endif diff --git a/package_bgs/lb/BGModelFuzzyGauss.cpp b/package_bgs/lb/BGModelFuzzyGauss.cpp index 8706b13..b249052 100644 --- a/package_bgs/lb/BGModelFuzzyGauss.cpp +++ b/package_bgs/lb/BGModelFuzzyGauss.cpp @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelFuzzyGauss.cpp Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -40,7 +40,7 @@ namespace lb_library { namespace FuzzyGaussian { - BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width,height) + BGModelFuzzyGauss::BGModelFuzzyGauss(int width, int height) : BGModel(width, height) { m_alphamax = ALPHAFUZZYGAUSS; m_threshold = THRESHOLDFUZZYGAUSS * THRESHOLDFUZZYGAUSS; @@ -53,7 +53,7 @@ namespace lb_library DBLRGB *pMu = m_pMu; DBLRGB *pVar = m_pVar; - for(int k = 0; k < (m_width * m_height); k++) + for (int k = 0; k < (m_width * m_height); k++) { pMu->Red = 0.0; pMu->Green = 0.0; @@ -70,15 +70,15 @@ namespace lb_library BGModelFuzzyGauss::~BGModelFuzzyGauss() { - delete [] m_pMu; - delete [] m_pVar; + delete[] m_pMu; + delete[] m_pVar; } void BGModelFuzzyGauss::setBGModelParameter(int id, int value) { - double dvalue = (double)value/255.0; + double dvalue = (double)value / 255.0; - switch(id) + switch (id) { case 0: m_threshold = 100.0*dvalue*dvalue; @@ -107,9 +107,9 @@ namespace lb_library Image<BYTERGB> prgbSrc(m_SrcImage); - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { pMu->Red = prgbSrc[i][j].Red; pMu->Green = prgbSrc[i][j].Green; @@ -136,13 +136,13 @@ namespace lb_library Image<BYTERGB> prgbBG(m_BGImage); Image<BYTERGB> prgbFG(m_FGImage); - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { - double srcR = (double) prgbSrc[i][j].Red; - double srcG = (double) prgbSrc[i][j].Green; - double srcB = (double) prgbSrc[i][j].Blue; + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; // Fuzzy background subtraction (Mahalanobis distance) @@ -150,53 +150,53 @@ namespace lb_library double dg = srcG - pMu->Green; double db = srcB - pMu->Blue; - double d2 = dr*dr/pVar->Red + dg*dg/pVar->Green + db*db/pVar->Blue; + double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; double fuzzyBG = 1.0; - if(d2 < m_threshold) - fuzzyBG = d2/m_threshold; + if (d2 < m_threshold) + fuzzyBG = d2 / m_threshold; // Fuzzy running average double alpha = m_alphamax*exp(FUZZYEXP*fuzzyBG); - if(dr*dr > DBL_MIN) + if (dr*dr > DBL_MIN) pMu->Red += alpha*dr; - if(dg*dg > DBL_MIN) + if (dg*dg > DBL_MIN) pMu->Green += alpha*dg; - if(db*db > DBL_MIN) + if (db*db > DBL_MIN) pMu->Blue += alpha*db; double d; d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Red += alpha*d; d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Green += alpha*d; d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Blue += alpha*d; - pVar->Red = (std::max)(pVar->Red,m_noise); - pVar->Green = (std::max)(pVar->Green,m_noise); - pVar->Blue = (std::max)(pVar->Blue,m_noise); + pVar->Red = (std::max)(pVar->Red, m_noise); + pVar->Green = (std::max)(pVar->Green, m_noise); + pVar->Blue = (std::max)(pVar->Blue, m_noise); // Set foreground and background - if(fuzzyBG >= m_threshBG) + if (fuzzyBG >= m_threshBG) prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; else prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; - prgbBG[i][j].Red = (unsigned char)pMu->Red; - prgbBG[i][j].Green = (unsigned char)pMu->Green; + prgbBG[i][j].Red = (unsigned char)pMu->Red; + prgbBG[i][j].Green = (unsigned char)pMu->Green; prgbBG[i][j].Blue = (unsigned char)pMu->Blue; pMu++; @@ -207,4 +207,4 @@ namespace lb_library return; } } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModelFuzzyGauss.h b/package_bgs/lb/BGModelFuzzyGauss.h index 98a92e5..a73b716 100644 --- a/package_bgs/lb/BGModelFuzzyGauss.h +++ b/package_bgs/lb/BGModelFuzzyGauss.h @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelFuzzyGauss.h Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -33,9 +33,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODELFUZZYGAUSS_H -#define BGMODELFUZZYGAUSS_H +#pragma once #include "BGModel.h" @@ -71,5 +69,3 @@ namespace lb_library }; } } - -#endif diff --git a/package_bgs/lb/BGModelFuzzySom.cpp b/package_bgs/lb/BGModelFuzzySom.cpp index 189cb1a..e7e59dd 100644 --- a/package_bgs/lb/BGModelFuzzySom.cpp +++ b/package_bgs/lb/BGModelFuzzySom.cpp @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelFuzzySom.cpp Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -40,27 +40,27 @@ namespace lb_library { namespace FuzzyAdaptiveSOM { - BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width,height) + BGModelFuzzySom::BGModelFuzzySom(int width, int height) : BGModel(width, height) { - m_offset = (KERNEL - 1)/2; + m_offset = (KERNEL - 1) / 2; - if(SPAN_NEIGHBORS) - m_pad = 0; + if (SPAN_NEIGHBORS) + m_pad = 0; else m_pad = m_offset; // SOM models - m_widthSOM = m_width*M + 2*m_offset + (m_width-1)*m_pad; - m_heightSOM = m_height*N + 2*m_offset + (m_height-1)*m_pad; + m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; + m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; - m_ppSOM = new DBLRGB*[m_heightSOM]; - for(int n = 0; n < m_heightSOM; n++) + m_ppSOM = new DBLRGB*[m_heightSOM]; + for (int n = 0; n < m_heightSOM; n++) m_ppSOM[n] = new DBLRGB[m_widthSOM]; - for(int j = 0; j < m_heightSOM; j++) + for (int j = 0; j < m_heightSOM; j++) { - for(int i = 0; i < m_widthSOM; i++) + for (int i = 0; i < m_widthSOM; i++) { m_ppSOM[j][i].Red = 0.0; m_ppSOM[j][i].Green = 0.0; @@ -71,7 +71,7 @@ namespace lb_library // Create weights m_ppW = new double*[KERNEL]; - for(int n = 0; n < KERNEL; n++) + for (int n = 0; n < KERNEL; n++) m_ppW[n] = new double[KERNEL]; // Construct Gaussian kernel using Pascal's triangle @@ -81,15 +81,15 @@ namespace lb_library m_Wmax = DBL_MIN; cN = 1; - for(int j = 0; j < KERNEL; j++) + for (int j = 0; j < KERNEL; j++) { - cM = 1; + cM = 1; - for(int i = 0; i < KERNEL; i++) + for (int i = 0; i < KERNEL; i++) { m_ppW[j][i] = cN*cM; - if(m_ppW[j][i] > m_Wmax) + if (m_ppW[j][i] > m_Wmax) m_Wmax = m_ppW[j][i]; cM = cM * (KERNEL - 1 - i) / (i + 1); @@ -103,8 +103,8 @@ namespace lb_library m_epsilon1 = EPS1*EPS1; m_epsilon2 = EPS2*EPS2; - m_alpha1 = C1/m_Wmax; - m_alpha2 = C2/m_Wmax; + m_alpha1 = C1 / m_Wmax; + m_alpha2 = C2 / m_Wmax; m_K = 0; m_TSteps = TRAINING_STEPS; @@ -112,22 +112,22 @@ namespace lb_library BGModelFuzzySom::~BGModelFuzzySom() { - for(int n = 0; n < m_heightSOM; n++) - delete [] m_ppSOM[n]; + for (int n = 0; n < m_heightSOM; n++) + delete[] m_ppSOM[n]; - delete [] m_ppSOM; + delete[] m_ppSOM; - for(int n = 0; n < KERNEL; n++) - delete [] m_ppW[n]; + for (int n = 0; n < KERNEL; n++) + delete[] m_ppW[n]; - delete [] m_ppW; + delete[] m_ppW; } void BGModelFuzzySom::setBGModelParameter(int id, int value) { - double dvalue = (double)value/255.0; + double dvalue = (double)value / 255.0; - switch(id) + switch (id) { case 0: m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; @@ -138,11 +138,11 @@ namespace lb_library break; case 2: - m_alpha2 = dvalue*dvalue*dvalue/m_Wmax; + m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; break; case 3: - m_alpha1 = dvalue*dvalue*dvalue/m_Wmax; + m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; break; case 5: @@ -157,21 +157,21 @@ namespace lb_library { Image<BYTERGB> prgbSrc(m_SrcImage); - for(int j = 0; j < m_height; j++) + for (int j = 0; j < m_height; j++) { int jj = m_offset + j*(N + m_pad); - for(int i = 0; i < m_width; i++) + for (int i = 0; i < m_width; i++) { - int ii = m_offset + i*(M + m_pad); + int ii = m_offset + i*(M + m_pad); - for(int l = 0; l < N; l++) + for (int l = 0; l < N; l++) { - for(int k = 0; k < M; k++) + for (int k = 0; k < M; k++) { - m_ppSOM[jj+l][ii+k].Red = (double)prgbSrc[j][i].Red; - m_ppSOM[jj+l][ii+k].Green = (double)prgbSrc[j][i].Green; - m_ppSOM[jj+l][ii+k].Blue = (double)prgbSrc[j][i].Blue; + m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; + m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; + m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; } } } @@ -184,11 +184,11 @@ namespace lb_library void BGModelFuzzySom::Update() { - double alpha,a; + double alpha, a; double epsilon; // calibration phase - if(m_K <= m_TSteps) + if (m_K <= m_TSteps) { epsilon = m_epsilon1; alpha = (m_alpha1 - m_K * (m_alpha1 - m_alpha2) / m_TSteps); @@ -204,11 +204,11 @@ namespace lb_library Image<BYTERGB> prgbBG(m_BGImage); Image<BYTERGB> prgbFG(m_FGImage); - for(int j = 0; j < m_height; j++) + for (int j = 0; j < m_height; j++) { int jj = m_offset + j*(N + m_pad); - for(int i = 0; i < m_width; i++) + for (int i = 0; i < m_width; i++) { int ii = m_offset + i*(M + m_pad); @@ -222,17 +222,17 @@ namespace lb_library int iiHit = ii; int jjHit = jj; - for(int l = 0; l < N; l++) + for (int l = 0; l < N; l++) { - for(int k = 0; k < M; k++) + for (int k = 0; k < M; k++) { - double dr = srcR - m_ppSOM[jj+l][ii+k].Red; - double dg = srcG - m_ppSOM[jj+l][ii+k].Green; - double db = srcB - m_ppSOM[jj+l][ii+k].Blue; + double dr = srcR - m_ppSOM[jj + l][ii + k].Red; + double dg = srcG - m_ppSOM[jj + l][ii + k].Green; + double db = srcB - m_ppSOM[jj + l][ii + k].Blue; double d2 = dr*dr + dg*dg + db*db; - if(d2 < d2min) + if (d2 < d2min) { d2min = d2; iiHit = ii + k; @@ -243,16 +243,16 @@ namespace lb_library double fuzzyBG = 1.0; - if(d2min < epsilon) - fuzzyBG = d2min/epsilon; + if (d2min < epsilon) + fuzzyBG = d2min / epsilon; // Update SOM double alphamax = alpha*exp(FUZZYEXP*fuzzyBG); - for(int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) + for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) { - for(int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) + for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) { a = alphamax * m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; @@ -261,20 +261,20 @@ namespace lb_library double d; d = srcR - m_ppSOM[l][k].Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Red += a*d; d = srcG - m_ppSOM[l][k].Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Green += a*d; d = srcB - m_ppSOM[l][k].Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Blue += a*d; } } - if(fuzzyBG >= FUZZYTHRESH) + if (fuzzyBG >= FUZZYTHRESH) { // Set foreground image prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 255; @@ -284,7 +284,7 @@ namespace lb_library // Set background image prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; - prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; + prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; // Set foreground image prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; @@ -295,4 +295,4 @@ namespace lb_library return; } } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModelFuzzySom.h b/package_bgs/lb/BGModelFuzzySom.h index 2f21d3e..ed0bf21 100644 --- a/package_bgs/lb/BGModelFuzzySom.h +++ b/package_bgs/lb/BGModelFuzzySom.h @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelFuzzySom.h Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -33,9 +33,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODELFUZZYSOM_H -#define BGMODELFUZZYSOM_H +#pragma once #include "BGModel.h" @@ -47,9 +45,9 @@ namespace lb_library const int M = 3; // width SOM (per pixel) const int N = 3; // height SOM (per pixel) - const int KERNEL = 3; // size Gaussian kernel + const int KERNEL = 3; // size Gaussian kernel - const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // + const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // const int TRAINING_STEPS = 100; // number of training steps const double EPS1 = 100.0; // model match distance during training @@ -84,12 +82,10 @@ namespace lb_library double m_alpha2; DBLRGB** m_ppSOM; // SOM grid - double** m_ppW; // Weights + double** m_ppW; // Weights void Init(); void Update(); }; } } - -#endif diff --git a/package_bgs/lb/BGModelGauss.cpp b/package_bgs/lb/BGModelGauss.cpp index 6892d13..28a8b93 100644 --- a/package_bgs/lb/BGModelGauss.cpp +++ b/package_bgs/lb/BGModelGauss.cpp @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelGauss.cpp Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -40,7 +40,7 @@ namespace lb_library { namespace SimpleGaussian { - BGModelGauss::BGModelGauss(int width, int height) : BGModel(width,height) + BGModelGauss::BGModelGauss(int width, int height) : BGModel(width, height) { m_alpha = ALPHAGAUSS; m_threshold = THRESHGAUSS*THRESHGAUSS; @@ -52,7 +52,7 @@ namespace lb_library DBLRGB *pMu = m_pMu; DBLRGB *pVar = m_pVar; - for(int k = 0; k < (m_width * m_height); k++) + for (int k = 0; k < (m_width * m_height); k++) { pMu->Red = 0.0; pMu->Green = 0.0; @@ -69,15 +69,15 @@ namespace lb_library BGModelGauss::~BGModelGauss() { - delete [] m_pMu; - delete [] m_pVar; + delete[] m_pMu; + delete[] m_pVar; } void BGModelGauss::setBGModelParameter(int id, int value) { - double dvalue = (double)value/255.0; + double dvalue = (double)value / 255.0; - switch(id) + switch (id) { case 0: m_threshold = 100.0*dvalue*dvalue; @@ -87,7 +87,7 @@ namespace lb_library m_noise = 100.0*dvalue; break; - case 2: + case 2: m_alpha = dvalue*dvalue*dvalue; break; } @@ -102,9 +102,9 @@ namespace lb_library Image<BYTERGB> prgbSrc(m_SrcImage); - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { pMu->Red = prgbSrc[i][j].Red; pMu->Green = prgbSrc[i][j].Green; @@ -131,62 +131,62 @@ namespace lb_library Image<BYTERGB> prgbBG(m_BGImage); Image<BYTERGB> prgbFG(m_FGImage); - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { - double srcR = (double) prgbSrc[i][j].Red; - double srcG = (double) prgbSrc[i][j].Green; - double srcB = (double) prgbSrc[i][j].Blue; + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; - // Mahalanobis distance + // Mahalanobis distance double dr = srcR - pMu->Red; double dg = srcG - pMu->Green; double db = srcB - pMu->Blue; - double d2 = dr*dr/pVar->Red + dg*dg/pVar->Green + db*db/pVar->Blue; + double d2 = dr*dr / pVar->Red + dg*dg / pVar->Green + db*db / pVar->Blue; // Classify - if(d2 < m_threshold) - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; + if (d2 < m_threshold) + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; else - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; // Update parameters - if(dr*dr > DBL_MIN) + if (dr*dr > DBL_MIN) pMu->Red += m_alpha*dr; - if(dg*dg > DBL_MIN) + if (dg*dg > DBL_MIN) pMu->Green += m_alpha*dg; - if(db*db > DBL_MIN) + if (db*db > DBL_MIN) pMu->Blue += m_alpha*db; double d; d = (srcR - pMu->Red)*(srcR - pMu->Red) - pVar->Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Red += m_alpha*d; d = (srcG - pMu->Green)*(srcG - pMu->Green) - pVar->Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Green += m_alpha*d; d = (srcB - pMu->Blue)*(srcB - pMu->Blue) - pVar->Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pVar->Blue += m_alpha*d; - pVar->Red = (std::min)(pVar->Red,m_noise); - pVar->Green = (std::min)(pVar->Green,m_noise); - pVar->Blue = (std::min)(pVar->Blue,m_noise); + pVar->Red = (std::min)(pVar->Red, m_noise); + pVar->Green = (std::min)(pVar->Green, m_noise); + pVar->Blue = (std::min)(pVar->Blue, m_noise); // Set background - prgbBG[i][j].Red = (unsigned char)pMu->Red; - prgbBG[i][j].Green = (unsigned char)pMu->Green; + prgbBG[i][j].Red = (unsigned char)pMu->Red; + prgbBG[i][j].Green = (unsigned char)pMu->Green; prgbBG[i][j].Blue = (unsigned char)pMu->Blue; pMu++; @@ -197,4 +197,4 @@ namespace lb_library return; } } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModelGauss.h b/package_bgs/lb/BGModelGauss.h index d36a716..0af6efe 100644 --- a/package_bgs/lb/BGModelGauss.h +++ b/package_bgs/lb/BGModelGauss.h @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelGauss.h Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -33,9 +33,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODELGAUSS_H -#define BGMODELGAUSS_H +#pragma once #include "BGModel.h" @@ -69,5 +67,3 @@ namespace lb_library }; } } - -#endif diff --git a/package_bgs/lb/BGModelMog.cpp b/package_bgs/lb/BGModelMog.cpp index df6986c..036feab 100644 --- a/package_bgs/lb/BGModelMog.cpp +++ b/package_bgs/lb/BGModelMog.cpp @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelMog.cpp Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -54,9 +54,9 @@ namespace lb_library MOGDATA *pMOG = m_pMOG; int *pK = m_pK; - for(int i = 0; i < (m_width * m_height); i++) + for (int i = 0; i < (m_width * m_height); i++) { - for(int k = 0; k < NUMBERGAUSSIANS; k++) + for (int k = 0; k < NUMBERGAUSSIANS; k++) { pMOG->mu.Red = 0.0; pMOG->mu.Green = 0.0; @@ -72,27 +72,27 @@ namespace lb_library pMOG++; } - pK[i] = 0; + pK[i] = 0; } } BGModelMog::~BGModelMog() { - delete [] m_pMOG; - delete [] m_pK; + delete[] m_pMOG; + delete[] m_pK; } void BGModelMog::setBGModelParameter(int id, int value) { - double dvalue = (double)value/255.0; + double dvalue = (double)value / 255.0; - switch(id) + switch (id) { case 0: m_threshold = 100.0*dvalue*dvalue; break; - case 1: + case 1: m_T = dvalue; break; @@ -100,7 +100,7 @@ namespace lb_library m_alpha = dvalue*dvalue*dvalue; break; - case 3: + case 3: m_noise = 100.0*dvalue;; break; } @@ -116,9 +116,9 @@ namespace lb_library Image<BYTERGB> prgbSrc(m_SrcImage); int n = 0; - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { pMOG[0].mu.Red = prgbSrc[i][j].Red; pMOG[0].mu.Green = prgbSrc[i][j].Green; @@ -129,7 +129,7 @@ namespace lb_library pMOG[0].var.Blue = m_noise; pMOG[0].w = 1.0; - pMOG[0].sortKey = pMOG[0].w/sqrt(pMOG[0].var.Red+pMOG[0].var.Green+pMOG[0].var.Blue); + pMOG[0].sortKey = pMOG[0].w / sqrt(pMOG[0].var.Red + pMOG[0].var.Green + pMOG[0].var.Blue); pK[n] = 1; n++; @@ -153,27 +153,27 @@ namespace lb_library Image<BYTERGB> prgbFG(m_FGImage); int n = 0; - for(int i = 0; i < m_height; i++) + for (int i = 0; i < m_height; i++) { - for(int j = 0; j < m_width; j++) + for (int j = 0; j < m_width; j++) { - double srcR = (double) prgbSrc[i][j].Red; - double srcG = (double) prgbSrc[i][j].Green; - double srcB = (double) prgbSrc[i][j].Blue; + double srcR = (double)prgbSrc[i][j].Red; + double srcG = (double)prgbSrc[i][j].Green; + double srcB = (double)prgbSrc[i][j].Blue; // Find matching distribution int kHit = -1; - for(int k = 0; k < pK[n]; k++) + for (int k = 0; k < pK[n]; k++) { // Mahalanobis distance double dr = srcR - pMOG[k].mu.Red; double dg = srcG - pMOG[k].mu.Green; double db = srcB - pMOG[k].mu.Blue; - double d2 = dr*dr/pMOG[k].var.Red + dg*dg/pMOG[k].var.Green + db*db/pMOG[k].var.Blue; + double d2 = dr*dr / pMOG[k].var.Red + dg*dg / pMOG[k].var.Green + db*db / pMOG[k].var.Blue; - if(d2 < m_threshold) + if (d2 < m_threshold) { kHit = k; break; @@ -183,43 +183,43 @@ namespace lb_library // Adjust parameters // matching distribution found - if(kHit != -1) + if (kHit != -1) { - for(int k = 0; k < pK[n]; k++) + for (int k = 0; k < pK[n]; k++) { - if(k == kHit) + if (k == kHit) { pMOG[k].w = pMOG[k].w + m_alpha*(1.0f - pMOG[k].w); double d; d = srcR - pMOG[k].mu.Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].mu.Red += m_alpha*d; d = srcG - pMOG[k].mu.Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].mu.Green += m_alpha*d; d = srcB - pMOG[k].mu.Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].mu.Blue += m_alpha*d; d = (srcR - pMOG[k].mu.Red)*(srcR - pMOG[k].mu.Red) - pMOG[k].var.Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].var.Red += m_alpha*d; d = (srcG - pMOG[k].mu.Green)*(srcG - pMOG[k].mu.Green) - pMOG[k].var.Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].var.Green += m_alpha*d; d = (srcB - pMOG[k].mu.Blue)*(srcB - pMOG[k].mu.Blue) - pMOG[k].var.Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) pMOG[k].var.Blue += m_alpha*d; - pMOG[k].var.Red = (std::max)(pMOG[k].var.Red,m_noise); - pMOG[k].var.Green = (std::max)(pMOG[k].var.Green,m_noise); - pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue,m_noise); + pMOG[k].var.Red = (std::max)(pMOG[k].var.Red, m_noise); + pMOG[k].var.Green = (std::max)(pMOG[k].var.Green, m_noise); + pMOG[k].var.Blue = (std::max)(pMOG[k].var.Blue, m_noise); } else pMOG[k].w = (1.0 - m_alpha)*pMOG[k].w; @@ -228,12 +228,12 @@ namespace lb_library // no match found... create new one else { - if(pK[n] < NUMBERGAUSSIANS) + if (pK[n] < NUMBERGAUSSIANS) pK[n]++; kHit = pK[n] - 1; - if(pK[n] == 1) + if (pK[n] == 1) pMOG[kHit].w = 1.0; else pMOG[kHit].w = LEARNINGRATEMOG; @@ -251,24 +251,24 @@ namespace lb_library double wsum = 0.0; - for(int k = 0; k < pK[n]; k++) + for (int k = 0; k < pK[n]; k++) wsum += pMOG[k].w; - double wfactor = 1.0/wsum; + double wfactor = 1.0 / wsum; - for(int k = 0; k < pK[n]; k++) + for (int k = 0; k < pK[n]; k++) { pMOG[k].w *= wfactor; - pMOG[k].sortKey = pMOG[k].w/sqrt(pMOG[k].var.Red+pMOG[k].var.Green+pMOG[k].var.Blue); + pMOG[k].sortKey = pMOG[k].w / sqrt(pMOG[k].var.Red + pMOG[k].var.Green + pMOG[k].var.Blue); } // Sort distributions for (int k = 0; k < kHit; k++) { - if(pMOG[kHit].sortKey > pMOG[k].sortKey) + if (pMOG[kHit].sortKey > pMOG[k].sortKey) { - std::swap(pMOG[kHit],pMOG[k]); + std::swap(pMOG[kHit], pMOG[k]); break; } } @@ -277,21 +277,21 @@ namespace lb_library wsum = 0.0; - for(int k = 0; k < pK[n]; k++) + for (int k = 0; k < pK[n]; k++) { wsum += pMOG[k].w; - if(wsum > m_T) + if (wsum > m_T) { kBG = k; break; } } - if(kHit > kBG) - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; + if (kHit > kBG) + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 255; else - prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; + prgbFG[i][j].Red = prgbFG[i][j].Green = prgbFG[i][j].Blue = 0; prgbBG[i][j].Red = (unsigned char)pMOG[0].mu.Red; prgbBG[i][j].Green = (unsigned char)pMOG[0].mu.Green; @@ -306,4 +306,4 @@ namespace lb_library return; } } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModelMog.h b/package_bgs/lb/BGModelMog.h index c4e51a4..c75d1fd 100644 --- a/package_bgs/lb/BGModelMog.h +++ b/package_bgs/lb/BGModelMog.h @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelMog.h Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -33,9 +33,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODELMOGRGB_H -#define BGMODELMOGRGB_H +#pragma once #include "BGModel.h" @@ -79,5 +77,3 @@ namespace lb_library }; } } - -#endif diff --git a/package_bgs/lb/BGModelSom.cpp b/package_bgs/lb/BGModelSom.cpp index 256d485..735af6e 100644 --- a/package_bgs/lb/BGModelSom.cpp +++ b/package_bgs/lb/BGModelSom.cpp @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelSom.cpp Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -40,28 +40,28 @@ namespace lb_library { namespace AdaptiveSOM { - BGModelSom::BGModelSom(int width, int height) : BGModel(width,height) + BGModelSom::BGModelSom(int width, int height) : BGModel(width, height) { - m_offset = (KERNEL - 1)/2; + m_offset = (KERNEL - 1) / 2; - if(SPAN_NEIGHBORS) - m_pad = 0; + if (SPAN_NEIGHBORS) + m_pad = 0; else m_pad = m_offset; // SOM models - m_widthSOM = m_width*M + 2*m_offset + (m_width-1)*m_pad; - m_heightSOM = m_height*N + 2*m_offset + (m_height-1)*m_pad; + m_widthSOM = m_width*M + 2 * m_offset + (m_width - 1)*m_pad; + m_heightSOM = m_height*N + 2 * m_offset + (m_height - 1)*m_pad; - m_ppSOM = new DBLRGB*[m_heightSOM]; - for(int n = 0; n < m_heightSOM; n++) + m_ppSOM = new DBLRGB*[m_heightSOM]; + for (int n = 0; n < m_heightSOM; n++) m_ppSOM[n] = new DBLRGB[m_widthSOM]; - for(int j = 0; j < m_heightSOM; j++) + for (int j = 0; j < m_heightSOM; j++) { - for(int i = 0; i < m_widthSOM; i++) - { + for (int i = 0; i < m_widthSOM; i++) + { m_ppSOM[j][i].Red = 0.0; m_ppSOM[j][i].Green = 0.0; m_ppSOM[j][i].Blue = 0.0; @@ -71,7 +71,7 @@ namespace lb_library // Create weights m_ppW = new double*[KERNEL]; - for(int n = 0; n < KERNEL; n++) + for (int n = 0; n < KERNEL; n++) m_ppW[n] = new double[KERNEL]; // Construct Gaussian kernel using Pascal's triangle @@ -81,16 +81,16 @@ namespace lb_library m_Wmax = DBL_MIN; cN = 1; - for(int j = 0; j < KERNEL; j++) + for (int j = 0; j < KERNEL; j++) { - cM = 1; + cM = 1; - for(int i = 0; i < KERNEL; i++) + for (int i = 0; i < KERNEL; i++) { m_ppW[j][i] = cN*cM; - if(m_ppW[j][i] > m_Wmax) - m_Wmax = m_ppW[j][i]; + if (m_ppW[j][i] > m_Wmax) + m_Wmax = m_ppW[j][i]; cM = cM * (KERNEL - 1 - i) / (i + 1); } @@ -103,8 +103,8 @@ namespace lb_library m_epsilon1 = EPS1*EPS1; m_epsilon2 = EPS2*EPS2; - m_alpha1 = C1/m_Wmax; - m_alpha2 = C2/m_Wmax; + m_alpha1 = C1 / m_Wmax; + m_alpha2 = C2 / m_Wmax; m_K = 0; m_TSteps = TRAINING_STEPS; @@ -112,22 +112,22 @@ namespace lb_library BGModelSom::~BGModelSom() { - for(int n = 0; n < m_heightSOM; n++) - delete [] m_ppSOM[n]; + for (int n = 0; n < m_heightSOM; n++) + delete[] m_ppSOM[n]; - delete [] m_ppSOM; + delete[] m_ppSOM; - for(int n = 0; n < KERNEL; n++) - delete [] m_ppW[n]; + for (int n = 0; n < KERNEL; n++) + delete[] m_ppW[n]; - delete [] m_ppW; + delete[] m_ppW; } void BGModelSom::setBGModelParameter(int id, int value) { - double dvalue = (double)value/255.0; + double dvalue = (double)value / 255.0; - switch(id) + switch (id) { case 0: m_epsilon2 = 255.0*255.0*dvalue*dvalue*dvalue*dvalue; @@ -138,11 +138,11 @@ namespace lb_library break; case 2: - m_alpha2 = dvalue*dvalue*dvalue/m_Wmax; + m_alpha2 = dvalue*dvalue*dvalue / m_Wmax; break; case 3: - m_alpha1 = dvalue*dvalue*dvalue/m_Wmax; + m_alpha1 = dvalue*dvalue*dvalue / m_Wmax; break; case 5: @@ -157,21 +157,21 @@ namespace lb_library { Image<BYTERGB> prgbSrc(m_SrcImage); - for(int j = 0; j < m_height; j++) + for (int j = 0; j < m_height; j++) { int jj = m_offset + j*(N + m_pad); - for(int i = 0; i < m_width; i++) + for (int i = 0; i < m_width; i++) { - int ii = m_offset + i*(M + m_pad); + int ii = m_offset + i*(M + m_pad); - for(int l = 0; l < N; l++) + for (int l = 0; l < N; l++) { - for(int k = 0; k < M; k++) + for (int k = 0; k < M; k++) { - m_ppSOM[jj+l][ii+k].Red = (double)prgbSrc[j][i].Red; - m_ppSOM[jj+l][ii+k].Green = (double)prgbSrc[j][i].Green; - m_ppSOM[jj+l][ii+k].Blue = (double)prgbSrc[j][i].Blue; + m_ppSOM[jj + l][ii + k].Red = (double)prgbSrc[j][i].Red; + m_ppSOM[jj + l][ii + k].Green = (double)prgbSrc[j][i].Green; + m_ppSOM[jj + l][ii + k].Blue = (double)prgbSrc[j][i].Blue; } } } @@ -184,18 +184,18 @@ namespace lb_library void BGModelSom::Update() { - double alpha,a; + double alpha, a; double epsilon; // calibration phase - if(m_K <= m_TSteps) - { + if (m_K <= m_TSteps) + { epsilon = m_epsilon1; - alpha = (m_alpha1-m_K*(m_alpha1-m_alpha2)/m_TSteps); + alpha = (m_alpha1 - m_K*(m_alpha1 - m_alpha2) / m_TSteps); m_K++; } else // online phase - { + { epsilon = m_epsilon2; alpha = m_alpha2; } @@ -204,11 +204,11 @@ namespace lb_library Image<BYTERGB> prgbBG(m_BGImage); Image<BYTERGB> prgbFG(m_FGImage); - for(int j = 0; j < m_height; j++) + for (int j = 0; j < m_height; j++) { int jj = m_offset + j*(N + m_pad); - for(int i = 0; i < m_width; i++) + for (int i = 0; i < m_width; i++) { int ii = m_offset + i*(M + m_pad); @@ -222,17 +222,17 @@ namespace lb_library int iiHit = ii; int jjHit = jj; - for(int l = 0; l < N; l++) + for (int l = 0; l < N; l++) { - for(int k = 0; k < M; k++) + for (int k = 0; k < M; k++) { - double dr = srcR - m_ppSOM[jj+l][ii+k].Red; - double dg = srcG - m_ppSOM[jj+l][ii+k].Green; - double db = srcB - m_ppSOM[jj+l][ii+k].Blue; + double dr = srcR - m_ppSOM[jj + l][ii + k].Red; + double dg = srcG - m_ppSOM[jj + l][ii + k].Green; + double db = srcB - m_ppSOM[jj + l][ii + k].Blue; double d2 = dr*dr + dg*dg + db*db; - if(d2 < d2min) + if (d2 < d2min) { d2min = d2; iiHit = ii + k; @@ -243,28 +243,28 @@ namespace lb_library // Update SOM - if(d2min <= epsilon) // matching model found + if (d2min <= epsilon) // matching model found { - for(int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) + for (int l = (jjHit - m_offset); l <= (jjHit + m_offset); l++) { - for(int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) + for (int k = (iiHit - m_offset); k <= (iiHit + m_offset); k++) { - a = alpha*m_ppW[l-jjHit+m_offset][k-iiHit+m_offset]; + a = alpha*m_ppW[l - jjHit + m_offset][k - iiHit + m_offset]; // speed hack.. avoid very small increment values. abs() is sloooow. double d; d = srcR - m_ppSOM[l][k].Red; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Red += a*d; d = srcG - m_ppSOM[l][k].Green; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Green += a*d; d = srcB - m_ppSOM[l][k].Blue; - if(d*d > DBL_MIN) + if (d*d > DBL_MIN) m_ppSOM[l][k].Blue += a*d; } } @@ -272,7 +272,7 @@ namespace lb_library // Set background image prgbBG[j][i].Red = m_ppSOM[jjHit][iiHit].Red; prgbBG[j][i].Green = m_ppSOM[jjHit][iiHit].Green; - prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; + prgbBG[j][i].Blue = m_ppSOM[jjHit][iiHit].Blue; // Set foreground image prgbFG[j][i].Red = prgbFG[j][i].Green = prgbFG[j][i].Blue = 0; @@ -288,4 +288,4 @@ namespace lb_library return; } } -} \ No newline at end of file +} diff --git a/package_bgs/lb/BGModelSom.h b/package_bgs/lb/BGModelSom.h index dcd7158..0975b0b 100644 --- a/package_bgs/lb/BGModelSom.h +++ b/package_bgs/lb/BGModelSom.h @@ -14,7 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. */ -/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments +/* Scene 1.0.1 -- Background subtraction and object tracking for complex environments BGModelSom.h Copyright (C) 2011 Laurence Bender <lbender@untref.edu.ar> @@ -33,9 +33,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef BGMODELSOM_H -#define BGMODELSOM_H +#pragma once #include "BGModel.h" @@ -47,9 +45,9 @@ namespace lb_library const int M = 3; // width SOM (per pixel) const int N = 3; // height SOM (per pixel) - const int KERNEL = 3; // size Gaussian kernel + const int KERNEL = 3; // size Gaussian kernel - const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // + const bool SPAN_NEIGHBORS = false; // true if update neighborhood spans different pixels // const int TRAINING_STEPS = 100; // number of training steps const float EPS1 = 100.0; // model match distance during training @@ -81,12 +79,10 @@ namespace lb_library double m_alpha2; DBLRGB** m_ppSOM; // SOM grid - double** m_ppW; // Weights + double** m_ppW; // Weights void Init(); void Update(); }; } } - -#endif diff --git a/package_bgs/lb/Types.h b/package_bgs/lb/Types.h index cb318a2..bd59c41 100644 --- a/package_bgs/lb/Types.h +++ b/package_bgs/lb/Types.h @@ -33,57 +33,55 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#ifndef TYPES_H -#define TYPES_H +#pragma once #include <opencv2/opencv.hpp> namespace lb_library { - template<class T> class Image - { - private: - IplImage* imgp; +template<class T> class Image +{ +private: + IplImage* imgp; - public: - Image(IplImage* img=0) {imgp=img;} - ~Image(){imgp=0;} +public: + Image(IplImage* img=0) {imgp=img;} + ~Image(){imgp=0;} - void operator=(IplImage* img) {imgp=img;} + void operator=(IplImage* img) {imgp=img;} - inline T* operator[](const int rowIndx) - { - return ((T *)(imgp->imageData + rowIndx*imgp->widthStep)); - } - }; - - typedef struct{ - unsigned char b,g,r; - } RgbPixel; - - typedef struct{ - unsigned char Blue,Green,Red; - } BYTERGB; - - typedef struct{ - unsigned int Blue,Green,Red; - } INTRGB; - - typedef struct{ - float b,g,r; - }RgbPixelFloat; - - typedef struct{ - double Blue,Green,Red; - } DBLRGB; - - typedef Image<RgbPixel> RgbImage; - typedef Image<RgbPixelFloat> RgbImageFloat; - typedef Image<unsigned char> BwImage; - typedef Image<float> BwImageFloat; - - /* + inline T* operator[](const int rowIndx) + { + return ((T *)(imgp->imageData + rowIndx*imgp->widthStep)); + } +}; + +typedef struct{ + unsigned char b,g,r; +} RgbPixel; + +typedef struct{ + unsigned char Blue,Green,Red; +} BYTERGB; + +typedef struct{ + unsigned int Blue,Green,Red; +} INTRGB; + +typedef struct{ + float b,g,r; +}RgbPixelFloat; + +typedef struct{ + double Blue,Green,Red; +} DBLRGB; + +typedef Image<RgbPixel> RgbImage; +typedef Image<RgbPixelFloat> RgbImageFloat; +typedef Image<unsigned char> BwImage; +typedef Image<float> BwImageFloat; + +/* IplImage* img = cvCreateImage(cvSize(640,480), IPL_DEPTH_32F, 3); RgbImageFloat imgA(img); for(int i = 0; i < m_height; i++) @@ -93,7 +91,3 @@ namespace lb_library imgA[i][j].r = 111; */ } - -//--------------------------------------------- - -#endif diff --git a/package_bgs/my/MyBGS.cpp b/package_bgs/my/MyBGS.cpp deleted file mode 100644 index 07b51cd..0000000 --- a/package_bgs/my/MyBGS.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "MyBGS.h" - -MyBGS::MyBGS(){} -MyBGS::~MyBGS(){} - -void MyBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - if(img_previous.empty()) - img_input.copyTo(img_previous); - - cv::Mat img_foreground; - cv::absdiff(img_previous, img_input, img_foreground); - - if(img_foreground.channels() == 3) - cv::cvtColor(img_foreground, img_foreground, CV_BGR2GRAY); - - cv::threshold(img_foreground, img_foreground, 15, 255, cv::THRESH_BINARY); - - img_foreground.copyTo(img_output); - img_previous.copyTo(img_bgmodel); - - img_input.copyTo(img_previous); -} diff --git a/package_bgs/my/MyBGS.h b/package_bgs/my/MyBGS.h deleted file mode 100644 index fa27484..0000000 --- a/package_bgs/my/MyBGS.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -class MyBGS : public IBGS -{ -private: - cv::Mat img_previous; - -public: - MyBGS(); - ~MyBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(){} - void loadConfig(){} -}; \ No newline at end of file diff --git a/package_bgs/pl/BackgroundSubtractorLBSP.cpp b/package_bgs/pl/BackgroundSubtractorLBSP.cpp deleted file mode 100644 index 6752f76..0000000 --- a/package_bgs/pl/BackgroundSubtractorLBSP.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "BackgroundSubtractorLBSP.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> -#include <exception> - -#ifndef SIZE_MAX -# if __WORDSIZE == 64 -# define SIZE_MAX (18446744073709551615UL) -# else -# define SIZE_MAX (4294967295U) -# endif -#endif - -// local define used to determine the default median blur kernel size -#define DEFAULT_MEDIAN_BLUR_KERNEL_SIZE (9) - -BackgroundSubtractorLBSP::BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset) - : m_nImgChannels(0) - ,m_nImgType(0) - ,m_nLBSPThresholdOffset(nLBSPThresholdOffset) - ,m_fRelLBSPThreshold(fRelLBSPThreshold) - ,m_nTotPxCount(0) - ,m_nTotRelevantPxCount(0) - ,m_nFrameIndex(SIZE_MAX) - ,m_nFramesSinceLastReset(0) - ,m_nModelResetCooldown(0) - ,m_aPxIdxLUT(nullptr) - ,m_aPxInfoLUT(nullptr) - ,m_nDefaultMedianBlurKernelSize(DEFAULT_MEDIAN_BLUR_KERNEL_SIZE) - ,m_bInitialized(false) - ,m_bAutoModelResetEnabled(true) - ,m_bUsingMovingCamera(false) - ,nDebugCoordX(0),nDebugCoordY(0) { - CV_Assert(m_fRelLBSPThreshold>=0); -} - -BackgroundSubtractorLBSP::~BackgroundSubtractorLBSP() {} - -void BackgroundSubtractorLBSP::initialize(const cv::Mat& oInitImg) { - this->initialize(oInitImg,cv::Mat()); -} - -/*cv::AlgorithmInfo* BackgroundSubtractorLBSP::info() const { - return nullptr; -}*/ - -cv::Mat BackgroundSubtractorLBSP::getROICopy() const { - return m_oROI.clone(); -} - -void BackgroundSubtractorLBSP::setROI(cv::Mat& oROI) { - LBSP::validateROI(oROI); - CV_Assert(cv::countNonZero(oROI)>0); - if(m_bInitialized) { - cv::Mat oLatestBackgroundImage; - getBackgroundImage(oLatestBackgroundImage); - initialize(oLatestBackgroundImage,oROI); - } - else - m_oROI = oROI.clone(); -} - -void BackgroundSubtractorLBSP::setAutomaticModelReset(bool bVal) { - m_bAutoModelResetEnabled = bVal; -} diff --git a/package_bgs/pl/BackgroundSubtractorLBSP.h b/package_bgs/pl/BackgroundSubtractorLBSP.h deleted file mode 100644 index 5602d34..0000000 --- a/package_bgs/pl/BackgroundSubtractorLBSP.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include <opencv2/features2d/features2d.hpp> -#include <opencv2/video/background_segm.hpp> -#include "LBSP.h" - -/*! - Local Binary Similarity Pattern (LBSP)-based change detection algorithm (abstract version/base class). - - For more details on the different parameters, see P.-L. St-Charles and G.-A. Bilodeau, "Improving Background - Subtraction using Local Binary Similarity Patterns", in WACV 2014, or G.-A. Bilodeau et al, "Change Detection - in Feature Space Using Local Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorLBSP : public cv::BackgroundSubtractor { -public: - //! full constructor - BackgroundSubtractorLBSP(float fRelLBSPThreshold, size_t nLBSPThresholdOffset=0); - //! default destructor - virtual ~BackgroundSubtractorLBSP(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI)=0; - //! primary model update function; the learning param is used to override the internal learning speed (ignored when <= 0) - virtual void operator()(cv::InputArray image, cv::OutputArray fgmask, double learningRate=0)=0; - //! unused, always returns nullptr - //virtual cv::AlgorithmInfo* info() const; - //! returns a copy of the ROI used for descriptor extraction - virtual cv::Mat getROICopy() const; - //! sets the ROI to be used for descriptor extraction (note: this function will reinit the model and return the usable ROI) - virtual void setROI(cv::Mat& oROI); - //! turns automatic model reset on or off - void setAutomaticModelReset(bool); - -protected: - struct PxInfoBase { - int nImgCoord_Y; - int nImgCoord_X; - size_t nModelIdx; - }; - //! background model ROI used for LBSP descriptor extraction (specific to the input image size) - cv::Mat m_oROI; - //! input image size - cv::Size m_oImgSize; - //! input image channel size - size_t m_nImgChannels; - //! input image type - int m_nImgType; - //! LBSP internal threshold offset value, used to reduce texture noise in dark regions - const size_t m_nLBSPThresholdOffset; - //! LBSP relative internal threshold (kept here since we don't keep an LBSP object) - const float m_fRelLBSPThreshold; - //! total number of pixels (depends on the input frame size) & total number of relevant pixels - size_t m_nTotPxCount, m_nTotRelevantPxCount; - //! current frame index, frame count since last model reset & model reset cooldown counters - size_t m_nFrameIndex, m_nFramesSinceLastReset, m_nModelResetCooldown; - //! pre-allocated internal LBSP threshold values LUT for all possible 8-bit intensities - size_t m_anLBSPThreshold_8bitLUT[UCHAR_MAX+1]; - //! internal pixel index LUT for all relevant analysis regions (based on the provided ROI) - size_t* m_aPxIdxLUT; - //! internal pixel info LUT for all possible pixel indexes - PxInfoBase* m_aPxInfoLUT; - //! default kernel size for median blur post-proc filtering - const int m_nDefaultMedianBlurKernelSize; - //! specifies whether the algorithm is fully initialized or not - bool m_bInitialized; - //! specifies whether automatic model resets are enabled or not - bool m_bAutoModelResetEnabled; - //! specifies whether the camera is considered moving or not - bool m_bUsingMovingCamera; - //! copy of latest pixel intensities (used when refreshing model) - cv::Mat m_oLastColorFrame; - //! copy of latest descriptors (used when refreshing model) - cv::Mat m_oLastDescFrame; - //! the foreground mask generated by the method at [t-1] - cv::Mat m_oLastFGMask; - -public: - // ######## DEBUG PURPOSES ONLY ########## - int nDebugCoordX, nDebugCoordY; - std::string sDebugName; -}; - diff --git a/package_bgs/pl/BackgroundSubtractorLOBSTER.cpp b/package_bgs/pl/BackgroundSubtractorLOBSTER.cpp deleted file mode 100644 index 78938ad..0000000 --- a/package_bgs/pl/BackgroundSubtractorLOBSTER.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#include "BackgroundSubtractorLOBSTER.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> - -BackgroundSubtractorLOBSTER::BackgroundSubtractorLOBSTER( float fRelLBSPThreshold - ,size_t nLBSPThresholdOffset - ,size_t nDescDistThreshold - ,size_t nColorDistThreshold - ,size_t nBGSamples - ,size_t nRequiredBGSamples) - : BackgroundSubtractorLBSP(fRelLBSPThreshold,nLBSPThresholdOffset) - ,m_nColorDistThreshold(nColorDistThreshold) - ,m_nDescDistThreshold(nDescDistThreshold) - ,m_nBGSamples(nBGSamples) - ,m_nRequiredBGSamples(nRequiredBGSamples) { - CV_Assert(m_nRequiredBGSamples<=m_nBGSamples); - m_bAutoModelResetEnabled = false; // @@@@@@ not supported here for now -} - -BackgroundSubtractorLOBSTER::~BackgroundSubtractorLOBSTER() { - if(m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if(m_aPxInfoLUT) - delete[] m_aPxInfoLUT; -} - -void BackgroundSubtractorLOBSTER::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { - CV_Assert(!oInitImg.empty() && oInitImg.cols>0 && oInitImg.rows>0); - CV_Assert(oInitImg.isContinuous()); - CV_Assert(oInitImg.type()==CV_8UC1 || oInitImg.type()==CV_8UC3); - if(oInitImg.type()==CV_8UC3) { - std::vector<cv::Mat> voInitImgChannels; - cv::split(oInitImg,voInitImgChannels); - if(!cv::countNonZero((voInitImgChannels[0]!=voInitImgChannels[1])|(voInitImgChannels[2]!=voInitImgChannels[1]))) - std::cout << std::endl << "\tBackgroundSubtractorLOBSTER : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; - } - cv::Mat oNewBGROI; - if(oROI.empty() && (m_oROI.empty() || oROI.size()!=oInitImg.size())) { - oNewBGROI.create(oInitImg.size(),CV_8UC1); - oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); - } - else if(oROI.empty()) - oNewBGROI = m_oROI; - else { - CV_Assert(oROI.size()==oInitImg.size() && oROI.type()==CV_8UC1); - CV_Assert(cv::countNonZero((oROI<UCHAR_MAX)&(oROI>0))==0); - oNewBGROI = oROI.clone(); - } - LBSP::validateROI(oNewBGROI); - const size_t nROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nROIPxCount>0); - m_oROI = oNewBGROI; - m_oImgSize = oInitImg.size(); - m_nImgType = oInitImg.type(); - m_nImgChannels = oInitImg.channels(); - m_nTotPxCount = m_oImgSize.area(); - m_nTotRelevantPxCount = nROIPxCount; - m_nFrameIndex = 0; - m_nFramesSinceLastReset = 0; - m_nModelResetCooldown = 0; - m_oLastFGMask.create(m_oImgSize,CV_8UC1); - m_oLastFGMask = cv::Scalar_<uchar>(0); - m_oLastColorFrame.create(m_oImgSize,CV_8UC((int)m_nImgChannels)); - m_oLastColorFrame = cv::Scalar_<uchar>::all(0); - m_oLastDescFrame.create(m_oImgSize,CV_16UC((int)m_nImgChannels)); - m_oLastDescFrame = cv::Scalar_<ushort>::all(0); - m_voBGColorSamples.resize(m_nBGSamples); - m_voBGDescSamples.resize(m_nBGSamples); - for(size_t s=0; s<m_nBGSamples; ++s) { - m_voBGColorSamples[s].create(m_oImgSize,CV_8UC((int)m_nImgChannels)); - m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); - m_voBGDescSamples[s].create(m_oImgSize,CV_16UC((int)m_nImgChannels)); - m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); - } - if(m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if(m_aPxInfoLUT) - delete[] m_aPxInfoLUT; - m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; - m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; - if(m_nImgChannels==1) { - CV_Assert(m_oLastColorFrame.step.p[0]==(size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1]==1); - CV_Assert(m_oLastDescFrame.step.p[0]==m_oLastColorFrame.step.p[0]*2 && m_oLastDescFrame.step.p[1]==m_oLastColorFrame.step.p[1]*2); - for(size_t t=0; t<=UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((t*m_fRelLBSPThreshold+m_nLBSPThresholdOffset)/2); - for(size_t nPxIter=0, nModelIter=0; nPxIter<m_nTotPxCount; ++nPxIter) { - if(m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter/m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; - const size_t nDescIter = nPxIter*2; - LBSP::computeGrayscaleDescriptor(oInitImg,oInitImg.data[nPxIter],m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]],*((ushort*)(m_oLastDescFrame.data+nDescIter))); - ++nModelIter; - } - } - } - else { //m_nImgChannels==3 - CV_Assert(m_oLastColorFrame.step.p[0]==(size_t)m_oImgSize.width*3 && m_oLastColorFrame.step.p[1]==3); - CV_Assert(m_oLastDescFrame.step.p[0]==m_oLastColorFrame.step.p[0]*2 && m_oLastDescFrame.step.p[1]==m_oLastColorFrame.step.p[1]*2); - for(size_t t=0; t<=UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(t*m_fRelLBSPThreshold+m_nLBSPThresholdOffset); - for(size_t nPxIter=0, nModelIter=0; nPxIter<m_nTotPxCount; ++nPxIter) { - if(m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter/m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - const size_t nPxRGBIter = nPxIter*3; - const size_t nDescRGBIter = nPxRGBIter*2; - for(size_t c=0; c<3; ++c) { - m_oLastColorFrame.data[nPxRGBIter+c] = oInitImg.data[nPxRGBIter+c]; - LBSP::computeSingleRGBDescriptor(oInitImg,oInitImg.data[nPxRGBIter+c],m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,c,m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter+c]],((ushort*)(m_oLastDescFrame.data+nDescRGBIter))[c]); - } - ++nModelIter; - } - } - } - m_bInitialized = true; - refreshModel(1.0f); -} - -void BackgroundSubtractorLOBSTER::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { - // == refresh - CV_Assert(m_bInitialized); - CV_Assert(fSamplesRefreshFrac>0.0f && fSamplesRefreshFrac<=1.0f); - const size_t nModelsToRefresh = fSamplesRefreshFrac<1.0f?(size_t)(fSamplesRefreshFrac*m_nBGSamples):m_nBGSamples; - const size_t nRefreshStartPos = fSamplesRefreshFrac<1.0f?rand()%m_nBGSamples:0; - if(m_nImgChannels==1) { - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if(bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for(size_t nCurrModelIdx=nRefreshStartPos; nCurrModelIdx<nRefreshStartPos+nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X,nSampleImgCoord_Y,m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if(bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data+nPxIter*2)) = *((ushort*)(m_oLastDescFrame.data+nSamplePxIdx*2)); - } - } - } - } - } - else { //m_nImgChannels==3 - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if(bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for(size_t nCurrModelIdx=nRefreshStartPos; nCurrModelIdx<nRefreshStartPos+nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X,nSampleImgCoord_Y,m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if(bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - for(size_t c=0; c<3; ++c) { - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter*3+c] = m_oLastColorFrame.data[nSamplePxIdx*3+c]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data+(nPxIter*3+c)*2)) = *((ushort*)(m_oLastDescFrame.data+(nSamplePxIdx*3+c)*2)); - } - } - } - } - } - } -} - -void BackgroundSubtractorLOBSTER::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRate) { - CV_Assert(m_bInitialized); - CV_Assert(learningRate>0); - cv::Mat oInputImg = _image.getMat(); - CV_Assert(oInputImg.type()==m_nImgType && oInputImg.size()==m_oImgSize); - CV_Assert(oInputImg.isContinuous()); - _fgmask.create(m_oImgSize,CV_8UC1); - cv::Mat oCurrFGMask = _fgmask.getMat(); - oCurrFGMask = cv::Scalar_<uchar>(0); - const size_t nLearningRate = (size_t)ceil(learningRate); - if(m_nImgChannels==1) { - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nDescIter = nPxIter*2; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const uchar nCurrColor = oInputImg.data[nPxIter]; - size_t nGoodSamplesCount=0, nModelIdx=0; - ushort nCurrInputDesc; - while(nGoodSamplesCount<m_nRequiredBGSamples && nModelIdx<m_nBGSamples) { - const uchar nBGColor = m_voBGColorSamples[nModelIdx].data[nPxIter]; - { - const size_t nColorDist = L1dist(nCurrColor,nBGColor); - if(nColorDist>m_nColorDistThreshold/2) - goto failedcheck1ch; - LBSP::computeGrayscaleDescriptor(oInputImg,nBGColor,nCurrImgCoord_X,nCurrImgCoord_Y,m_anLBSPThreshold_8bitLUT[nBGColor],nCurrInputDesc); - const size_t nDescDist = hdist(nCurrInputDesc,*((ushort*)(m_voBGDescSamples[nModelIdx].data+nDescIter))); - if(nDescDist>m_nDescDistThreshold) - goto failedcheck1ch; - nGoodSamplesCount++; - } - failedcheck1ch: - nModelIdx++; - } - if(nGoodSamplesCount<m_nRequiredBGSamples) - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - else { - if((rand()%nLearningRate)==0) { - const size_t nSampleModelIdx = rand()%m_nBGSamples; - ushort& nRandInputDesc = *((ushort*)(m_voBGDescSamples[nSampleModelIdx].data+nDescIter)); - LBSP::computeGrayscaleDescriptor(oInputImg,nCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,m_anLBSPThreshold_8bitLUT[nCurrColor],nRandInputDesc); - m_voBGColorSamples[nSampleModelIdx].data[nPxIter] = nCurrColor; - } - if((rand()%nLearningRate)==0) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandNeighborPosition_3x3(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSampleModelIdx = rand()%m_nBGSamples; - ushort& nRandInputDesc = m_voBGDescSamples[nSampleModelIdx].at<ushort>(nSampleImgCoord_Y,nSampleImgCoord_X); - LBSP::computeGrayscaleDescriptor(oInputImg,nCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,m_anLBSPThreshold_8bitLUT[nCurrColor],nRandInputDesc); - m_voBGColorSamples[nSampleModelIdx].at<uchar>(nSampleImgCoord_Y,nSampleImgCoord_X) = nCurrColor; - } - } - } - } - else { //m_nImgChannels==3 - const size_t nCurrDescDistThreshold = m_nDescDistThreshold*3; - const size_t nCurrColorDistThreshold = m_nColorDistThreshold*3; - const size_t nCurrSCDescDistThreshold = nCurrDescDistThreshold/2; - const size_t nCurrSCColorDistThreshold = nCurrColorDistThreshold/2; - const size_t desc_row_step = m_voBGDescSamples[0].step.p[0]; - const size_t img_row_step = m_voBGColorSamples[0].step.p[0]; - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const size_t nPxIterRGB = nPxIter*3; - const size_t nDescIterRGB = nPxIterRGB*2; - const uchar* const anCurrColor = oInputImg.data+nPxIterRGB; - size_t nGoodSamplesCount=0, nModelIdx=0; - ushort anCurrInputDesc[3]; - while(nGoodSamplesCount<m_nRequiredBGSamples && nModelIdx<m_nBGSamples) { - const ushort* const anBGDesc = (ushort*)(m_voBGDescSamples[nModelIdx].data+nDescIterRGB); - const uchar* const anBGColor = m_voBGColorSamples[nModelIdx].data+nPxIterRGB; - size_t nTotColorDist = 0; - size_t nTotDescDist = 0; - for(size_t c=0;c<3; ++c) { - const size_t nColorDist = L1dist(anCurrColor[c],anBGColor[c]); - if(nColorDist>nCurrSCColorDistThreshold) - goto failedcheck3ch; - LBSP::computeSingleRGBDescriptor(oInputImg,anBGColor[c],nCurrImgCoord_X,nCurrImgCoord_Y,c,m_anLBSPThreshold_8bitLUT[anBGColor[c]],anCurrInputDesc[c]); - const size_t nDescDist = hdist(anCurrInputDesc[c],anBGDesc[c]); - if(nDescDist>nCurrSCDescDistThreshold) - goto failedcheck3ch; - nTotColorDist += nColorDist; - nTotDescDist += nDescDist; - } - if(nTotDescDist<=nCurrDescDistThreshold && nTotColorDist<=nCurrColorDistThreshold) - nGoodSamplesCount++; - failedcheck3ch: - nModelIdx++; - } - if(nGoodSamplesCount<m_nRequiredBGSamples) - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - else { - if((rand()%nLearningRate)==0) { - const size_t nSampleModelIdx = rand()%m_nBGSamples; - ushort* anRandInputDesc = ((ushort*)(m_voBGDescSamples[nSampleModelIdx].data+nDescIterRGB)); - const size_t anCurrIntraLBSPThresholds[3] = {m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]]}; - LBSP::computeRGBDescriptor(oInputImg,anCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,anCurrIntraLBSPThresholds,anRandInputDesc); - for(size_t c=0; c<3; ++c) - *(m_voBGColorSamples[nSampleModelIdx].data+nPxIterRGB+c) = anCurrColor[c]; - } - if((rand()%nLearningRate)==0) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandNeighborPosition_3x3(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSampleModelIdx = rand()%m_nBGSamples; - ushort* anRandInputDesc = ((ushort*)(m_voBGDescSamples[nSampleModelIdx].data + desc_row_step*nSampleImgCoord_Y + 6*nSampleImgCoord_X)); - const size_t anCurrIntraLBSPThresholds[3] = {m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]]}; - LBSP::computeRGBDescriptor(oInputImg,anCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,anCurrIntraLBSPThresholds,anRandInputDesc); - for(size_t c=0; c<3; ++c) - *(m_voBGColorSamples[nSampleModelIdx].data + img_row_step*nSampleImgCoord_Y + 3*nSampleImgCoord_X + c) = anCurrColor[c]; - } - } - } - } - cv::medianBlur(oCurrFGMask,m_oLastFGMask,m_nDefaultMedianBlurKernelSize); - m_oLastFGMask.copyTo(oCurrFGMask); -} - -void BackgroundSubtractorLOBSTER::getBackgroundImage(cv::OutputArray backgroundImage) const { - CV_DbgAssert(m_bInitialized); - cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize,CV_32FC((int)m_nImgChannels)); - for(size_t s=0; s<m_nBGSamples; ++s) { - for(int y=0; y<m_oImgSize.height; ++y) { - for(int x=0; x<m_oImgSize.width; ++x) { - const size_t idx_nimg = m_voBGColorSamples[s].step.p[0]*y + m_voBGColorSamples[s].step.p[1]*x; - const size_t idx_flt32 = idx_nimg*4; - float* oAvgBgImgPtr = (float*)(oAvgBGImg.data+idx_flt32); - const uchar* const oBGImgPtr = m_voBGColorSamples[s].data+idx_nimg; - for(size_t c=0; c<m_nImgChannels; ++c) - oAvgBgImgPtr[c] += ((float)oBGImgPtr[c])/m_nBGSamples; - } - } - } - oAvgBGImg.convertTo(backgroundImage,CV_8U); -} - -void BackgroundSubtractorLOBSTER::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { - CV_Assert(LBSP::DESC_SIZE==2); - CV_Assert(m_bInitialized); - cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize,CV_32FC((int)m_nImgChannels)); - for(size_t n=0; n<m_voBGDescSamples.size(); ++n) { - for(int y=0; y<m_oImgSize.height; ++y) { - for(int x=0; x<m_oImgSize.width; ++x) { - const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x; - const size_t idx_flt32 = idx_ndesc*2; - float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+idx_flt32); - const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+idx_ndesc); - for(size_t c=0; c<m_nImgChannels; ++c) - oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size(); - } - } - } - oAvgBGDesc.convertTo(backgroundDescImage,CV_16U); -} diff --git a/package_bgs/pl/BackgroundSubtractorLOBSTER.h b/package_bgs/pl/BackgroundSubtractorLOBSTER.h deleted file mode 100644 index bedc55d..0000000 --- a/package_bgs/pl/BackgroundSubtractorLOBSTER.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "BackgroundSubtractorLBSP.h" - -//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold -#define BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.365f) -//! defines the default value for BackgroundSubtractorLBSP::m_nLBSPThresholdOffset -#define BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD (0) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nDescDistThreshold -#define BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD (4) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nColorDistThreshold -#define BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD (30) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nBGSamples -#define BGSLOBSTER_DEFAULT_NB_BG_SAMPLES (35) -//! defines the default value for BackgroundSubtractorLOBSTER::m_nRequiredBGSamples -#define BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) -//! defines the default value for the learning rate passed to BackgroundSubtractorLOBSTER::operator() -#define BGSLOBSTER_DEFAULT_LEARNING_RATE (16) - -/*! - LOcal Binary Similarity segmenTER (LOBSTER) change detection algorithm. - - Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). - For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. - - For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles and - G.-A. Bilodeau, "Improving Background Subtraction using Local Binary Similarity Patterns", in WACV 2014. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorLOBSTER : public BackgroundSubtractorLBSP { -public: - //! full constructor - BackgroundSubtractorLOBSTER(float fRelLBSPThreshold=BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, - size_t nLBSPThresholdOffset=BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD, - size_t nDescDistThreshold=BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD, - size_t nColorDistThreshold=BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD, - size_t nBGSamples=BGSLOBSTER_DEFAULT_NB_BG_SAMPLES, - size_t nRequiredBGSamples=BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); - //! default destructor - virtual ~BackgroundSubtractorLOBSTER(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); - //! refreshes all samples based on the last analyzed frame - virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate=false); - //! primary model update function; the learning param is reinterpreted as an integer and should be > 0 (smaller values == faster adaptation) - virtual void operator()(cv::InputArray image, cv::OutputArray fgmask, double learningRate=BGSLOBSTER_DEFAULT_LEARNING_RATE); - //! returns a copy of the latest reconstructed background image - void getBackgroundImage(cv::OutputArray backgroundImage) const; - //! returns a copy of the latest reconstructed background descriptors image - virtual void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; - -protected: - //! absolute color distance threshold - const size_t m_nColorDistThreshold; - //! absolute descriptor distance threshold - const size_t m_nDescDistThreshold; - //! number of different samples per pixel/block to be taken from input frames to build the background model - const size_t m_nBGSamples; - //! number of similar samples needed to consider the current pixel/block as 'background' - const size_t m_nRequiredBGSamples; - //! background model pixel intensity samples - std::vector<cv::Mat> m_voBGColorSamples; - //! background model descriptors samples - std::vector<cv::Mat> m_voBGDescSamples; -}; - diff --git a/package_bgs/pl/BackgroundSubtractorSuBSENSE.cpp b/package_bgs/pl/BackgroundSubtractorSuBSENSE.cpp deleted file mode 100644 index c7d5dac..0000000 --- a/package_bgs/pl/BackgroundSubtractorSuBSENSE.cpp +++ /dev/null @@ -1,737 +0,0 @@ -#include "BackgroundSubtractorSuBSENSE.h" -#include "DistanceUtils.h" -#include "RandUtils.h" -#include <iostream> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/highgui/highgui.hpp> -#include <iomanip> - -/* - * - * Intrinsic parameters for our method are defined here; tuning these for better - * performance should not be required in most cases -- although improvements in - * very specific scenarios are always possible. - * - */ -//! defines the threshold value(s) used to detect long-term ghosting and trigger the fast edge-based absorption heuristic -#define GHOSTDET_D_MAX (0.010f) // defines 'negligible' change here -#define GHOSTDET_S_MIN (0.995f) // defines the required minimum local foreground saturation value -//! parameter used to scale dynamic distance threshold adjustments ('R(x)') -#define FEEDBACK_R_VAR (0.01f) -//! parameters used to adjust the variation step size of 'v(x)' -#define FEEDBACK_V_INCR (1.000f) -#define FEEDBACK_V_DECR (0.100f) -//! parameters used to scale dynamic learning rate adjustments ('T(x)') -#define FEEDBACK_T_DECR (0.2500f) -#define FEEDBACK_T_INCR (0.5000f) -#define FEEDBACK_T_LOWER (2.0000f) -#define FEEDBACK_T_UPPER (256.00f) -//! parameters used to define 'unstable' regions, based on segm noise/bg dynamics and local dist threshold values -#define UNSTABLE_REG_RATIO_MIN (0.100f) -#define UNSTABLE_REG_RDIST_MIN (3.000f) -//! parameters used to scale the relative LBSP intensity threshold used for internal comparisons -#define LBSPDESC_NONZERO_RATIO_MIN (0.100f) -#define LBSPDESC_NONZERO_RATIO_MAX (0.500f) -//! parameters used to define model reset/learning rate boosts in our frame-level component -#define FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD (m_nMinColorDistThreshold/2) -#define FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO (8) - -// local define used to display debug information -#define DISPLAY_SUBSENSE_DEBUG_INFO 0 -// local define used to specify the default frame size (320x240 = QVGA) -#define DEFAULT_FRAME_SIZE cv::Size(320,240) -// local define used to specify the color dist threshold offset used for unstable regions -#define STAB_COLOR_DIST_OFFSET (m_nMinColorDistThreshold/5) -// local define used to specify the desc dist threshold offset used for unstable regions -#define UNSTAB_DESC_DIST_OFFSET (m_nDescDistThresholdOffset) - -static const size_t s_nColorMaxDataRange_1ch = UCHAR_MAX; -static const size_t s_nDescMaxDataRange_1ch = LBSP::DESC_SIZE*8; -static const size_t s_nColorMaxDataRange_3ch = s_nColorMaxDataRange_1ch*3; -static const size_t s_nDescMaxDataRange_3ch = s_nDescMaxDataRange_1ch*3; - -BackgroundSubtractorSuBSENSE::BackgroundSubtractorSuBSENSE( float fRelLBSPThreshold - ,size_t nDescDistThresholdOffset - ,size_t nMinColorDistThreshold - ,size_t nBGSamples - ,size_t nRequiredBGSamples - ,size_t nSamplesForMovingAvgs) - : BackgroundSubtractorLBSP(fRelLBSPThreshold) - ,m_nMinColorDistThreshold(nMinColorDistThreshold) - ,m_nDescDistThresholdOffset(nDescDistThresholdOffset) - ,m_nBGSamples(nBGSamples) - ,m_nRequiredBGSamples(nRequiredBGSamples) - ,m_nSamplesForMovingAvgs(nSamplesForMovingAvgs) - ,m_fLastNonZeroDescRatio(0.0f) - ,m_bLearningRateScalingEnabled(true) - ,m_fCurrLearningRateLowerCap(FEEDBACK_T_LOWER) - ,m_fCurrLearningRateUpperCap(FEEDBACK_T_UPPER) - ,m_nMedianBlurKernelSize(m_nDefaultMedianBlurKernelSize) - ,m_bUse3x3Spread(true) { - CV_Assert(m_nBGSamples>0 && m_nRequiredBGSamples<=m_nBGSamples); - CV_Assert(m_nMinColorDistThreshold>=STAB_COLOR_DIST_OFFSET); -} - -BackgroundSubtractorSuBSENSE::~BackgroundSubtractorSuBSENSE() { - if(m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if(m_aPxInfoLUT) - delete[] m_aPxInfoLUT; -} - -void BackgroundSubtractorSuBSENSE::initialize(const cv::Mat& oInitImg, const cv::Mat& oROI) { - // == init - CV_Assert(!oInitImg.empty() && oInitImg.cols>0 && oInitImg.rows>0); - CV_Assert(oInitImg.isContinuous()); - CV_Assert(oInitImg.type()==CV_8UC3 || oInitImg.type()==CV_8UC1); - if(oInitImg.type()==CV_8UC3) { - std::vector<cv::Mat> voInitImgChannels; - cv::split(oInitImg,voInitImgChannels); - if(!cv::countNonZero((voInitImgChannels[0]!=voInitImgChannels[1])|(voInitImgChannels[2]!=voInitImgChannels[1]))) - std::cout << std::endl << "\tBackgroundSubtractorSuBSENSE : Warning, grayscale images should always be passed in CV_8UC1 format for optimal performance." << std::endl; - } - cv::Mat oNewBGROI; - if(oROI.empty() && (m_oROI.empty() || oROI.size()!=oInitImg.size())) { - oNewBGROI.create(oInitImg.size(),CV_8UC1); - oNewBGROI = cv::Scalar_<uchar>(UCHAR_MAX); - } - else if(oROI.empty()) - oNewBGROI = m_oROI; - else { - CV_Assert(oROI.size()==oInitImg.size() && oROI.type()==CV_8UC1); - CV_Assert(cv::countNonZero((oROI<UCHAR_MAX)&(oROI>0))==0); - oNewBGROI = oROI.clone(); - cv::Mat oTempROI; - cv::dilate(oNewBGROI,oTempROI,cv::Mat(),cv::Point(-1,-1),LBSP::PATCH_SIZE/2); - cv::bitwise_or(oNewBGROI,oTempROI/2,oNewBGROI); - } - const size_t nOrigROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nOrigROIPxCount>0); - LBSP::validateROI(oNewBGROI); - const size_t nFinalROIPxCount = (size_t)cv::countNonZero(oNewBGROI); - CV_Assert(nFinalROIPxCount>0); - m_oROI = oNewBGROI; - m_oImgSize = oInitImg.size(); - m_nImgType = oInitImg.type(); - m_nImgChannels = oInitImg.channels(); - m_nTotPxCount = m_oImgSize.area(); - m_nTotRelevantPxCount = nFinalROIPxCount; - m_nFrameIndex = 0; - m_nFramesSinceLastReset = 0; - m_nModelResetCooldown = 0; - m_fLastNonZeroDescRatio = 0.0f; - const int nTotImgPixels = m_oImgSize.height*m_oImgSize.width; - if(nOrigROIPxCount>=m_nTotPxCount/2 && (int)m_nTotPxCount>=DEFAULT_FRAME_SIZE.area()) { - m_bLearningRateScalingEnabled = true; - m_bAutoModelResetEnabled = true; - m_bUse3x3Spread = !(nTotImgPixels>DEFAULT_FRAME_SIZE.area()*2); - const int nRawMedianBlurKernelSize = std::min((int)floor((float)nTotImgPixels/DEFAULT_FRAME_SIZE.area()+0.5f)+m_nDefaultMedianBlurKernelSize,14); - m_nMedianBlurKernelSize = (nRawMedianBlurKernelSize%2)?nRawMedianBlurKernelSize:nRawMedianBlurKernelSize-1; - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; - } - else { - m_bLearningRateScalingEnabled = false; - m_bAutoModelResetEnabled = false; - m_bUse3x3Spread = true; - m_nMedianBlurKernelSize = m_nDefaultMedianBlurKernelSize; - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER*2; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER*2; - } - m_oUpdateRateFrame.create(m_oImgSize,CV_32FC1); - m_oUpdateRateFrame = cv::Scalar(m_fCurrLearningRateLowerCap); - m_oDistThresholdFrame.create(m_oImgSize,CV_32FC1); - m_oDistThresholdFrame = cv::Scalar(1.0f); - m_oVariationModulatorFrame.create(m_oImgSize,CV_32FC1); - m_oVariationModulatorFrame = cv::Scalar(10.0f); // should always be >= FEEDBACK_V_DECR - m_oMeanLastDistFrame.create(m_oImgSize,CV_32FC1); - m_oMeanLastDistFrame = cv::Scalar(0.0f); - m_oMeanMinDistFrame_LT.create(m_oImgSize,CV_32FC1); - m_oMeanMinDistFrame_LT = cv::Scalar(0.0f); - m_oMeanMinDistFrame_ST.create(m_oImgSize,CV_32FC1); - m_oMeanMinDistFrame_ST = cv::Scalar(0.0f); - m_oDownSampledFrameSize = cv::Size(m_oImgSize.width/FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO,m_oImgSize.height/FRAMELEVEL_ANALYSIS_DOWNSAMPLE_RATIO); - m_oMeanDownSampledLastDistFrame_LT.create(m_oDownSampledFrameSize,CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_LT = cv::Scalar(0.0f); - m_oMeanDownSampledLastDistFrame_ST.create(m_oDownSampledFrameSize,CV_32FC((int)m_nImgChannels)); - m_oMeanDownSampledLastDistFrame_ST = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_LT.create(m_oImgSize,CV_32FC1); - m_oMeanRawSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanRawSegmResFrame_ST.create(m_oImgSize,CV_32FC1); - m_oMeanRawSegmResFrame_ST = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_LT.create(m_oImgSize,CV_32FC1); - m_oMeanFinalSegmResFrame_LT = cv::Scalar(0.0f); - m_oMeanFinalSegmResFrame_ST.create(m_oImgSize,CV_32FC1); - m_oMeanFinalSegmResFrame_ST = cv::Scalar(0.0f); - m_oUnstableRegionMask.create(m_oImgSize,CV_8UC1); - m_oUnstableRegionMask = cv::Scalar_<uchar>(0); - m_oBlinksFrame.create(m_oImgSize,CV_8UC1); - m_oBlinksFrame = cv::Scalar_<uchar>(0); - m_oDownSampledFrame_MotionAnalysis.create(m_oDownSampledFrameSize,CV_8UC((int)m_nImgChannels)); - m_oDownSampledFrame_MotionAnalysis = cv::Scalar_<uchar>::all(0); - m_oLastColorFrame.create(m_oImgSize,CV_8UC((int)m_nImgChannels)); - m_oLastColorFrame = cv::Scalar_<uchar>::all(0); - m_oLastDescFrame.create(m_oImgSize,CV_16UC((int)m_nImgChannels)); - m_oLastDescFrame = cv::Scalar_<ushort>::all(0); - m_oLastRawFGMask.create(m_oImgSize,CV_8UC1); - m_oLastRawFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask.create(m_oImgSize,CV_8UC1); - m_oLastFGMask = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated.create(m_oImgSize,CV_8UC1); - m_oLastFGMask_dilated = cv::Scalar_<uchar>(0); - m_oLastFGMask_dilated_inverted.create(m_oImgSize,CV_8UC1); - m_oLastFGMask_dilated_inverted = cv::Scalar_<uchar>(0); - m_oFGMask_FloodedHoles.create(m_oImgSize,CV_8UC1); - m_oFGMask_FloodedHoles = cv::Scalar_<uchar>(0); - m_oFGMask_PreFlood.create(m_oImgSize,CV_8UC1); - m_oFGMask_PreFlood = cv::Scalar_<uchar>(0); - m_oCurrRawFGBlinkMask.create(m_oImgSize,CV_8UC1); - m_oCurrRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_oLastRawFGBlinkMask.create(m_oImgSize,CV_8UC1); - m_oLastRawFGBlinkMask = cv::Scalar_<uchar>(0); - m_voBGColorSamples.resize(m_nBGSamples); - m_voBGDescSamples.resize(m_nBGSamples); - for(size_t s=0; s<m_nBGSamples; ++s) { - m_voBGColorSamples[s].create(m_oImgSize,CV_8UC((int)m_nImgChannels)); - m_voBGColorSamples[s] = cv::Scalar_<uchar>::all(0); - m_voBGDescSamples[s].create(m_oImgSize,CV_16UC((int)m_nImgChannels)); - m_voBGDescSamples[s] = cv::Scalar_<ushort>::all(0); - } - if(m_aPxIdxLUT) - delete[] m_aPxIdxLUT; - if(m_aPxInfoLUT) - delete[] m_aPxInfoLUT; - m_aPxIdxLUT = new size_t[m_nTotRelevantPxCount]; - m_aPxInfoLUT = new PxInfoBase[m_nTotPxCount]; - if(m_nImgChannels==1) { - CV_Assert(m_oLastColorFrame.step.p[0]==(size_t)m_oImgSize.width && m_oLastColorFrame.step.p[1]==1); - CV_Assert(m_oLastDescFrame.step.p[0]==m_oLastColorFrame.step.p[0]*2 && m_oLastDescFrame.step.p[1]==m_oLastColorFrame.step.p[1]*2); - for(size_t t=0; t<=UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>((m_nLBSPThresholdOffset+t*m_fRelLBSPThreshold)/3); - for(size_t nPxIter=0, nModelIter=0; nPxIter<m_nTotPxCount; ++nPxIter) { - if(m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter/m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - m_oLastColorFrame.data[nPxIter] = oInitImg.data[nPxIter]; - const size_t nDescIter = nPxIter*2; - LBSP::computeGrayscaleDescriptor(oInitImg,oInitImg.data[nPxIter],m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxIter]],*((ushort*)(m_oLastDescFrame.data+nDescIter))); - ++nModelIter; - } - } - } - else { //m_nImgChannels==3 - CV_Assert(m_oLastColorFrame.step.p[0]==(size_t)m_oImgSize.width*3 && m_oLastColorFrame.step.p[1]==3); - CV_Assert(m_oLastDescFrame.step.p[0]==m_oLastColorFrame.step.p[0]*2 && m_oLastDescFrame.step.p[1]==m_oLastColorFrame.step.p[1]*2); - for(size_t t=0; t<=UCHAR_MAX; ++t) - m_anLBSPThreshold_8bitLUT[t] = cv::saturate_cast<uchar>(m_nLBSPThresholdOffset+t*m_fRelLBSPThreshold); - for(size_t nPxIter=0, nModelIter=0; nPxIter<m_nTotPxCount; ++nPxIter) { - if(m_oROI.data[nPxIter]) { - m_aPxIdxLUT[nModelIter] = nPxIter; - m_aPxInfoLUT[nPxIter].nImgCoord_Y = (int)nPxIter/m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nImgCoord_X = (int)nPxIter%m_oImgSize.width; - m_aPxInfoLUT[nPxIter].nModelIdx = nModelIter; - const size_t nPxRGBIter = nPxIter*3; - const size_t nDescRGBIter = nPxRGBIter*2; - for(size_t c=0; c<3; ++c) { - m_oLastColorFrame.data[nPxRGBIter+c] = oInitImg.data[nPxRGBIter+c]; - LBSP::computeSingleRGBDescriptor(oInitImg,oInitImg.data[nPxRGBIter+c],m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,c,m_anLBSPThreshold_8bitLUT[oInitImg.data[nPxRGBIter+c]],((ushort*)(m_oLastDescFrame.data+nDescRGBIter))[c]); - } - ++nModelIter; - } - } - } - m_bInitialized = true; - refreshModel(1.0f); -} - -void BackgroundSubtractorSuBSENSE::refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate) { - // == refresh - CV_Assert(m_bInitialized); - CV_Assert(fSamplesRefreshFrac>0.0f && fSamplesRefreshFrac<=1.0f); - const size_t nModelsToRefresh = fSamplesRefreshFrac<1.0f?(size_t)(fSamplesRefreshFrac*m_nBGSamples):m_nBGSamples; - const size_t nRefreshStartPos = fSamplesRefreshFrac<1.0f?rand()%m_nBGSamples:0; - if(m_nImgChannels==1) { - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if(bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for(size_t nCurrModelIdx=nRefreshStartPos; nCurrModelIdx<nRefreshStartPos+nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X,nSampleImgCoord_Y,m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if(bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter] = m_oLastColorFrame.data[nSamplePxIdx]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data+nPxIter*2)) = *((ushort*)(m_oLastDescFrame.data+nSamplePxIdx*2)); - } - } - } - } - } - else { //m_nImgChannels==3 - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - if(bForceFGUpdate || !m_oLastFGMask.data[nPxIter]) { - for(size_t nCurrModelIdx=nRefreshStartPos; nCurrModelIdx<nRefreshStartPos+nModelsToRefresh; ++nCurrModelIdx) { - int nSampleImgCoord_Y, nSampleImgCoord_X; - getRandSamplePosition(nSampleImgCoord_X,nSampleImgCoord_Y,m_aPxInfoLUT[nPxIter].nImgCoord_X,m_aPxInfoLUT[nPxIter].nImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t nSamplePxIdx = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - if(bForceFGUpdate || !m_oLastFGMask.data[nSamplePxIdx]) { - const size_t nCurrRealModelIdx = nCurrModelIdx%m_nBGSamples; - for(size_t c=0; c<3; ++c) { - m_voBGColorSamples[nCurrRealModelIdx].data[nPxIter*3+c] = m_oLastColorFrame.data[nSamplePxIdx*3+c]; - *((ushort*)(m_voBGDescSamples[nCurrRealModelIdx].data+(nPxIter*3+c)*2)) = *((ushort*)(m_oLastDescFrame.data+(nSamplePxIdx*3+c)*2)); - } - } - } - } - } - } -} - -void BackgroundSubtractorSuBSENSE::operator()(cv::InputArray _image, cv::OutputArray _fgmask, double learningRateOverride) { - // == process - CV_Assert(m_bInitialized); - cv::Mat oInputImg = _image.getMat(); - CV_Assert(oInputImg.type()==m_nImgType && oInputImg.size()==m_oImgSize); - CV_Assert(oInputImg.isContinuous()); - _fgmask.create(m_oImgSize,CV_8UC1); - cv::Mat oCurrFGMask = _fgmask.getMat(); - memset(oCurrFGMask.data,0,oCurrFGMask.cols*oCurrFGMask.rows); - size_t nNonZeroDescCount = 0; - const float fRollAvgFactor_LT = 1.0f/std::min(++m_nFrameIndex,m_nSamplesForMovingAvgs); - const float fRollAvgFactor_ST = 1.0f/std::min(m_nFrameIndex,m_nSamplesForMovingAvgs/4); - if(m_nImgChannels==1) { - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const size_t nDescIter = nPxIter*2; - const size_t nFloatIter = nPxIter*4; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const uchar nCurrColor = oInputImg.data[nPxIter]; - size_t nMinDescDist = s_nDescMaxDataRange_1ch; - size_t nMinSumDist = s_nColorMaxDataRange_1ch; - float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data+nFloatIter); - float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data+nFloatIter); - float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data+nFloatIter)); - float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data+nFloatIter)); - float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data+nFloatIter)); - float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data+nFloatIter)); - float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data+nFloatIter)); - float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data+nFloatIter)); - float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data+nFloatIter)); - float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data+nFloatIter)); - ushort& nLastIntraDesc = *((ushort*)(m_oLastDescFrame.data+nDescIter)); - uchar& nLastColor = m_oLastColorFrame.data[nPxIter]; - const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold)-((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET))/2; - const size_t nCurrDescDistThreshold = ((size_t)1<<((size_t)floor(*pfCurrDistThresholdFactor+0.5f)))+m_nDescDistThresholdOffset+(m_oUnstableRegionMask.data[nPxIter]*UNSTAB_DESC_DIST_OFFSET); - ushort nCurrInterDesc, nCurrIntraDesc; - LBSP::computeGrayscaleDescriptor(oInputImg,nCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,m_anLBSPThreshold_8bitLUT[nCurrColor],nCurrIntraDesc); - m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor)>UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT-*pfCurrMeanFinalSegmRes_LT)>UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST-*pfCurrMeanFinalSegmRes_ST)>UNSTABLE_REG_RATIO_MIN)?1:0; - size_t nGoodSamplesCount=0, nSampleIdx=0; - while(nGoodSamplesCount<m_nRequiredBGSamples && nSampleIdx<m_nBGSamples) { - const uchar& nBGColor = m_voBGColorSamples[nSampleIdx].data[nPxIter]; - { - const size_t nColorDist = L1dist(nCurrColor,nBGColor); - if(nColorDist>nCurrColorDistThreshold) - goto failedcheck1ch; - const ushort& nBGIntraDesc = *((ushort*)(m_voBGDescSamples[nSampleIdx].data+nDescIter)); - const size_t nIntraDescDist = hdist(nCurrIntraDesc,nBGIntraDesc); - LBSP::computeGrayscaleDescriptor(oInputImg,nBGColor,nCurrImgCoord_X,nCurrImgCoord_Y,m_anLBSPThreshold_8bitLUT[nBGColor],nCurrInterDesc); - const size_t nInterDescDist = hdist(nCurrInterDesc,nBGIntraDesc); - const size_t nDescDist = (nIntraDescDist+nInterDescDist)/2; - if(nDescDist>nCurrDescDistThreshold) - goto failedcheck1ch; - const size_t nSumDist = std::min((nDescDist/4)*(s_nColorMaxDataRange_1ch/s_nDescMaxDataRange_1ch)+nColorDist,s_nColorMaxDataRange_1ch); - if(nSumDist>nCurrColorDistThreshold) - goto failedcheck1ch; - if(nMinDescDist>nDescDist) - nMinDescDist = nDescDist; - if(nMinSumDist>nSumDist) - nMinSumDist = nSumDist; - nGoodSamplesCount++; - } - failedcheck1ch: - nSampleIdx++; - } - const float fNormalizedLastDist = ((float)L1dist(nLastColor,nCurrColor)/s_nColorMaxDataRange_1ch+(float)hdist(nLastIntraDesc,nCurrIntraDesc)/s_nDescMaxDataRange_1ch)/2; - *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f-fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; - if(nGoodSamplesCount<m_nRequiredBGSamples) { - // == foreground - const float fNormalizedMinDist = std::min(1.0f,((float)nMinSumDist/s_nColorMaxDataRange_1ch+(float)nMinDescDist/s_nDescMaxDataRange_1ch)/2 + (float)(m_nRequiredBGSamples-nGoodSamplesCount)/m_nRequiredBGSamples); - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f-fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f-fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f-fRollAvgFactor_LT) + fRollAvgFactor_LT; - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f-fRollAvgFactor_ST) + fRollAvgFactor_ST; - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - if(m_nModelResetCooldown && (rand()%(size_t)FEEDBACK_T_LOWER)==0) { - const size_t s_rand = rand()%m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data+nDescIter)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; - } - } - else { - // == background - const float fNormalizedMinDist = ((float)nMinSumDist/s_nColorMaxDataRange_1ch+(float)nMinDescDist/s_nDescMaxDataRange_1ch)/2; - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f-fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f-fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f-fRollAvgFactor_LT); - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f-fRollAvgFactor_ST); - const size_t nLearningRate = learningRateOverride>0?(size_t)ceil(learningRateOverride):(size_t)ceil(*pfCurrLearningRate); - if((rand()%nLearningRate)==0) { - const size_t s_rand = rand()%m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data+nDescIter)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[nPxIter] = nCurrColor; - } - int nSampleImgCoord_Y, nSampleImgCoord_X; - const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; - if(bCurrUsing3x3Spread) - getRandNeighborPosition_3x3(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - else - getRandNeighborPosition_5x5(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t n_rand = rand(); - const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - const size_t idx_rand_flt32 = idx_rand_uchar*4; - const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data+idx_rand_flt32)); - const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data+idx_rand_flt32)); - if((n_rand%(bCurrUsing3x3Spread?nLearningRate:(nLearningRate/2+1)))==0 - || (fRandMeanRawSegmRes>GHOSTDET_S_MIN && fRandMeanLastDist<GHOSTDET_D_MAX && (n_rand%((size_t)m_fCurrLearningRateLowerCap))==0)) { - const size_t idx_rand_ushrt = idx_rand_uchar*2; - const size_t s_rand = rand()%m_nBGSamples; - *((ushort*)(m_voBGDescSamples[s_rand].data+idx_rand_ushrt)) = nCurrIntraDesc; - m_voBGColorSamples[s_rand].data[idx_rand_uchar] = nCurrColor; - } - } - if(m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)<UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { - if((*pfCurrLearningRate)<m_fCurrLearningRateUpperCap) - *pfCurrLearningRate += FEEDBACK_T_INCR/(std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); - } - else if((*pfCurrLearningRate)>m_fCurrLearningRateLowerCap) - *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor)/std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST); - if((*pfCurrLearningRate)<m_fCurrLearningRateLowerCap) - *pfCurrLearningRate = m_fCurrLearningRateLowerCap; - else if((*pfCurrLearningRate)>m_fCurrLearningRateUpperCap) - *pfCurrLearningRate = m_fCurrLearningRateUpperCap; - if(std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)>UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (*pfCurrVariationFactor) += FEEDBACK_V_INCR; - else if((*pfCurrVariationFactor)>FEEDBACK_V_DECR) { - (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter]?FEEDBACK_V_DECR/4:m_oUnstableRegionMask.data[nPxIter]?FEEDBACK_V_DECR/2:FEEDBACK_V_DECR; - if((*pfCurrVariationFactor)<FEEDBACK_V_DECR) - (*pfCurrVariationFactor) = FEEDBACK_V_DECR; - } - if((*pfCurrDistThresholdFactor)<std::pow(1.0f+std::min(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)*2,2)) - (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor-FEEDBACK_V_DECR); - else { - (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR/(*pfCurrVariationFactor); - if((*pfCurrDistThresholdFactor)<1.0f) - (*pfCurrDistThresholdFactor) = 1.0f; - } - if(popcount(nCurrIntraDesc)>=2) - ++nNonZeroDescCount; - nLastIntraDesc = nCurrIntraDesc; - nLastColor = nCurrColor; - } - } - else { //m_nImgChannels==3 - for(size_t nModelIter=0; nModelIter<m_nTotRelevantPxCount; ++nModelIter) { - const size_t nPxIter = m_aPxIdxLUT[nModelIter]; - const int nCurrImgCoord_X = m_aPxInfoLUT[nPxIter].nImgCoord_X; - const int nCurrImgCoord_Y = m_aPxInfoLUT[nPxIter].nImgCoord_Y; - const size_t nPxIterRGB = nPxIter*3; - const size_t nDescIterRGB = nPxIterRGB*2; - const size_t nFloatIter = nPxIter*4; - const uchar* const anCurrColor = oInputImg.data+nPxIterRGB; - size_t nMinTotDescDist=s_nDescMaxDataRange_3ch; - size_t nMinTotSumDist=s_nColorMaxDataRange_3ch; - float* pfCurrDistThresholdFactor = (float*)(m_oDistThresholdFrame.data+nFloatIter); - float* pfCurrVariationFactor = (float*)(m_oVariationModulatorFrame.data+nFloatIter); - float* pfCurrLearningRate = ((float*)(m_oUpdateRateFrame.data+nFloatIter)); - float* pfCurrMeanLastDist = ((float*)(m_oMeanLastDistFrame.data+nFloatIter)); - float* pfCurrMeanMinDist_LT = ((float*)(m_oMeanMinDistFrame_LT.data+nFloatIter)); - float* pfCurrMeanMinDist_ST = ((float*)(m_oMeanMinDistFrame_ST.data+nFloatIter)); - float* pfCurrMeanRawSegmRes_LT = ((float*)(m_oMeanRawSegmResFrame_LT.data+nFloatIter)); - float* pfCurrMeanRawSegmRes_ST = ((float*)(m_oMeanRawSegmResFrame_ST.data+nFloatIter)); - float* pfCurrMeanFinalSegmRes_LT = ((float*)(m_oMeanFinalSegmResFrame_LT.data+nFloatIter)); - float* pfCurrMeanFinalSegmRes_ST = ((float*)(m_oMeanFinalSegmResFrame_ST.data+nFloatIter)); - ushort* anLastIntraDesc = ((ushort*)(m_oLastDescFrame.data+nDescIterRGB)); - uchar* anLastColor = m_oLastColorFrame.data+nPxIterRGB; - const size_t nCurrColorDistThreshold = (size_t)(((*pfCurrDistThresholdFactor)*m_nMinColorDistThreshold)-((!m_oUnstableRegionMask.data[nPxIter])*STAB_COLOR_DIST_OFFSET)); - const size_t nCurrDescDistThreshold = ((size_t)1<<((size_t)floor(*pfCurrDistThresholdFactor+0.5f)))+m_nDescDistThresholdOffset+(m_oUnstableRegionMask.data[nPxIter]*UNSTAB_DESC_DIST_OFFSET); - const size_t nCurrTotColorDistThreshold = nCurrColorDistThreshold*3; - const size_t nCurrTotDescDistThreshold = nCurrDescDistThreshold*3; - const size_t nCurrSCColorDistThreshold = nCurrTotColorDistThreshold/2; - ushort anCurrInterDesc[3], anCurrIntraDesc[3]; - const size_t anCurrIntraLBSPThresholds[3] = {m_anLBSPThreshold_8bitLUT[anCurrColor[0]],m_anLBSPThreshold_8bitLUT[anCurrColor[1]],m_anLBSPThreshold_8bitLUT[anCurrColor[2]]}; - LBSP::computeRGBDescriptor(oInputImg,anCurrColor,nCurrImgCoord_X,nCurrImgCoord_Y,anCurrIntraLBSPThresholds,anCurrIntraDesc); - m_oUnstableRegionMask.data[nPxIter] = ((*pfCurrDistThresholdFactor)>UNSTABLE_REG_RDIST_MIN || (*pfCurrMeanRawSegmRes_LT-*pfCurrMeanFinalSegmRes_LT)>UNSTABLE_REG_RATIO_MIN || (*pfCurrMeanRawSegmRes_ST-*pfCurrMeanFinalSegmRes_ST)>UNSTABLE_REG_RATIO_MIN)?1:0; - size_t nGoodSamplesCount=0, nSampleIdx=0; - while(nGoodSamplesCount<m_nRequiredBGSamples && nSampleIdx<m_nBGSamples) { - const ushort* const anBGIntraDesc = (ushort*)(m_voBGDescSamples[nSampleIdx].data+nDescIterRGB); - const uchar* const anBGColor = m_voBGColorSamples[nSampleIdx].data+nPxIterRGB; - size_t nTotDescDist = 0; - size_t nTotSumDist = 0; - for(size_t c=0;c<3; ++c) { - const size_t nColorDist = L1dist(anCurrColor[c],anBGColor[c]); - if(nColorDist>nCurrSCColorDistThreshold) - goto failedcheck3ch; - const size_t nIntraDescDist = hdist(anCurrIntraDesc[c],anBGIntraDesc[c]); - LBSP::computeSingleRGBDescriptor(oInputImg,anBGColor[c],nCurrImgCoord_X,nCurrImgCoord_Y,c,m_anLBSPThreshold_8bitLUT[anBGColor[c]],anCurrInterDesc[c]); - const size_t nInterDescDist = hdist(anCurrInterDesc[c],anBGIntraDesc[c]); - const size_t nDescDist = (nIntraDescDist+nInterDescDist)/2; - const size_t nSumDist = std::min((nDescDist/2)*(s_nColorMaxDataRange_1ch/s_nDescMaxDataRange_1ch)+nColorDist,s_nColorMaxDataRange_1ch); - if(nSumDist>nCurrSCColorDistThreshold) - goto failedcheck3ch; - nTotDescDist += nDescDist; - nTotSumDist += nSumDist; - } - if(nTotDescDist>nCurrTotDescDistThreshold || nTotSumDist>nCurrTotColorDistThreshold) - goto failedcheck3ch; - if(nMinTotDescDist>nTotDescDist) - nMinTotDescDist = nTotDescDist; - if(nMinTotSumDist>nTotSumDist) - nMinTotSumDist = nTotSumDist; - nGoodSamplesCount++; - failedcheck3ch: - nSampleIdx++; - } - const float fNormalizedLastDist = ((float)L1dist<3>(anLastColor,anCurrColor)/s_nColorMaxDataRange_3ch+(float)hdist<3>(anLastIntraDesc,anCurrIntraDesc)/s_nDescMaxDataRange_3ch)/2; - *pfCurrMeanLastDist = (*pfCurrMeanLastDist)*(1.0f-fRollAvgFactor_ST) + fNormalizedLastDist*fRollAvgFactor_ST; - if(nGoodSamplesCount<m_nRequiredBGSamples) { - // == foreground - const float fNormalizedMinDist = std::min(1.0f,((float)nMinTotSumDist/s_nColorMaxDataRange_3ch+(float)nMinTotDescDist/s_nDescMaxDataRange_3ch)/2 + (float)(m_nRequiredBGSamples-nGoodSamplesCount)/m_nRequiredBGSamples); - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f-fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f-fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f-fRollAvgFactor_LT) + fRollAvgFactor_LT; - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f-fRollAvgFactor_ST) + fRollAvgFactor_ST; - oCurrFGMask.data[nPxIter] = UCHAR_MAX; - if(m_nModelResetCooldown && (rand()%(size_t)FEEDBACK_T_LOWER)==0) { - const size_t s_rand = rand()%m_nBGSamples; - for(size_t c=0; c<3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data+nDescIterRGB+2*c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data+nPxIterRGB+c) = anCurrColor[c]; - } - } - } - else { - // == background - const float fNormalizedMinDist = ((float)nMinTotSumDist/s_nColorMaxDataRange_3ch+(float)nMinTotDescDist/s_nDescMaxDataRange_3ch)/2; - *pfCurrMeanMinDist_LT = (*pfCurrMeanMinDist_LT)*(1.0f-fRollAvgFactor_LT) + fNormalizedMinDist*fRollAvgFactor_LT; - *pfCurrMeanMinDist_ST = (*pfCurrMeanMinDist_ST)*(1.0f-fRollAvgFactor_ST) + fNormalizedMinDist*fRollAvgFactor_ST; - *pfCurrMeanRawSegmRes_LT = (*pfCurrMeanRawSegmRes_LT)*(1.0f-fRollAvgFactor_LT); - *pfCurrMeanRawSegmRes_ST = (*pfCurrMeanRawSegmRes_ST)*(1.0f-fRollAvgFactor_ST); - const size_t nLearningRate = learningRateOverride>0?(size_t)ceil(learningRateOverride):(size_t)ceil(*pfCurrLearningRate); - if((rand()%nLearningRate)==0) { - const size_t s_rand = rand()%m_nBGSamples; - for(size_t c=0; c<3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data+nDescIterRGB+2*c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data+nPxIterRGB+c) = anCurrColor[c]; - } - } - int nSampleImgCoord_Y, nSampleImgCoord_X; - const bool bCurrUsing3x3Spread = m_bUse3x3Spread && !m_oUnstableRegionMask.data[nPxIter]; - if(bCurrUsing3x3Spread) - getRandNeighborPosition_3x3(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - else - getRandNeighborPosition_5x5(nSampleImgCoord_X,nSampleImgCoord_Y,nCurrImgCoord_X,nCurrImgCoord_Y,LBSP::PATCH_SIZE/2,m_oImgSize); - const size_t n_rand = rand(); - const size_t idx_rand_uchar = m_oImgSize.width*nSampleImgCoord_Y + nSampleImgCoord_X; - const size_t idx_rand_flt32 = idx_rand_uchar*4; - const float fRandMeanLastDist = *((float*)(m_oMeanLastDistFrame.data+idx_rand_flt32)); - const float fRandMeanRawSegmRes = *((float*)(m_oMeanRawSegmResFrame_ST.data+idx_rand_flt32)); - if((n_rand%(bCurrUsing3x3Spread?nLearningRate:(nLearningRate/2+1)))==0 - || (fRandMeanRawSegmRes>GHOSTDET_S_MIN && fRandMeanLastDist<GHOSTDET_D_MAX && (n_rand%((size_t)m_fCurrLearningRateLowerCap))==0)) { - const size_t idx_rand_uchar_rgb = idx_rand_uchar*3; - const size_t idx_rand_ushrt_rgb = idx_rand_uchar_rgb*2; - const size_t s_rand = rand()%m_nBGSamples; - for(size_t c=0; c<3; ++c) { - *((ushort*)(m_voBGDescSamples[s_rand].data+idx_rand_ushrt_rgb+2*c)) = anCurrIntraDesc[c]; - *(m_voBGColorSamples[s_rand].data+idx_rand_uchar_rgb+c) = anCurrColor[c]; - } - } - } - if(m_oLastFGMask.data[nPxIter] || (std::min(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)<UNSTABLE_REG_RATIO_MIN && oCurrFGMask.data[nPxIter])) { - if((*pfCurrLearningRate)<m_fCurrLearningRateUpperCap) - *pfCurrLearningRate += FEEDBACK_T_INCR/(std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)*(*pfCurrVariationFactor)); - } - else if((*pfCurrLearningRate)>m_fCurrLearningRateLowerCap) - *pfCurrLearningRate -= FEEDBACK_T_DECR*(*pfCurrVariationFactor)/std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST); - if((*pfCurrLearningRate)<m_fCurrLearningRateLowerCap) - *pfCurrLearningRate = m_fCurrLearningRateLowerCap; - else if((*pfCurrLearningRate)>m_fCurrLearningRateUpperCap) - *pfCurrLearningRate = m_fCurrLearningRateUpperCap; - if(std::max(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)>UNSTABLE_REG_RATIO_MIN && m_oBlinksFrame.data[nPxIter]) - (*pfCurrVariationFactor) += FEEDBACK_V_INCR; - else if((*pfCurrVariationFactor)>FEEDBACK_V_DECR) { - (*pfCurrVariationFactor) -= m_oLastFGMask.data[nPxIter]?FEEDBACK_V_DECR/4:m_oUnstableRegionMask.data[nPxIter]?FEEDBACK_V_DECR/2:FEEDBACK_V_DECR; - if((*pfCurrVariationFactor)<FEEDBACK_V_DECR) - (*pfCurrVariationFactor) = FEEDBACK_V_DECR; - } - if((*pfCurrDistThresholdFactor)<std::pow(1.0f+std::min(*pfCurrMeanMinDist_LT,*pfCurrMeanMinDist_ST)*2,2)) - (*pfCurrDistThresholdFactor) += FEEDBACK_R_VAR*(*pfCurrVariationFactor-FEEDBACK_V_DECR); - else { - (*pfCurrDistThresholdFactor) -= FEEDBACK_R_VAR/(*pfCurrVariationFactor); - if((*pfCurrDistThresholdFactor)<1.0f) - (*pfCurrDistThresholdFactor) = 1.0f; - } - if(popcount<3>(anCurrIntraDesc)>=4) - ++nNonZeroDescCount; - for(size_t c=0; c<3; ++c) { - anLastIntraDesc[c] = anCurrIntraDesc[c]; - anLastColor[c] = anCurrColor[c]; - } - } - } -#if DISPLAY_SUBSENSE_DEBUG_INFO - std::cout << std::endl; - cv::Point dbgpt(nDebugCoordX,nDebugCoordY); - cv::Mat oMeanMinDistFrameNormalized; m_oMeanMinDistFrame_ST.copyTo(oMeanMinDistFrameNormalized); - cv::circle(oMeanMinDistFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oMeanMinDistFrameNormalized,oMeanMinDistFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("d_min(x)",oMeanMinDistFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " d_min(" << dbgpt << ") = " << m_oMeanMinDistFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oMeanLastDistFrameNormalized; m_oMeanLastDistFrame.copyTo(oMeanLastDistFrameNormalized); - cv::circle(oMeanLastDistFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oMeanLastDistFrameNormalized,oMeanLastDistFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("d_last(x)",oMeanLastDistFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " d_last(" << dbgpt << ") = " << m_oMeanLastDistFrame.at<float>(dbgpt) << std::endl; - cv::Mat oMeanRawSegmResFrameNormalized; m_oMeanRawSegmResFrame_ST.copyTo(oMeanRawSegmResFrameNormalized); - cv::circle(oMeanRawSegmResFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oMeanRawSegmResFrameNormalized,oMeanRawSegmResFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("s_avg(x)",oMeanRawSegmResFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " s_avg(" << dbgpt << ") = " << m_oMeanRawSegmResFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oMeanFinalSegmResFrameNormalized; m_oMeanFinalSegmResFrame_ST.copyTo(oMeanFinalSegmResFrameNormalized); - cv::circle(oMeanFinalSegmResFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oMeanFinalSegmResFrameNormalized,oMeanFinalSegmResFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("z_avg(x)",oMeanFinalSegmResFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " z_avg(" << dbgpt << ") = " << m_oMeanFinalSegmResFrame_ST.at<float>(dbgpt) << std::endl; - cv::Mat oDistThresholdFrameNormalized; m_oDistThresholdFrame.convertTo(oDistThresholdFrameNormalized,CV_32FC1,0.25f,-0.25f); - cv::circle(oDistThresholdFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oDistThresholdFrameNormalized,oDistThresholdFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("r(x)",oDistThresholdFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " r(" << dbgpt << ") = " << m_oDistThresholdFrame.at<float>(dbgpt) << std::endl; - cv::Mat oVariationModulatorFrameNormalized; cv::normalize(m_oVariationModulatorFrame,oVariationModulatorFrameNormalized,0,255,cv::NORM_MINMAX,CV_8UC1); - cv::circle(oVariationModulatorFrameNormalized,dbgpt,5,cv::Scalar(255)); - cv::resize(oVariationModulatorFrameNormalized,oVariationModulatorFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("v(x)",oVariationModulatorFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " v(" << dbgpt << ") = " << m_oVariationModulatorFrame.at<float>(dbgpt) << std::endl; - cv::Mat oUpdateRateFrameNormalized; m_oUpdateRateFrame.convertTo(oUpdateRateFrameNormalized,CV_32FC1,1.0f/FEEDBACK_T_UPPER,-FEEDBACK_T_LOWER/FEEDBACK_T_UPPER); - cv::circle(oUpdateRateFrameNormalized,dbgpt,5,cv::Scalar(1.0f)); - cv::resize(oUpdateRateFrameNormalized,oUpdateRateFrameNormalized,DEFAULT_FRAME_SIZE); - cv::imshow("t(x)",oUpdateRateFrameNormalized); - std::cout << std::fixed << std::setprecision(5) << " t(" << dbgpt << ") = " << m_oUpdateRateFrame.at<float>(dbgpt) << std::endl; -#endif //DISPLAY_SUBSENSE_DEBUG_INFO - cv::bitwise_xor(oCurrFGMask,m_oLastRawFGMask,m_oCurrRawFGBlinkMask); - cv::bitwise_or(m_oCurrRawFGBlinkMask,m_oLastRawFGBlinkMask,m_oBlinksFrame); - m_oCurrRawFGBlinkMask.copyTo(m_oLastRawFGBlinkMask); - oCurrFGMask.copyTo(m_oLastRawFGMask); - cv::morphologyEx(oCurrFGMask,m_oFGMask_PreFlood,cv::MORPH_CLOSE,cv::Mat()); - m_oFGMask_PreFlood.copyTo(m_oFGMask_FloodedHoles); - cv::floodFill(m_oFGMask_FloodedHoles,cv::Point(0,0),UCHAR_MAX); - cv::bitwise_not(m_oFGMask_FloodedHoles,m_oFGMask_FloodedHoles); - cv::erode(m_oFGMask_PreFlood,m_oFGMask_PreFlood,cv::Mat(),cv::Point(-1,-1),3); - cv::bitwise_or(oCurrFGMask,m_oFGMask_FloodedHoles,oCurrFGMask); - cv::bitwise_or(oCurrFGMask,m_oFGMask_PreFlood,oCurrFGMask); - cv::medianBlur(oCurrFGMask,m_oLastFGMask,m_nMedianBlurKernelSize); - cv::dilate(m_oLastFGMask,m_oLastFGMask_dilated,cv::Mat(),cv::Point(-1,-1),3); - cv::bitwise_and(m_oBlinksFrame,m_oLastFGMask_dilated_inverted,m_oBlinksFrame); - cv::bitwise_not(m_oLastFGMask_dilated,m_oLastFGMask_dilated_inverted); - cv::bitwise_and(m_oBlinksFrame,m_oLastFGMask_dilated_inverted,m_oBlinksFrame); - m_oLastFGMask.copyTo(oCurrFGMask); - cv::addWeighted(m_oMeanFinalSegmResFrame_LT,(1.0f-fRollAvgFactor_LT),m_oLastFGMask,(1.0/UCHAR_MAX)*fRollAvgFactor_LT,0,m_oMeanFinalSegmResFrame_LT,CV_32F); - cv::addWeighted(m_oMeanFinalSegmResFrame_ST,(1.0f-fRollAvgFactor_ST),m_oLastFGMask,(1.0/UCHAR_MAX)*fRollAvgFactor_ST,0,m_oMeanFinalSegmResFrame_ST,CV_32F); - const float fCurrNonZeroDescRatio = (float)nNonZeroDescCount/m_nTotRelevantPxCount; - if(fCurrNonZeroDescRatio<LBSPDESC_NONZERO_RATIO_MIN && m_fLastNonZeroDescRatio<LBSPDESC_NONZERO_RATIO_MIN) { - for(size_t t=0; t<=UCHAR_MAX; ++t) - if(m_anLBSPThreshold_8bitLUT[t]>cv::saturate_cast<uchar>(m_nLBSPThresholdOffset+ceil(t*m_fRelLBSPThreshold/4))) - --m_anLBSPThreshold_8bitLUT[t]; - } - else if(fCurrNonZeroDescRatio>LBSPDESC_NONZERO_RATIO_MAX && m_fLastNonZeroDescRatio>LBSPDESC_NONZERO_RATIO_MAX) { - for(size_t t=0; t<=UCHAR_MAX; ++t) - if(m_anLBSPThreshold_8bitLUT[t]<cv::saturate_cast<uchar>(m_nLBSPThresholdOffset+UCHAR_MAX*m_fRelLBSPThreshold)) - ++m_anLBSPThreshold_8bitLUT[t]; - } - m_fLastNonZeroDescRatio = fCurrNonZeroDescRatio; - if(m_bLearningRateScalingEnabled) { - cv::resize(oInputImg,m_oDownSampledFrame_MotionAnalysis,m_oDownSampledFrameSize,0,0,cv::INTER_AREA); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis,m_oMeanDownSampledLastDistFrame_LT,fRollAvgFactor_LT); - cv::accumulateWeighted(m_oDownSampledFrame_MotionAnalysis,m_oMeanDownSampledLastDistFrame_ST,fRollAvgFactor_ST); - size_t nTotColorDiff = 0; - for(int i=0; i<m_oMeanDownSampledLastDistFrame_ST.rows; ++i) { - const size_t idx1 = m_oMeanDownSampledLastDistFrame_ST.step.p[0]*i; - for(int j=0; j<m_oMeanDownSampledLastDistFrame_ST.cols; ++j) { - const size_t idx2 = idx1+m_oMeanDownSampledLastDistFrame_ST.step.p[1]*j; - nTotColorDiff += (m_nImgChannels==1)? - (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data+idx2))-(*(float*)(m_oMeanDownSampledLastDistFrame_LT.data+idx2)))/2 - : //(m_nImgChannels==3) - std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data+idx2))-(*(float*)(m_oMeanDownSampledLastDistFrame_LT.data+idx2))), - std::max((size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data+idx2+4))-(*(float*)(m_oMeanDownSampledLastDistFrame_LT.data+idx2+4))), - (size_t)fabs((*(float*)(m_oMeanDownSampledLastDistFrame_ST.data+idx2+8))-(*(float*)(m_oMeanDownSampledLastDistFrame_LT.data+idx2+8))))); - } - } - const float fCurrColorDiffRatio = (float)nTotColorDiff/(m_oMeanDownSampledLastDistFrame_ST.rows*m_oMeanDownSampledLastDistFrame_ST.cols); - if(m_bAutoModelResetEnabled) { - if(m_nFramesSinceLastReset>1000) - m_bAutoModelResetEnabled = false; - else if(fCurrColorDiffRatio>=FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD && m_nModelResetCooldown==0) { - m_nFramesSinceLastReset = 0; - refreshModel(0.1f); // reset 10% of the bg model - m_nModelResetCooldown = m_nSamplesForMovingAvgs/4; - m_oUpdateRateFrame = cv::Scalar(1.0f); - } - else - ++m_nFramesSinceLastReset; - } - else if(fCurrColorDiffRatio>=FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD*2) { - m_nFramesSinceLastReset = 0; - m_bAutoModelResetEnabled = true; - } - if(fCurrColorDiffRatio>=FRAMELEVEL_MIN_COLOR_DIFF_THRESHOLD/2) { - m_fCurrLearningRateLowerCap = (float)std::max((int)FEEDBACK_T_LOWER>>(int)(fCurrColorDiffRatio/2),1); - m_fCurrLearningRateUpperCap = (float)std::max((int)FEEDBACK_T_UPPER>>(int)(fCurrColorDiffRatio/2),1); - } - else { - m_fCurrLearningRateLowerCap = FEEDBACK_T_LOWER; - m_fCurrLearningRateUpperCap = FEEDBACK_T_UPPER; - } - if(m_nModelResetCooldown>0) - --m_nModelResetCooldown; - } -} - -void BackgroundSubtractorSuBSENSE::getBackgroundImage(cv::OutputArray backgroundImage) const { - CV_Assert(m_bInitialized); - cv::Mat oAvgBGImg = cv::Mat::zeros(m_oImgSize,CV_32FC((int)m_nImgChannels)); - for(size_t s=0; s<m_nBGSamples; ++s) { - for(int y=0; y<m_oImgSize.height; ++y) { - for(int x=0; x<m_oImgSize.width; ++x) { - const size_t idx_nimg = m_voBGColorSamples[s].step.p[0]*y + m_voBGColorSamples[s].step.p[1]*x; - const size_t nFloatIter = idx_nimg*4; - float* oAvgBgImgPtr = (float*)(oAvgBGImg.data+nFloatIter); - const uchar* const oBGImgPtr = m_voBGColorSamples[s].data+idx_nimg; - for(size_t c=0; c<m_nImgChannels; ++c) - oAvgBgImgPtr[c] += ((float)oBGImgPtr[c])/m_nBGSamples; - } - } - } - oAvgBGImg.convertTo(backgroundImage,CV_8U); -} - -void BackgroundSubtractorSuBSENSE::getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const { - CV_Assert(LBSP::DESC_SIZE==2); - CV_Assert(m_bInitialized); - cv::Mat oAvgBGDesc = cv::Mat::zeros(m_oImgSize,CV_32FC((int)m_nImgChannels)); - for(size_t n=0; n<m_voBGDescSamples.size(); ++n) { - for(int y=0; y<m_oImgSize.height; ++y) { - for(int x=0; x<m_oImgSize.width; ++x) { - const size_t idx_ndesc = m_voBGDescSamples[n].step.p[0]*y + m_voBGDescSamples[n].step.p[1]*x; - const size_t nFloatIter = idx_ndesc*2; - float* oAvgBgDescPtr = (float*)(oAvgBGDesc.data+nFloatIter); - const ushort* const oBGDescPtr = (ushort*)(m_voBGDescSamples[n].data+idx_ndesc); - for(size_t c=0; c<m_nImgChannels; ++c) - oAvgBgDescPtr[c] += ((float)oBGDescPtr[c])/m_voBGDescSamples.size(); - } - } - } - oAvgBGDesc.convertTo(backgroundDescImage,CV_16U); -} diff --git a/package_bgs/pl/BackgroundSubtractorSuBSENSE.h b/package_bgs/pl/BackgroundSubtractorSuBSENSE.h deleted file mode 100644 index f8424ad..0000000 --- a/package_bgs/pl/BackgroundSubtractorSuBSENSE.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once - -#include "BackgroundSubtractorLBSP.h" - -//! defines the default value for BackgroundSubtractorLBSP::m_fRelLBSPThreshold -#define BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD (0.333f) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nDescDistThresholdOffset -#define BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET (3) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nMinColorDistThreshold -#define BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD (30) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nBGSamples -#define BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES (50) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nRequiredBGSamples -#define BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES (2) -//! defines the default value for BackgroundSubtractorSuBSENSE::m_nSamplesForMovingAvgs -#define BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS (100) - -/*! - Self-Balanced Sensitivity segmenTER (SuBSENSE) change detection algorithm. - - Note: both grayscale and RGB/BGR images may be used with this extractor (parameters are adjusted automatically). - For optimal grayscale results, use CV_8UC1 frames instead of CV_8UC3. - - For more details on the different parameters or on the algorithm itself, see P.-L. St-Charles et al., - "Flexible Background Subtraction With Self-Balanced Local Sensitivity", in CVPRW 2014. - - This algorithm is currently NOT thread-safe. - */ -class BackgroundSubtractorSuBSENSE : public BackgroundSubtractorLBSP { -public: - //! full constructor - BackgroundSubtractorSuBSENSE( float fRelLBSPThreshold=BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD, - size_t nDescDistThresholdOffset=BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET, - size_t nMinColorDistThreshold=BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD, - size_t nBGSamples=BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES, - size_t nRequiredBGSamples=BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES, - size_t nSamplesForMovingAvgs=BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - //! default destructor - virtual ~BackgroundSubtractorSuBSENSE(); - //! (re)initiaization method; needs to be called before starting background subtraction - virtual void initialize(const cv::Mat& oInitImg, const cv::Mat& oROI); - //! refreshes all samples based on the last analyzed frame - virtual void refreshModel(float fSamplesRefreshFrac, bool bForceFGUpdate=false); - //! primary model update function; the learning param is used to override the internal learning thresholds (ignored when <= 0) - virtual void operator()(cv::InputArray image, cv::OutputArray fgmask, double learningRateOverride=0); - //! returns a copy of the latest reconstructed background image - void getBackgroundImage(cv::OutputArray backgroundImage) const; - //! returns a copy of the latest reconstructed background descriptors image - void getBackgroundDescriptorsImage(cv::OutputArray backgroundDescImage) const; - -protected: - //! absolute minimal color distance threshold ('R' or 'radius' in the original ViBe paper, used as the default/initial 'R(x)' value here) - const size_t m_nMinColorDistThreshold; - //! absolute descriptor distance threshold offset - const size_t m_nDescDistThresholdOffset; - //! number of different samples per pixel/block to be taken from input frames to build the background model (same as 'N' in ViBe/PBAS) - const size_t m_nBGSamples; - //! number of similar samples needed to consider the current pixel/block as 'background' (same as '#_min' in ViBe/PBAS) - const size_t m_nRequiredBGSamples; - //! number of samples to use to compute the learning rate of moving averages - const size_t m_nSamplesForMovingAvgs; - //! last calculated non-zero desc ratio - float m_fLastNonZeroDescRatio; - //! specifies whether Tmin/Tmax scaling is enabled or not - bool m_bLearningRateScalingEnabled; - //! current learning rate caps - float m_fCurrLearningRateLowerCap, m_fCurrLearningRateUpperCap; - //! current kernel size for median blur post-proc filtering - int m_nMedianBlurKernelSize; - //! specifies the px update spread range - bool m_bUse3x3Spread; - //! specifies the downsampled frame size used for cam motion analysis - cv::Size m_oDownSampledFrameSize; - - //! background model pixel color intensity samples (equivalent to 'B(x)' in PBAS) - std::vector<cv::Mat> m_voBGColorSamples; - //! background model descriptors samples - std::vector<cv::Mat> m_voBGDescSamples; - - //! per-pixel update rates ('T(x)' in PBAS, which contains pixel-level 'sigmas', as referred to in ViBe) - cv::Mat m_oUpdateRateFrame; - //! per-pixel distance thresholds (equivalent to 'R(x)' in PBAS, but used as a relative value to determine both intensity and descriptor variation thresholds) - cv::Mat m_oDistThresholdFrame; - //! per-pixel distance variation modulators ('v(x)', relative value used to modulate 'R(x)' and 'T(x)' variations) - cv::Mat m_oVariationModulatorFrame; - //! per-pixel mean distances between consecutive frames ('D_last(x)', used to detect ghosts and high variation regions in the sequence) - cv::Mat m_oMeanLastDistFrame; - //! per-pixel mean minimal distances from the model ('D_min(x)' in PBAS, used to control variation magnitude and direction of 'T(x)' and 'R(x)') - cv::Mat m_oMeanMinDistFrame_LT, m_oMeanMinDistFrame_ST; - //! per-pixel mean downsampled distances between consecutive frames (used to analyze camera movement and control max learning rates globally) - cv::Mat m_oMeanDownSampledLastDistFrame_LT, m_oMeanDownSampledLastDistFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanRawSegmResFrame_LT, m_oMeanRawSegmResFrame_ST; - //! per-pixel mean raw segmentation results (used to detect unstable segmentation regions) - cv::Mat m_oMeanFinalSegmResFrame_LT, m_oMeanFinalSegmResFrame_ST; - //! a lookup map used to keep track of unstable regions (based on segm. noise & local dist. thresholds) - cv::Mat m_oUnstableRegionMask; - //! per-pixel blink detection map ('Z(x)') - cv::Mat m_oBlinksFrame; - //! pre-allocated matrix used to downsample the input frame when needed - cv::Mat m_oDownSampledFrame_MotionAnalysis; - //! the foreground mask generated by the method at [t-1] (without post-proc, used for blinking px detection) - cv::Mat m_oLastRawFGMask; - - //! pre-allocated CV_8UC1 matrices used to speed up morph ops - cv::Mat m_oFGMask_PreFlood; - cv::Mat m_oFGMask_FloodedHoles; - cv::Mat m_oLastFGMask_dilated; - cv::Mat m_oLastFGMask_dilated_inverted; - cv::Mat m_oCurrRawFGBlinkMask; - cv::Mat m_oLastRawFGBlinkMask; -}; - diff --git a/package_bgs/pl/DistanceUtils.h b/package_bgs/pl/DistanceUtils.h deleted file mode 100644 index 54d1cec..0000000 --- a/package_bgs/pl/DistanceUtils.h +++ /dev/null @@ -1,316 +0,0 @@ -#pragma once - -#include <opencv2/core/types_c.h> - -//! computes the L1 distance between two integer values -template<typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type L1dist(T a, T b) { - return (size_t)abs((int)a-b); -} - -//! computes the L1 distance between two float values -template<typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type L1dist(T a, T b) { - return fabs((float)a-(float)b); -} - -//! computes the L1 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b) -> decltype(L1dist(*a,*b)) { - decltype(L1dist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L1dist(a[c],b[c]); - return oResult; -} - -//! computes the L1 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L1dist<nChannels>(a,b)) { - decltype(L1dist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L1dist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L1dist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the L1 distance between two generic arrays -template<typename T> static inline auto L1dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L1dist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L1dist<1>(a,b,nElements,m); - case 2: return L1dist<2>(a,b,nElements,m); - case 3: return L1dist<3>(a,b,nElements,m); - case 4: return L1dist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the L1 distance between two opencv vectors -template<size_t nChannels, typename T> static inline auto L1dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L1dist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L1dist<nChannels>(a_array,b_array); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! computes the squared L2 distance between two generic variables -template<typename T> static inline auto L2sqrdist(T a, T b) -> decltype(L1dist(a,b)) { - auto oResult = L1dist(a,b); - return oResult*oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b) -> decltype(L2sqrdist(*a,*b)) { - decltype(L2sqrdist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L2sqrdist(a[c],b[c]); - return oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(L2sqrdist<nChannels>(a,b)) { - decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the squared L2 distance between two generic arrays -template<typename T> static inline auto L2sqrdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(L2sqrdist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L2sqrdist<1>(a,b,nElements,m); - case 2: return L2sqrdist<2>(a,b,nElements,m); - case 3: return L2sqrdist<3>(a,b,nElements,m); - case 4: return L2sqrdist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the squared L2 distance between two opencv vectors -template<size_t nChannels, typename T> static inline auto L2sqrdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(L2sqrdist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L2sqrdist<nChannels>(a_array,b_array); -} - -//! computes the L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b) { - decltype(L2sqrdist(*a,*b)) oResult = 0; - for(size_t c=0; c<nChannels; ++c) - oResult += L2sqrdist(a[c],b[c]); - return sqrt((float)oResult); -} - -//! computes the L2 distance between two generic arrays -template<size_t nChannels, typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) { - decltype(L2sqrdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += L2sqrdist<nChannels>(a+n,b+n); - } - return sqrt((float)oResult); -} - -//! computes the squared L2 distance between two generic arrays -template<typename T> static inline float L2dist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) { - CV_Assert(nChannels>0 && nChannels<=4); - switch(nChannels) { - case 1: return L2dist<1>(a,b,nElements,m); - case 2: return L2dist<2>(a,b,nElements,m); - case 3: return L2dist<3>(a,b,nElements,m); - case 4: return L2dist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the L2 distance between two opencv vectors -template<size_t nChannels, typename T> static inline float L2dist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return L2dist<nChannels>(a_array,b_array); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! computes the color distortion between two integer arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cdist(const T* curr, const T* bg) { - static_assert(nChannels>1,"cdist: requires more than one channel"); - size_t curr_sqr = 0; - bool bSkip = true; - for(size_t c=0; c<nChannels; ++c) { - curr_sqr += curr[c]*curr[c]; - bSkip = bSkip&(bg[c]<=0); - } - if(bSkip) - return (size_t)sqrt((float)curr_sqr); - size_t bg_sqr = 0; - size_t mix = 0; - for(size_t c=0; c<nChannels; ++c) { - bg_sqr += bg[c]*bg[c]; - mix += curr[c]*bg[c]; - } - return (size_t)sqrt(curr_sqr-((float)(mix*mix)/bg_sqr)); -} - -//! computes the color distortion between two float arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cdist(const T* curr, const T* bg) { - static_assert(nChannels>1,"cdist: requires more than one channel"); - float curr_sqr = 0; - bool bSkip = true; - for(size_t c=0; c<nChannels; ++c) { - curr_sqr += (float)curr[c]*curr[c]; - bSkip = bSkip&(bg[c]<=0); - } - if(bSkip) - return sqrt(curr_sqr); - float bg_sqr = 0; - float mix = 0; - for(size_t c=0; c<nChannels; ++c) { - bg_sqr += (float)bg[c]*bg[c]; - mix += (float)curr[c]*bg[c]; - } - return sqrt(curr_sqr-((mix*mix)/bg_sqr)); -} - -//! computes the color distortion between two generic arrays -template<size_t nChannels, typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, const uchar* m=NULL) -> decltype(cdist<nChannels>(a,b)) { - decltype(cdist<nChannels>(a,b)) oResult = 0; - size_t nTotElements = nElements*nChannels; - if(m) { - for(size_t n=0,i=0; n<nTotElements; n+=nChannels,++i) - if(m[i]) - oResult += cdist<nChannels>(a+n,b+n); - } - else { - for(size_t n=0; n<nTotElements; n+=nChannels) - oResult += cdist<nChannels>(a+n,b+n); - } - return oResult; -} - -//! computes the color distortion between two generic arrays -template<typename T> static inline auto cdist(const T* a, const T* b, size_t nElements, size_t nChannels, const uchar* m=NULL) -> decltype(cdist<3>(a,b,nElements,m)) { - CV_Assert(nChannels>1 && nChannels<=4); - switch(nChannels) { - case 2: return cdist<2>(a,b,nElements,m); - case 3: return cdist<3>(a,b,nElements,m); - case 4: return cdist<4>(a,b,nElements,m); - default: return 0; - } -} - -//! computes the color distortion between two opencv vectors -template<size_t nChannels, typename T> static inline auto cdist_(const cv::Vec<T,nChannels>& a, const cv::Vec<T,nChannels>& b) -> decltype(cdist<nChannels,T>((T*)(0),(T*)(0))) { - T a_array[nChannels], b_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) { - a_array[c] = a[(int)c]; - b_array[c] = b[(int)c]; - } - return cdist<nChannels>(a_array,b_array); -} - -//! computes a color distortion-distance mix using two generic distances -template<typename T> static inline T cmixdist(T oL1Distance, T oCDistortion) { - return (oL1Distance/2+oCDistortion*4); -} - -//! computes a color distoirtion-distance mix using two generic arrays -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_integral<T>::value,size_t>::type cmixdist(const T* curr, const T* bg) { - return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); -} - -template<size_t nChannels, typename T> static inline typename std::enable_if<std::is_floating_point<T>::value,float>::type cmixdist(const T* curr, const T* bg) { - return cmixdist(L1dist<nChannels>(curr,bg),cdist<nChannels>(curr,bg)); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -//! popcount LUT for 8-bit vectors -static const uchar popcount_LUT8[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -//! computes the population count of an N-byte vector using an 8-bit popcount LUT -template<typename T> static inline size_t popcount(T x) { - size_t nBytes = sizeof(T); - size_t nResult = 0; - for(size_t l=0; l<nBytes; ++l) - nResult += popcount_LUT8[(uchar)(x>>l*8)]; - return nResult; -} - -//! computes the hamming distance between two N-byte vectors using an 8-bit popcount LUT -template<typename T> static inline size_t hdist(T a, T b) { - return popcount(a^b); -} - -//! computes the gradient magnitude distance between two N-byte vectors using an 8-bit popcount LUT -template<typename T> static inline size_t gdist(T a, T b) { - return L1dist(popcount(a),popcount(b)); -} - -//! computes the population count of a (nChannels*N)-byte vector using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t popcount(const T* x) { - size_t nBytes = sizeof(T); - size_t nResult = 0; - for(size_t c=0; c<nChannels; ++c) - for(size_t l=0; l<nBytes; ++l) - nResult += popcount_LUT8[(uchar)(*(x+c)>>l*8)]; - return nResult; -} - -//! computes the hamming distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t hdist(const T* a, const T* b) { - T xor_array[nChannels]; - for(size_t c=0; c<nChannels; ++c) - xor_array[c] = a[c]^b[c]; - return popcount<nChannels>(xor_array); -} - -//! computes the gradient magnitude distance between two (nChannels*N)-byte vectors using an 8-bit popcount LUT -template<size_t nChannels, typename T> static inline size_t gdist(const T* a, const T* b) { - return L1dist(popcount<nChannels>(a),popcount<nChannels>(b)); -} diff --git a/package_bgs/pl/LBSP.cpp b/package_bgs/pl/LBSP.cpp deleted file mode 100644 index de35f1a..0000000 --- a/package_bgs/pl/LBSP.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include "LBSP.h" - -LBSP::LBSP(size_t nThreshold) - : m_bOnlyUsingAbsThreshold(true) - ,m_fRelThreshold(0) // unused - ,m_nThreshold(nThreshold) - ,m_oRefImage() {} - -LBSP::LBSP(float fRelThreshold, size_t nThresholdOffset) - : m_bOnlyUsingAbsThreshold(false) - ,m_fRelThreshold(fRelThreshold) - ,m_nThreshold(nThresholdOffset) - ,m_oRefImage() { - CV_Assert(m_fRelThreshold>=0); -} - -LBSP::~LBSP() {} - -void LBSP::read(const cv::FileNode& /*fn*/) { - // ... = fn["..."]; -} - -void LBSP::write(cv::FileStorage& /*fs*/) const { - //fs << "..." << ...; -} - -void LBSP::setReference(const cv::Mat& img) { - CV_DbgAssert(img.empty() || img.type()==CV_8UC1 || img.type()==CV_8UC3); - m_oRefImage = img; -} - -int LBSP::descriptorSize() const { - return DESC_SIZE; -} - -int LBSP::descriptorType() const { - return CV_16U; -} - -bool LBSP::isUsingRelThreshold() const { - return !m_bOnlyUsingAbsThreshold; -} - -float LBSP::getRelThreshold() const { - return m_fRelThreshold; -} - -size_t LBSP::getAbsThreshold() const { - return m_nThreshold; -} - -static inline void lbsp_computeImpl( const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size==oInputImg.size && oRefImg.type()==oInputImg.type())); - CV_DbgAssert(oInputImg.type()==CV_8UC1 || oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty()?oInputImg.data:oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if(nChannels==1) { - oDesc.create((int)nKeyPoints,1,CV_16UC1); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); - #include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints,1,CV_16UC3); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata+_step_row*(_y)+3*(_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0]*k)); - #include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void lbsp_computeImpl( const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size==oInputImg.size && oRefImg.type()==oInputImg.type())); - CV_DbgAssert(oInputImg.type()==CV_8UC1 || oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold>=0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty()?oInputImg.data:oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if(nChannels==1) { - oDesc.create((int)nKeyPoints,1,CV_16UC1); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>((int)k); - const size_t _t = (size_t)(_ref*fThreshold)+nThresholdOffset; - #include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create((int)nKeyPoints,1,CV_16UC3); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata+_step_row*(_y)+3*(_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0]*k)); - const size_t _t[3] = {(size_t)(_ref[0]*fThreshold)+nThresholdOffset,(size_t)(_ref[1]*fThreshold)+nThresholdOffset,(size_t)(_ref[2]*fThreshold)+nThresholdOffset}; - #include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -static inline void lbsp_computeImpl2( const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - size_t _t) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size==oInputImg.size && oRefImg.type()==oInputImg.type())); - CV_DbgAssert(oInputImg.type()==CV_8UC1 || oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty()?oInputImg.data:oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if(nChannels==1) { - oDesc.create(oInputImg.size(),CV_16UC1); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y,_x); - #include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(),CV_16UC3); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata+_step_row*(_y)+3*(_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0]*_y + oDesc.step.p[1]*_x)); - #include "LBSP_16bits_dbcross_3ch1t.i" - } - } -} - -static inline void lbsp_computeImpl2( const cv::Mat& oInputImg, - const cv::Mat& oRefImg, - const std::vector<cv::KeyPoint>& voKeyPoints, - cv::Mat& oDesc, - float fThreshold, - size_t nThresholdOffset) { - CV_DbgAssert(oRefImg.empty() || (oRefImg.size==oInputImg.size && oRefImg.type()==oInputImg.type())); - CV_DbgAssert(oInputImg.type()==CV_8UC1 || oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(fThreshold>=0); - const size_t nChannels = (size_t)oInputImg.channels(); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* _data = oInputImg.data; - const uchar* _refdata = oRefImg.empty()?oInputImg.data:oRefImg.data; - const size_t nKeyPoints = voKeyPoints.size(); - if(nChannels==1) { - oDesc.create(oInputImg.size(),CV_16UC1); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar _ref = _refdata[_step_row*(_y)+_x]; - ushort& _res = oDesc.at<ushort>(_y,_x); - const size_t _t = (size_t)(_ref*fThreshold)+nThresholdOffset; - #include "LBSP_16bits_dbcross_1ch.i" - } - } - else { //nChannels==3 - oDesc.create(oInputImg.size(),CV_16UC3); - for(size_t k=0; k<nKeyPoints; ++k) { - const int _x = (int)voKeyPoints[k].pt.x; - const int _y = (int)voKeyPoints[k].pt.y; - const uchar* _ref = _refdata+_step_row*(_y)+3*(_x); - ushort* _res = ((ushort*)(oDesc.data + oDesc.step.p[0]*_y + oDesc.step.p[1]*_x)); - const size_t _t[3] = {(size_t)(_ref[0]*fThreshold)+nThresholdOffset,(size_t)(_ref[1]*fThreshold)+nThresholdOffset,(size_t)(_ref[2]*fThreshold)+nThresholdOffset}; - #include "LBSP_16bits_dbcross_3ch3t.i" - } - } -} - -void LBSP::compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints,oImage.size(),PATCH_SIZE/2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints,std::numeric_limits<float>::epsilon()); - if(voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if(m_bOnlyUsingAbsThreshold) - lbsp_computeImpl2(oImage,m_oRefImage,voKeypoints,oDescriptors,m_nThreshold); - else - lbsp_computeImpl2(oImage,m_oRefImage,voKeypoints,oDescriptors,m_fRelThreshold,m_nThreshold); -} - -void LBSP::compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const { - CV_Assert(voImageCollection.size() == vvoPointCollection.size()); - voDescCollection.resize(voImageCollection.size()); - for(size_t i=0; i<voImageCollection.size(); i++) - compute2(voImageCollection[i], vvoPointCollection[i], voDescCollection[i]); -} - -void LBSP::computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const { - CV_Assert(!oImage.empty()); - cv::KeyPointsFilter::runByImageBorder(voKeypoints,oImage.size(),PATCH_SIZE/2); - cv::KeyPointsFilter::runByKeypointSize(voKeypoints,std::numeric_limits<float>::epsilon()); - if(voKeypoints.empty()) { - oDescriptors.release(); - return; - } - if(m_bOnlyUsingAbsThreshold) - lbsp_computeImpl(oImage,m_oRefImage,voKeypoints,oDescriptors,m_nThreshold); - else - lbsp_computeImpl(oImage,m_oRefImage,voKeypoints,oDescriptors,m_fRelThreshold,m_nThreshold); -} - -void LBSP::reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput) { - CV_DbgAssert(!voKeypoints.empty()); - CV_DbgAssert(!oDescriptors.empty() && oDescriptors.cols==1); - CV_DbgAssert(oSize.width>0 && oSize.height>0); - CV_DbgAssert(DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDescriptors.type()==CV_16UC1 || oDescriptors.type()==CV_16UC3); - const size_t nChannels = (size_t)oDescriptors.channels(); - const size_t nKeyPoints = voKeypoints.size(); - if(nChannels==1) { - oOutput.create(oSize,CV_16UC1); - oOutput = cv::Scalar_<ushort>(0); - for(size_t k=0; k<nKeyPoints; ++k) - oOutput.at<ushort>(voKeypoints[k].pt) = oDescriptors.at<ushort>((int)k); - } - else { //nChannels==3 - oOutput.create(oSize,CV_16UC3); - oOutput = cv::Scalar_<ushort>(0,0,0); - for(size_t k=0; k<nKeyPoints; ++k) { - ushort* output_ptr = (ushort*)(oOutput.data + oOutput.step.p[0]*(int)voKeypoints[k].pt.y); - const ushort* const desc_ptr = (ushort*)(oDescriptors.data + oDescriptors.step.p[0]*k); - const size_t idx = 3*(int)voKeypoints[k].pt.x; - for(size_t n=0; n<3; ++n) - output_ptr[idx+n] = desc_ptr[n]; - } - } -} - -void LBSP::calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels) { - CV_DbgAssert(oDesc1.size()==oDesc2.size() && oDesc1.type()==oDesc2.type()); - CV_DbgAssert(DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(oDesc1.type()==CV_16UC1 || oDesc1.type()==CV_16UC3); - CV_DbgAssert(CV_MAT_DEPTH(oDesc1.type())==CV_16U); - CV_DbgAssert(DESC_SIZE*8<=UCHAR_MAX); - CV_DbgAssert(oDesc1.step.p[0]==oDesc2.step.p[0] && oDesc1.step.p[1]==oDesc2.step.p[1]); - const float fScaleFactor = (float)UCHAR_MAX/(DESC_SIZE*8); - const size_t nChannels = CV_MAT_CN(oDesc1.type()); - const size_t _step_row = oDesc1.step.p[0]; - if(nChannels==1) { - oOutput.create(oDesc1.size(),CV_8UC1); - oOutput = cv::Scalar(0); - for(int i=0; i<oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data+idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data+idx); - for(int j=0; j<oDesc1.cols; ++j) - oOutput.at<uchar>(i,j) = (uchar)(fScaleFactor*hdist(desc1_ptr[j],desc2_ptr[j])); - } - } - else { //nChannels==3 - if(bForceMergeChannels) - oOutput.create(oDesc1.size(),CV_8UC1); - else - oOutput.create(oDesc1.size(),CV_8UC3); - oOutput = cv::Scalar::all(0); - for(int i=0; i<oDesc1.rows; ++i) { - const size_t idx = _step_row*i; - const ushort* const desc1_ptr = (ushort*)(oDesc1.data+idx); - const ushort* const desc2_ptr = (ushort*)(oDesc2.data+idx); - uchar* output_ptr = oOutput.data + oOutput.step.p[0]*i; - for(int j=0; j<oDesc1.cols; ++j) { - for(size_t n=0;n<3; ++n) { - const size_t idx2 = 3*j+n; - if(bForceMergeChannels) - output_ptr[j] += (uchar)((fScaleFactor*hdist(desc1_ptr[idx2],desc2_ptr[idx2]))/3); - else - output_ptr[idx2] = (uchar)(fScaleFactor*hdist(desc1_ptr[idx2],desc2_ptr[idx2])); - } - } - } - } -} - -void LBSP::validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize) { - cv::KeyPointsFilter::runByImageBorder(voKeypoints,oImgSize,PATCH_SIZE/2); -} - -void LBSP::validateROI(cv::Mat& oROI) { - CV_Assert(!oROI.empty() && oROI.type()==CV_8UC1); - cv::Mat oROI_new(oROI.size(),CV_8UC1,cv::Scalar_<uchar>(0)); - const size_t nBorderSize = PATCH_SIZE/2; - const cv::Rect nROI_inner(nBorderSize,nBorderSize,oROI.cols-nBorderSize*2,oROI.rows-nBorderSize*2); - cv::Mat(oROI,nROI_inner).copyTo(cv::Mat(oROI_new,nROI_inner)); - oROI = oROI_new; -} diff --git a/package_bgs/pl/LBSP.h b/package_bgs/pl/LBSP.h deleted file mode 100644 index 1ca17a0..0000000 --- a/package_bgs/pl/LBSP.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -#include <opencv2/core/core.hpp> -#include <opencv2/imgproc/imgproc.hpp> -#include <opencv2/features2d/features2d.hpp> -#include "DistanceUtils.h" - -/*! - Local Binary Similarity Pattern (LBSP) feature extractor - - Note 1: both grayscale and RGB/BGR images may be used with this extractor. - Note 2: using LBSP::compute2(...) is logically equivalent to using LBSP::compute(...) followed by LBSP::reshapeDesc(...). - - For more details on the different parameters, see G.-A. Bilodeau et al, "Change Detection in Feature Space Using Local - Binary Similarity Patterns", in CRV 2013. - - This algorithm is currently NOT thread-safe. - */ -class LBSP : public cv::DescriptorExtractor { -public: - //! constructor 1, threshold = absolute intensity 'similarity' threshold used when computing comparisons - LBSP(size_t nThreshold); - //! constructor 2, threshold = relative intensity 'similarity' threshold used when computing comparisons - LBSP(float fRelThreshold, size_t nThresholdOffset=0); - //! default destructor - virtual ~LBSP(); - //! loads extractor params from the specified file node @@@@ not impl - virtual void read(const cv::FileNode&); - //! writes extractor params to the specified file storage @@@@ not impl - virtual void write(cv::FileStorage&) const; - //! sets the 'reference' image to be used for inter-frame comparisons (note: if no image is set or if the image is empty, the algorithm will default back to intra-frame comparisons) - virtual void setReference(const cv::Mat&); - //! returns the current descriptor size, in bytes - virtual int descriptorSize() const; - //! returns the current descriptor data type - virtual int descriptorType() const; - //! returns whether this extractor is using a relative threshold or not - virtual bool isUsingRelThreshold() const; - //! returns the current relative threshold used for comparisons (-1 = invalid/not used) - virtual float getRelThreshold() const; - //! returns the current absolute threshold used for comparisons (-1 = invalid/not used) - virtual size_t getAbsThreshold() const; - - //! similar to DescriptorExtractor::compute(const cv::Mat& image, ...), but in this case, the descriptors matrix has the same shape as the input matrix (possibly slower, but the result can be displayed) - void compute2(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - //! batch version of LBSP::compute2(const cv::Mat& image, ...), also similar to DescriptorExtractor::compute(const std::vector<cv::Mat>& imageCollection, ...) - void compute2(const std::vector<cv::Mat>& voImageCollection, std::vector<std::vector<cv::KeyPoint> >& vvoPointCollection, std::vector<cv::Mat>& voDescCollection) const; - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel version) - inline static void computeGrayscaleDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type()==CV_8UC1); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x>=(int)LBSP::PATCH_SIZE/2 && _y>=(int)LBSP::PATCH_SIZE/2); - CV_DbgAssert(_x<oInputImg.cols-(int)LBSP::PATCH_SIZE/2 && _y<oInputImg.rows-(int)LBSP::PATCH_SIZE/2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; - #include "LBSP_16bits_dbcross_1ch.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t* const _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x>=(int)LBSP::PATCH_SIZE/2 && _y>=(int)LBSP::PATCH_SIZE/2); - CV_DbgAssert(_x<oInputImg.cols-(int)LBSP::PATCH_SIZE/2 && _y<oInputImg.rows-(int)LBSP::PATCH_SIZE/2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; - #include "LBSP_16bits_dbcross_3ch3t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (3-channels version) - inline static void computeRGBDescriptor(const cv::Mat& oInputImg, const uchar* const _ref, const int _x, const int _y, const size_t _t, ushort* _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type()==CV_8UC3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x>=(int)LBSP::PATCH_SIZE/2 && _y>=(int)LBSP::PATCH_SIZE/2); - CV_DbgAssert(_x<oInputImg.cols-(int)LBSP::PATCH_SIZE/2 && _y<oInputImg.rows-(int)LBSP::PATCH_SIZE/2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; - #include "LBSP_16bits_dbcross_3ch1t.i" - } - - //! utility function, shortcut/lightweight/direct single-point LBSP computation function for extra flexibility (1-channel-RGB version) - inline static void computeSingleRGBDescriptor(const cv::Mat& oInputImg, const uchar _ref, const int _x, const int _y, const size_t _c, const size_t _t, ushort& _res) { - CV_DbgAssert(!oInputImg.empty()); - CV_DbgAssert(oInputImg.type()==CV_8UC3 && _c<3); - CV_DbgAssert(LBSP::DESC_SIZE==2); // @@@ also relies on a constant desc size - CV_DbgAssert(_x>=(int)LBSP::PATCH_SIZE/2 && _y>=(int)LBSP::PATCH_SIZE/2); - CV_DbgAssert(_x<oInputImg.cols-(int)LBSP::PATCH_SIZE/2 && _y<oInputImg.rows-(int)LBSP::PATCH_SIZE/2); - const size_t _step_row = oInputImg.step.p[0]; - const uchar* const _data = oInputImg.data; - #include "LBSP_16bits_dbcross_s3ch.i" - } - - //! utility function, used to reshape a descriptors matrix to its input image size via their keypoint locations - static void reshapeDesc(cv::Size oSize, const std::vector<cv::KeyPoint>& voKeypoints, const cv::Mat& oDescriptors, cv::Mat& oOutput); - //! utility function, used to illustrate the difference between two descriptor images - static void calcDescImgDiff(const cv::Mat& oDesc1, const cv::Mat& oDesc2, cv::Mat& oOutput, bool bForceMergeChannels=false); - //! utility function, used to filter out bad keypoints that would trigger out of bounds error because they're too close to the image border - static void validateKeyPoints(std::vector<cv::KeyPoint>& voKeypoints, cv::Size oImgSize); - //! utility function, used to filter out bad pixels in a ROI that would trigger out of bounds error because they're too close to the image border - static void validateROI(cv::Mat& oROI); - //! utility, specifies the pixel size of the pattern used (width and height) - static const size_t PATCH_SIZE = 5; - //! utility, specifies the number of bytes per descriptor (should be the same as calling 'descriptorSize()') - static const size_t DESC_SIZE = 2; - -protected: - //! classic 'compute' implementation, based on the regular DescriptorExtractor::computeImpl arguments & expected output - virtual void computeImpl(const cv::Mat& oImage, std::vector<cv::KeyPoint>& voKeypoints, cv::Mat& oDescriptors) const; - - const bool m_bOnlyUsingAbsThreshold; - const float m_fRelThreshold; - const size_t m_nThreshold; - cv::Mat m_oRefImage; -}; diff --git a/package_bgs/pl/LOBSTER.cpp b/package_bgs/pl/LOBSTER.cpp deleted file mode 100644 index f4e9bf6..0000000 --- a/package_bgs/pl/LOBSTER.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "LOBSTER.h" -#include "BackgroundSubtractorLOBSTER.h" - - -LOBSTERBGS::LOBSTERBGS() : -pLOBSTER(0), firstTime(true), showOutput(true), -fRelLBSPThreshold (BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), -nLBSPThresholdOffset (BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD), -nDescDistThreshold (BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD), -nColorDistThreshold (BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD), -nBGSamples (BGSLOBSTER_DEFAULT_NB_BG_SAMPLES), -nRequiredBGSamples (BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES) -{ -} - -LOBSTERBGS::~LOBSTERBGS() { - if (pLOBSTER) - delete pLOBSTER; -} - -void LOBSTERBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - loadConfig(); - - if (firstTime) { - saveConfig(); - pLOBSTER = new BackgroundSubtractorLOBSTER( - fRelLBSPThreshold, nLBSPThresholdOffset, nDescDistThreshold, - nColorDistThreshold, nBGSamples, nRequiredBGSamples); - - pLOBSTER->initialize(img_input, cv::Mat (img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); - firstTime = false; - } - - (*pLOBSTER)(img_input, img_output); - pLOBSTER->getBackgroundImage(img_bgmodel); - - if(showOutput) { - imshow("LOBSTER FG", img_output); - imshow("LOBSTER BG", img_bgmodel); - } -} - -void LOBSTERBGS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/LOBSTERBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); - cvWriteInt(fs, "nLBSPThresholdOffset", nLBSPThresholdOffset); - cvWriteInt(fs, "nDescDistThreshold", nDescDistThreshold); - cvWriteInt(fs, "nColorDistThreshold", nColorDistThreshold); - cvWriteInt(fs, "nBGSamples", nBGSamples); - cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void LOBSTERBGS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/LOBSTERBGS.xml", 0, CV_STORAGE_READ); - - fRelLBSPThreshold = cvReadRealByName(fs, 0, "fRelLBSPThreshold", BGSLOBSTER_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); - nLBSPThresholdOffset = cvReadIntByName(fs, 0, "nLBSPThresholdOffset", BGSLOBSTER_DEFAULT_LBSP_OFFSET_SIMILARITY_THRESHOLD); - nDescDistThreshold = cvReadIntByName(fs, 0, "nDescDistThreshold", BGSLOBSTER_DEFAULT_DESC_DIST_THRESHOLD); - nColorDistThreshold = cvReadIntByName(fs, 0, "nColorDistThreshold", BGSLOBSTER_DEFAULT_COLOR_DIST_THRESHOLD); - nBGSamples = cvReadIntByName(fs, 0, "nBGSamples", BGSLOBSTER_DEFAULT_NB_BG_SAMPLES); - nRequiredBGSamples = cvReadIntByName(fs, 0, "nRequiredBGSamples", BGSLOBSTER_DEFAULT_REQUIRED_NB_BG_SAMPLES); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/pl/LOBSTER.h b/package_bgs/pl/LOBSTER.h deleted file mode 100644 index f5954ca..0000000 --- a/package_bgs/pl/LOBSTER.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -class BackgroundSubtractorLOBSTER; - -class LOBSTERBGS : public IBGS -{ -private: - BackgroundSubtractorLOBSTER* pLOBSTER; - bool firstTime; - bool showOutput; - - float fRelLBSPThreshold; - size_t nLBSPThresholdOffset; - size_t nDescDistThreshold; - size_t nColorDistThreshold; - size_t nBGSamples; - size_t nRequiredBGSamples; - -public: - LOBSTERBGS(); - ~LOBSTERBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/pl/RandUtils.h b/package_bgs/pl/RandUtils.h deleted file mode 100644 index 24ca5f6..0000000 --- a/package_bgs/pl/RandUtils.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -/*// gaussian 3x3 pattern, based on 'floor(fspecial('gaussian', 3, 1)*256)' -static const int s_nSamplesInitPatternWidth = 3; -static const int s_nSamplesInitPatternHeight = 3; -static const int s_nSamplesInitPatternTot = 256; -static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { - {19, 32, 19,}, - {32, 52, 32,}, - {19, 32, 19,}, -};*/ - -// gaussian 7x7 pattern, based on 'floor(fspecial('gaussian',7,2)*512)' -static const int s_nSamplesInitPatternWidth = 7; -static const int s_nSamplesInitPatternHeight = 7; -static const int s_nSamplesInitPatternTot = 512; -static const int s_anSamplesInitPattern[s_nSamplesInitPatternHeight][s_nSamplesInitPatternWidth] = { - {2, 4, 6, 7, 6, 4, 2,}, - {4, 8, 12, 14, 12, 8, 4,}, - {6, 12, 21, 25, 21, 12, 6,}, - {7, 14, 25, 28, 25, 14, 7,}, - {6, 12, 21, 25, 21, 12, 6,}, - {4, 8, 12, 14, 12, 8, 4,}, - {2, 4, 6, 7, 6, 4, 2,}, -}; - -//! returns a random init/sampling position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandSamplePosition(int& x_sample, int& y_sample, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = 1+rand()%s_nSamplesInitPatternTot; - for(x_sample=0; x_sample<s_nSamplesInitPatternWidth; ++x_sample) { - for(y_sample=0; y_sample<s_nSamplesInitPatternHeight; ++y_sample) { - r -= s_anSamplesInitPattern[y_sample][x_sample]; - if(r<=0) - goto stop; - } - } - stop: - x_sample += x_orig-s_nSamplesInitPatternWidth/2; - y_sample += y_orig-s_nSamplesInitPatternHeight/2; - if(x_sample<border) - x_sample = border; - else if(x_sample>=imgsize.width-border) - x_sample = imgsize.width-border-1; - if(y_sample<border) - y_sample = border; - else if(y_sample>=imgsize.height-border) - y_sample = imgsize.height-border-1; -} - -// simple 8-connected (3x3) neighbors pattern -static const int s_anNeighborPatternSize_3x3 = 8; -static const int s_anNeighborPattern_3x3[8][2] = { - {-1, 1}, { 0, 1}, { 1, 1}, - {-1, 0}, { 1, 0}, - {-1,-1}, { 0,-1}, { 1,-1}, -}; - -//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandNeighborPosition_3x3(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = rand()%s_anNeighborPatternSize_3x3; - x_neighbor = x_orig+s_anNeighborPattern_3x3[r][0]; - y_neighbor = y_orig+s_anNeighborPattern_3x3[r][1]; - if(x_neighbor<border) - x_neighbor = border; - else if(x_neighbor>=imgsize.width-border) - x_neighbor = imgsize.width-border-1; - if(y_neighbor<border) - y_neighbor = border; - else if(y_neighbor>=imgsize.height-border) - y_neighbor = imgsize.height-border-1; -} - -// 5x5 neighbors pattern -static const int s_anNeighborPatternSize_5x5 = 24; -static const int s_anNeighborPattern_5x5[24][2] = { - {-2, 2}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 2}, - {-2, 1}, {-1, 1}, { 0, 1}, { 1, 1}, { 2, 1}, - {-2, 0}, {-1, 0}, { 1, 0}, { 2, 0}, - {-2,-1}, {-1,-1}, { 0,-1}, { 1,-1}, { 2,-1}, - {-2,-2}, {-1,-2}, { 0,-2}, { 1,-2}, { 2,-2}, -}; - -//! returns a random neighbor position for the specified pixel position; also guards against out-of-bounds values via image/border size check. -static inline void getRandNeighborPosition_5x5(int& x_neighbor, int& y_neighbor, const int x_orig, const int y_orig, const int border, const cv::Size& imgsize) { - int r = rand()%s_anNeighborPatternSize_5x5; - x_neighbor = x_orig+s_anNeighborPattern_5x5[r][0]; - y_neighbor = y_orig+s_anNeighborPattern_5x5[r][1]; - if(x_neighbor<border) - x_neighbor = border; - else if(x_neighbor>=imgsize.width-border) - x_neighbor = imgsize.width-border-1; - if(y_neighbor<border) - y_neighbor = border; - else if(y_neighbor>=imgsize.height-border) - y_neighbor = imgsize.height-border-1; -} diff --git a/package_bgs/pl/SuBSENSE.cpp b/package_bgs/pl/SuBSENSE.cpp deleted file mode 100644 index a4aab0c..0000000 --- a/package_bgs/pl/SuBSENSE.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "SuBSENSE.h" -#include "BackgroundSubtractorSuBSENSE.h" - - -SuBSENSEBGS::SuBSENSEBGS() : -pSubsense(0), firstTime(true), showOutput(true), -fRelLBSPThreshold (BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD), -nDescDistThresholdOffset (BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET), -nMinColorDistThreshold (BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD), -nBGSamples (BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES), -nRequiredBGSamples (BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES), -nSamplesForMovingAvgs (BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS) -{ -} - -SuBSENSEBGS::~SuBSENSEBGS() { - if (pSubsense) - delete pSubsense; -} - -void SuBSENSEBGS::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) -{ - if(img_input.empty()) - return; - - loadConfig(); - - if (firstTime) { - saveConfig(); - pSubsense = new BackgroundSubtractorSuBSENSE( - fRelLBSPThreshold, nDescDistThresholdOffset, nMinColorDistThreshold, - nBGSamples, nRequiredBGSamples, nSamplesForMovingAvgs); - - pSubsense->initialize(img_input, cv::Mat (img_input.size(), CV_8UC1, cv::Scalar_<uchar>(255))); - firstTime = false; - } - - (*pSubsense)(img_input, img_output); - pSubsense->getBackgroundImage(img_bgmodel); - - if(showOutput) { - imshow("SuBSENSE FG", img_output); - imshow("SuBSENSE BG", img_bgmodel); - } -} - -void SuBSENSEBGS::saveConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/SuBSENSEBGS.xml", 0, CV_STORAGE_WRITE); - - cvWriteReal(fs, "fRelLBSPThreshold", fRelLBSPThreshold); - cvWriteInt(fs, "nDescDistThresholdOffset", nDescDistThresholdOffset); - cvWriteInt(fs, "nMinColorDistThreshold", nMinColorDistThreshold); - cvWriteInt(fs, "nBGSamples", nBGSamples); - cvWriteInt(fs, "nRequiredBGSamples", nRequiredBGSamples); - cvWriteInt(fs, "nSamplesForMovingAvgs", nSamplesForMovingAvgs); - cvWriteInt(fs, "showOutput", showOutput); - - cvReleaseFileStorage(&fs); -} - -void SuBSENSEBGS::loadConfig() -{ - CvFileStorage* fs = cvOpenFileStorage("./config/SuBSENSEBGS.xml", 0, CV_STORAGE_READ); - - fRelLBSPThreshold = cvReadRealByName(fs, 0, "fRelLBSPThreshold", BGSSUBSENSE_DEFAULT_LBSP_REL_SIMILARITY_THRESHOLD); - nDescDistThresholdOffset = cvReadIntByName(fs, 0, "nDescDistThresholdOffset", BGSSUBSENSE_DEFAULT_DESC_DIST_THRESHOLD_OFFSET); - nMinColorDistThreshold = cvReadIntByName(fs, 0, "nMinColorDistThreshold", BGSSUBSENSE_DEFAULT_MIN_COLOR_DIST_THRESHOLD); - nBGSamples = cvReadIntByName(fs, 0, "nBGSamples", BGSSUBSENSE_DEFAULT_NB_BG_SAMPLES); - nRequiredBGSamples = cvReadIntByName(fs, 0, "nRequiredBGSamples", BGSSUBSENSE_DEFAULT_REQUIRED_NB_BG_SAMPLES); - nSamplesForMovingAvgs = cvReadIntByName(fs, 0, "nSamplesForMovingAvgs", BGSSUBSENSE_DEFAULT_N_SAMPLES_FOR_MV_AVGS); - showOutput = cvReadIntByName(fs, 0, "showOutput", true); - - cvReleaseFileStorage(&fs); -} diff --git a/package_bgs/pl/SuBSENSE.h b/package_bgs/pl/SuBSENSE.h deleted file mode 100644 index b527c27..0000000 --- a/package_bgs/pl/SuBSENSE.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include <opencv2/opencv.hpp> - -#include "../IBGS.h" - -class BackgroundSubtractorSuBSENSE; - -class SuBSENSEBGS: public IBGS { -private: - BackgroundSubtractorSuBSENSE* pSubsense; - bool firstTime; - bool showOutput; - - float fRelLBSPThreshold; - size_t nDescDistThresholdOffset; - size_t nMinColorDistThreshold; - size_t nBGSamples; - size_t nRequiredBGSamples; - size_t nSamplesForMovingAvgs; - -public: - SuBSENSEBGS(); - ~SuBSENSEBGS(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, - cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/sjn/SJN_MultiCueBGS.h b/package_bgs/sjn/SJN_MultiCueBGS.h deleted file mode 100644 index 0891c08..0000000 --- a/package_bgs/sjn/SJN_MultiCueBGS.h +++ /dev/null @@ -1,248 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#define MIN3(x,y,z) ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z))) -#define MAX3(x,y,z) ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z))) - -#ifndef PI - #define PI 3.14159 -#endif - -typedef int BOOL; - -#ifndef FALSE - #define FALSE 0 -#endif - -#ifndef TRUE - #define TRUE 1 -#endif - -#if !defined(__APPLE__) -#include <malloc.h> -#endif -#include "math.h" - -#include <vector> -using std::vector; - -#include <algorithm> -using std::sort; - -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -//------------------------------------Structure Lists-------------------------------------// -struct point{ - short m_nX; - short m_nY; -}; - -struct neighbor_pos{ - short m_nX; - short m_nY; -}; -//1) Bounding Box Structure -struct BoundingBoxInfo{ - int m_iBoundBoxNum; //# of bounding boxes for all foreground and false-positive blobs - int m_iArraySize; //the size of the below arrays to store bounding box information - - short *m_aLeft, *m_aRight, *m_aUpper, *m_aBottom; //arrays to store bounding box information for (the original frame size) - short *m_aRLeft, *m_aRRight, *m_aRUpper, *m_aRBottom; //arrays to store bounding box information for (the reduced frame size) - BOOL* m_ValidBox; //If this value is true, the corresponding bounding box is for a foreground blob. - //Else, it is for a false-positive blob -}; - -//2) Texture Model Structure -struct TextureCodeword{ - int m_iMNRL; //the maximum negative run-length - int m_iT_first_time; //the first access time - int m_iT_last_time; //the last access time - - //��� MTLBP�� - float m_fLowThre; //a low threshold for the matching - float m_fHighThre; //a high threshold for the matching - float m_fMean; //mean of the codeword -}; - -struct TextureModel{ - TextureCodeword** m_Codewords; //the texture-codeword Array - - int m_iTotal; //# of learned samples after the last clear process - int m_iElementArraySize; //the array size of m_Codewords - int m_iNumEntries; //# of codewords - - BOOL m_bID; //id=1 --> background model, id=0 --> cachebook -}; - -//3) Color Model Structure -struct ColorCodeword{ - int m_iMNRL; //the maximum negative run-length - int m_iT_first_time; //the first access time - int m_iT_last_time; //the last access time - - double m_dMean[3]; //mean vector of the codeword - -}; - -struct ColorModel{ - ColorCodeword** m_Codewords; //the color-codeword Array - - int m_iTotal; //# of learned samples after the last clear process - int m_iElementArraySize; //the array size of m_Codewords - int m_iNumEntries; //# of codewords - - BOOL m_bID; //id=1 --> background model, id=0 --> cachebookk -}; - - -class SJN_MultiCueBGS : public IBGS -{ -private: - bool firstTime; - bool showOutput; - void saveConfig(); - void loadConfig(); - -public: - SJN_MultiCueBGS(); - ~SJN_MultiCueBGS(void); - -public: - //---------------------------------------------------- - // APIs and User-Adjustable Parameters - //---------------------------------------------------- - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); //the main function to background modeling and subtraction - - void GetForegroundMap(IplImage* return_image, IplImage* input_frame=NULL); //the function returning a foreground binary-map - void Destroy(); //the function to release allocated memories - - int g_iTrainingPeriod; //the training period (The parameter t in the paper) - int g_iT_ModelThreshold; //the threshold for texture-model based BGS. (The parameter tau_T in the paper) - int g_iC_ModelThreshold; //the threshold for appearance based verification. (The parameter tau_A in the paper) - - float g_fLearningRate; //the learning rate for background models. (The parameter alpha in the paper) - - short g_nTextureTrainVolRange; //the codebook size factor for texture models. (The parameter k in the paper) - short g_nColorTrainVolRange; //the codebook size factor for color models. (The parameter eta_1 in the paper) - -public: - //---------------------------------------------------- - // Implemented Function Lists - //---------------------------------------------------- - - //--1) General Functions - void Initialize(IplImage* frame); - - void PreProcessing(IplImage* frame); - void ReduceImageSize(IplImage* SrcImage, IplImage* DstImage); - void GaussianFiltering(IplImage* frame, uchar*** aFilteredFrame); - void BGR2HSVxyz_Par(uchar*** aBGR, uchar*** aXYZ); - - void BackgroundModeling_Par(IplImage* frame); - void ForegroundExtraction(IplImage* frame); - void CreateLandmarkArray_Par(float fConfThre, short nTrainVolRange, float**aConfMap, int iNehborNum, uchar*** aXYZ, - point*** aNeiDir, TextureModel**** TModel, ColorModel*** CModel, uchar**aLandmarkArr); - - void PostProcessing(IplImage* frame); - void MorphologicalOpearions(uchar** aInput, uchar** aOutput, double dThresholdRatio, int iMaskSize, int iWidth, int iHeight); - void Labeling(uchar** aBinaryArray, int* pLabelCount, int** aLabelTable); - void SetBoundingBox(int iLabelCount, int** aLabelTable); - void BoundBoxVerification(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); - void EvaluateBoxSize( BoundingBoxInfo* BoundBoxInfo); - void EvaluateOverlapRegionSize(BoundingBoxInfo* SrcBoxInfo); - void EvaluateGhostRegion(IplImage* frame, uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); - double CalculateHausdorffDist(IplImage* input_image, IplImage* model_image); - void RemovingInvalidForeRegions(uchar** aResForeMap, BoundingBoxInfo* BoundBoxInfo); - - void UpdateModel_Par(); - void GetEnlargedMap(float** aOriginMap, float** aEnlargedMap); - - //--2) Texture Model Related Functions - void T_AllocateTextureModelRelatedMemory(); - void T_ReleaseTextureModelRelatedMemory(); - void T_SetNeighborDirection(point*** aNeighborPos); - void T_ModelConstruction(short nTrainVolRange,float fLearningRate, uchar*** aXYZ,point center, point* aNei, TextureModel** aModel); - void T_ClearNonEssentialEntries(short nClearNum, TextureModel** aModel); - void T_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short* nReferredIdxArr, short nClearNum, TextureModel** pCachebook); - void T_GetConfidenceMap_Par(uchar*** aXYZ, float** aTextureMap, point*** aNeiDirArr, TextureModel**** aModel); - void T_Absorption(int iAbsorbCnt, point pos, short*** aContinuCnt, short*** aRefferedIndex, TextureModel** pModel, TextureModel** pCache); - - //--3) Color Model Related Functions - void C_AllocateColorModelRelatedMemory(); - void C_ReleaseColorModelRelatedMemory(); - void C_CodebookConstruction(uchar* aP,int iPosX, int iPosY, short nTrainVolRange, float fLearningRate, ColorModel* pC); - void C_ClearNonEssentialEntries(short nClearNum, ColorModel* pModel); - void C_ClearNonEssentialEntriesForCachebook(uchar bLandmark, short nReferredIdx, short nClearNum, ColorModel* pCachebook); - void C_Absorption(int iAbsorbCnt, point pos , short** aContinuCnt, short** aRefferedIndex, ColorModel* pModel, ColorModel* pCache); -public: - //---------------------------------------------------- - // Implemented Variable Lists - //---------------------------------------------------- - - //--1) General Variables - int g_iFrameCount; //the counter of processed frames - - int g_iBackClearPeriod; //the period to clear background models - int g_iCacheClearPeriod; //the period to clear cache-book models - - int g_iAbsortionPeriod; //the period to absorb static ghost regions - BOOL g_bAbsorptionEnable; //If True, procedures for ghost region absorption are activated. - - BOOL g_bModelMemAllocated; //To handle memory.. - BOOL g_bNonModelMemAllocated; //To handle memory.. - - float g_fConfidenceThre; //the final decision threshold - - int g_iWidth, g_iHeight; //width and height of input frames - int g_iRWidth, g_iRHeight; //width and height of reduced frames (For efficiency, the reduced size of frames are processed) - int g_iForegroundNum; //# of detected foreground regions - BOOL g_bForegroundMapEnable; //TRUE only when BGS is successful - - IplImage* g_ResizedFrame; //reduced size of frame (For efficiency, the reduced size of frames are processed) - uchar*** g_aGaussFilteredFrame; - uchar*** g_aXYZFrame; - uchar** g_aLandmarkArray; //the landmark map - uchar** g_aResizedForeMap; //the resized foreground map - uchar** g_aForegroundMap; //the final foreground map - BOOL** g_aUpdateMap; //the location map of update candidate pixels - - BoundingBoxInfo* g_BoundBoxInfo; //the array of bounding boxes of each foreground blob - - //--2) Texture Model Related - TextureModel**** g_TextureModel; //the texture background model - TextureModel**** g_TCacheBook; //the texture cache-book - short*** g_aTReferredIndex; //To handle cache-book - short*** g_aTContinuousCnt; //To handle cache-book - point*** g_aNeighborDirection; - float**g_aTextureConfMap; //the texture confidence map - - short g_nNeighborNum; //# of neighborhoods - short g_nRadius; - short g_nBoundarySize; - - //--3) Texture Model Related - ColorModel*** g_ColorModel; //the color background model - ColorModel*** g_CCacheBook; //the color cache-book - short** g_aCReferredIndex; //To handle cache-book - short** g_aCContinuousCnt; //To handle cache-book -}; - - diff --git a/package_bgs/tb/FuzzyChoquetIntegral.h b/package_bgs/tb/FuzzyChoquetIntegral.h deleted file mode 100644 index 76ba158..0000000 --- a/package_bgs/tb/FuzzyChoquetIntegral.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -#include "FuzzyUtils.h" - -class FuzzyChoquetIntegral : public IBGS -{ -private: - bool firstTime; - long frameNumber; - bool showOutput; - - int framesToLearn; - double alphaLearn; - double alphaUpdate; - int colorSpace; - int option; - bool smooth; - double threshold; - - FuzzyUtils fu; - cv::Mat img_background_f3; - -public: - FuzzyChoquetIntegral(); - ~FuzzyChoquetIntegral(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - diff --git a/package_bgs/tb/FuzzySugenoIntegral.h b/package_bgs/tb/FuzzySugenoIntegral.h deleted file mode 100644 index cfa91b7..0000000 --- a/package_bgs/tb/FuzzySugenoIntegral.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" - -#include "FuzzyUtils.h" - -class FuzzySugenoIntegral : public IBGS -{ -private: - bool firstTime; - long long frameNumber; - bool showOutput; - - int framesToLearn; - double alphaLearn; - double alphaUpdate; - int colorSpace; - int option; - bool smooth; - double threshold; - - FuzzyUtils fu; - cv::Mat img_background_f3; - -public: - FuzzySugenoIntegral(); - ~FuzzySugenoIntegral(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; - diff --git a/package_bgs/tb/FuzzyUtils.cpp b/package_bgs/tb/FuzzyUtils.cpp deleted file mode 100644 index fcb1972..0000000 --- a/package_bgs/tb/FuzzyUtils.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "FuzzyUtils.h" - -FuzzyUtils::FuzzyUtils(void){} - -FuzzyUtils::~FuzzyUtils(void){} - -void FuzzyUtils::LBP(IplImage* InputImage, IplImage* LBPimage) -{ - PixelUtils p; - - float* neighberPixel = (float*) malloc(9*sizeof(float)); - float* BinaryValue = (float*) malloc(9*sizeof(float)); - float* CarreExp = (float*) malloc(9*sizeof(float)); - float* valLBP = (float*) malloc(1*sizeof(float)); - - *valLBP = 0; - - int x = 0, y = 0; - - // on implemente les 8 valeurs puissance de 2 qui correspondent aux 8 elem. d'image voisins au elem. d'image central - *(CarreExp+0)=1.0; - *(CarreExp+1)=2.0; - *(CarreExp+2)=4.0; - *(CarreExp+3)=8.0; - *(CarreExp+4)=0.0; - *(CarreExp+5)=16.0; - *(CarreExp+6)=32.0; - *(CarreExp+7)=64.0; - *(CarreExp+8)=128.0; - - //le calcule de LBP - //pour les 4 coins - /* 1.*/ - if(x==0 && y==0) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,4,0); - *valLBP=*valLBP+((*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - - /* 2.*/ - if(x==0 && y==InputImage->width) - { - *valLBP=0; - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,4,1); - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - - /* 3.*/ - if(x==InputImage->height && y==0) - { - *valLBP=0; - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,4,2); - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+3))*(*(CarreExp+3)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - - /* 4.*/ - if(x==InputImage->height && y==InputImage->width) - { - *valLBP=0; - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,4,3); - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - - //le calcul de LBP pour la premi�re ligne : L(0) - if(x==0 && (y!=0 && y!=InputImage->width)) - { - for(int y = 1; y < InputImage->width-1; y++) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,6,4); - *valLBP=0; - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - } - - //le calcul de LBP pour la derni�re colonne : C(w) - if((x!=0 && x!=InputImage->height) && y==InputImage->width) - { - for(int x = 1; x < InputImage->height-1; x++) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,6,4); - *valLBP=0; - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+1))*(*(CarreExp+1))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - } - - //le calcul de LBP pour la derni�re ligne : L(h) - if(x==InputImage->height && (y!=0 && y!=InputImage->width)) - { - for(int y = 1; y < InputImage->width-1; y++) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,6,1); - *valLBP=0; - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp))+(*(BinaryValue+2))*(*(CarreExp+2))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+4))*(*(CarreExp+4))+(*(BinaryValue+5))*(*(CarreExp+5)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - } - - //le calcul de LBP pour la premi�re colonne : C(0) - if((x!=0 && x!=InputImage->height) && y==0) - { - for(int x = 1; x <InputImage->height-1; x++) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,6,2); - *valLBP=0; - *valLBP=*valLBP+((*(BinaryValue))*(*(CarreExp+5))+(*(BinaryValue+1))*(*(CarreExp+6))+(*(BinaryValue+3))*(*(CarreExp+3))+(*(BinaryValue+4))*(*(CarreExp))+(*(BinaryValue+5))*(*(CarreExp+1)))/255.0; - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - } - - //pour le reste des elements d'image - for(int y = 1; y < InputImage->height-1; y++) - { - for(int x = 1; x < InputImage->width-1; x++) - { - p.getNeighberhoodGrayPixel(InputImage, x,y,neighberPixel); - getBinValue(neighberPixel,BinaryValue,9,4); - //le calcul de la valeur du LBP pour chaque elem. d'im. - *valLBP=0; - for(int l = 0; l < 9; l++) - *valLBP = *valLBP + ((*(BinaryValue+l)) * (*(CarreExp+l))) / 255.0; - //printf("\nvalLBP(%d,%d)=%f",x,y,*valLBP); - p.PutGrayPixel(LBPimage,x,y,*valLBP); - } - } - - free(neighberPixel); - free(BinaryValue); - free(CarreExp); - free(valLBP); -} - -void FuzzyUtils::getBinValue(float* neighberGrayPixel, float* BinaryValue, int m, int n) -{ - // la comparaison entre la valeur d'elem d'image central et les valeurs des elem. d'im. voisins - // m = le numero des elements (4, 6 ou 9); - // n = la position de l'element central; - - int h = 0; - for(int k = 0; k < m; k++) - { - if(*(neighberGrayPixel+k) >= *(neighberGrayPixel+n)) - { - *(BinaryValue+h)=1; - h++; - } - else - { - *(BinaryValue+h)=0; - h++; - } - } -} - -void FuzzyUtils::SimilarityDegreesImage(IplImage* CurrentImage, IplImage* BGImage, IplImage* DeltaImage, int n, int color_space) -{ - PixelUtils p; - int i, j; - - if(n == 1) - { - float* CurrentGrayPixel = (float*) malloc (1*(sizeof(float))); - float* BGGrayPixel = (float*) malloc (1*(sizeof(float))); - float* DeltaGrayPixel = (float*) malloc (1*(sizeof(float))); - - for(i = 0; i < CurrentImage->width; i++) - { - for(j = 0; j < CurrentImage->height; j++) - { - p.GetGrayPixel(CurrentImage,i,j,CurrentGrayPixel); - p.GetGrayPixel(BGImage,i,j,BGGrayPixel); - RatioPixels(CurrentGrayPixel,BGGrayPixel,DeltaGrayPixel,1); - p.PutGrayPixel(DeltaImage,i,j,*DeltaGrayPixel); - } - } - - free(CurrentGrayPixel); - free(BGGrayPixel); - free(DeltaGrayPixel); - } - - if(n != 1) - { - IplImage* ConvertedCurrentImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3); - IplImage* ConvertedBGImage = cvCreateImage(cvSize(CurrentImage->width, CurrentImage->height), IPL_DEPTH_32F, 3); - - float* ConvertedCurrentPixel = (float*) malloc(3*(sizeof(float))); - float* ConvertedBGPixel = (float*) malloc(3*(sizeof(float))); - float* DeltaConvertedPixel = (float*) malloc(3*(sizeof(float))); - - p.ColorConversion(CurrentImage,ConvertedCurrentImage,color_space); - p.ColorConversion(BGImage,ConvertedBGImage,color_space); - - for(i = 0; i < CurrentImage->width; i++) - { - for(j = 0; j < CurrentImage->height; j++) - { - p.GetPixel(ConvertedCurrentImage,i,j,ConvertedCurrentPixel); - p.GetPixel(ConvertedBGImage,i,j,ConvertedBGPixel); - RatioPixels(ConvertedCurrentPixel,ConvertedBGPixel,DeltaConvertedPixel,3); - p.PutPixel(DeltaImage,i,j,DeltaConvertedPixel); - } - } - - free(ConvertedCurrentPixel); - free(ConvertedBGPixel); - free(DeltaConvertedPixel); - - cvReleaseImage(&ConvertedCurrentImage); - cvReleaseImage(&ConvertedBGImage); - } -} - -void FuzzyUtils::RatioPixels(float* CurrentPixel, float* BGPixel, float* DeltaPixel, int n) -{ - if(n == 1) - { - if(*CurrentPixel < *BGPixel) - *DeltaPixel = *CurrentPixel / *BGPixel; - - if(*CurrentPixel > *BGPixel) - *DeltaPixel = *BGPixel / *CurrentPixel; - - if(*CurrentPixel == *BGPixel) - *DeltaPixel = 1.0; - } - - if(n == 3) - for(int i = 0; i < 3; i++) - { - if(*(CurrentPixel+i) < *(BGPixel+i)) - *(DeltaPixel+i) = *(CurrentPixel+i) / *(BGPixel+i); - - if(*(CurrentPixel+i) > *(BGPixel+i)) - *(DeltaPixel+i) = *(BGPixel+i) / *(CurrentPixel+i); - - if(*(CurrentPixel+i) == *(BGPixel+i)) - *(DeltaPixel+i) = 1.0; - } -} - -void FuzzyUtils::getFuzzyIntegralSugeno(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage) -{ - // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1 - // n : =2 cad aggreger les 2 images "H" et "Delta" - // =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta" - - PixelUtils p; - - float* HTexturePixel = (float*) malloc(1*sizeof(float)); - float* DeltaOhtaPixel = (float*) malloc(3*(sizeof(float))); - int *Indice = (int*) malloc(3*(sizeof(int))); - float *HI = (float*) malloc(3*(sizeof(float))); - float *Integral = (float*) malloc(3*(sizeof(float))); - float* X = (float*) malloc(1*sizeof(float)); - float* XiXj = (float*) malloc(1*sizeof(float)); - float IntegralFlou; - - *Indice = 0; - *(Indice+1) = 1; - *(Indice+2) = 2; - *X = 1.0; - - for(int i = 0; i < H->width; i++) - { - for(int j = 0; j < H->height; j++) - { - p.GetGrayPixel(H,i,j,HTexturePixel); - p.GetPixel(Delta,i,j,DeltaOhtaPixel); - - *(HI+0) = *(HTexturePixel+0); - *(HI+1) = *(DeltaOhtaPixel+0); - *(HI+2) = *(DeltaOhtaPixel+1); - - Trier(HI,3,Indice); - - *XiXj = *(MeasureG + (*(Indice+1))) + (*(MeasureG + (*(Indice+2)))); - - *(Integral+0) = min((HI + (*(Indice+0))), X); - *(Integral+1) = min((HI + (*(Indice+1))), XiXj); - *(Integral+2) = min((HI + (*(Indice+2))), ((MeasureG+(*(Indice+2))))); - - IntegralFlou = max(Integral,3); - p.PutGrayPixel(OutputImage,i,j,IntegralFlou); - } - } - - free(HTexturePixel); - free(DeltaOhtaPixel); - free(Indice); - free(HI); - free(X); - free(XiXj); - free(Integral); -} - -void FuzzyUtils::getFuzzyIntegralChoquet(IplImage* H, IplImage* Delta, int n, float *MeasureG, IplImage* OutputImage) -{ - // MeasureG : est un vecteur contenant 3 mesure g (g1,g2,g3) tel que : g1+g2+g3=1 - // n : =2 cad aggreger les 2 images "H" et "Delta" - // =1 cad aggreger uniquement les valeurs des composantes couleurs de l'image "Delta" - - PixelUtils p; - - float* HTexturePixel = (float*) malloc(1*sizeof(float)); - float* DeltaOhtaPixel = (float*) malloc(3*(sizeof(float))); - int *Indice = (int*) malloc(3*(sizeof(int))); - float *HI = (float*) malloc(3*(sizeof(float))); - float *Integral = (float*) malloc(3*(sizeof(float))); - float* X = (float*) malloc(1*sizeof(float)); - float* XiXj = (float*) malloc(1*sizeof(float)); - float IntegralFlou; - - *Indice = 0; - *(Indice+1) = 1; - *(Indice+2) = 2; - *X = 1.0; - - for(int i = 0; i < Delta->width; i++) - { - for(int j = 0; j < Delta->height; j++) - { - if(n == 2) - { - p.GetGrayPixel(H,i,j,HTexturePixel); - p.GetPixel(Delta,i,j,DeltaOhtaPixel); - - *(HI+0) = *(HTexturePixel+0); - *(HI+1) = *(DeltaOhtaPixel+0); - *(HI+2) = *(DeltaOhtaPixel+1); - } - - if(n==1) - { - //remplir HI par les valeurs des 3 composantes couleurs uniquement - p.GetPixel(Delta,i,j,DeltaOhtaPixel); - - *(HI+0) = *(DeltaOhtaPixel+0); - //*(HI+0) = *(DeltaOhtaPixel+2); - *(HI+1) = *(DeltaOhtaPixel+1); - *(HI+2) = *(DeltaOhtaPixel+2); - } - - Trier(HI,3,Indice); - *XiXj = *(MeasureG + (*(Indice+1))) + (*(MeasureG + (*(Indice+2)))); - - *(Integral+0) = *(HI+(*(Indice+0)))* (*X-*XiXj); - *(Integral+1) = *(HI+(*(Indice+1)))* (*XiXj-*(MeasureG+(*(Indice+2)))); - *(Integral+2) = *(HI+(*(Indice+2)))* (*(MeasureG+(*(Indice+2)))); - - IntegralFlou = *(Integral+0) + *(Integral+1) + *(Integral+2); - p.PutGrayPixel(OutputImage,i,j,IntegralFlou); - } - } - - free(HTexturePixel); - free(DeltaOhtaPixel); - free(Indice); - free(HI); - free(X); - free(XiXj); - free(Integral); -} - -void FuzzyUtils::FuzzyMeasureG(float g1, float g2, float g3, float *G) -{ - *(G+0) = g1; - *(G+1) = g2; - *(G+2) = g3; -} - -void FuzzyUtils::Trier(float* g,int n,int* index) -{ - // Cette fonction trie un vecteur g par ordre croissant et - // sort egalement l'indice des elements selon le trie dans le vecteur "index" suppos� initialis� par des valeurs de 1 a n - - float t; - int r,a,b; - - for(a = 1; a <= n; a++) - { - for(b = n-1; b >= a; b--) - if(*(g + b-1) < (*(g + b))) - { - // ordre croissant des �lements - t = *(g + b-1); - *(g + b-1) = *(g + b); - *(g + b) = t; - - // ordre des indices des �lements du vecteur g - r = *(index + b-1); - *(index + b-1) = *(index + b); - *(index + b) = r; - } - } -} - -float FuzzyUtils::min(float *a,float *b) -{ - float min = 0; - - if(*a >= (*b)) - min = *b; - else - min = *a; - - return min; -} - -float FuzzyUtils::max(float* g , int n) -{ - float max = 0; - - for(int i = 0; i < n; i++) - { - if(*(g+i) >= max) - max = *(g+i); - } - - return max; -} - -void FuzzyUtils::gDeDeux(float* a, float* b, float* lambda) -{ - float* c = (float*) malloc(1*sizeof(float)); - *c = *a + (*b) + (*lambda) * (*a) * (*b); -} - -void FuzzyUtils::getLambda(float* g) -{ - float a,b; - float* lambda = (float*) malloc(1*sizeof(float)); - - a = (*(g+0) * (*(g+1)) + (*(g+1)) * (*(g+2)) + (*(g+0)) * (*(g+2))); - *lambda = -(*(g+0) * (*(g+1)) + (*(g+1)) * (*(g+2)) + (*(g+0)) * (*(g+2))) / (*(g+0) * (*(g+1)) * (*(g+2))); - b = (*(g+0) * (*(g+1)) * (*(g+2))); - - //printf("\na:%f",a); - //printf("\nb:%f",b); - //printf("\nlambda:%f", *lambda); - - free(lambda); -} - -void FuzzyUtils::AdaptativeSelectiveBackgroundModelUpdate(IplImage* CurrentImage, IplImage* BGImage, IplImage* OutputImage, IplImage* Integral, float seuil, float alpha) -{ - PixelUtils p; - - float beta = 0.0; - float* CurentImagePixel = (float*) malloc(3*sizeof(float)); - float* BGImagePixel = (float*) malloc(3*sizeof(float)); - float* OutputImagePixel = (float*) malloc(3*sizeof(float)); - float* IntegralImagePixel = (float*) malloc(1*sizeof(float)); - float *Maximum = (float*) malloc(1*sizeof(float)); - float *Minimum = (float*) malloc(1*sizeof(float)); - - p.ForegroundMaximum(Integral, Maximum, 1); - p.ForegroundMinimum(Integral, Minimum, 1); - - for(int i = 0; i < CurrentImage->width; i++) - { - for(int j = 0; j < CurrentImage->height; j++) - { - p.GetPixel(CurrentImage, i, j, CurentImagePixel); - p.GetPixel(BGImage, i, j, BGImagePixel); - p.GetGrayPixel(Integral, i, j, IntegralImagePixel); - - beta = 1 - ((*IntegralImagePixel) - ((*Minimum / (*Minimum - *Maximum)) * (*IntegralImagePixel) - (*Minimum * (*Maximum) / (*Minimum - *Maximum)))); - - for(int k = 0; k < 3; k++) - *(OutputImagePixel + k) = beta * (*(BGImagePixel + k)) + (1 - beta) * (alpha * (*(CurentImagePixel+k)) + (1-alpha) * (*(BGImagePixel+k))); - - p.PutPixel(OutputImage, i, j, OutputImagePixel); - } - } - - free(CurentImagePixel); - free(BGImagePixel); - free(OutputImagePixel); - free(IntegralImagePixel); - free(Maximum); - free(Minimum); -} diff --git a/package_bgs/tb/PixelUtils.cpp b/package_bgs/tb/PixelUtils.cpp deleted file mode 100644 index d647e05..0000000 --- a/package_bgs/tb/PixelUtils.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#include "PixelUtils.h" - -PixelUtils::PixelUtils(void){} -PixelUtils::~PixelUtils(void){} - -void PixelUtils::ColorConversion(IplImage* RGBImage, IplImage* ConvertedImage, int color_space) -{ - // Space Color RGB - Nothing to do! - if(color_space == 1) - cvCopy(RGBImage, ConvertedImage); - - // Space Color Ohta - if(color_space == 2) - cvttoOTHA(RGBImage, ConvertedImage); - - // Space Color HSV - V Intensity - (H,S) Chromaticity - if(color_space == 3) - cvCvtColor(RGBImage, ConvertedImage, CV_BGR2HSV); - - // Space Color YCrCb - Y Intensity - (Cr,Cb) Chromaticity - if(color_space == 4) - cvCvtColor(RGBImage,ConvertedImage,CV_BGR2YCrCb); -} - -void PixelUtils::cvttoOTHA(IplImage* RGBImage, IplImage* OthaImage) -{ - float* OhtaPixel = (float*) malloc(3*(sizeof(float))); - float* RGBPixel = (float*) malloc(3*(sizeof(float))); - - for(int i = 0; i < RGBImage->width; i++) - { - for(int j = 0;j < RGBImage->height; j++) - { - GetPixel(RGBImage, i, j, RGBPixel); - - // I1 = (R + G + B) / 3 - *OhtaPixel = (*(RGBPixel) + (*(RGBPixel + 1)) + (*(RGBPixel + 2))) / 3.0; - - // I2 = (R - B) / 2 - *(OhtaPixel+1) = (*RGBPixel - (*(RGBPixel + 2))) / 2.0; - - // I3 = (2G - R - B) / 4 - *(OhtaPixel+2) = (2 * (*(RGBPixel + 1)) - (*RGBPixel) - (*(RGBPixel + 2))) / 4.0; - - PutPixel(OthaImage, i, j, OhtaPixel); - } - } - - free(OhtaPixel); - free(RGBPixel); -} - -void PixelUtils::PostProcessing(IplImage *InputImage) -{ - IplImage *ResultImage = cvCreateImage(cvSize(InputImage->width, InputImage->height), IPL_DEPTH_32F, 3); - - cvErode(InputImage, ResultImage, NULL, 1); - cvDilate(ResultImage, InputImage, NULL, 0); - - cvReleaseImage(&ResultImage); -} - -void PixelUtils::GetPixel(IplImage *image, int m, int n, unsigned char *pixelcourant) -{ - for(int k = 0; k < 3; k++) - pixelcourant[k] = ((unsigned char*)(image->imageData + image->widthStep*n))[m*3 + k]; -} - -void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, unsigned char *pixelcourant) -{ - *pixelcourant = ((unsigned char*)(image->imageData + image->widthStep*n))[m]; -} - -void PixelUtils::PutPixel(IplImage *image,int p,int q,unsigned char *pixelcourant) -{ - for(int r = 0; r < 3; r++) - ((unsigned char*)(image->imageData + image->widthStep*q))[p*3 + r] = pixelcourant[r]; -} - -void PixelUtils::PutGrayPixel(IplImage *image, int p, int q, unsigned char pixelcourant) -{ - ((unsigned char*)(image->imageData + image->widthStep*q))[p] = pixelcourant; -} - -void PixelUtils::GetPixel(IplImage *image, int m, int n, float *pixelcourant) -{ - for(int k = 0; k < 3; k++) - pixelcourant[k] = ((float*)(image->imageData + image->widthStep*n))[m*3 + k]; -} - -void PixelUtils::GetGrayPixel(IplImage *image, int m, int n, float *pixelcourant) -{ - *pixelcourant = ((float*)(image->imageData + image->widthStep*n))[m]; -} - -void PixelUtils::PutPixel(IplImage *image, int p, int q, float *pixelcourant) -{ - for(int r = 0; r < 3; r++) - ((float*)(image->imageData + image->widthStep*q))[p*3 + r] = pixelcourant[r]; -} - -void PixelUtils::PutGrayPixel(IplImage *image,int p,int q,float pixelcourant) -{ - ((float*)(image->imageData + image->widthStep*q))[p] = pixelcourant; -} - -void PixelUtils::getNeighberhoodGrayPixel(IplImage* InputImage, int x, int y, float* neighberPixel) -{ - int i,j,k; - - float* pixelCourant = (float*) malloc(1*(sizeof(float))); - - //le calcul de voisinage pour les 4 coins; - /* 1.*/ - if(x==0 && y==0) - { - k = 0; - for(i = x; i < x+2; i++) - for(j = y; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - /* 2.*/ - if(x==0 && y==InputImage->width) - { - k = 0; - for(i = x; i < x+2; i++) - for(j = y-1; j < y+1; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - /* 3.*/ - if(x==InputImage->height && y==0) - { - k = 0; - for(i = x-1; i < x+1; i++) - for(j = y; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - /* 4.*/ - if(x==InputImage->height && y==InputImage->width) - { - k = 0; - for(i = x-1; i <x+1; i++) - for(j = y-1; j < y+1; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - // Voisinage de la premiere ligne : L(0) - if(x==0 && (y!=0 && y!=InputImage->width)) - { - k = 0; - for(i = x+1; i >= x; i--) - for(j = y-1; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - // Voisinage de la derni�re colonne : C(w) - if((x!=0 && x!=InputImage->height) && y==InputImage->width) - { - k = 0; - for(i = x+1; i > x-2; i--) - for(j = y-1; j < y+1; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - // Voisinage de la derni�re ligne : L(h) - if(x==InputImage->height && (y!=0 && y!=InputImage->width)) - { - k = 0; - for(i = x; i > x-2; i--) - for(j = y-1; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - // Voisinage de la premiere colonne : C(0) - if((x!=0 && x!=InputImage->height) && y==0) - { - k = 0; - for(i = x-1; i < x+2; i++) - for(j = y; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - //le calcul du voisinage pour le reste des elementes d'image - if((x!=0 && x!=InputImage->height)&&(y!=0 && y!=InputImage->width)) - { - k = 0; - for(i = x+1;i > x-2; i--) - for(j = y-1; j < y+2; j++) - { - GetGrayPixel(InputImage,i,j,pixelCourant); - *(neighberPixel+k) = *pixelCourant; - k++; - } - } - - free(pixelCourant); -} - -void PixelUtils::ForegroundMinimum(IplImage *Foreground, float *Minimum, int n) -{ - int i,j,k; - float *pixelcourant; - - pixelcourant = (float *) malloc(n*sizeof(float)); - - for(k = 0; k < n; k++) - *(Minimum + k) = 255; - - for(i = 0; i < Foreground->width; i++) - for(j = 0; j < Foreground->height; j++) - { - if(n == 3) - { - GetPixel(Foreground,i,j,pixelcourant); - - for(k = 0; k < n; k++) - if(*(pixelcourant + k) < *(Minimum + k)) - *(Minimum + k) = *(pixelcourant + k); - } - - if(n==1) - { - GetGrayPixel(Foreground,i,j,pixelcourant); - - if(*pixelcourant < *Minimum) - *Minimum = *pixelcourant; - } - } - - free(pixelcourant); -} - -void PixelUtils::ForegroundMaximum(IplImage *Foreground, float *Maximum, int n) -{ - int i,j,k; - float *pixelcourant; - - pixelcourant = (float *) malloc(n*sizeof(float)); - - for(k = 0; k < n; k++) - *(Maximum + k) = 0; - - for(i = 0; i < Foreground->width; i++) - for(j = 0; j < Foreground->height; j++) - { - if(n == 3) - { - GetPixel(Foreground,i,j,pixelcourant); - - for(k = 0; k < n; k++) - if(*(pixelcourant + k) > *(Maximum + k)) - *(Maximum + k) = *(pixelcourant + k); - } - - if(n == 1) - { - GetGrayPixel(Foreground,i,j,pixelcourant); - - if(*pixelcourant > *Maximum) - *Maximum = *pixelcourant; - } - } - - free(pixelcourant); -} - -void PixelUtils::ComplementaryAlphaImageCreation(IplImage *AlphaImage, IplImage *ComplementaryAlphaImage, int n) -{ - int i,j,k; - float *pixelcourant, *pixelcourant1; - - pixelcourant = (float *) malloc(n * sizeof(float)); - pixelcourant1 = (float *) malloc(n * sizeof(float)); - - for(i = 0; i < AlphaImage->width; i++) - for(j = 0; j < AlphaImage->height; j++) - { - if(n == 1) - { - GetGrayPixel(AlphaImage,i,j,pixelcourant); - *pixelcourant1 = 1 - *(pixelcourant); - PutGrayPixel(ComplementaryAlphaImage,i,j,*pixelcourant1); - } - - if(n == 3) - { - GetPixel(AlphaImage,i,j,pixelcourant); - for(k = 0; k < 3; k++) - { - *pixelcourant1 = 1.0 - *(pixelcourant); - *(pixelcourant1+1) = 1.0 - *(pixelcourant+1); - *(pixelcourant1+2) = 1.0 - *(pixelcourant+2); - } - PutPixel(ComplementaryAlphaImage,i,j,pixelcourant1); - } - } - - free(pixelcourant); - free(pixelcourant1); -} diff --git a/package_bgs/tb/T2FMRF_UM.h b/package_bgs/tb/T2FMRF_UM.h deleted file mode 100644 index fd0da7b..0000000 --- a/package_bgs/tb/T2FMRF_UM.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "MRF.h" - -using namespace Algorithms::BackgroundSubtraction; - -class T2FMRF_UM : public IBGS -{ -private: - bool firstTime; - long frameNumber; - IplImage *frame; - RgbImage frame_data; - - IplImage *old_labeling; - IplImage *old; - - T2FMRFParams params; - T2FMRF bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - bool showOutput; - - MRF_TC mrf; - GMM *gmm; - HMM *hmm; - -public: - T2FMRF_UM(); - ~T2FMRF_UM(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/package_bgs/tb/T2FMRF_UV.h b/package_bgs/tb/T2FMRF_UV.h deleted file mode 100644 index 28fcb67..0000000 --- a/package_bgs/tb/T2FMRF_UV.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -This file is part of BGSLibrary. - -BGSLibrary is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -BGSLibrary is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. -*/ -#pragma once - -#include <iostream> -#include <opencv2/opencv.hpp> - - -#include "../IBGS.h" -#include "MRF.h" - -using namespace Algorithms::BackgroundSubtraction; - -class T2FMRF_UV : public IBGS -{ -private: - bool firstTime; - long frameNumber; - IplImage *frame; - RgbImage frame_data; - - IplImage *old_labeling; - IplImage *old; - - T2FMRFParams params; - T2FMRF bgs; - BwImage lowThresholdMask; - BwImage highThresholdMask; - - double threshold; - double alpha; - float km; - float kv; - int gaussians; - bool showOutput; - - MRF_TC mrf; - GMM *gmm; - HMM *hmm; - -public: - T2FMRF_UV(); - ~T2FMRF_UV(); - - void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); - -private: - void saveConfig(); - void loadConfig(); -}; diff --git a/vs2010/.gitignore b/vs2010/.gitignore deleted file mode 100644 index affde92..0000000 --- a/vs2010/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Ignore everything in this directory -* -# Except these files -!.gitignore -!README.txt -!bgslibrary.sln -!bgslibrary.suo -!bgslibrary.vcxproj -!bgslibrary.vcxproj.filters -!bgslibrary.vcxproj.user -!bgslibrary_demo.vcxproj -!bgslibrary_demo.vcxproj.filters -!bgslibrary_demo.vcxproj.user -!bgslibrary_demo2.vcxproj -!bgslibrary_demo2.vcxproj.filters -!bgslibrary_demo2.vcxproj.user diff --git a/vs2010/README.txt b/vs2010/README.txt deleted file mode 100644 index 7b0a5cf..0000000 --- a/vs2010/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -VISUAL STUDIO 2010 TEMPLATE PROJECT ------------------------------------ -Change to [Release][Win32] - -Tested with: - VISUAL STUDIO 2010 - VISUAL STUDIO 2012 - VISUAL STUDIO 2013 - VISUAL STUDIO 2015 - -You need to install OpenCV at: - C:\OpenCV2.4.10 -or change the project settings. - -Build and run! ;) \ No newline at end of file diff --git a/vs2010/bgslibrary.sln b/vs2010/bgslibrary.sln deleted file mode 100644 index ab59be3..0000000 --- a/vs2010/bgslibrary.sln +++ /dev/null @@ -1,27 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary", "bgslibrary.vcxproj", "{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary_demo", "bgslibrary_demo.vcxproj", "{EBE7FE0E-9FE6-41D2-B744-D43E7446D50C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary_demo2", "bgslibrary_demo2.vcxproj", "{EAA15CCC-270A-460B-A61C-2DB864D67718}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.ActiveCfg = Release|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.Build.0 = Release|Win32 - {EBE7FE0E-9FE6-41D2-B744-D43E7446D50C}.Release|Win32.ActiveCfg = Release|Win32 - {EBE7FE0E-9FE6-41D2-B744-D43E7446D50C}.Release|Win32.Build.0 = Release|Win32 - {EAA15CCC-270A-460B-A61C-2DB864D67718}.Release|Win32.ActiveCfg = Release|Win32 - {EAA15CCC-270A-460B-A61C-2DB864D67718}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs2010/bgslibrary.suo b/vs2010/bgslibrary.suo deleted file mode 100644 index 3dc8e43797f0d1ee8f60b5d84b6328c180a83479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11776 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 MgV7|qf1s5E0LfUny8r+H diff --git a/vs2010/bgslibrary.vcxproj b/vs2010/bgslibrary.vcxproj deleted file mode 100644 index 2485865..0000000 --- a/vs2010/bgslibrary.vcxproj +++ /dev/null @@ -1,279 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>bgslibrary</RootNamespace> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\build</OutDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc10\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\Demo.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\Demo2.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\FrameProcessor.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\Main.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\ae\KDE.cpp" /> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackground.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp" /> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp" /> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp" /> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp" /> - <ClCompile Include="..\package_bgs\ck\graph.cpp" /> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp" /> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp" /> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp" /> - <ClCompile Include="..\package_bgs\db\imbs.cpp" /> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp" /> - <ClCompile Include="..\package_bgs\dp\Error.cpp" /> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp" /> - <ClCompile Include="..\package_bgs\dp\Image.cpp" /> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp" /> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp" /> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\GMG.cpp" /> - <ClCompile Include="..\package_bgs\jmo\blob.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp" /> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp" /> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp" /> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\MRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp" /> - <ClCompile Include="..\PreProcessor.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\VideoAnalysis.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\VideoCapture.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\Config.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\FrameProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\IFrameProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h" /> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\ae\KDE.h" /> - <ClInclude Include="..\package_bgs\ae\KernelTable.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h" /> - <ClInclude Include="..\package_bgs\av\TBackground.h" /> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h" /> - <ClInclude Include="..\package_bgs\av\VuMeter.h" /> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h" /> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h" /> - <ClInclude Include="..\package_bgs\bl\stdbool.h" /> - <ClInclude Include="..\package_bgs\ck\block.h" /> - <ClInclude Include="..\package_bgs\ck\graph.h" /> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h" /> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp" /> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp" /> - <ClInclude Include="..\package_bgs\db\imbs.hpp" /> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h" /> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Bgs.h" /> - <ClInclude Include="..\package_bgs\dp\BgsParams.h" /> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h" /> - <ClInclude Include="..\package_bgs\dp\Error.h" /> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h" /> - <ClInclude Include="..\package_bgs\dp\Image.h" /> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\WrenGA.h" /> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h" /> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\GMG.h" /> - <ClInclude Include="..\package_bgs\IBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h" /> - <ClInclude Include="..\package_bgs\jmo\BGS.h" /> - <ClInclude Include="..\package_bgs\jmo\blob.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h" /> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h" /> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h" /> - <ClInclude Include="..\package_bgs\lb\BGModel.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h" /> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h" /> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\Types.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h" /> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h" /> - <ClInclude Include="..\package_bgs\pl\LBSP.h" /> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\RandUtils.h" /> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h" /> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h" /> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h" /> - <ClInclude Include="..\package_bgs\tb\MRF.h" /> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h" /> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h" /> - <ClInclude Include="..\PreProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\VideoAnalysis.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\VideoCapture.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary.vcxproj.filters b/vs2010/bgslibrary.vcxproj.filters deleted file mode 100644 index ab0fbf0..0000000 --- a/vs2010/bgslibrary.vcxproj.filters +++ /dev/null @@ -1,644 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - <Filter Include="Header Files\package_bgs"> - <UniqueIdentifier>{8cb396e6-81b6-4db9-a1b0-5c2b7c122bd9}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ae"> - <UniqueIdentifier>{e1ab6d45-3486-42fa-8f51-69a300c0c173}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\av"> - <UniqueIdentifier>{7992fa8c-e616-4e72-b249-6ede4f4291b4}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\db"> - <UniqueIdentifier>{667f4048-d125-4453-9f0c-42f9abd4ed3a}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\dp"> - <UniqueIdentifier>{89c4b817-936b-483c-abed-3e7e7c1fc427}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\jmo"> - <UniqueIdentifier>{c5e0f44c-6120-4906-917d-c8c8af3eafec}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\lb"> - <UniqueIdentifier>{728fbe82-1489-4878-89ea-a62ba0932204}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pt"> - <UniqueIdentifier>{6b017402-c47a-49a4-8f57-b5db863e1bde}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\sjn"> - <UniqueIdentifier>{e25c1e03-530d-4c7a-b776-26bf17595213}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\tb"> - <UniqueIdentifier>{53f2c4fb-9468-44ce-b76e-e25ea018c084}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files\demo"> - <UniqueIdentifier>{23f1cd4a-e9b2-4338-a5e7-128f451d3c89}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_analysis"> - <UniqueIdentifier>{52a9f254-d817-4577-96c2-0b3b0a9527b7}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\bl"> - <UniqueIdentifier>{0494c5d4-b4bb-421c-b032-176903ba8e1b}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ck"> - <UniqueIdentifier>{87961eee-b843-45bd-b642-9dcd9d78b661}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pl"> - <UniqueIdentifier>{cd33a41f-6151-46a5-95b6-b79022786144}</UniqueIdentifier> - </Filter> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\GMG.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KDE.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackground.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\imbs.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Error.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Image.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\blob.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\MRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\FrameProcessor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\Main.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\PreProcessor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\VideoAnalysis.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\VideoCapture.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\Demo.cpp"> - <Filter>Source Files\demo</Filter> - </ClCompile> - <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp"> - <Filter>Header Files\package_analysis</Filter> - </ClCompile> - <ClCompile Include="..\Demo2.cpp"> - <Filter>Source Files\demo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\graph.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\GMG.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\IBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KDE.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KernelTable.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackground.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\VuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\imbs.hpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Bgs.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\BgsParams.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Error.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Image.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\WrenGA.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\blob.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModel.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\Types.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\MRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\Config.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\FrameProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\IFrameProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\PreProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\VideoAnalysis.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\VideoCapture.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h"> - <Filter>Header Files\package_analysis</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\stdbool.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\block.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\graph.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\RandUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary.vcxproj.user b/vs2010/bgslibrary.vcxproj.user deleted file mode 100644 index ebebb3b..0000000 --- a/vs2010/bgslibrary.vcxproj.user +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments>-uf -fn=dataset/video.avi</LocalDebuggerCommandArguments> - </PropertyGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo.vcxproj b/vs2010/bgslibrary_demo.vcxproj deleted file mode 100644 index 966d57b..0000000 --- a/vs2010/bgslibrary_demo.vcxproj +++ /dev/null @@ -1,241 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{EBE7FE0E-9FE6-41D2-B744-D43E7446D50C}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>bgslibrary</RootNamespace> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\build</OutDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc10\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\Demo.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\ae\KDE.cpp" /> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackground.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp" /> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp" /> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp" /> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp" /> - <ClCompile Include="..\package_bgs\ck\graph.cpp" /> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp" /> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp" /> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp" /> - <ClCompile Include="..\package_bgs\db\imbs.cpp" /> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp" /> - <ClCompile Include="..\package_bgs\dp\Error.cpp" /> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp" /> - <ClCompile Include="..\package_bgs\dp\Image.cpp" /> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp" /> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp" /> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\GMG.cpp" /> - <ClCompile Include="..\package_bgs\jmo\blob.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp" /> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp" /> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp" /> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\MRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\ae\KDE.h" /> - <ClInclude Include="..\package_bgs\ae\KernelTable.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h" /> - <ClInclude Include="..\package_bgs\av\TBackground.h" /> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h" /> - <ClInclude Include="..\package_bgs\av\VuMeter.h" /> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h" /> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h" /> - <ClInclude Include="..\package_bgs\bl\stdbool.h" /> - <ClInclude Include="..\package_bgs\ck\block.h" /> - <ClInclude Include="..\package_bgs\ck\graph.h" /> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h" /> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp" /> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp" /> - <ClInclude Include="..\package_bgs\db\imbs.hpp" /> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h" /> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Bgs.h" /> - <ClInclude Include="..\package_bgs\dp\BgsParams.h" /> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h" /> - <ClInclude Include="..\package_bgs\dp\Error.h" /> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h" /> - <ClInclude Include="..\package_bgs\dp\Image.h" /> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\WrenGA.h" /> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h" /> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\GMG.h" /> - <ClInclude Include="..\package_bgs\IBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h" /> - <ClInclude Include="..\package_bgs\jmo\BGS.h" /> - <ClInclude Include="..\package_bgs\jmo\blob.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h" /> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h" /> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h" /> - <ClInclude Include="..\package_bgs\lb\BGModel.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h" /> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h" /> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\Types.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h" /> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h" /> - <ClInclude Include="..\package_bgs\pl\LBSP.h" /> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\RandUtils.h" /> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h" /> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h" /> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h" /> - <ClInclude Include="..\package_bgs\tb\MRF.h" /> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h" /> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h" /> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo.vcxproj.filters b/vs2010/bgslibrary_demo.vcxproj.filters deleted file mode 100644 index d9f3aa8..0000000 --- a/vs2010/bgslibrary_demo.vcxproj.filters +++ /dev/null @@ -1,596 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - <Filter Include="Header Files\package_bgs"> - <UniqueIdentifier>{8cb396e6-81b6-4db9-a1b0-5c2b7c122bd9}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ae"> - <UniqueIdentifier>{e1ab6d45-3486-42fa-8f51-69a300c0c173}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\av"> - <UniqueIdentifier>{7992fa8c-e616-4e72-b249-6ede4f4291b4}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\db"> - <UniqueIdentifier>{667f4048-d125-4453-9f0c-42f9abd4ed3a}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\dp"> - <UniqueIdentifier>{89c4b817-936b-483c-abed-3e7e7c1fc427}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\jmo"> - <UniqueIdentifier>{c5e0f44c-6120-4906-917d-c8c8af3eafec}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\lb"> - <UniqueIdentifier>{728fbe82-1489-4878-89ea-a62ba0932204}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pt"> - <UniqueIdentifier>{6b017402-c47a-49a4-8f57-b5db863e1bde}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\sjn"> - <UniqueIdentifier>{e25c1e03-530d-4c7a-b776-26bf17595213}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\tb"> - <UniqueIdentifier>{53f2c4fb-9468-44ce-b76e-e25ea018c084}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\bl"> - <UniqueIdentifier>{0494c5d4-b4bb-421c-b032-176903ba8e1b}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ck"> - <UniqueIdentifier>{87961eee-b843-45bd-b642-9dcd9d78b661}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pl"> - <UniqueIdentifier>{cd33a41f-6151-46a5-95b6-b79022786144}</UniqueIdentifier> - </Filter> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\GMG.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KDE.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackground.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\imbs.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Error.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Image.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\blob.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\MRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\graph.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\Demo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\GMG.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\IBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KDE.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KernelTable.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackground.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\VuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\imbs.hpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Bgs.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\BgsParams.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Error.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Image.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\WrenGA.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\blob.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModel.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\Types.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\MRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\stdbool.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\block.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\graph.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\RandUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo.vcxproj.user b/vs2010/bgslibrary_demo.vcxproj.user deleted file mode 100644 index abe8dd8..0000000 --- a/vs2010/bgslibrary_demo.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup /> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo2.vcxproj b/vs2010/bgslibrary_demo2.vcxproj deleted file mode 100644 index ad0f4c4..0000000 --- a/vs2010/bgslibrary_demo2.vcxproj +++ /dev/null @@ -1,241 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{EAA15CCC-270A-460B-A61C-2DB864D67718}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>bgslibrary</RootNamespace> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\build</OutDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc10\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\Demo2.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\ae\KDE.cpp" /> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackground.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp" /> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp" /> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp" /> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp" /> - <ClCompile Include="..\package_bgs\ck\graph.cpp" /> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp" /> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp" /> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp" /> - <ClCompile Include="..\package_bgs\db\imbs.cpp" /> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp" /> - <ClCompile Include="..\package_bgs\dp\Error.cpp" /> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp" /> - <ClCompile Include="..\package_bgs\dp\Image.cpp" /> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp" /> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp" /> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\GMG.cpp" /> - <ClCompile Include="..\package_bgs\jmo\blob.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp" /> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp" /> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp" /> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\MRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\ae\KDE.h" /> - <ClInclude Include="..\package_bgs\ae\KernelTable.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h" /> - <ClInclude Include="..\package_bgs\av\TBackground.h" /> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h" /> - <ClInclude Include="..\package_bgs\av\VuMeter.h" /> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h" /> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h" /> - <ClInclude Include="..\package_bgs\bl\stdbool.h" /> - <ClInclude Include="..\package_bgs\ck\block.h" /> - <ClInclude Include="..\package_bgs\ck\graph.h" /> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h" /> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp" /> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp" /> - <ClInclude Include="..\package_bgs\db\imbs.hpp" /> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h" /> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Bgs.h" /> - <ClInclude Include="..\package_bgs\dp\BgsParams.h" /> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h" /> - <ClInclude Include="..\package_bgs\dp\Error.h" /> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h" /> - <ClInclude Include="..\package_bgs\dp\Image.h" /> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\WrenGA.h" /> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h" /> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\GMG.h" /> - <ClInclude Include="..\package_bgs\IBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h" /> - <ClInclude Include="..\package_bgs\jmo\BGS.h" /> - <ClInclude Include="..\package_bgs\jmo\blob.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h" /> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h" /> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h" /> - <ClInclude Include="..\package_bgs\lb\BGModel.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h" /> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h" /> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\Types.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h" /> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h" /> - <ClInclude Include="..\package_bgs\pl\LBSP.h" /> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\RandUtils.h" /> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h" /> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h" /> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h" /> - <ClInclude Include="..\package_bgs\tb\MRF.h" /> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h" /> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h" /> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo2.vcxproj.filters b/vs2010/bgslibrary_demo2.vcxproj.filters deleted file mode 100644 index 45de1b6..0000000 --- a/vs2010/bgslibrary_demo2.vcxproj.filters +++ /dev/null @@ -1,596 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - <Filter Include="Header Files\package_bgs"> - <UniqueIdentifier>{8cb396e6-81b6-4db9-a1b0-5c2b7c122bd9}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ae"> - <UniqueIdentifier>{e1ab6d45-3486-42fa-8f51-69a300c0c173}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\av"> - <UniqueIdentifier>{7992fa8c-e616-4e72-b249-6ede4f4291b4}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\db"> - <UniqueIdentifier>{667f4048-d125-4453-9f0c-42f9abd4ed3a}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\dp"> - <UniqueIdentifier>{89c4b817-936b-483c-abed-3e7e7c1fc427}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\jmo"> - <UniqueIdentifier>{c5e0f44c-6120-4906-917d-c8c8af3eafec}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\lb"> - <UniqueIdentifier>{728fbe82-1489-4878-89ea-a62ba0932204}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pt"> - <UniqueIdentifier>{6b017402-c47a-49a4-8f57-b5db863e1bde}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\sjn"> - <UniqueIdentifier>{e25c1e03-530d-4c7a-b776-26bf17595213}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\tb"> - <UniqueIdentifier>{53f2c4fb-9468-44ce-b76e-e25ea018c084}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\bl"> - <UniqueIdentifier>{0494c5d4-b4bb-421c-b032-176903ba8e1b}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ck"> - <UniqueIdentifier>{87961eee-b843-45bd-b642-9dcd9d78b661}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pl"> - <UniqueIdentifier>{cd33a41f-6151-46a5-95b6-b79022786144}</UniqueIdentifier> - </Filter> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\GMG.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KDE.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackground.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\imbs.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Error.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Image.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\blob.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\MRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\graph.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\Demo2.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\GMG.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\IBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KDE.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KernelTable.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackground.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\VuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\imbs.hpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Bgs.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\BgsParams.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Error.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Image.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\WrenGA.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\blob.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModel.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\Types.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\MRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\stdbool.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\block.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\graph.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\RandUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/vs2010/bgslibrary_demo2.vcxproj.user b/vs2010/bgslibrary_demo2.vcxproj.user deleted file mode 100644 index abe8dd8..0000000 --- a/vs2010/bgslibrary_demo2.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup /> -</Project> \ No newline at end of file diff --git a/vs2010mfc/outputs/background/KEEP_THIS_FOLDER b/vs2010mfc/outputs/background/KEEP_THIS_FOLDER deleted file mode 100644 index e69de29..0000000 diff --git a/vs2010mfc/outputs/foreground/KEEP_THIS_FOLDER b/vs2010mfc/outputs/foreground/KEEP_THIS_FOLDER deleted file mode 100644 index e69de29..0000000 diff --git a/vs2010mfc/outputs/input/KEEP_THIS_FOLDER b/vs2010mfc/outputs/input/KEEP_THIS_FOLDER deleted file mode 100644 index e69de29..0000000 diff --git a/vs2010mfc/src/ReadMe.txt b/vs2010mfc/src/ReadMe.txt deleted file mode 100644 index 6c7fde0..0000000 --- a/vs2010mfc/src/ReadMe.txt +++ /dev/null @@ -1,100 +0,0 @@ -================================================================================ - MICROSOFT FOUNDATION CLASS LIBRARY : bgslibrary_vs2010_mfc Project Overview -=============================================================================== - -The application wizard has created this bgslibrary_vs2010_mfc application for -you. This application not only demonstrates the basics of using the Microsoft -Foundation Classes but is also a starting point for writing your application. - -This file contains a summary of what you will find in each of the files that -make up your bgslibrary_vs2010_mfc application. - -bgslibrary_vs2010_mfc.vcxproj - This is the main project file for VC++ projects generated using an application wizard. - It contains information about the version of Visual C++ that generated the file, and - information about the platforms, configurations, and project features selected with the - application wizard. - -bgslibrary_vs2010_mfc.vcxproj.filters - This is the filters file for VC++ projects generated using an Application Wizard. - It contains information about the association between the files in your project - and the filters. This association is used in the IDE to show grouping of files with - similar extensions under a specific node (for e.g. ".cpp" files are associated with the - "Source Files" filter). - -bgslibrary_vs2010_mfc.h - This is the main header file for the application. It includes other - project specific headers (including Resource.h) and declares the - CApp application class. - -bgslibrary_vs2010_mfc.cpp - This is the main application source file that contains the application - class CApp. - -bgslibrary_vs2010_mfc.rc - This is a listing of all of the Microsoft Windows resources that the - program uses. It includes the icons, bitmaps, and cursors that are stored - in the RES subdirectory. This file can be directly edited in Microsoft - Visual C++. Your project resources are in 1033. - -res\bgslibrary_vs2010_mfc.ico - This is an icon file, which is used as the application's icon. This - icon is included by the main resource file bgslibrary_vs2010_mfc.rc. - -res\bgslibrary_vs2010_mfc.rc2 - This file contains resources that are not edited by Microsoft - Visual C++. You should place all resources not editable by - the resource editor in this file. - - -///////////////////////////////////////////////////////////////////////////// - -The application wizard creates one dialog class: - -Dlg.h, Dlg.cpp - the dialog - These files contain your CDlg class. This class defines - the behavior of your application's main dialog. The dialog's template is - in bgslibrary_vs2010_mfc.rc, which can be edited in Microsoft Visual C++. - - -///////////////////////////////////////////////////////////////////////////// - -Other Features: - -ActiveX Controls - The application includes support to use ActiveX controls. - -///////////////////////////////////////////////////////////////////////////// - -Other standard files: - -StdAfx.h, StdAfx.cpp - These files are used to build a precompiled header (PCH) file - named bgslibrary_vs2010_mfc.pch and a precompiled types file named StdAfx.obj. - -Resource.h - This is the standard header file, which defines new resource IDs. - Microsoft Visual C++ reads and updates this file. - -bgslibrary_vs2010_mfc.manifest - Application manifest files are used by Windows XP to describe an applications - dependency on specific versions of Side-by-Side assemblies. The loader uses this - information to load the appropriate assembly from the assembly cache or private - from the application. The Application manifest maybe included for redistribution - as an external .manifest file that is installed in the same folder as the application - executable or it may be included in the executable in the form of a resource. -///////////////////////////////////////////////////////////////////////////// - -Other notes: - -The application wizard uses "TODO:" to indicate parts of the source code you -should add to or customize. - -If your application uses MFC in a shared DLL, you will need -to redistribute the MFC DLLs. If your application is in a language -other than the operating system's locale, you will also have to -redistribute the corresponding localized resources MFC100XXX.DLL. -For more information on both of these topics, please see the section on -redistributing Visual C++ applications in MSDN documentation. - -///////////////////////////////////////////////////////////////////////////// diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.rc b/vs2010mfc/src/bgslibrary_vs2010_mfc.rc deleted file mode 100644 index 7251658acf1cfb47e9ec6c5f95ae0d54e0237ed3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17930 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 Nc?|jBdWqQf0|4<lw^jfE diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.sln b/vs2010mfc/src/bgslibrary_vs2010_mfc.sln deleted file mode 100644 index f082581..0000000 --- a/vs2010mfc/src/bgslibrary_vs2010_mfc.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary_vs2010_mfc", "bgslibrary_vs2010_mfc.vcxproj", "{236E77EE-00D6-4B4E-80C7-C38847B1B60E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {236E77EE-00D6-4B4E-80C7-C38847B1B60E}.Debug|Win32.ActiveCfg = Debug|Win32 - {236E77EE-00D6-4B4E-80C7-C38847B1B60E}.Debug|Win32.Build.0 = Debug|Win32 - {236E77EE-00D6-4B4E-80C7-C38847B1B60E}.Release|Win32.ActiveCfg = Release|Win32 - {236E77EE-00D6-4B4E-80C7-C38847B1B60E}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.v12.suo b/vs2010mfc/src/bgslibrary_vs2010_mfc.v12.suo deleted file mode 100644 index dde25911dbe9553c86ec3483e9f01294bcef873b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29696 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 U7O`I=L2l^<ZgrBcnSp@;0MKeRwg3PC diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj b/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj deleted file mode 100644 index 1ed007d..0000000 --- a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj +++ /dev/null @@ -1,296 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{236E77EE-00D6-4B4E-80C7-C38847B1B60E}</ProjectGuid> - <RootNamespace>bgslibrary_vs2010_mfc</RootNamespace> - <Keyword>MFCProj</Keyword> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - <UseOfMfc>Static</UseOfMfc> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <UseOfMfc>Static</UseOfMfc> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <LinkIncremental>true</LinkIncremental> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <OutDir>../</OutDir> - <TargetName>mfc_bgslibrary</TargetName> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - </Link> - <Midl> - <MkTypLibCompatible>false</MkTypLibCompatible> - <ValidateAllParameters>true</ValidateAllParameters> - <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </Midl> - <ResourceCompile> - <Culture>0x0409</Culture> - <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;C:\boost_1_55_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc10\staticlib\*.lib;C:\boost_1_55_0\stage32\lib\vc10\*.lib;comctl32.lib;VFW32.lib;uafxcw.lib;LIBCMT.lib;%(AdditionalDependencies)</AdditionalDependencies> - <ShowProgress>NotSet</ShowProgress> - <IgnoreSpecificDefaultLibraries>uafxcw.lib;LIBCMT.lib</IgnoreSpecificDefaultLibraries> - </Link> - <Midl> - <MkTypLibCompatible>false</MkTypLibCompatible> - <ValidateAllParameters>true</ValidateAllParameters> - <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </Midl> - <ResourceCompile> - <Culture>0x0409</Culture> - <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ResourceCompile> - </ItemDefinitionGroup> - <ItemGroup> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i" /> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i" /> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i" /> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i" /> - <None Include="ReadMe.txt" /> - <None Include="res\bgslibrary_vs2010_mfc.ico" /> - <None Include="res\bgslibrary_vs2010_mfc.rc2" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorLBSP.h" /> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorLOBSTER.h" /> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h" /> - <ClInclude Include="..\..\package_bgs\pl\DistanceUtils.h" /> - <ClInclude Include="..\..\package_bgs\pl\LBSP.h" /> - <ClInclude Include="..\..\package_bgs\pl\LOBSTER.h" /> - <ClInclude Include="..\..\package_bgs\pl\RandUtils.h" /> - <ClInclude Include="..\..\package_bgs\pl\SuBSENSE.h" /> - <ClInclude Include="App.h" /> - <ClInclude Include="Dlg.h" /> - <ClInclude Include="..\..\package_bgs\AdaptiveBackgroundLearning.h" /> - <ClInclude Include="..\..\package_bgs\AdaptiveSelectiveBackgroundLearning.h" /> - <ClInclude Include="..\..\package_bgs\ae\KDE.h" /> - <ClInclude Include="..\..\package_bgs\ae\KernelTable.h" /> - <ClInclude Include="..\..\package_bgs\ae\NPBGmodel.h" /> - <ClInclude Include="..\..\package_bgs\ae\NPBGSubtractor.h" /> - <ClInclude Include="..\..\package_bgs\av\TBackground.h" /> - <ClInclude Include="..\..\package_bgs\av\TBackgroundVuMeter.h" /> - <ClInclude Include="..\..\package_bgs\av\VuMeter.h" /> - <ClInclude Include="..\..\package_bgs\bl\sdLaMa091.h" /> - <ClInclude Include="..\..\package_bgs\bl\SigmaDeltaBGS.h" /> - <ClInclude Include="..\..\package_bgs\bl\stdbool.h" /> - <ClInclude Include="..\..\package_bgs\db\imbs.hpp" /> - <ClInclude Include="..\..\package_bgs\db\IndependentMultimodalBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\AdaptiveMedianBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\Bgs.h" /> - <ClInclude Include="..\..\package_bgs\dp\BgsParams.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPAdaptiveMedianBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPEigenbackgroundBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPGrimsonGMMBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPMeanBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPPratiMediodBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPTextureBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPWrenGABGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\DPZivkovicAGMMBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\Eigenbackground.h" /> - <ClInclude Include="..\..\package_bgs\dp\Error.h" /> - <ClInclude Include="..\..\package_bgs\dp\GrimsonGMM.h" /> - <ClInclude Include="..\..\package_bgs\dp\Image.h" /> - <ClInclude Include="..\..\package_bgs\dp\MeanBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\PratiMediodBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\TextureBGS.h" /> - <ClInclude Include="..\..\package_bgs\dp\WrenGA.h" /> - <ClInclude Include="..\..\package_bgs\dp\ZivkovicAGMM.h" /> - <ClInclude Include="..\..\package_bgs\FrameDifferenceBGS.h" /> - <ClInclude Include="..\..\package_bgs\GMG.h" /> - <ClInclude Include="..\..\package_bgs\IBGS.h" /> - <ClInclude Include="..\..\package_bgs\jmo\BackgroundSubtractionAPI.h" /> - <ClInclude Include="..\..\package_bgs\jmo\BGS.h" /> - <ClInclude Include="..\..\package_bgs\jmo\blob.h" /> - <ClInclude Include="..\..\package_bgs\jmo\BlobExtraction.h" /> - <ClInclude Include="..\..\package_bgs\jmo\BlobLibraryConfiguration.h" /> - <ClInclude Include="..\..\package_bgs\jmo\BlobResult.h" /> - <ClInclude Include="..\..\package_bgs\jmo\CMultiLayerBGS.h" /> - <ClInclude Include="..\..\package_bgs\jmo\LocalBinaryPattern.h" /> - <ClInclude Include="..\..\package_bgs\jmo\MultiLayerBGS.h" /> - <ClInclude Include="..\..\package_bgs\jmo\OpenCvDataConversion.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModel.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModelFuzzyGauss.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModelFuzzySom.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModelGauss.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModelMog.h" /> - <ClInclude Include="..\..\package_bgs\lb\BGModelSom.h" /> - <ClInclude Include="..\..\package_bgs\lb\LBAdaptiveSOM.h" /> - <ClInclude Include="..\..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" /> - <ClInclude Include="..\..\package_bgs\lb\LBFuzzyGaussian.h" /> - <ClInclude Include="..\..\package_bgs\lb\LBMixtureOfGaussians.h" /> - <ClInclude Include="..\..\package_bgs\lb\LBSimpleGaussian.h" /> - <ClInclude Include="..\..\package_bgs\lb\Types.h" /> - <ClInclude Include="..\..\package_bgs\MixtureOfGaussianV1BGS.h" /> - <ClInclude Include="..\..\package_bgs\MixtureOfGaussianV2BGS.h" /> - <ClInclude Include="..\..\package_bgs\sjn\SJN_MultiCueBGS.h" /> - <ClInclude Include="..\..\package_bgs\StaticFrameDifferenceBGS.h" /> - <ClInclude Include="..\..\package_bgs\tb\FuzzyChoquetIntegral.h" /> - <ClInclude Include="..\..\package_bgs\tb\FuzzySugenoIntegral.h" /> - <ClInclude Include="..\..\package_bgs\tb\FuzzyUtils.h" /> - <ClInclude Include="..\..\package_bgs\tb\MRF.h" /> - <ClInclude Include="..\..\package_bgs\tb\PerformanceUtils.h" /> - <ClInclude Include="..\..\package_bgs\tb\PixelUtils.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM_UM.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM_UV.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF_UM.h" /> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF_UV.h" /> - <ClInclude Include="..\..\package_bgs\WeightedMovingMeanBGS.h" /> - <ClInclude Include="..\..\package_bgs\WeightedMovingVarianceBGS.h" /> - <ClInclude Include="Resource.h" /> - <ClInclude Include="stdafx.h" /> - <ClInclude Include="targetver.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorLBSP.cpp" /> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp" /> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp" /> - <ClCompile Include="..\..\package_bgs\pl\LBSP.cpp" /> - <ClCompile Include="..\..\package_bgs\pl\LOBSTER.cpp" /> - <ClCompile Include="..\..\package_bgs\pl\SuBSENSE.cpp" /> - <ClCompile Include="App.cpp" /> - <ClCompile Include="Dlg.cpp" /> - <ClCompile Include="..\..\package_bgs\AdaptiveBackgroundLearning.cpp" /> - <ClCompile Include="..\..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" /> - <ClCompile Include="..\..\package_bgs\ae\KDE.cpp" /> - <ClCompile Include="..\..\package_bgs\ae\KernelTable.cpp" /> - <ClCompile Include="..\..\package_bgs\ae\NPBGmodel.cpp" /> - <ClCompile Include="..\..\package_bgs\ae\NPBGSubtractor.cpp" /> - <ClCompile Include="..\..\package_bgs\av\TBackground.cpp" /> - <ClCompile Include="..\..\package_bgs\av\TBackgroundVuMeter.cpp" /> - <ClCompile Include="..\..\package_bgs\av\VuMeter.cpp" /> - <ClCompile Include="..\..\package_bgs\bl\sdLaMa091.cpp" /> - <ClCompile Include="..\..\package_bgs\bl\SigmaDeltaBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\db\imbs.cpp" /> - <ClCompile Include="..\..\package_bgs\db\IndependentMultimodalBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\AdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPEigenbackgroundBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPGrimsonGMMBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPMeanBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPPratiMediodBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPTextureBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPWrenGABGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\Eigenbackground.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\Error.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\GrimsonGMM.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\Image.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\MeanBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\PratiMediodBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\TextureBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\WrenGA.cpp" /> - <ClCompile Include="..\..\package_bgs\dp\ZivkovicAGMM.cpp" /> - <ClCompile Include="..\..\package_bgs\FrameDifferenceBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\GMG.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\blob.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\BlobExtraction.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\BlobResult.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\CMultiLayerBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\LocalBinaryPattern.cpp" /> - <ClCompile Include="..\..\package_bgs\jmo\MultiLayerBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModel.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModelFuzzyGauss.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModelFuzzySom.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModelGauss.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModelMog.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\BGModelSom.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\LBAdaptiveSOM.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\LBFuzzyGaussian.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\LBMixtureOfGaussians.cpp" /> - <ClCompile Include="..\..\package_bgs\lb\LBSimpleGaussian.cpp" /> - <ClCompile Include="..\..\package_bgs\MixtureOfGaussianV1BGS.cpp" /> - <ClCompile Include="..\..\package_bgs\MixtureOfGaussianV2BGS.cpp" /> - <ClCompile Include="..\..\package_bgs\sjn\SJN_MultiCueBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\StaticFrameDifferenceBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\FuzzyChoquetIntegral.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\FuzzySugenoIntegral.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\FuzzyUtils.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\MRF.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\PerformanceUtils.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\PixelUtils.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM_UM.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM_UV.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF_UM.cpp" /> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF_UV.cpp" /> - <ClCompile Include="..\..\package_bgs\WeightedMovingMeanBGS.cpp" /> - <ClCompile Include="..\..\package_bgs\WeightedMovingVarianceBGS.cpp" /> - <ClCompile Include="stdafx.cpp"> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="bgslibrary_vs2010_mfc.rc" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> - <ProjectExtensions> - <VisualStudio> - <UserProperties RESOURCE_FILE="bgslibrary_vs2010_mfc.rc" /> - </VisualStudio> - </ProjectExtensions> -</Project> \ No newline at end of file diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.filters b/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.filters deleted file mode 100644 index 28d979d..0000000 --- a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.filters +++ /dev/null @@ -1,581 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - <Filter Include="Header Files\package_bgs"> - <UniqueIdentifier>{be6b45b0-e96c-4347-a65e-a72506b4195f}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\av"> - <UniqueIdentifier>{c4756493-26d9-46f4-93d6-024b4d1ca61a}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\dp"> - <UniqueIdentifier>{a3dff805-136a-4fc5-a8e9-a7eadebcd6f2}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\jmo"> - <UniqueIdentifier>{d9c40f02-d18f-46bb-a956-522e83a8a2e7}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\lb"> - <UniqueIdentifier>{77576fcd-de50-4205-8072-cb25a1aab145}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\tb"> - <UniqueIdentifier>{50f16e47-ef1d-46b0-a0cb-f7c07599cd21}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ae"> - <UniqueIdentifier>{704bbcb4-9bbe-4fe1-8a80-78ee8d7f49c5}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\sjn"> - <UniqueIdentifier>{d365878b-8639-4bfd-8008-adb158c9cd8b}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\db"> - <UniqueIdentifier>{f7961eef-2755-4712-a9b7-1b840b7936b1}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\bl"> - <UniqueIdentifier>{e23418b4-562b-41ae-bd15-e9ad45ece1d1}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pl"> - <UniqueIdentifier>{2a0f8129-33e2-4829-a112-edba4c8f5ef6}</UniqueIdentifier> - </Filter> - </ItemGroup> - <ItemGroup> - <None Include="ReadMe.txt" /> - <None Include="res\bgslibrary_vs2010_mfc.rc2"> - <Filter>Resource Files</Filter> - </None> - <None Include="res\bgslibrary_vs2010_mfc.ico"> - <Filter>Resource Files</Filter> - </None> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - </ItemGroup> - <ItemGroup> - <ClInclude Include="Dlg.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="stdafx.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="targetver.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="Resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="App.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\AdaptiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\FrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\GMG.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\IBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\MixtureOfGaussianV1BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\MixtureOfGaussianV2BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\StaticFrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\WeightedMovingMeanBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\WeightedMovingVarianceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\av\TBackground.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\av\TBackgroundVuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\av\VuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\BackgroundSubtractionAPI.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\BGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\blob.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\BlobExtraction.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\BlobLibraryConfiguration.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\BlobResult.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\CMultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\LocalBinaryPattern.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\MultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\jmo\OpenCvDataConversion.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModel.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModelFuzzyGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModelFuzzySom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModelGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModelMog.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\BGModelSom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\LBAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\LBFuzzyAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\LBFuzzyGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\LBMixtureOfGaussians.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\LBSimpleGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\lb\Types.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\FuzzyChoquetIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\FuzzySugenoIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\FuzzyUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\MRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\PerformanceUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\PixelUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FGMM_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\tb\T2FMRF_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\ae\KDE.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\ae\KernelTable.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\ae\NPBGmodel.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\ae\NPBGSubtractor.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\AdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\Bgs.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\BgsParams.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPAdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPEigenbackgroundBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPGrimsonGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPMeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPPratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPTextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPWrenGABGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\DPZivkovicAGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\Eigenbackground.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\Error.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\GrimsonGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\Image.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\MeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\PratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\TextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\WrenGA.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\dp\ZivkovicAGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\sjn\SJN_MultiCueBGS.h"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\db\imbs.hpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\db\IndependentMultimodalBGS.h"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\AdaptiveSelectiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\bl\sdLaMa091.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\bl\SigmaDeltaBGS.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\bl\stdbool.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorLBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorLOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\DistanceUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\LBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\LOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\RandUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\..\package_bgs\pl\SuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ClCompile Include="Dlg.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="stdafx.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="App.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\AdaptiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\FrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\GMG.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\MixtureOfGaussianV1BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\MixtureOfGaussianV2BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\StaticFrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\WeightedMovingMeanBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\WeightedMovingVarianceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\av\TBackground.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\av\TBackgroundVuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\av\VuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\blob.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\BlobExtraction.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\BlobResult.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\CMultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\LocalBinaryPattern.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\jmo\MultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModel.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModelFuzzyGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModelFuzzySom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModelGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModelMog.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\BGModelSom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\LBAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\LBFuzzyGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\LBMixtureOfGaussians.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\lb\LBSimpleGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\FuzzyChoquetIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\FuzzySugenoIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\FuzzyUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\MRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\PerformanceUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\PixelUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FGMM_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\tb\T2FMRF_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\ae\KDE.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\ae\KernelTable.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\ae\NPBGmodel.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\ae\NPBGSubtractor.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\AdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPAdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPEigenbackgroundBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPGrimsonGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPMeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPPratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPTextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPWrenGABGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\DPZivkovicAGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\Eigenbackground.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\Error.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\GrimsonGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\Image.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\MeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\PratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\TextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\WrenGA.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\dp\ZivkovicAGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\sjn\SJN_MultiCueBGS.cpp"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\db\imbs.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\db\IndependentMultimodalBGS.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\bl\sdLaMa091.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\bl\SigmaDeltaBGS.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorLBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\LBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\LOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\..\package_bgs\pl\SuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="bgslibrary_vs2010_mfc.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.user b/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.user deleted file mode 100644 index 882b48c..0000000 --- a/vs2010mfc/src/bgslibrary_vs2010_mfc.vcxproj.user +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - </PropertyGroup> -</Project> \ No newline at end of file diff --git a/vs2010mfc/src/res/bgslibrary_vs2010_mfc.ico b/vs2010mfc/src/res/bgslibrary_vs2010_mfc.ico deleted file mode 100644 index d56fbcdfdf6eac0f4727c34770c26689271d96af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67777 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 diff --git a/vs2010mfc/src/res/bgslibrary_vs2010_mfc.rc2 b/vs2010mfc/src/res/bgslibrary_vs2010_mfc.rc2 deleted file mode 100644 index e327fa85913f2210efffc3a01eb0194aadda29e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 826 zcmezWPoF`bftP`c0Yob>Br&8j6f@*7WHKZ%6fq<+6fsmX#50sJ6f+nx7%&(z7%;>$ z<T9i&Bs1tS1Ti=>7%?a?=rSlU6fvYS6f@*Alrj`CB!k%s489DR49N^d4EbQ0G=>re z1%@z&Oon2HQieo^90mmjX9jHsZ3YE~6o!1Lo;-$pu)0)+6oyPN3q*rVPi81#$YH32 zyA|YS5LRZ$WJqI3VMt|2V^CmlWC&mgW(Z*jWpH8eWbkK*XYge3V+dpLXYgilWpDxO zR%S?LC<42yh(Up&gdqd$CIyBxhD?SWhExUxC?DM|i3~|l`6Px)2IBn(ab+q)9@tMH zSAxQt7?*-{f-p$^;KVT3fkHloA%#JKA(tVMArBhEp!iZ?fW;+<#-36#z%i1_pa+H^ OGeLN8`WWOYkm~?zwr!vQ diff --git a/vs2013/.gitignore b/vs2013/.gitignore deleted file mode 100644 index e289c95..0000000 --- a/vs2013/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Ignore everything in this directory -* -# Except these files -!.gitignore -!bgslibrary.sln -!bgslibrary.suo -!bgslibrary.vcxproj -!bgslibrary.vcxproj.filters -!bgslibrary.vcxproj.user -!README.txt \ No newline at end of file diff --git a/vs2013/README.txt b/vs2013/README.txt deleted file mode 100644 index e090e33..0000000 --- a/vs2013/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -VISUAL STUDIO 2013 TEMPLATE PROJECT ------------------------------------ -Select [Release][Win32] or [Release][x64] - -YOU NEEDS TO INSTALL OPENCV AT: - C:\OpenCV2.4.10 - -BUILD AND RUN! \ No newline at end of file diff --git a/vs2013/bgslibrary.sln b/vs2013/bgslibrary.sln deleted file mode 100644 index 8013b8e..0000000 --- a/vs2013/bgslibrary.sln +++ /dev/null @@ -1,40 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bgslibrary", "bgslibrary.vcxproj", "{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - ReleaseDemo|Win32 = ReleaseDemo|Win32 - ReleaseDemo|x64 = ReleaseDemo|x64 - ReleaseDemo2|Win32 = ReleaseDemo2|Win32 - ReleaseDemo2|x64 = ReleaseDemo2|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|Win32.ActiveCfg = Debug|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|Win32.Build.0 = Debug|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|x64.ActiveCfg = Debug|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Debug|x64.Build.0 = Debug|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.ActiveCfg = Release|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|Win32.Build.0 = Release|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|x64.ActiveCfg = Release|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.Release|x64.Build.0 = Release|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo|Win32.ActiveCfg = ReleaseDemo|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo|Win32.Build.0 = ReleaseDemo|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo|x64.ActiveCfg = ReleaseDemo|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo|x64.Build.0 = ReleaseDemo|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo2|Win32.ActiveCfg = ReleaseDemo2|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo2|Win32.Build.0 = ReleaseDemo2|Win32 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo2|x64.ActiveCfg = ReleaseDemo2|x64 - {3B6BF763-9CDE-4859-ADD9-8EB7B282659F}.ReleaseDemo2|x64.Build.0 = ReleaseDemo2|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/vs2013/bgslibrary.suo b/vs2013/bgslibrary.suo deleted file mode 100644 index 3dc8e43797f0d1ee8f60b5d84b6328c180a83479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11776 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 MgV7|qf1s5E0LfUny8r+H diff --git a/vs2013/bgslibrary.vcxproj b/vs2013/bgslibrary.vcxproj deleted file mode 100644 index de8e328..0000000 --- a/vs2013/bgslibrary.vcxproj +++ /dev/null @@ -1,600 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup Label="ProjectConfigurations"> - <ProjectConfiguration Include="Debug|Win32"> - <Configuration>Debug</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Debug|x64"> - <Configuration>Debug</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="ReleaseDemo2|Win32"> - <Configuration>ReleaseDemo2</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="ReleaseDemo2|x64"> - <Configuration>ReleaseDemo2</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="ReleaseDemo|Win32"> - <Configuration>ReleaseDemo</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="ReleaseDemo|x64"> - <Configuration>ReleaseDemo</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|Win32"> - <Configuration>Release</Configuration> - <Platform>Win32</Platform> - </ProjectConfiguration> - <ProjectConfiguration Include="Release|x64"> - <Configuration>Release</Configuration> - <Platform>x64</Platform> - </ProjectConfiguration> - </ItemGroup> - <PropertyGroup Label="Globals"> - <ProjectGuid>{3B6BF763-9CDE-4859-ADD9-8EB7B282659F}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>bgslibrary</RootNamespace> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - <PlatformToolset>v120</PlatformToolset> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> - <ImportGroup Label="ExtensionSettings"> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'" Label="PropertySheets"> - <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> - </ImportGroup> - <PropertyGroup Label="UserMacros" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <LinkIncremental>true</LinkIncremental> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <LinkIncremental>true</LinkIncremental> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\</OutDir> - <IntDir>$(Platform)\$(Configuration)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>../</OutDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\</OutDir> - <TargetName>Demo</TargetName> - <IntDir>$(Platform)\$(Configuration)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'"> - <TargetName>Demo</TargetName> - <LinkIncremental>false</LinkIncremental> - <OutDir>../</OutDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>..\</OutDir> - <TargetName>Demo2</TargetName> - <IntDir>$(Platform)\$(Configuration)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'"> - <TargetName>Demo2</TargetName> - <LinkIncremental>false</LinkIncremental> - <OutDir>../</OutDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <PrecompiledHeader> - </PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <PrecompiledHeader> - </PrecompiledHeader> - <WarningLevel>Level3</WarningLevel> - <Optimization>Disabled</Optimization> - <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x64\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x64\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x86\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <PrecompiledHeader> - </PrecompiledHeader> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <AdditionalIncludeDirectories>C:\OpenCV2.4.10\build\include;C:\OpenCV2.4.10\build\include\opencv;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <AdditionalDependencies>C:\OpenCV2.4.10\build\x64\vc12\staticlib\*.lib;comctl32.lib;VFW32.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="..\Demo.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">true</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\Demo2.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\FrameProcessor.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\Main.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">true</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">true</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" /> - <ClCompile Include="..\package_bgs\ae\KDE.cpp" /> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp" /> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackground.cpp" /> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp" /> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp" /> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp" /> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp" /> - <ClCompile Include="..\package_bgs\ck\graph.cpp" /> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp" /> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp" /> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp" /> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp" /> - <ClCompile Include="..\package_bgs\db\imbs.cpp" /> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp" /> - <ClCompile Include="..\package_bgs\dp\Error.cpp" /> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp" /> - <ClCompile Include="..\package_bgs\dp\Image.cpp" /> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp" /> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp" /> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp" /> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\GMG.cpp" /> - <ClCompile Include="..\package_bgs\jmo\blob.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp" /> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp" /> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp" /> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp" /> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp" /> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp" /> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp" /> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp" /> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp" /> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp" /> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp" /> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\MRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp" /> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp" /> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp" /> - <ClCompile Include="..\PreProcessor.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\VideoAnalysis.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClCompile> - <ClCompile Include="..\VideoCapture.cpp"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\Config.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\FrameProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\IFrameProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h" /> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h" /> - <ClInclude Include="..\package_bgs\ae\KDE.h" /> - <ClInclude Include="..\package_bgs\ae\KernelTable.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h" /> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h" /> - <ClInclude Include="..\package_bgs\av\TBackground.h" /> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h" /> - <ClInclude Include="..\package_bgs\av\VuMeter.h" /> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h" /> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h" /> - <ClInclude Include="..\package_bgs\bl\stdbool.h" /> - <ClInclude Include="..\package_bgs\ck\block.h" /> - <ClInclude Include="..\package_bgs\ck\graph.h" /> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h" /> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp" /> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp" /> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp" /> - <ClInclude Include="..\package_bgs\db\imbs.hpp" /> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h" /> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Bgs.h" /> - <ClInclude Include="..\package_bgs\dp\BgsParams.h" /> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h" /> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h" /> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h" /> - <ClInclude Include="..\package_bgs\dp\Error.h" /> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h" /> - <ClInclude Include="..\package_bgs\dp\Image.h" /> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h" /> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h" /> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h" /> - <ClInclude Include="..\package_bgs\dp\WrenGA.h" /> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h" /> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\GMG.h" /> - <ClInclude Include="..\package_bgs\IBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h" /> - <ClInclude Include="..\package_bgs\jmo\BGS.h" /> - <ClInclude Include="..\package_bgs\jmo\blob.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h" /> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h" /> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h" /> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h" /> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h" /> - <ClInclude Include="..\package_bgs\lb\BGModel.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h" /> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h" /> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h" /> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h" /> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h" /> - <ClInclude Include="..\package_bgs\lb\Types.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h" /> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h" /> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h" /> - <ClInclude Include="..\package_bgs\pl\LBSP.h" /> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h" /> - <ClInclude Include="..\package_bgs\pl\RandUtils.h" /> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h" /> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h" /> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h" /> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h" /> - <ClInclude Include="..\package_bgs\tb\MRF.h" /> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h" /> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h" /> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h" /> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h" /> - <ClInclude Include="..\PreProcessor.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\VideoAnalysis.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - <ClInclude Include="..\VideoCapture.h"> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'">false</ExcludedFromBuild> - <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'">false</ExcludedFromBuild> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i" /> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project> \ No newline at end of file diff --git a/vs2013/bgslibrary.vcxproj.filters b/vs2013/bgslibrary.vcxproj.filters deleted file mode 100644 index ab0fbf0..0000000 --- a/vs2013/bgslibrary.vcxproj.filters +++ /dev/null @@ -1,644 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <Filter Include="Source Files"> - <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> - <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> - </Filter> - <Filter Include="Header Files"> - <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> - <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> - </Filter> - <Filter Include="Resource Files"> - <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> - <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> - </Filter> - <Filter Include="Header Files\package_bgs"> - <UniqueIdentifier>{8cb396e6-81b6-4db9-a1b0-5c2b7c122bd9}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ae"> - <UniqueIdentifier>{e1ab6d45-3486-42fa-8f51-69a300c0c173}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\av"> - <UniqueIdentifier>{7992fa8c-e616-4e72-b249-6ede4f4291b4}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\db"> - <UniqueIdentifier>{667f4048-d125-4453-9f0c-42f9abd4ed3a}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\dp"> - <UniqueIdentifier>{89c4b817-936b-483c-abed-3e7e7c1fc427}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\jmo"> - <UniqueIdentifier>{c5e0f44c-6120-4906-917d-c8c8af3eafec}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\lb"> - <UniqueIdentifier>{728fbe82-1489-4878-89ea-a62ba0932204}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pt"> - <UniqueIdentifier>{6b017402-c47a-49a4-8f57-b5db863e1bde}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\sjn"> - <UniqueIdentifier>{e25c1e03-530d-4c7a-b776-26bf17595213}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\tb"> - <UniqueIdentifier>{53f2c4fb-9468-44ce-b76e-e25ea018c084}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files\demo"> - <UniqueIdentifier>{23f1cd4a-e9b2-4338-a5e7-128f451d3c89}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_analysis"> - <UniqueIdentifier>{52a9f254-d817-4577-96c2-0b3b0a9527b7}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\bl"> - <UniqueIdentifier>{0494c5d4-b4bb-421c-b032-176903ba8e1b}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\ck"> - <UniqueIdentifier>{87961eee-b843-45bd-b642-9dcd9d78b661}</UniqueIdentifier> - </Filter> - <Filter Include="Header Files\package_bgs\pl"> - <UniqueIdentifier>{cd33a41f-6151-46a5-95b6-b79022786144}</UniqueIdentifier> - </Filter> - </ItemGroup> - <ItemGroup> - <ClCompile Include="..\package_bgs\AdaptiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\FrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\GMG.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV1BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\MixtureOfGaussianV2BGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\StaticFrameDifferenceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingMeanBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\WeightedMovingVarianceBGS.cpp"> - <Filter>Header Files\package_bgs</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KDE.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\KernelTable.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGmodel.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ae\NPBGSubtractor.cpp"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackground.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\TBackgroundVuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\av\VuMeter.cpp"> - <Filter>Header Files\package_bgs\av</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\imbs.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\db\IndependentMultimodalBGS.cpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\AdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPAdaptiveMedianBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPEigenbackgroundBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPGrimsonGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPMeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPPratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPTextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPWrenGABGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\DPZivkovicAGMMBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Eigenbackground.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Error.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\GrimsonGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\Image.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\MeanBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\PratiMediodBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\TextureBGS.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\WrenGA.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\dp\ZivkovicAGMM.cpp"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\blob.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobExtraction.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\BlobResult.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\CMultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\LocalBinaryPattern.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\jmo\MultiLayerBGS.cpp"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModel.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzyGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelFuzzySom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelGauss.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelMog.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\BGModelSom.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBFuzzyGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBMixtureOfGaussians.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\lb\LBSimpleGaussian.cpp"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\sjn\SJN_MultiCueBGS.cpp"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyChoquetIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzySugenoIntegral.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\FuzzyUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\MRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PerformanceUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\PixelUtils.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FGMM_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UM.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\tb\T2FMRF_UV.cpp"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClCompile> - <ClCompile Include="..\FrameProcessor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\Main.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\PreProcessor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\VideoAnalysis.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\VideoCapture.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="..\Demo.cpp"> - <Filter>Source Files\demo</Filter> - </ClCompile> - <ClCompile Include="..\package_analysis\ForegroundMaskAnalysis.cpp"> - <Filter>Header Files\package_analysis</Filter> - </ClCompile> - <ClCompile Include="..\Demo2.cpp"> - <Filter>Source Files\demo</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\SigmaDeltaBGS.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\bl\sdLaMa091.cpp"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\graph.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\LbpMrf.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\maxflow.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEDefs.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEHistogram.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MEImage.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\ck\MotionDetection.cpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LBSP.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\LOBSTER.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - <ClCompile Include="..\package_bgs\pl\SuBSENSE.cpp"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="..\package_bgs\AdaptiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\AdaptiveSelectiveBackgroundLearning.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\FrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\GMG.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\IBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV1BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\MixtureOfGaussianV2BGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\StaticFrameDifferenceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingMeanBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\WeightedMovingVarianceBGS.h"> - <Filter>Header Files\package_bgs</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KDE.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\KernelTable.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGmodel.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ae\NPBGSubtractor.h"> - <Filter>Header Files\package_bgs\ae</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackground.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\TBackgroundVuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\av\VuMeter.h"> - <Filter>Header Files\package_bgs\av</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\imbs.hpp"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\db\IndependentMultimodalBGS.h"> - <Filter>Header Files\package_bgs\db</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\AdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Bgs.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\BgsParams.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPAdaptiveMedianBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPEigenbackgroundBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPGrimsonGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPMeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPPratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPTextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPWrenGABGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\DPZivkovicAGMMBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Eigenbackground.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Error.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\GrimsonGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\Image.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\MeanBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\PratiMediodBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\TextureBGS.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\WrenGA.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\dp\ZivkovicAGMM.h"> - <Filter>Header Files\package_bgs\dp</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BackgroundSubtractionAPI.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\blob.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobExtraction.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobLibraryConfiguration.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\BlobResult.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\CMultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\LocalBinaryPattern.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\MultiLayerBGS.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\jmo\OpenCvDataConversion.h"> - <Filter>Header Files\package_bgs\jmo</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModel.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzyGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelFuzzySom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelGauss.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelMog.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\BGModelSom.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyAdaptiveSOM.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBFuzzyGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBMixtureOfGaussians.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\LBSimpleGaussian.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\lb\Types.h"> - <Filter>Header Files\package_bgs\lb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\sjn\SJN_MultiCueBGS.h"> - <Filter>Header Files\package_bgs\sjn</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyChoquetIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzySugenoIntegral.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\FuzzyUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\MRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PerformanceUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\PixelUtils.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FGMM_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UM.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\tb\T2FMRF_UV.h"> - <Filter>Header Files\package_bgs\tb</Filter> - </ClInclude> - <ClInclude Include="..\Config.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\FrameProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\IFrameProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\PreProcessor.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\VideoAnalysis.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\VideoCapture.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\package_analysis\ForegroundMaskAnalysis.h"> - <Filter>Header Files\package_analysis</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\sdLaMa091.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\SigmaDeltaBGS.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\bl\stdbool.h"> - <Filter>Header Files\package_bgs\bl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\block.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\graph.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\LbpMrf.h"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEDefs.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEHistogram.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MEImage.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\ck\MotionDetection.hpp"> - <Filter>Header Files\package_bgs\ck</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorLOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\BackgroundSubtractorSuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\DistanceUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LBSP.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\LOBSTER.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\RandUtils.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - <ClInclude Include="..\package_bgs\pl\SuBSENSE.h"> - <Filter>Header Files\package_bgs\pl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_1ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch1t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_3ch3t.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - <None Include="..\package_bgs\pl\LBSP_16bits_dbcross_s3ch.i"> - <Filter>Header Files\package_bgs\pl</Filter> - </None> - </ItemGroup> -</Project> \ No newline at end of file diff --git a/vs2013/bgslibrary.vcxproj.user b/vs2013/bgslibrary.vcxproj.user deleted file mode 100644 index 02146ba..0000000 --- a/vs2013/bgslibrary.vcxproj.user +++ /dev/null @@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments>-uf=true -fn=dataset/video.avi</LocalDebuggerCommandArguments> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments>-uf=true -fn=dataset/video.avi</LocalDebuggerCommandArguments> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|Win32'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments> - </LocalDebuggerCommandArguments> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo|x64'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments /> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|Win32'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments /> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseDemo2|x64'"> - <LocalDebuggerWorkingDirectory>../</LocalDebuggerWorkingDirectory> - <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> - <LocalDebuggerCommandArguments /> - </PropertyGroup> -</Project> \ No newline at end of file diff --git a/vs2013mfc/.gitignore b/vs2013mfc/.gitignore deleted file mode 100644 index fc99052..0000000 --- a/vs2013mfc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.exe -*.pdb -*.dll \ No newline at end of file diff --git a/vs2013mfc/config/AdaptiveBackgroundLearning.xml b/vs2013mfc/config/AdaptiveBackgroundLearning.xml deleted file mode 100644 index 313e1d4..0000000 --- a/vs2013mfc/config/AdaptiveBackgroundLearning.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<alpha>5.0000000000000003e-002</alpha> -<limit>-1</limit> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showForeground>0</showForeground> -<showBackground>0</showBackground> -</opencv_storage> diff --git a/vs2013mfc/config/AdaptiveSelectiveBackgroundLearning.xml b/vs2013mfc/config/AdaptiveSelectiveBackgroundLearning.xml deleted file mode 100644 index f175558..0000000 --- a/vs2013mfc/config/AdaptiveSelectiveBackgroundLearning.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<learningFrames>90</learningFrames> -<alphaLearn>5.0000000000000003e-002</alphaLearn> -<alphaDetection>5.0000000000000003e-002</alphaDetection> -<threshold>25</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPAdaptiveMedianBGS.xml b/vs2013mfc/config/DPAdaptiveMedianBGS.xml deleted file mode 100644 index 8d09e85..0000000 --- a/vs2013mfc/config/DPAdaptiveMedianBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>40</threshold> -<samplingRate>7</samplingRate> -<learningFrames>30</learningFrames> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPEigenbackgroundBGS.xml b/vs2013mfc/config/DPEigenbackgroundBGS.xml deleted file mode 100644 index d610426..0000000 --- a/vs2013mfc/config/DPEigenbackgroundBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>225</threshold> -<historySize>20</historySize> -<embeddedDim>10</embeddedDim> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPGrimsonGMMBGS.xml b/vs2013mfc/config/DPGrimsonGMMBGS.xml deleted file mode 100644 index 8ade44f..0000000 --- a/vs2013mfc/config/DPGrimsonGMMBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>9.</threshold> -<alpha>1.0000000000000000e-002</alpha> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPMeanBGS.xml b/vs2013mfc/config/DPMeanBGS.xml deleted file mode 100644 index 9bd59a8..0000000 --- a/vs2013mfc/config/DPMeanBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>2700</threshold> -<alpha>9.9999999747524271e-007</alpha> -<learningFrames>30</learningFrames> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPPratiMediodBGS.xml b/vs2013mfc/config/DPPratiMediodBGS.xml deleted file mode 100644 index fdf20b4..0000000 --- a/vs2013mfc/config/DPPratiMediodBGS.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>30</threshold> -<samplingRate>5</samplingRate> -<historySize>16</historySize> -<weight>5</weight> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPTextureBGS.xml b/vs2013mfc/config/DPTextureBGS.xml deleted file mode 100644 index 0d63e78..0000000 --- a/vs2013mfc/config/DPTextureBGS.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPWrenGABGS.xml b/vs2013mfc/config/DPWrenGABGS.xml deleted file mode 100644 index 7eaa78b..0000000 --- a/vs2013mfc/config/DPWrenGABGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>1.2250000000000000e+001</threshold> -<alpha>4.9999998882412910e-003</alpha> -<learningFrames>30</learningFrames> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/DPZivkovicAGMMBGS.xml b/vs2013mfc/config/DPZivkovicAGMMBGS.xml deleted file mode 100644 index 98ee82a..0000000 --- a/vs2013mfc/config/DPZivkovicAGMMBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>25.</threshold> -<alpha>1.0000000474974513e-003</alpha> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/FrameDifferenceBGS.xml b/vs2013mfc/config/FrameDifferenceBGS.xml deleted file mode 100644 index 943a6c9..0000000 --- a/vs2013mfc/config/FrameDifferenceBGS.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/FuzzyChoquetIntegral.xml b/vs2013mfc/config/FuzzyChoquetIntegral.xml deleted file mode 100644 index 22074aa..0000000 --- a/vs2013mfc/config/FuzzyChoquetIntegral.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<showOutput>0</showOutput> -<framesToLearn>10</framesToLearn> -<alphaLearn>1.0000000000000001e-001</alphaLearn> -<alphaUpdate>1.0000000000000000e-002</alphaUpdate> -<colorSpace>1</colorSpace> -<option>2</option> -<smooth>1</smooth> -<threshold>6.7000000000000004e-001</threshold> -</opencv_storage> diff --git a/vs2013mfc/config/FuzzySugenoIntegral.xml b/vs2013mfc/config/FuzzySugenoIntegral.xml deleted file mode 100644 index 22074aa..0000000 --- a/vs2013mfc/config/FuzzySugenoIntegral.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<showOutput>0</showOutput> -<framesToLearn>10</framesToLearn> -<alphaLearn>1.0000000000000001e-001</alphaLearn> -<alphaUpdate>1.0000000000000000e-002</alphaUpdate> -<colorSpace>1</colorSpace> -<option>2</option> -<smooth>1</smooth> -<threshold>6.7000000000000004e-001</threshold> -</opencv_storage> diff --git a/vs2013mfc/config/GMG.xml b/vs2013mfc/config/GMG.xml deleted file mode 100644 index e3ebdc7..0000000 --- a/vs2013mfc/config/GMG.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<initializationFrames>20</initializationFrames> -<decisionThreshold>6.9999999999999996e-001</decisionThreshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/IndependentMultimodalBGS.xml b/vs2013mfc/config/IndependentMultimodalBGS.xml deleted file mode 100644 index 0d63e78..0000000 --- a/vs2013mfc/config/IndependentMultimodalBGS.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/KDE.xml b/vs2013mfc/config/KDE.xml deleted file mode 100644 index c9b7402..0000000 --- a/vs2013mfc/config/KDE.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<framesToLearn>10</framesToLearn> -<SequenceLength>50</SequenceLength> -<TimeWindowSize>100</TimeWindowSize> -<SDEstimationFlag>1</SDEstimationFlag> -<lUseColorRatiosFlag>1</lUseColorRatiosFlag> -<th>9.9999999999999995e-008</th> -<alpha>2.9999999999999999e-001</alpha> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LBAdaptiveSOM.xml b/vs2013mfc/config/LBAdaptiveSOM.xml deleted file mode 100644 index 94b2570..0000000 --- a/vs2013mfc/config/LBAdaptiveSOM.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<sensitivity>75</sensitivity> -<trainingSensitivity>245</trainingSensitivity> -<learningRate>62</learningRate> -<trainingLearningRate>255</trainingLearningRate> -<trainingSteps>55</trainingSteps> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LBFuzzyAdaptiveSOM.xml b/vs2013mfc/config/LBFuzzyAdaptiveSOM.xml deleted file mode 100644 index 7168563..0000000 --- a/vs2013mfc/config/LBFuzzyAdaptiveSOM.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<sensitivity>90</sensitivity> -<trainingSensitivity>240</trainingSensitivity> -<learningRate>38</learningRate> -<trainingLearningRate>255</trainingLearningRate> -<trainingSteps>81</trainingSteps> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LBFuzzyGaussian.xml b/vs2013mfc/config/LBFuzzyGaussian.xml deleted file mode 100644 index 18635a1..0000000 --- a/vs2013mfc/config/LBFuzzyGaussian.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<sensitivity>72</sensitivity> -<bgThreshold>162</bgThreshold> -<learningRate>49</learningRate> -<noiseVariance>195</noiseVariance> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LBMixtureOfGaussians.xml b/vs2013mfc/config/LBMixtureOfGaussians.xml deleted file mode 100644 index 2273720..0000000 --- a/vs2013mfc/config/LBMixtureOfGaussians.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<sensitivity>81</sensitivity> -<bgThreshold>83</bgThreshold> -<learningRate>59</learningRate> -<noiseVariance>206</noiseVariance> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LBSimpleGaussian.xml b/vs2013mfc/config/LBSimpleGaussian.xml deleted file mode 100644 index a803f3f..0000000 --- a/vs2013mfc/config/LBSimpleGaussian.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<sensitivity>66</sensitivity> -<noiseVariance>162</noiseVariance> -<learningRate>18</learningRate> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/LOBSTERBGS.xml b/vs2013mfc/config/LOBSTERBGS.xml deleted file mode 100644 index c17b551..0000000 --- a/vs2013mfc/config/LOBSTERBGS.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<fRelLBSPThreshold>3.6500000953674316e-001</fRelLBSPThreshold> -<nLBSPThresholdOffset>0</nLBSPThresholdOffset> -<nDescDistThreshold>4</nDescDistThreshold> -<nColorDistThreshold>30</nColorDistThreshold> -<nBGSamples>35</nBGSamples> -<nRequiredBGSamples>2</nRequiredBGSamples> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/MixtureOfGaussianV1BGS.xml b/vs2013mfc/config/MixtureOfGaussianV1BGS.xml deleted file mode 100644 index 1e09ceb..0000000 --- a/vs2013mfc/config/MixtureOfGaussianV1BGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<alpha>5.0000000000000003e-002</alpha> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/MixtureOfGaussianV2BGS.xml b/vs2013mfc/config/MixtureOfGaussianV2BGS.xml deleted file mode 100644 index 1e09ceb..0000000 --- a/vs2013mfc/config/MixtureOfGaussianV2BGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<alpha>5.0000000000000003e-002</alpha> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/MultiCueBGS.xml b/vs2013mfc/config/MultiCueBGS.xml deleted file mode 100644 index 0d63e78..0000000 --- a/vs2013mfc/config/MultiCueBGS.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/MultiLayerBGS.xml b/vs2013mfc/config/MultiLayerBGS.xml deleted file mode 100644 index 9b803db..0000000 --- a/vs2013mfc/config/MultiLayerBGS.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<preloadModel>"./models/MultiLayerBGSModel.yml"</preloadModel> -<saveModel>0</saveModel> -<detectAfter>0</detectAfter> -<disableDetectMode>1</disableDetectMode> -<disableLearningInDetecMode>0</disableLearningInDetecMode> -<loadDefaultParams>1</loadDefaultParams> -<max_mode_num>5</max_mode_num> -<weight_updating_constant>5.</weight_updating_constant> -<texture_weight>5.0000000000000000e-001</texture_weight> -<bg_mode_percent>6.0000002384185791e-001</bg_mode_percent> -<pattern_neig_half_size>4</pattern_neig_half_size> -<pattern_neig_gaus_sigma>3.</pattern_neig_gaus_sigma> -<bg_prob_threshold>2.0000000298023224e-001</bg_prob_threshold> -<bg_prob_updating_threshold>2.0000000298023224e-001</bg_prob_updating_threshold> -<robust_LBP_constant>3</robust_LBP_constant> -<min_noised_angle>1.7453293502330780e-001</min_noised_angle> -<shadow_rate>6.0000002384185791e-001</shadow_rate> -<highlight_rate>1.2000000476837158e+000</highlight_rate> -<bilater_filter_sigma_s>3.</bilater_filter_sigma_s> -<bilater_filter_sigma_r>1.0000000149011612e-001</bilater_filter_sigma_r> -<frame_duration>1.0000000149011612e-001</frame_duration> -<learn_mode_learn_rate_per_second>5.0000000000000000e-001</learn_mode_learn_rate_per_second> -<learn_weight_learn_rate_per_second>5.0000000000000000e-001</learn_weight_learn_rate_per_second> -<learn_init_mode_weight>5.0000000745058060e-002</learn_init_mode_weight> -<detect_mode_learn_rate_per_second>9.9999997764825821e-003</detect_mode_learn_rate_per_second> -<detect_weight_learn_rate_per_second>9.9999997764825821e-003</detect_weight_learn_rate_per_second> -<detect_init_mode_weight>1.0000000474974513e-003</detect_init_mode_weight> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/SigmaDeltaBGS.xml b/vs2013mfc/config/SigmaDeltaBGS.xml deleted file mode 100644 index f1b2b2f..0000000 --- a/vs2013mfc/config/SigmaDeltaBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<ampFactor>1</ampFactor> -<minVar>15</minVar> -<maxVar>255</maxVar> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/StaticFrameDifferenceBGS.xml b/vs2013mfc/config/StaticFrameDifferenceBGS.xml deleted file mode 100644 index 943a6c9..0000000 --- a/vs2013mfc/config/StaticFrameDifferenceBGS.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/SuBSENSEBGS.xml b/vs2013mfc/config/SuBSENSEBGS.xml deleted file mode 100644 index 05509c1..0000000 --- a/vs2013mfc/config/SuBSENSEBGS.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<fRelLBSPThreshold>3.3300000429153442e-001</fRelLBSPThreshold> -<nDescDistThresholdOffset>3</nDescDistThresholdOffset> -<nMinColorDistThreshold>30</nMinColorDistThreshold> -<nBGSamples>50</nBGSamples> -<nRequiredBGSamples>2</nRequiredBGSamples> -<nSamplesForMovingAvgs>100</nSamplesForMovingAvgs> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/T2FGMM_UM.xml b/vs2013mfc/config/T2FGMM_UM.xml deleted file mode 100644 index d2f1054..0000000 --- a/vs2013mfc/config/T2FGMM_UM.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>9.</threshold> -<alpha>1.0000000000000000e-002</alpha> -<km>1.5000000000000000e+000</km> -<kv>6.0000002384185791e-001</kv> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/T2FGMM_UV.xml b/vs2013mfc/config/T2FGMM_UV.xml deleted file mode 100644 index d2f1054..0000000 --- a/vs2013mfc/config/T2FGMM_UV.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>9.</threshold> -<alpha>1.0000000000000000e-002</alpha> -<km>1.5000000000000000e+000</km> -<kv>6.0000002384185791e-001</kv> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/T2FMRF_UM.xml b/vs2013mfc/config/T2FMRF_UM.xml deleted file mode 100644 index 9a65c57..0000000 --- a/vs2013mfc/config/T2FMRF_UM.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>9.</threshold> -<alpha>1.0000000000000000e-002</alpha> -<km>2.</km> -<kv>8.9999997615814209e-001</kv> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/T2FMRF_UV.xml b/vs2013mfc/config/T2FMRF_UV.xml deleted file mode 100644 index 9a65c57..0000000 --- a/vs2013mfc/config/T2FMRF_UV.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<threshold>9.</threshold> -<alpha>1.0000000000000000e-002</alpha> -<km>2.</km> -<kv>8.9999997615814209e-001</kv> -<gaussians>3</gaussians> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/VuMeter.xml b/vs2013mfc/config/VuMeter.xml deleted file mode 100644 index d28fda7..0000000 --- a/vs2013mfc/config/VuMeter.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<enableFilter>1</enableFilter> -<binSize>8</binSize> -<alpha>9.9500000000000000e-001</alpha> -<threshold>2.9999999999999999e-002</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/config/WeightedMovingMeanBGS.xml b/vs2013mfc/config/WeightedMovingMeanBGS.xml deleted file mode 100644 index 008ad74..0000000 --- a/vs2013mfc/config/WeightedMovingMeanBGS.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<enableWeight>1</enableWeight> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -<showBackground>0</showBackground> -</opencv_storage> diff --git a/vs2013mfc/config/WeightedMovingVarianceBGS.xml b/vs2013mfc/config/WeightedMovingVarianceBGS.xml deleted file mode 100644 index d9de1d4..0000000 --- a/vs2013mfc/config/WeightedMovingVarianceBGS.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0"?> -<opencv_storage> -<enableWeight>1</enableWeight> -<enableThreshold>1</enableThreshold> -<threshold>15</threshold> -<showOutput>0</showOutput> -</opencv_storage> diff --git a/vs2013mfc/dataset/video.avi b/vs2013mfc/dataset/video.avi deleted file mode 100644 index a29f00658be7d05b10344859e6bee9a501a7a2b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1049784 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ü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%0DOBjHZ}0zW=cniIiGQi5 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 z%0D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ⅇo_@D0_ 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̽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%0AC0p0bmfKcqxpDc% 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%0Dt#eC>I0HRj*aRF2gwB`>%3J@qU2 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 diff --git a/vs2013mfc/src/.gitignore b/vs2013mfc/src/.gitignore deleted file mode 100644 index 4ad092e..0000000 --- a/vs2013mfc/src/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -Release/ -ipch/ -*.exe -*.pdb -*.sdf -*.opensdf \ No newline at end of file diff --git a/vs2013mfc/src/App.cpp b/vs2013mfc/src/App.cpp deleted file mode 100644 index a6f45c7..0000000 --- a/vs2013mfc/src/App.cpp +++ /dev/null @@ -1,94 +0,0 @@ - -// App.cpp : Defines the class behaviors for the application. -// - -#include "stdafx.h" -#include "App.h" -#include "Dlg.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - - -// CApp - -BEGIN_MESSAGE_MAP(CApp, CWinApp) - ON_COMMAND(ID_HELP, &CWinApp::OnHelp) -END_MESSAGE_MAP() - - -// CApp construction - -CApp::CApp() -{ - // support Restart Manager - m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; - - // TODO: add construction code here, - // Place all significant initialization in InitInstance -} - - -// The one and only CApp object - -CApp theApp; - - -// CApp initialization - -BOOL CApp::InitInstance() -{ - // InitCommonControlsEx() is required on Windows XP if an application - // manifest specifies use of ComCtl32.dll version 6 or later to enable - // visual styles. Otherwise, any window creation will fail. - INITCOMMONCONTROLSEX InitCtrls; - InitCtrls.dwSize = sizeof(InitCtrls); - // Set this to include all the common control classes you want to use - // in your application. - InitCtrls.dwICC = ICC_WIN95_CLASSES; - InitCommonControlsEx(&InitCtrls); - - CWinApp::InitInstance(); - - - AfxEnableControlContainer(); - - // Create the shell manager, in case the dialog contains - // any shell tree view or shell list view controls. - CShellManager *pShellManager = new CShellManager; - - // Standard initialization - // If you are not using these features and wish to reduce the size - // of your final executable, you should remove from the following - // the specific initialization routines you do not need - // Change the registry key under which our settings are stored - // TODO: You should modify this string to be something appropriate - // such as the name of your company or organization - SetRegistryKey(_T("Local AppWizard-Generated Applications")); - - CDlg dlg; - m_pMainWnd = &dlg; - INT_PTR nResponse = dlg.DoModal(); - if (nResponse == IDOK) - { - // TODO: Place code here to handle when the dialog is - // dismissed with OK - } - else if (nResponse == IDCANCEL) - { - // TODO: Place code here to handle when the dialog is - // dismissed with Cancel - } - - // Delete the shell manager created above. - if (pShellManager != NULL) - { - delete pShellManager; - } - - // Since the dialog has been closed, return FALSE so that we exit the - // application, rather than start the application's message pump. - return FALSE; -} - diff --git a/vs2013mfc/src/App.h b/vs2013mfc/src/App.h deleted file mode 100644 index 5ef9764..0000000 --- a/vs2013mfc/src/App.h +++ /dev/null @@ -1,32 +0,0 @@ - -// App.h : main header file for the application -// - -#pragma once - -#ifndef __AFXWIN_H__ - #error "include 'stdafx.h' before including this file for PCH" -#endif - -#include "resource.h" // main symbols - - -// CApp: -// See App.cpp for the implementation of this class -// - -class CApp : public CWinApp -{ -public: - CApp(); - -// Overrides -public: - virtual BOOL InitInstance(); - -// Implementation - - DECLARE_MESSAGE_MAP() -}; - -extern CApp theApp; \ No newline at end of file diff --git a/vs2013mfc/src/Dlg.cpp b/vs2013mfc/src/Dlg.cpp deleted file mode 100644 index f39249e..0000000 --- a/vs2013mfc/src/Dlg.cpp +++ /dev/null @@ -1,709 +0,0 @@ - -// Dlg.cpp : implementation file -// - -#include "stdafx.h" -#include "App.h" -#include "Dlg.h" -#include "afxdialogex.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - - -// CAboutDlg dialog used for App About - -class CAboutDlg : public CDialogEx -{ -public: - CAboutDlg(); - -// Dialog Data - enum { IDD = IDD_ABOUTBOX }; - - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - -// Implementation -protected: - DECLARE_MESSAGE_MAP() -}; - -CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) -{ -} - -void CAboutDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialogEx::DoDataExchange(pDX); -} - -BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) -END_MESSAGE_MAP() - - -// CDlg dialog - - - - -CDlg::CDlg(CWnd* pParent /*=NULL*/) - : CDialogEx(CDlg::IDD, pParent) -{ - m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); -} - -void CDlg::DoDataExchange(CDataExchange* pDX) -{ - CDialogEx::DoDataExchange(pDX); - DDX_Control(pDX, IDC_COMBO_BGSLIST, m_bgslist); - DDX_Control(pDX, IDC_LOG, m_log); - DDX_Control(pDX, IDC_INPUT_VIDEO, m_inputVideo); - DDX_Control(pDX, IDC_USE_WEBCAM, m_useWebCam); - DDX_Control(pDX, IDC_SPIN_WEBCAM_INDEX, m_spinWebCamIndex); - DDX_Control(pDX, IDC_EDIT_WEBCAM_INDEX, m_webCamIndex); - DDX_Control(pDX, IDC_FRAME_NUMBER, m_frameNumber); - DDX_Control(pDX, IDC_SAVE_FRAME, m_saveFrame); - DDX_Control(pDX, IDC_SAVE_MASK, m_saveMask); - DDX_Control(pDX, IDC_SAVE_BKG, m_saveBkg); - DDX_Control(pDX, IDC_IMG_SEQ, m_isImgSeq); - DDX_Control(pDX, IDC_EDIT_START_IDX, m_startIdx); - DDX_Control(pDX, IDC_EDIT_STOP_IDX, m_stopIdx); - DDX_Control(pDX, IDC_COMBO_FILE_TYPE, m_fileTypeList); - DDX_Control(pDX, IDC_SPIN_START_IDX, m_spinStartIdx); - DDX_Control(pDX, IDC_SPIN_STOP_IDX, m_spinStopIdx); - DDX_Control(pDX, IDC_EDIT_DELAY, m_delay); - DDX_Control(pDX, IDC_EXEC_TIME, m_execTime); - DDX_Control(pDX, IDC_MEDIAN_FILTER, m_medianFilter); -} - -BEGIN_MESSAGE_MAP(CDlg, CDialogEx) - ON_WM_SYSCOMMAND() - ON_WM_PAINT() - ON_WM_QUERYDRAGICON() - ON_BN_CLICKED(IDSTART, &CDlg::OnBnClickedStart) - ON_BN_CLICKED(IDSTOP, &CDlg::OnBnClickedStop) - ON_BN_CLICKED(IDC_USE_WEBCAM, &CDlg::OnBnClickedUseWebcam) - ON_BN_CLICKED(IDC_IMG_SEQ, &CDlg::OnBnClickedImgSeq) - ON_BN_CLICKED(IDSAVE, &CDlg::OnBnClickedSave) -END_MESSAGE_MAP() - - -// CDlg message handlers - -BOOL CDlg::OnInitDialog() -{ - CDialogEx::OnInitDialog(); - - // Add "About..." menu item to system menu. - - // IDM_ABOUTBOX must be in the system command range. - ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); - ASSERT(IDM_ABOUTBOX < 0xF000); - - CMenu* pSysMenu = GetSystemMenu(FALSE); - if (pSysMenu != NULL) - { - BOOL bNameValid; - CString strAboutMenu; - bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); - ASSERT(bNameValid); - if (!strAboutMenu.IsEmpty()) - { - pSysMenu->AppendMenu(MF_SEPARATOR); - pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); - } - } - - // Set the icon for this dialog. The framework does this automatically - // when the application's main window is not a dialog - SetIcon(m_hIcon, TRUE); // Set big icon - SetIcon(m_hIcon, FALSE); // Set small icon - - // TODO: Add extra initialization here - methodName = L""; - useWebCam = false; - useImgSeq = false; - filePath = L""; - bgs = NULL; - webCamIndex = 0; - m_spinWebCamIndex.SetRange(0, 9); - m_spinStartIdx.SetRange(0, 999999); - m_spinStopIdx.SetRange(0, 999999); - m_frameNumber.SetWindowTextW(L"0"); - - addBgsList(); - m_fileTypeList.AddString(L"PNG"); - m_fileTypeList.AddString(L"JPG"); - m_fileTypeList.AddString(L"JPEG"); - m_fileTypeList.AddString(L"JPE"); - m_fileTypeList.AddString(L"JP2"); - m_fileTypeList.AddString(L"BMP"); - m_fileTypeList.AddString(L"DIB"); - m_fileTypeList.AddString(L"PBM"); - m_fileTypeList.AddString(L"PGM"); - m_fileTypeList.AddString(L"PPM"); - m_fileTypeList.AddString(L"SR"); - m_fileTypeList.AddString(L"RAS"); - m_fileTypeList.AddString(L"TIFF"); - m_fileTypeList.AddString(L"TIF"); - m_fileTypeList.SelectString(0,L"PNG"); - m_inputVideo.SetWindowTextW(L"dataset/video.avi"); - m_delay.SetWindowTextW(L"1"); - m_execTime.SetWindowTextW(L"0"); - - started = false; - if(started == false) - { - cv::namedWindow("INPUT", 1); - HWND hWnd = (HWND) cvGetWindowHandle("INPUT"); - HWND hParent = ::GetParent(hWnd); - ::SetParent(hWnd, GetDlgItem(IDC_FRAME_INPUT)->m_hWnd); - ::ShowWindow(hParent, SW_HIDE); - } - - if(started == false) - { - cv::namedWindow("MASK", 1); - HWND hWnd = (HWND) cvGetWindowHandle("MASK"); - HWND hParent = ::GetParent(hWnd); - ::SetParent(hWnd, GetDlgItem(IDC_FRAME_MASK)->m_hWnd); - ::ShowWindow(hParent, SW_HIDE); - } - - if(started == false) - { - cv::namedWindow("BKG", 1); - HWND hWnd = (HWND) cvGetWindowHandle("BKG"); - HWND hParent = ::GetParent(hWnd); - ::SetParent(hWnd, GetDlgItem(IDC_FRAME_BKG)->m_hWnd); - ::ShowWindow(hParent, SW_HIDE); - } - - return TRUE; // return TRUE unless you set the focus to a control -} - -void CDlg::OnSysCommand(UINT nID, LPARAM lParam) -{ - if ((nID & 0xFFF0) == IDM_ABOUTBOX) - { - CAboutDlg dlgAbout; - dlgAbout.DoModal(); - } - else - { - CDialogEx::OnSysCommand(nID, lParam); - } -} - -// If you add a minimize button to your dialog, you will need the code below -// to draw the icon. For MFC applications using the document/view model, -// this is automatically done for you by the framework. - -void CDlg::OnPaint() -{ - if (IsIconic()) - { - CPaintDC dc(this); // device context for painting - - SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); - - // Center icon in client rectangle - int cxIcon = GetSystemMetrics(SM_CXICON); - int cyIcon = GetSystemMetrics(SM_CYICON); - CRect rect; - GetClientRect(&rect); - int x = (rect.Width() - cxIcon + 1) / 2; - int y = (rect.Height() - cyIcon + 1) / 2; - - // Draw the icon - dc.DrawIcon(x, y, m_hIcon); - } - else - { - CDialogEx::OnPaint(); - } -} - -// The system calls this function to obtain the cursor to display while the user drags -// the minimized window. -HCURSOR CDlg::OnQueryDragIcon() -{ - return static_cast<HCURSOR>(m_hIcon); -} - -void CDlg::addBgsList() -{ - // 37 algorithms - m_bgslist.AddString(L"FrameDifferenceBGS"); - m_bgslist.AddString(L"StaticFrameDifferenceBGS"); - m_bgslist.AddString(L"WeightedMovingMeanBGS"); - m_bgslist.AddString(L"WeightedMovingVarianceBGS"); - m_bgslist.AddString(L"MixtureOfGaussianV1BGS"); - m_bgslist.AddString(L"MixtureOfGaussianV2BGS"); - m_bgslist.AddString(L"AdaptiveBackgroundLearning"); - m_bgslist.AddString(L"AdaptiveSelectiveBackgroundLearning"); - m_bgslist.AddString(L"GMG"); - m_bgslist.AddString(L"DPAdaptiveMedianBGS"); - m_bgslist.AddString(L"DPGrimsonGMMBGS"); - m_bgslist.AddString(L"DPZivkovicAGMMBGS"); - m_bgslist.AddString(L"DPMeanBGS"); - m_bgslist.AddString(L"DPWrenGABGS"); - m_bgslist.AddString(L"DPPratiMediodBGS"); - m_bgslist.AddString(L"DPEigenbackgroundBGS"); - m_bgslist.AddString(L"DPTextureBGS"); - m_bgslist.AddString(L"T2FGMM_UM"); - m_bgslist.AddString(L"T2FGMM_UV"); - m_bgslist.AddString(L"T2FMRF_UM"); - m_bgslist.AddString(L"T2FMRF_UV"); - m_bgslist.AddString(L"FuzzySugenoIntegral"); - m_bgslist.AddString(L"FuzzyChoquetIntegral"); - m_bgslist.AddString(L"LBSimpleGaussian"); - m_bgslist.AddString(L"LBFuzzyGaussian"); - m_bgslist.AddString(L"LBMixtureOfGaussians"); - m_bgslist.AddString(L"LBAdaptiveSOM"); - m_bgslist.AddString(L"LBFuzzyAdaptiveSOM"); - m_bgslist.AddString(L"MultiLayerBGS"); - //m_bgslist.AddString(L"PBAS"); - m_bgslist.AddString(L"VuMeter"); - m_bgslist.AddString(L"KDE"); - m_bgslist.AddString(L"IndependentMultimodalBGS"); - m_bgslist.AddString(L"SJN_MultiCueBGS"); - m_bgslist.AddString(L"SigmaDeltaBGS"); - m_bgslist.AddString(L"SuBSENSEBGS"); - m_bgslist.AddString(L"LOBSTERBGS"); -} - -bool CDlg::getBgsMethodName() -{ - int nIndex = m_bgslist.GetCurSel(); - if(nIndex != CB_ERR) - { - m_bgslist.GetLBText(nIndex, methodName); - return true; - } - else - { - AfxMessageBox(L"Please, select one background subtraction method!"); - return false; - } -} - -bool CDlg::getFileType() -{ - int nIndex = m_fileTypeList.GetCurSel(); - if(nIndex != CB_ERR) - { - m_fileTypeList.GetLBText(nIndex, fileType); - return true; - } - else - { - AfxMessageBox(L"Please, select one file type or extension!"); - return false; - } -} - -bool CDlg::getInputVideoFilePath() -{ - m_inputVideo.GetWindowTextW(filePath); - - if(filePath.GetLength() > 0) - return true; - else - { - AfxMessageBox(L"Please, select one video file or image sequence folder!"); - return false; - } -} - -void CDlg::OnBnClickedStart() -{ - if(started == false) - { - m_log.SetWindowTextW(L"Checking..."); - - if(!getBgsMethodName()) - { - m_log.SetWindowTextW(L"Stopped..."); - return; - } - - useWebCam = false; - if(m_useWebCam.GetCheck() == BST_CHECKED) - useWebCam = true; - - useImgSeq = false; - if(m_isImgSeq.GetCheck() == BST_CHECKED) - { - useImgSeq = true; - - if(!getFileType()) - { - m_log.SetWindowTextW(L"Stopped..."); - return; - } - } - - if(useWebCam == false) - if(!getInputVideoFilePath()) - { - m_log.SetWindowTextW(L"Stopped..."); - return; - } - - m_log.SetWindowTextW(L"Starting..."); - thread = AfxBeginThread((AFX_THREADPROC) CDlg::Thread, (LPVOID) this); - } - else - { - AfxMessageBox(L"Thread is already initialized!"); - return; - } -} - -DWORD CDlg::Thread(LPVOID *lpvParam) -{ - CDlg *thr = (CDlg*) lpvParam; - thr->ThreadProcess(); - return NULL; -} - -void CDlg::ThreadProcess() -{ - CString csStartIdx; - m_startIdx.GetWindowTextW(csStartIdx); - startIdx = _tstoi(csStartIdx); - - CString csStopIdx; - m_stopIdx.GetWindowTextW(csStopIdx); - stopIdx = _tstoi(csStopIdx); - - if(useImgSeq == false) - { - if(useWebCam) - { - CString strIndex; - m_webCamIndex.GetWindowTextW(strIndex); - webCamIndex = _tstoi(strIndex); - capture = cvCaptureFromCAM(webCamIndex); - } - else - { - CStringA file_path_aux(filePath); - capture = cvCaptureFromFile((const char *) file_path_aux); - } - - if(!capture) - { - AfxMessageBox(L"ERROR: Cannot initialize video!"); - m_log.SetWindowTextW(L"Stopped..."); - return; - } - } - else - { - if(stopIdx == 0) - { - AfxMessageBox(L"Stop index not defined!"); - return; - } - - if(startIdx > stopIdx) - { - AfxMessageBox(L"Start index is higher than stop index!"); - return; - } - } - - /* Background Subtraction Methods */ - - if(methodName == "FrameDifferenceBGS") - bgs = new FrameDifferenceBGS; - if(methodName == "StaticFrameDifferenceBGS") - bgs = new StaticFrameDifferenceBGS; - if(methodName == "WeightedMovingMeanBGS") - bgs = new WeightedMovingMeanBGS; - if(methodName == "WeightedMovingVarianceBGS") - bgs = new WeightedMovingVarianceBGS; - if(methodName == "MixtureOfGaussianV1BGS") - bgs = new MixtureOfGaussianV1BGS; - if(methodName == "MixtureOfGaussianV2BGS") - bgs = new MixtureOfGaussianV2BGS; - if(methodName == "AdaptiveBackgroundLearning") - bgs = new AdaptiveBackgroundLearning; - if(methodName == "AdaptiveSelectiveBackgroundLearning") - bgs = new AdaptiveSelectiveBackgroundLearning; - if(methodName == "GMG") - bgs = new GMG; - - if(methodName == "DPAdaptiveMedianBGS") - bgs = new DPAdaptiveMedianBGS; - if(methodName == "DPGrimsonGMMBGS") - bgs = new DPGrimsonGMMBGS; - if(methodName == "DPZivkovicAGMMBGS") - bgs = new DPZivkovicAGMMBGS; - if(methodName == "DPMeanBGS") - bgs = new DPMeanBGS; - if(methodName == "DPWrenGABGS") - bgs = new DPWrenGABGS; - if(methodName == "DPPratiMediodBGS") - bgs = new DPPratiMediodBGS; - if(methodName == "DPEigenbackgroundBGS") - bgs = new DPEigenbackgroundBGS; - if(methodName == "DPTextureBGS") - bgs = new DPTextureBGS; - - if(methodName == "T2FGMM_UM") - bgs = new T2FGMM_UM; - if(methodName == "T2FGMM_UV") - bgs = new T2FGMM_UV; - if(methodName == "T2FMRF_UM") - bgs = new T2FMRF_UM; - if(methodName == "T2FMRF_UV") - bgs = new T2FMRF_UV; - if(methodName == "FuzzySugenoIntegral") - bgs = new FuzzySugenoIntegral; - if(methodName == "FuzzyChoquetIntegral") - bgs = new FuzzyChoquetIntegral; - - if(methodName == "LBSimpleGaussian") - bgs = new LBSimpleGaussian; - if(methodName == "LBFuzzyGaussian") - bgs = new LBFuzzyGaussian; - if(methodName == "LBMixtureOfGaussians") - bgs = new LBMixtureOfGaussians; - if(methodName == "LBAdaptiveSOM") - bgs = new LBAdaptiveSOM; - if(methodName == "LBFuzzyAdaptiveSOM") - bgs = new LBFuzzyAdaptiveSOM; - if(methodName == "MultiLayerBGS") - bgs = new MultiLayerBGS; - //if(methodName == "PBAS") - //bgs = new PixelBasedAdaptiveSegmenter; - if(methodName == "VuMeter") - bgs = new VuMeter; - if(methodName == "KDE") - bgs = new KDE; - if(methodName == "IndependentMultimodalBGS") - bgs = new IndependentMultimodalBGS; - if(methodName == "SJN_MultiCueBGS") - bgs = new SJN_MultiCueBGS; - if (methodName == "SigmaDeltaBGS") - bgs = new SigmaDeltaBGS; - if (methodName == "SuBSENSEBGS") - bgs = new SuBSENSEBGS; - if (methodName == "LOBSTERBGS") - bgs = new LOBSTERBGS; - - if(bgs == NULL) - { - AfxMessageBox(L"BGS object not defined!"); - return; - } - - started = true; - int i = 0; - if(useImgSeq == true && startIdx > 0) - i = startIdx - 1; - CString strFrameNumber; - CString strExecTime; - cv::Size default_size; - default_size.width = 235; - default_size.height = 189; - IplImage* frame; - std::string input_filename; - cv::Mat img_input; - // Convert a TCHAR string to a LPCSTR - CT2CA fileType2(fileType); - CT2CA filePath2(filePath); - // construct a std::string using the LPCSTR input - std::string str_fileType(fileType2); - std::string str_filePath(filePath2); - // delay - CString csDelay; - m_delay.GetWindowTextW(csDelay); - int delay = _tstoi(csDelay); - - do - { - m_log.SetWindowTextW(L"Running..."); - - i++; - //::Sleep(1); - - if(useImgSeq == true && i == (stopIdx + 1)) - break; - - if(useImgSeq) - { - input_filename = str_filePath + "\\" + boost::lexical_cast<std::string>(i) + "." + str_fileType; - img_input = cv::imread(input_filename); - - CString input_filename2(input_filename.c_str()); - m_log.SetWindowTextW(input_filename2); - - strFrameNumber.Format(L"%d",i); - m_frameNumber.SetWindowTextW(strFrameNumber); - - if(img_input.data == NULL) - { - AfxMessageBox(L"File can not be read!"); - break; - } - } - else - { - if(useWebCam == false && stopIdx >= 2 && i > stopIdx) - break; - - frame = cvQueryFrame(capture); - if(!frame) - break; - - if(useWebCam == false && startIdx >= 2 && i < startIdx) - continue; - - img_input = cv::Mat(frame,true); - } - - cv::Mat img_mask; - cv::Mat img_bkg; - Clock::time_point t0 = Clock::now(); - bgs->process(img_input, img_mask, img_bkg); - Clock::time_point t1 = Clock::now(); - auto d = boost::chrono::duration_cast<milliseconds>(t1 - t0); - //std::cout << "\nElapsed time: " << d.count() << "ms" << std::endl; - - cv::Mat img_input_aux; - cv::resize(img_input, img_input_aux, default_size); - - cv::Mat img_mask_aux; - if(img_mask.empty()) - img_mask = cv::Mat::zeros(cv::Size(img_input.size().width, img_input.size().height), img_input.type()); - if(m_medianFilter.GetCheck() == BST_CHECKED) - cv::medianBlur(img_mask, img_mask, 5); - cv::resize(img_mask, img_mask_aux, default_size); - - cv::Mat img_bgk_aux; - if(img_bkg.empty()) - img_bkg = cv::Mat::zeros(cv::Size(img_input.size().width, img_input.size().height), img_input.type()); - cv::resize(img_bkg, img_bgk_aux, default_size); - - cv::imshow("INPUT", img_input_aux); - cv::imshow("MASK", img_mask_aux); - cv::imshow("BKG", img_bgk_aux); - - extern_input_filename = "outputs/input/" + boost::lexical_cast<std::string>(i)+".png"; - img_input.copyTo(extern_input_img); - if(m_saveFrame.GetCheck() == BST_CHECKED) - cv::imwrite(extern_input_filename, img_input); - - extern_fg_filename = "outputs/foreground/" + boost::lexical_cast<std::string>(i)+".png"; - img_mask.copyTo(extern_fg_img); - if(m_saveMask.GetCheck() == BST_CHECKED) - cv::imwrite(extern_fg_filename, img_mask); - - extern_bg_filename = "outputs/background/" + boost::lexical_cast<std::string>(i)+".png"; - img_bkg.copyTo(extern_bg_img); - if(m_saveBkg.GetCheck() == BST_CHECKED) - cv::imwrite(extern_bg_filename, img_bkg); - - strFrameNumber.Format(L"%d",i); - m_frameNumber.SetWindowTextW(strFrameNumber); - - //strExecTime.Format(_T("%.2f"), d.count()); - strExecTime.Format(_T("%d"), d.count()); - m_execTime.SetWindowTextW(strExecTime); - - ::Sleep(delay); - - }while(1); - - delete bgs; - - if(!useImgSeq) - cvReleaseCapture(&capture); - - //AfxMessageBox(L"Thread is finished!"); - m_log.SetWindowTextW(L"Finished!"); - started = false; -} - - -void CDlg::OnBnClickedStop() -{ - if(started) - { - m_log.SetWindowTextW(L"Stopping..."); - - StopThread(); - - if(!useImgSeq) - if(capture) - cvReleaseCapture(&capture); - - delete bgs; - bgs = NULL; - - m_log.SetWindowTextW(L"Stopped!"); - started = false; - } -} - -void CDlg::StopThread() -{ - DWORD exit_code = NULL; - - if(thread != NULL) - { - GetExitCodeThread(thread->m_hThread, &exit_code); - - if(exit_code == STILL_ACTIVE) - { - ::TerminateThread(thread->m_hThread, 0); - CloseHandle(thread->m_hThread); - } - - thread->m_hThread = NULL; - thread = NULL; - } -} - -void CDlg::OnBnClickedUseWebcam() -{ - if(m_useWebCam.GetCheck() == BST_CHECKED) - m_isImgSeq.SetCheck(BST_UNCHECKED); - - m_inputVideo.EnableFileBrowseButton(); -} - -void CDlg::OnBnClickedImgSeq() -{ - if(m_isImgSeq.GetCheck() == BST_CHECKED) - { - m_inputVideo.EnableFolderBrowseButton(); - m_useWebCam.SetCheck(BST_UNCHECKED); - } - else - { - m_startIdx.SetWindowTextW(L"0"); - m_stopIdx.SetWindowTextW(L"0"); - m_inputVideo.EnableFileBrowseButton(); - } -} - -void CDlg::OnBnClickedSave() -{ - if(m_saveFrame.GetCheck() == BST_CHECKED) - cv::imwrite(extern_input_filename, extern_input_img); - - if(m_saveMask.GetCheck() == BST_CHECKED) - cv::imwrite(extern_fg_filename, extern_fg_img); - - if(m_saveBkg.GetCheck() == BST_CHECKED) - cv::imwrite(extern_bg_filename, extern_bg_img); - - m_log.SetWindowTextW(L"OK! Saved!"); -} diff --git a/vs2013mfc/src/Dlg.h b/vs2013mfc/src/Dlg.h deleted file mode 100644 index 479d727..0000000 --- a/vs2013mfc/src/Dlg.h +++ /dev/null @@ -1,92 +0,0 @@ - -// Dlg.h : header file -// - -#pragma once -#include "stdafx.h" -#include "afxwin.h" -#include "afxcmn.h" - -// CDlg dialog -class CDlg : public CDialogEx -{ -// Construction -public: - CDlg(CWnd* pParent = NULL); // standard constructor - -// Dialog Data - enum { IDD = IDD_APP }; - - protected: - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - - -// Implementation -protected: - HICON m_hIcon; - - // Generated message map functions - virtual BOOL OnInitDialog(); - afx_msg void OnSysCommand(UINT nID, LPARAM lParam); - afx_msg void OnPaint(); - afx_msg HCURSOR OnQueryDragIcon(); - DECLARE_MESSAGE_MAP() - -private: - bool started; - CWinThread* thread; - CvCapture* capture; - IBGS* bgs; - CString methodName; - CString fileType; - bool useWebCam; - bool useImgSeq; - int webCamIndex; - int startIdx; - int stopIdx; - int extern_i; - std::string extern_input_filename; - cv::Mat extern_input_img; - std::string extern_fg_filename; - cv::Mat extern_fg_img; - std::string extern_bg_filename; - cv::Mat extern_bg_img; - - CString filePath; - -public: - afx_msg void ThreadProcess(); - static DWORD Thread(LPVOID *x); - afx_msg void StopThread(); - afx_msg bool ipDraw(HDC hdc, IplImage* img, int xoffset=0, int yoffset=0); - -public: - void addBgsList(); - bool getBgsMethodName(); - CComboBox m_bgslist; - afx_msg void OnBnClickedStart(); - CStatic m_log; - CMFCEditBrowseCtrl m_inputVideo; - bool getInputVideoFilePath(); - CButton m_useWebCam; - afx_msg void OnBnClickedStop(); - CSpinButtonCtrl m_spinWebCamIndex; - CEdit m_webCamIndex; - CStatic m_frameNumber; - CButton m_saveFrame; - CButton m_saveMask; - CButton m_saveBkg; - CButton m_isImgSeq; - CEdit m_startIdx; - CEdit m_stopIdx; - CComboBox m_fileTypeList; - bool getFileType(); - CSpinButtonCtrl m_spinStartIdx; - CSpinButtonCtrl m_spinStopIdx; - afx_msg void OnBnClickedUseWebcam(); - afx_msg void OnBnClickedImgSeq(); - CEdit m_delay; - CStatic m_execTime; - CButton m_medianFilter; - afx_msg void OnBnClickedSave(); -}; diff --git a/vs2013mfc/src/resource.h b/vs2013mfc/src/resource.h deleted file mode 100644 index 606dd8c2eebd167158db80652c82fc50419d8ec6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4240 zcmezWPoF`bp_-wZ!H>b8A)dj7!IdF^!Ii-e%<^M!X7FTiWe8@dWvFG~W#D1}sa9a{ zWyoYmW+-CFXDDXKXGmixVNhTQW5{GEW+-JyWXNGqU~p#8X3%C(U`S_3WyoVlWhi1u zWGG=sWk_LAV8~?1V@PJmVJKxtVMt|AU`S)gWXNGiWza*iA(WvQsyd0Gl0ktXi6Nb# zm?4KDlOYLgRuMxbLp(znLotI9g8_pfg8@T4LoP!aLo$ONLlHwV+$4~jmBIFaYyr7M zfx(l(g~690p23m9iNT*ClpzF6M=&T52@M!37!07c;xgZb0`oz>F#!7jo6CbKG}#cR z$q+XOFa!`84#?pJa<dUmlY<!I8GIQW89W*M7~B|w7#taV8C;39#gM^>!2+kr!3-e` zjtoHzAw-&n?q*Ot;)+9%+5TjOh5|T6g3=`}vz-~@8JrpX8GONMFP_1P!JQ$P!H2<< z0c0z(D>2!iur^@89oitXeHi>1+{q3TW1Qg)G8+_&0pNTS&kzRAO|A_7MA!v!w;5iu z5vd~{oLV6EV1@y@2*hl2qRj@S#$X0-B3uoNOWbJ?6eghz!3?ep@eJV%t_)5L&fpY| z?nZ2Uh`TNEy4#h(g~5{{1kH3v_<+i5TqPICY(ob8;T_Bn01jtVmlJC?@!{>q5DHG~ zt_(p0!yMvn{NWwK;K~pI4in@QL)aFG+4#ddn8A@D3>=#Xv$4e;x){i8P;G=S&m+tx zB?Us#pb>#Q@66!A;L704;LTu6FpQDi4skdBJdbd<6N5JiB?~cTBSINe4iaxV#B37= zeBtfM;LG675D(6sfh2?q#B5W%W+U<?sLY1cLZF=E!hkDBLP8y4HnI7V9JBG~OH_A* zYB*wC4NHUg^ChA@0lAx0v+?IkM15&ULQF#3ZOnkX-2*DW5oX6TxG{J#_<-|&2ty>e zH4KS2Y$PZy37L%uZ%}FN!{EpeNtF8`X5+8t5qX}RFu|YaL2Wcp&Ev@6#{dfzP`OK} z1c$gAzuBPD8&p=sGlVdJ@+k4GK?4S32K;#*k@6f#Y8OJ>jX%$$nr%c>Jc7~<#B4%& z9@drx^-YLx(GoHnR(6BjK`Mrr4Jl7R<t(KC=f{xBPyz1sfqHOh42cY-3^`za8Myyf z%8<%X4DQ+GGZZl>fO~-D3<?bS3`q=G45<vs3?&T3;Ib8B9>`>6hD?SuXirUn!I2>V z+!782w|zi8Q&6ijjKQD5n*o%c5IXYk=m}zQWpHG0Ven`0WAI^!1lI$R;C6^VgAYS6 z*ahf)EKt~k?2c#fgSRn2<^+TLia`v{;F2MX!I8m-Arwn5#*o370ekNao5_%J2h<h- z^|(RpX<X(iFc>o!F_<%$<0#2+neN9B!Vts&@-KeVAu)};bjN0PFaszgL2-fKTu_Pw TnGGv{LE`}_;JAjwAu1mLW#Q*d diff --git a/vs2013mfc/src/stdafx.cpp b/vs2013mfc/src/stdafx.cpp deleted file mode 100644 index 9e260e7..0000000 --- a/vs2013mfc/src/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ - -// stdafx.cpp : source file that includes just the standard includes -// bgslibrary_vs2010_mfc.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - - diff --git a/vs2013mfc/src/stdafx.h b/vs2013mfc/src/stdafx.h deleted file mode 100644 index 4d734a9..0000000 --- a/vs2013mfc/src/stdafx.h +++ /dev/null @@ -1,104 +0,0 @@ - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, -// but are changed infrequently - -#pragma once - -#ifndef _SECURE_ATL -#define _SECURE_ATL 1 -#endif - -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers -#endif - -#include "targetver.h" - -#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit - -// turns off MFC's hiding of some common and often safely ignored warning messages -#define _AFX_ALL_WARNINGS - -#include <afxwin.h> // MFC core and standard components -#include <afxext.h> // MFC extensions - - -#include <afxdisp.h> // MFC Automation classes - - - -#ifndef _AFX_NO_OLE_SUPPORT -#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls -#endif -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include <afxcmn.h> // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT - -#include <afxcontrolbars.h> // MFC support for ribbons and control bars - -#ifdef _UNICODE -#if defined _M_IX86 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") -#elif defined _M_X64 -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") -#else -#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") -#endif -#endif - -#include <boost/lexical_cast.hpp> -#include <boost/chrono.hpp> -typedef boost::chrono::high_resolution_clock Clock; -typedef boost::chrono::milliseconds milliseconds; -typedef boost::chrono::microseconds microseconds; - -#include <iostream> - -#include <cv.h> -#include <highgui.h> - -// BGSLibrary algorithms - -#include "../../package_bgs/FrameDifferenceBGS.h" -#include "../../package_bgs/StaticFrameDifferenceBGS.h" -#include "../../package_bgs/WeightedMovingMeanBGS.h" -#include "../../package_bgs/WeightedMovingVarianceBGS.h" -#include "../../package_bgs/MixtureOfGaussianV1BGS.h" -#include "../../package_bgs/MixtureOfGaussianV2BGS.h" -#include "../../package_bgs/AdaptiveBackgroundLearning.h" -#include "../../package_bgs/AdaptiveSelectiveBackgroundLearning.h" -#include "../../package_bgs/GMG.h" - -#include "../../package_bgs/dp/DPAdaptiveMedianBGS.h" -#include "../../package_bgs/dp/DPGrimsonGMMBGS.h" -#include "../../package_bgs/dp/DPZivkovicAGMMBGS.h" -#include "../../package_bgs/dp/DPMeanBGS.h" -#include "../../package_bgs/dp/DPWrenGABGS.h" -#include "../../package_bgs/dp/DPPratiMediodBGS.h" -#include "../../package_bgs/dp/DPEigenbackgroundBGS.h" -#include "../../package_bgs/dp/DPTextureBGS.h" - -#include "../../package_bgs/tb/T2FGMM_UM.h" -#include "../../package_bgs/tb/T2FGMM_UV.h" -#include "../../package_bgs/tb/T2FMRF_UM.h" -#include "../../package_bgs/tb/T2FMRF_UV.h" -#include "../../package_bgs/tb/FuzzySugenoIntegral.h" -#include "../../package_bgs/tb/FuzzyChoquetIntegral.h" - -#include "../../package_bgs/lb/LBSimpleGaussian.h" -#include "../../package_bgs/lb/LBFuzzyGaussian.h" -#include "../../package_bgs/lb/LBMixtureOfGaussians.h" -#include "../../package_bgs/lb/LBAdaptiveSOM.h" -#include "../../package_bgs/lb/LBFuzzyAdaptiveSOM.h" - -#include "../../package_bgs/jmo/MultiLayerBGS.h" -//#include "../../package_bgs/pt/PixelBasedAdaptiveSegmenter.h" -#include "../../package_bgs/av/VuMeter.h" -#include "../../package_bgs/ae/KDE.h" -#include "../../package_bgs/db/IndependentMultimodalBGS.h" -#include "../../package_bgs/sjn/SJN_MultiCueBGS.h" -#include "../../package_bgs/bl/SigmaDeltaBGS.h" - -#include "../../package_bgs/pl/SuBSENSE.h" -#include "../../package_bgs/pl/LOBSTER.h" diff --git a/vs2013mfc/src/targetver.h b/vs2013mfc/src/targetver.h deleted file mode 100644 index 87c0086..0000000 --- a/vs2013mfc/src/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include <SDKDDKVer.h> diff --git a/wrapper_matlab/.gitignore b/wrapper_matlab/.gitignore new file mode 100644 index 0000000..1c363bf --- /dev/null +++ b/wrapper_matlab/.gitignore @@ -0,0 +1 @@ +*.mex* diff --git a/wrapper_matlab/backgroundSubtractor.m b/wrapper_matlab/backgroundSubtractor.m new file mode 100644 index 0000000..e431766 --- /dev/null +++ b/wrapper_matlab/backgroundSubtractor.m @@ -0,0 +1,81 @@ +%{ +/* + * This file is part of BGSLibrary. + * + * BGSLibrary is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BGSLibrary is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. + */ +%} +classdef backgroundSubtractor + %backgroundSubtractor Wrapper class for BGSLibrary + % obj = backgroundSubtractor(algorithm) + % creates an object with properties + % + % Properties: + % algorithm - Algorithm name (e.g. "FrameDifference"). + % + % fgMask = getForegroundMask(obj, img) computes foreground mask on + % input image, img, for the object defined by obj. + % + % reset(obj) resets object. + % + % release(obj) releases object memory. + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Properties + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + properties + % See the full list of available algorithms in the BGSLibrary website. + algorithm = 'FrameDifference'; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Public methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods + % Constructor + function obj = backgroundSubtractor(algorithm) + if(nargin > 0) + obj.algorithm = algorithm; + else + obj.algorithm = 'FrameDifference'; + end + disp(['Selected algorithm: ' obj.algorithm]); + params = struct('algorithm', obj.algorithm); + backgroundSubtractor_wrapper('construct', params); + end + + % Get foreground mask and background model + function [fgMask, bgModel] = getForegroundMask(~, img) + [fgMask, bgModel] = backgroundSubtractor_wrapper('compute', img); + end + + % Reset object states + function reset(obj) + % Reset the background model with default parameters + % This is done in two steps. First free the persistent + % memory and then reconstruct the model with original + % parameters + backgroundSubtractor_wrapper('destroy'); + params = struct('algorithm', obj.algorithm); + backgroundSubtractor_wrapper('construct', params); + end + + % Release object memory + function release(~) + % free persistent memory for model + backgroundSubtractor_wrapper('destroy'); + end + + end +end \ No newline at end of file diff --git a/wrapper_matlab/backgroundSubtractor_wrapper.cpp b/wrapper_matlab/backgroundSubtractor_wrapper.cpp new file mode 100644 index 0000000..5470120 --- /dev/null +++ b/wrapper_matlab/backgroundSubtractor_wrapper.cpp @@ -0,0 +1,395 @@ +/* + * This file is part of BGSLibrary. + * + * BGSLibrary is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BGSLibrary is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "opencvmex.hpp" + // On some platforms, the following include is needed for "placement new". + // For more information see: http://en.wikipedia.org/wiki/Placement_syntax +#include <memory> + +#include <typeinfo> +#include "mxarray.h" + +#include "IBGS.h" +#include "FrameDifference.h" +#include "StaticFrameDifference.h" +#include "WeightedMovingMean.h" +#include "WeightedMovingVariance.h" +#include "MixtureOfGaussianV1.h" +#include "MixtureOfGaussianV2.h" +#include "AdaptiveBackgroundLearning.h" +#include "AdaptiveSelectiveBackgroundLearning.h" +#include "GMG.h" +#include "KNN.h" +#include "DPAdaptiveMedian.h" +#include "DPGrimsonGMM.h" +#include "DPZivkovicAGMM.h" +#include "DPMean.h" +#include "DPWrenGA.h" +#include "DPPratiMediod.h" +#include "DPEigenbackground.h" +#include "DPTexture.h" +#include "T2FGMM_UM.h" +#include "T2FGMM_UV.h" +#include "T2FMRF_UM.h" +#include "T2FMRF_UV.h" +#include "FuzzySugenoIntegral.h" +#include "FuzzyChoquetIntegral.h" +#include "LBSimpleGaussian.h" +#include "LBFuzzyGaussian.h" +#include "LBMixtureOfGaussians.h" +#include "LBAdaptiveSOM.h" +#include "LBFuzzyAdaptiveSOM.h" +#include "LBP_MRF.h" +#include "MultiLayer.h" +#include "PixelBasedAdaptiveSegmenter.h" +#include "VuMeter.h" +#include "KDE.h" +#include "IndependentMultimodal.h" +#include "MultiCue.h" +#include "SigmaDelta.h" +#include "SuBSENSE.h" +#include "LOBSTER.h" +#include "PAWCS.h" +#include "TwoPoints.h" +#include "ViBe.h" + +using namespace bgslibrary::algorithms; + +static IBGS *ptrBGS = NULL; + +namespace bgslibrary +{ + IBGS* init_alg(std::string alg_name) + { + if (alg_name.compare("FrameDifference") == 0) + return (IBGS *)mxCalloc(1, sizeof(FrameDifference)); + if (alg_name.compare("StaticFrameDifference") == 0) + return (IBGS *)mxCalloc(1, sizeof(StaticFrameDifference)); + if (alg_name.compare("WeightedMovingMean") == 0) + return (IBGS *)mxCalloc(1, sizeof(WeightedMovingMean)); + if (alg_name.compare("WeightedMovingVariance") == 0) + return (IBGS *)mxCalloc(1, sizeof(WeightedMovingVariance)); +#if CV_MAJOR_VERSION == 2 + if (alg_name.compare("MixtureOfGaussianV1") == 0) + return (IBGS *)mxCalloc(1, sizeof(MixtureOfGaussianV1)); // only for OpenCV 2.x +#endif + if (alg_name.compare("MixtureOfGaussianV2") == 0) + return (IBGS *)mxCalloc(1, sizeof(MixtureOfGaussianV2)); + if (alg_name.compare("AdaptiveBackgroundLearning") == 0) + return (IBGS *)mxCalloc(1, sizeof(AdaptiveBackgroundLearning)); + if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0) + return (IBGS *)mxCalloc(1, sizeof(AdaptiveSelectiveBackgroundLearning)); +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (alg_name.compare("GMG") == 0) + return (IBGS *)mxCalloc(1, sizeof(GMG)); // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION == 3 + if (alg_name.compare("KNN") == 0) + return (IBGS *)mxCalloc(1, sizeof(KNN)); // only for OpenCV 3.x +#endif + if (alg_name.compare("DPAdaptiveMedian") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPAdaptiveMedian)); + if (alg_name.compare("DPGrimsonGMM") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPGrimsonGMM)); + if (alg_name.compare("DPZivkovicAGMM") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPZivkovicAGMM)); + if (alg_name.compare("DPMean") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPMean)); + if (alg_name.compare("DPWrenGA") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPWrenGA)); + if (alg_name.compare("DPPratiMediod") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPPratiMediod)); + if (alg_name.compare("DPEigenbackground") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPEigenbackground)); + if (alg_name.compare("DPTexture") == 0) + return (IBGS *)mxCalloc(1, sizeof(DPTexture)); + if (alg_name.compare("T2FGMM_UM") == 0) + return (IBGS *)mxCalloc(1, sizeof(T2FGMM_UM)); + if (alg_name.compare("T2FGMM_UV") == 0) + return (IBGS *)mxCalloc(1, sizeof(T2FGMM_UV)); + if (alg_name.compare("T2FMRF_UM") == 0) + return (IBGS *)mxCalloc(1, sizeof(T2FMRF_UM)); + if (alg_name.compare("T2FMRF_UV") == 0) + return (IBGS *)mxCalloc(1, sizeof(T2FMRF_UV)); + if (alg_name.compare("FuzzySugenoIntegral") == 0) + return (IBGS *)mxCalloc(1, sizeof(FuzzySugenoIntegral)); + if (alg_name.compare("FuzzyChoquetIntegral") == 0) + return (IBGS *)mxCalloc(1, sizeof(FuzzyChoquetIntegral)); + if (alg_name.compare("LBSimpleGaussian") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBSimpleGaussian)); + if (alg_name.compare("LBFuzzyGaussian") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBFuzzyGaussian)); + if (alg_name.compare("LBMixtureOfGaussians") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBMixtureOfGaussians)); + if (alg_name.compare("LBAdaptiveSOM") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBAdaptiveSOM)); + if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBFuzzyAdaptiveSOM)); + if (alg_name.compare("LBP_MRF") == 0) + return (IBGS *)mxCalloc(1, sizeof(LBP_MRF)); + if (alg_name.compare("MultiLayer") == 0) + return (IBGS *)mxCalloc(1, sizeof(MultiLayer)); + if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0) + return (IBGS *)mxCalloc(1, sizeof(PixelBasedAdaptiveSegmenter)); + if (alg_name.compare("VuMeter") == 0) + return (IBGS *)mxCalloc(1, sizeof(VuMeter)); + if (alg_name.compare("KDE") == 0) + return (IBGS *)mxCalloc(1, sizeof(KDE)); + if (alg_name.compare("IndependentMultimodal") == 0) + return (IBGS *)mxCalloc(1, sizeof(IndependentMultimodal)); + if (alg_name.compare("MultiCue") == 0) + return (IBGS *)mxCalloc(1, sizeof(MultiCue)); + if (alg_name.compare("SigmaDelta") == 0) + return (IBGS *)mxCalloc(1, sizeof(SigmaDelta)); + if (alg_name.compare("SuBSENSE") == 0) + return (IBGS *)mxCalloc(1, sizeof(SuBSENSE)); + if (alg_name.compare("LOBSTER") == 0) + return (IBGS *)mxCalloc(1, sizeof(LOBSTER)); + if (alg_name.compare("PAWCS") == 0) + return (IBGS *)mxCalloc(1, sizeof(PAWCS)); + if (alg_name.compare("TwoPoints") == 0) + return (IBGS *)mxCalloc(1, sizeof(TwoPoints)); + if (alg_name.compare("ViBe") == 0) + return (IBGS *)mxCalloc(1, sizeof(ViBe)); + return NULL; + } + + IBGS* get_alg(std::string alg_name) + { + if (alg_name.compare("FrameDifference") == 0) + return new (ptrBGS) FrameDifference(); + if (alg_name.compare("StaticFrameDifference") == 0) + return new (ptrBGS) StaticFrameDifference(); + if (alg_name.compare("WeightedMovingMean") == 0) + return new (ptrBGS) WeightedMovingMean(); + if (alg_name.compare("WeightedMovingVariance") == 0) + return new (ptrBGS) WeightedMovingVariance(); +#if CV_MAJOR_VERSION == 2 + if (alg_name.compare("MixtureOfGaussianV1") == 0) + return new (ptrBGS) MixtureOfGaussianV1(); // only for OpenCV 2.x +#endif + if (alg_name.compare("MixtureOfGaussianV2") == 0) + return new (ptrBGS) MixtureOfGaussianV2(); + if (alg_name.compare("AdaptiveBackgroundLearning") == 0) + return new (ptrBGS) AdaptiveBackgroundLearning(); + if (alg_name.compare("AdaptiveSelectiveBackgroundLearning") == 0) + return new (ptrBGS) AdaptiveSelectiveBackgroundLearning(); +#if CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4 && CV_SUBMINOR_VERSION >= 3 + if (alg_name.compare("GMG") == 0) + return new (ptrBGS) GMG(); // only for OpenCV >= 2.4.3 +#endif +#if CV_MAJOR_VERSION == 3 + if (alg_name.compare("KNN") == 0) + return new (ptrBGS) KNN(); // only on OpenCV 3.x +#endif + if (alg_name.compare("DPAdaptiveMedian") == 0) + return new (ptrBGS) DPAdaptiveMedian(); + if (alg_name.compare("DPGrimsonGMM") == 0) + return new (ptrBGS) DPGrimsonGMM(); + if (alg_name.compare("DPZivkovicAGMM") == 0) + return new (ptrBGS) DPZivkovicAGMM(); + if (alg_name.compare("DPMean") == 0) + return new (ptrBGS) DPMean(); + if (alg_name.compare("DPWrenGA") == 0) + return new (ptrBGS) DPWrenGA(); + if (alg_name.compare("DPPratiMediod") == 0) + return new (ptrBGS) DPPratiMediod(); + if (alg_name.compare("DPEigenbackground") == 0) + return new (ptrBGS) DPEigenbackground(); + if (alg_name.compare("DPTexture") == 0) + return new (ptrBGS) DPTexture(); + if (alg_name.compare("T2FGMM_UM") == 0) + return new (ptrBGS) T2FGMM_UM(); + if (alg_name.compare("T2FGMM_UV") == 0) + return new (ptrBGS) T2FGMM_UV(); + if (alg_name.compare("T2FMRF_UM") == 0) + return new (ptrBGS) T2FMRF_UM(); + if (alg_name.compare("T2FMRF_UV") == 0) + return new (ptrBGS) T2FMRF_UV(); + if (alg_name.compare("FuzzySugenoIntegral") == 0) + return new (ptrBGS) FuzzySugenoIntegral(); + if (alg_name.compare("FuzzyChoquetIntegral") == 0) + return new (ptrBGS) FuzzyChoquetIntegral(); + if (alg_name.compare("LBSimpleGaussian") == 0) + return new (ptrBGS) LBSimpleGaussian(); + if (alg_name.compare("LBFuzzyGaussian") == 0) + return new (ptrBGS) LBFuzzyGaussian(); + if (alg_name.compare("LBMixtureOfGaussians") == 0) + return new (ptrBGS) LBMixtureOfGaussians(); + if (alg_name.compare("LBAdaptiveSOM") == 0) + return new (ptrBGS) LBAdaptiveSOM(); + if (alg_name.compare("LBFuzzyAdaptiveSOM") == 0) + return new (ptrBGS) LBFuzzyAdaptiveSOM(); + if (alg_name.compare("LBP_MRF") == 0) + return new (ptrBGS) LBP_MRF(); + if (alg_name.compare("MultiLayer") == 0) + return new (ptrBGS) MultiLayer(); + if (alg_name.compare("PixelBasedAdaptiveSegmenter") == 0) + return new (ptrBGS) PixelBasedAdaptiveSegmenter(); + if (alg_name.compare("VuMeter") == 0) + return new (ptrBGS) VuMeter(); + if (alg_name.compare("KDE") == 0) + return new (ptrBGS) KDE(); + if (alg_name.compare("IndependentMultimodal") == 0) + return new (ptrBGS) IndependentMultimodal(); + if (alg_name.compare("MultiCue") == 0) + return new (ptrBGS) MultiCue(); + if (alg_name.compare("SigmaDelta") == 0) + return new (ptrBGS) SigmaDelta(); + if (alg_name.compare("SuBSENSE") == 0) + return new (ptrBGS) SuBSENSE(); + if (alg_name.compare("LOBSTER") == 0) + return new (ptrBGS) LOBSTER(); + if (alg_name.compare("PAWCS") == 0) + return new (ptrBGS) PAWCS(); + if (alg_name.compare("TwoPoints") == 0) + return new (ptrBGS) TwoPoints(); + if (alg_name.compare("ViBe") == 0) + return new (ptrBGS) ViBe(); + return NULL; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Check inputs +////////////////////////////////////////////////////////////////////////////// +void checkInputs(int nrhs, const mxArray *prhs[]) +{ + //mexPrintf("checkInputs()\n"); + if ((nrhs < 1) || (nrhs > 2)) + mexErrMsgTxt("Incorrect number of inputs. Function expects 1 or 2 inputs."); +} + +////////////////////////////////////////////////////////////////////////////// +// Get MEX function inputs +////////////////////////////////////////////////////////////////////////////// +void getParams(std::string &algorithm, const mxArray* mxParams) +{ + //mexPrintf("getParams()\n"); + const mxArray* mxfield; + mxfield = mxGetField(mxParams, 0, "algorithm"); + algorithm = mexplus::MxArray::to<std::string>(mxfield); + //mexPrintf(algorithm.c_str()); + //mexPrintf("\n"); +} + +////////////////////////////////////////////////////////////////////////////// +// Exit function for freeing persistent memory +////////////////////////////////////////////////////////////////////////////// +void exitFcn() +{ + //mexPrintf("exitFcn()\n"); + if (ptrBGS != NULL) + { + // explicitly call destructor for "placement new" + ptrBGS->~IBGS(); + mxFree(ptrBGS); + ptrBGS = NULL; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Construct object +////////////////////////////////////////////////////////////////////////////// +void constructObject(const mxArray *prhs[]) +{ + //mexPrintf("constructObject()\n"); + std::string algorithm; + + // second input must be struct + if (mxIsStruct(prhs[1])) + getParams(algorithm, prhs[1]); + + if (ptrBGS != NULL) exitFcn(); + + // Allocate memory for background subtractor model + //ptrBGS = (IBGS *)mxCalloc(1, sizeof(IBGS)); + ptrBGS = bgslibrary::init_alg(algorithm); + if (ptrBGS != NULL) + { + // Make memory allocated by MATLAB software persist after MEX-function completes. + // This lets us use the updated background subtractor model for the next frame. + mexMakeMemoryPersistent(ptrBGS); + + // Use "placement new" to construct an object on memory that was + // already allocated using mxCalloc + ptrBGS = bgslibrary::get_alg(algorithm); + if (ptrBGS == NULL) + mexErrMsgTxt("Failed to construct an object on memory. Algorithm not initialized."); + } + else + mexErrMsgTxt("Failed to allocate memory. Algorithm not found?"); + + // Register a function that gets called when the MEX-function is cleared. + // This function is responsible for freeing persistent memory + mexAtExit(exitFcn); +} + +////////////////////////////////////////////////////////////////////////////// +// Compute foreground mask +////////////////////////////////////////////////////////////////////////////// +void computeForegroundMask(mxArray *plhs[], const mxArray *prhs[]) +{ + //mexPrintf("computeForegroundMask()\n"); + if (ptrBGS != NULL) + { + cv::Ptr<cv::Mat> img = ocvMxArrayToImage_uint8(prhs[1], true); + cv::Mat fgmask, bgmodel; + + ptrBGS->process(*img, fgmask, bgmodel); + + if (fgmask.empty()) + fgmask = cv::Mat::zeros((*img).size(), CV_8UC1); + if (bgmodel.empty()) + bgmodel = cv::Mat::zeros((*img).size(), CV_8UC3); // (*img).type() + + // https://fr.mathworks.com/help/vision/ref/ocvmxarrayfromimage_datatype.html + plhs[0] = ocvMxArrayFromImage_uint8(fgmask); + plhs[1] = ocvMxArrayFromImage_uint8(bgmodel); + + //if(!fgmask.empty()) + fgmask.release(); + //if(!bgmodel.empty()) + bgmodel.release(); + } + else + mexErrMsgTxt("Algorithm not initialized."); +} + +////////////////////////////////////////////////////////////////////////////// +// The main MEX function entry point +////////////////////////////////////////////////////////////////////////////// +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + //mexPrintf("mexFunction()\n"); + checkInputs(nrhs, prhs); + const char *str = mxIsChar(prhs[0]) ? mxArrayToString(prhs[0]) : NULL; + + if (str != NULL) + { + //mexPrintf("%s\n",str); + if (strcmp(str, "construct") == 0) + constructObject(prhs); + else if (strcmp(str, "compute") == 0) + computeForegroundMask(plhs, prhs); + else if (strcmp(str, "destroy") == 0) + exitFcn(); + + // Free memory allocated by mxArrayToString + mxFree((void *)str); + } +} diff --git a/wrapper_matlab/compile.m b/wrapper_matlab/compile.m new file mode 100644 index 0000000..314ada1 --- /dev/null +++ b/wrapper_matlab/compile.m @@ -0,0 +1,94 @@ +%% Compile +clc; +mexOpenCV -v -DMEX_COMPILE_FLAG -I"..\package_bgs" backgroundSubtractor_wrapper.cpp ... + "..\package_bgs\FrameDifference.cpp" ... + "..\package_bgs\StaticFrameDifference.cpp" ... + "..\package_bgs\WeightedMovingMean.cpp" ... + "..\package_bgs\WeightedMovingVariance.cpp" ... + "..\package_bgs\MixtureOfGaussianV1.cpp" ... + "..\package_bgs\MixtureOfGaussianV2.cpp" ... + "..\package_bgs\AdaptiveBackgroundLearning.cpp" ... + "..\package_bgs\AdaptiveSelectiveBackgroundLearning.cpp" ... + "..\package_bgs\GMG.cpp" ... + "..\package_bgs\KNN.cpp" ... + "..\package_bgs\DPAdaptiveMedian.cpp" ... + "..\package_bgs\DPGrimsonGMM.cpp" ... + "..\package_bgs\DPZivkovicAGMM.cpp" ... + "..\package_bgs\DPMean.cpp" ... + "..\package_bgs\DPWrenGA.cpp" ... + "..\package_bgs\DPPratiMediod.cpp" ... + "..\package_bgs\DPEigenbackground.cpp" ... + "..\package_bgs\DPTexture.cpp" ... + "..\package_bgs\dp\AdaptiveMedianBGS.cpp" ... + "..\package_bgs\dp\Image.cpp" ... + "..\package_bgs\dp\Error.cpp" ... + "..\package_bgs\dp\GrimsonGMM.cpp" ... + "..\package_bgs\dp\ZivkovicAGMM.cpp" ... + "..\package_bgs\dp\MeanBGS.cpp" ... + "..\package_bgs\dp\WrenGA.cpp" ... + "..\package_bgs\dp\PratiMediodBGS.cpp" ... + "..\package_bgs\dp\Eigenbackground.cpp" ... + "..\package_bgs\dp\TextureBGS.cpp" ... + "..\package_bgs\T2FGMM_UM.cpp" ... + "..\package_bgs\T2FGMM_UV.cpp" ... + "..\package_bgs\T2FMRF_UM.cpp" ... + "..\package_bgs\T2FMRF_UV.cpp" ... + "..\package_bgs\FuzzyChoquetIntegral.cpp" ... + "..\package_bgs\FuzzySugenoIntegral.cpp" ... + "..\package_bgs\T2F\T2FGMM.cpp" ... + "..\package_bgs\T2F\T2FMRF.cpp" ... + "..\package_bgs\T2F\MRF.cpp" ... + "..\package_bgs\T2F\FuzzyUtils.cpp" ... + "..\package_analysis\PixelUtils.cpp" ... + "..\package_bgs\MultiLayer.cpp" ... + "..\package_bgs\MultiLayer\CMultiLayerBGS.cpp" ... + "..\package_bgs\MultiLayer\LocalBinaryPattern.cpp" ... + "..\package_bgs\MultiLayer\BlobResult.cpp" ... + "..\package_bgs\MultiLayer\BlobExtraction.cpp" ... + "..\package_bgs\MultiLayer\blob.cpp" ... + "..\package_bgs\LBSimpleGaussian.cpp" ... + "..\package_bgs\LBFuzzyGaussian.cpp" ... + "..\package_bgs\LBMixtureOfGaussians.cpp" ... + "..\package_bgs\LBAdaptiveSOM.cpp" ... + "..\package_bgs\LBFuzzyAdaptiveSOM.cpp" ... + "..\package_bgs\lb\BGModel.cpp" ... + "..\package_bgs\lb\BGModelFuzzyGauss.cpp" ... + "..\package_bgs\lb\BGModelFuzzySom.cpp" ... + "..\package_bgs\lb\BGModelGauss.cpp" ... + "..\package_bgs\lb\BGModelMog.cpp" ... + "..\package_bgs\lb\BGModelSom.cpp" ... + "..\package_bgs\LBP_MRF.cpp" ... + "..\package_bgs\LBP_MRF\MotionDetection.cpp" ... + "..\package_bgs\LBP_MRF\MEImage.cpp" ... + "..\package_bgs\LBP_MRF\MEHistogram.cpp" ... + "..\package_bgs\LBP_MRF\MEDefs.cpp" ... + "..\package_bgs\LBP_MRF\maxflow.cpp" ... + "..\package_bgs\LBP_MRF\graph.cpp" ... + "..\package_bgs\PixelBasedAdaptiveSegmenter.cpp" ... + "..\package_bgs\PBAS\PBAS.cpp" ... + "..\package_bgs\VuMeter.cpp" ... + "..\package_bgs\VuMeter\TBackgroundVuMeter.cpp" ... + "..\package_bgs\VuMeter\TBackground.cpp" ... + "..\package_bgs\KDE.cpp" ... + "..\package_bgs\KDE\NPBGSubtractor.cpp" ... + "..\package_bgs\KDE\NPBGmodel.cpp" ... + "..\package_bgs\KDE\KernelTable.cpp" ... + "..\package_bgs\IndependentMultimodal.cpp" ... + "..\package_bgs\IMBS\IMBS.cpp" ... + "..\package_bgs\MultiCue.cpp" ... + "..\package_bgs\SigmaDelta.cpp" ... + "..\package_bgs\SigmaDelta\sdLaMa091.cpp" ... + "..\package_bgs\SuBSENSE.cpp" ... + "..\package_bgs\LOBSTER.cpp" ... + "..\package_bgs\PAWCS.cpp" ... + "..\package_bgs\LBSP\LBSP.cpp" ... + "..\package_bgs\LBSP\LBSP_.cpp" ... + "..\package_bgs\LBSP\BackgroundSubtractorLBSP.cpp" ... + "..\package_bgs\LBSP\BackgroundSubtractorLBSP_.cpp" ... + "..\package_bgs\LBSP\BackgroundSubtractorLOBSTER.cpp" ... + "..\package_bgs\LBSP\BackgroundSubtractorPAWCS.cpp" ... + "..\package_bgs\LBSP\BackgroundSubtractorSuBSENSE.cpp" ... + "..\package_bgs\ViBe.cpp" ... + "..\package_bgs\ViBe\vibe-background-sequential.cpp" ... + "..\package_bgs\TwoPoints.cpp" ... + "..\package_bgs\TwoPoints\two_points.cpp" diff --git a/wrapper_matlab/config/.gitignore b/wrapper_matlab/config/.gitignore new file mode 100644 index 0000000..4e2a98b --- /dev/null +++ b/wrapper_matlab/config/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except these files +!.gitignore diff --git a/wrapper_matlab/demo.m b/wrapper_matlab/demo.m new file mode 100644 index 0000000..942e457 --- /dev/null +++ b/wrapper_matlab/demo.m @@ -0,0 +1,65 @@ +%{ +/* + * This file is part of BGSLibrary. + * + * BGSLibrary is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * BGSLibrary is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. + */ +%} +% Example: +% demo('FrameDifference') +% demo('StaticFrameDifference') +% See the full list of available algorithms in the BGSLibrary website. +function demo(algorithm) +if(nargin < 1) + algorithm = 'FrameDifference'; +end + +% Create video reader object +%filename = 'visiontraffic.avi'; +filename = '../dataset/demo.avi'; +hsrc = vision.VideoFileReader(filename, ... + 'ImageColorSpace', 'RGB', ... + 'VideoOutputDataType', 'uint8'); + +% Create background/foreground segmentation object +hfg = backgroundSubtractor(algorithm); + +disp('Starting...'); +frameCnt = 1; +while ~isDone(hsrc), %disp(frameCnt) + % Read frame + frame = step(hsrc); + + % Compute foreground mask and background model + [fgMask, bgModel] = getForegroundMask(hfg, frame); + + % View results + subplot(1,3,1), imshow(frame,'InitialMagnification','fit'); + subplot(1,3,2), imshow(fgMask,'InitialMagnification','fit'); + subplot(1,3,3), imshow(bgModel,'InitialMagnification','fit'); + pause(0.01); + + % Reset background model + % This step just demonstrates how to use reset method + if (frameCnt==15) + %reset(hfg); + %break; + end + + frameCnt = frameCnt + 1; +end +disp('Finished!'); + +release(hfg); +release(hsrc); diff --git a/wrapper_matlab/mxarray.h b/wrapper_matlab/mxarray.h new file mode 100644 index 0000000..6a9afe9 --- /dev/null +++ b/wrapper_matlab/mxarray.h @@ -0,0 +1,1555 @@ +/** MxArray data conversion library. + * + * Copyright 2014 Kota Yamaguchi. + * + * The library provides mexplus::MxArray class for data conversion between + * mxArray* and C++ types. The static API's are the core of the high-level + * conversions. + * + * int value = MxArray::to<int>(prhs[0]); + * string value = MxArray::to<string>(prhs[0]); + * vector<double> value = MxArray::to<vector<double> >(prhs[0]); + * + * plhs[0] = MxArray::from(20); + * plhs[0] = MxArray::from("text value."); + * plhs[0] = MxArray::from(vector<double>(20, 0)); + * + * Additionally, object API's are there to wrap around a complicated data + * access. + * + * ### Read access + * + * MxArray cell(prhs[0]); // Assumes cell array in prhs[0]. + * int x = cell.at<int>(0); + * vector<double> y = cell.at<vector<double> >(1); + * + * MxArray numeric(prhs[0]); // Assumes numeric array in prhs[0]. + * double x = numeric.at<double>(0); + * int y = numeric.at<int>(1); + * + * ### Write access + * + * MxArray cell(MxArray::Cell(1, 3)); + * cell.set(0, 12); + * cell.set(1, "text value."); + * cell.set(2, vector<double>(4, 0)); + * plhs[0] = cell.release(); + * + * MxArray numeric(MxArray::Numeric<double>(2, 2)); + * numeric.set(0, 0, 1); + * numeric.set(0, 1, 2); + * numeric.set(1, 0, 3); + * numeric.set(1, 1, 4); + * plhs[0] = numeric.release(); + * + * To add your own data conversion, define in namespace mexplus a template + * specialization of MxArray::from() and MxArray::to(). + * + */ + +#ifndef INCLUDE_MEXPLUS_MXARRAY_H_ +#define INCLUDE_MEXPLUS_MXARRAY_H_ + +#include <mex.h> +#include <algorithm> +#include <cstdint> +#include <set> +#include <string> +#include <typeinfo> +#include <vector> +#include "mxtypes.h" + +#pragma warning(once : 4244) + +/** Macro definitions. + */ +#define MEXPLUS_CHECK_NOTNULL(pointer) \ + if (!(pointer)) \ + mexErrMsgIdAndTxt("mexplus:error", \ + "Null pointer exception: %s:%d:%s `" #pointer "`.", \ + __FILE__, \ + __LINE__, \ + __FUNCTION__) + +#define MEXPLUS_ERROR(...) mexErrMsgIdAndTxt("mexplus:error", __VA_ARGS__) +#define MEXPLUS_WARNING(...) mexWarnMsgIdAndTxt("mexplus:warning", __VA_ARGS__) +#define MEXPLUS_ASSERT(condition, ...) \ + if (!(condition)) mexErrMsgIdAndTxt("mexplus:error", __VA_ARGS__) + +namespace mexplus { + +/** mxArray object wrapper for data conversion and manipulation. + * + * The class is similar to a combination of unique_ptr and wrapper around + * Matlab's matrix API. An MxArray object created from a mutable mxArray* + * pointer automatically frees its internal memory unless explicitly + * released. When MxArray is created from a const mxArray*, the object does not + * manage memory but still provides the same matrix API. + */ +class MxArray { + public: + /** Empty MxArray constructor. Use reset() to set a pointer. + */ + MxArray() : array_(NULL), owner_(false) {} + /** NULL assignment. + */ + MxArray& operator= (std::nullptr_t) { + reset(); + return *this; + } + /** Move constructor. + */ + MxArray(MxArray&& array) : array_(NULL), owner_(false) { + *this = std::move(array); + } + /** Move assignment. + */ + MxArray& operator= (MxArray&& rhs) { + if (this != &rhs) { + array_ = rhs.array_; + owner_ = rhs.owner_; + rhs.array_ = NULL; + rhs.owner_ = false; + } + return *this; + } + /** MxArray constructor from const mxArray*. MxArray will not manage memory. + * @param array mxArray pointer given by mexFunction. + */ + explicit MxArray(const mxArray* array) : + array_(const_cast<mxArray*>(array)), + owner_(false) {} + /** MxArray constructor from mutable mxArray*. MxArray will manage memory. + * @param array mxArray pointer. + */ + explicit MxArray(mxArray* array) : array_(array), owner_(array != NULL) {} + /** Assignment from const mxArray*. MxArray will not manage memory. + */ + MxArray& operator= (const mxArray* rhs) { + reset(rhs); + return *this; + } + /** Assignment from mutable mxArray*. MxArray will manage memory. + */ + MxArray& operator= (mxArray* rhs) { + reset(rhs); + return *this; + } + /** MxArray constructor from scalar. + */ + template <typename T> + explicit MxArray(const T& value) : array_(from(value)), owner_(true) {} + /** Destructor. Unreleased pointers will be destroyed. + */ + virtual ~MxArray() { + if (array_ && owner_) + mxDestroyArray(array_); + } + /** Swap operation. + */ + void swap(MxArray& rhs) { + if (this != &rhs) { + mxArray* array = rhs.array_; + bool owner = rhs.owner_; + rhs.array_ = array_; + rhs.owner_ = owner_; + array_ = array; + owner_ = owner; + } + } + /** Reset an mxArray to a const mxArray*. + * + * Caller must be VERY careful with this, as the behavior is undefined when + * the original mxArray* is destroyed. For example, the following will crash. + * @code + * MxArray foo; + * { + * MxArray bar(1); + * foo.reset(bar.get()); + * } + * foo.toInt(); // Error! + * @endcode + */ + void reset(const mxArray* array = NULL) { + if (array_ && owner_) + mxDestroyArray(array_); + array_ = const_cast<mxArray*>(array); + owner_ = false; + } + /** Reset an mxArray. + */ + void reset(mxArray* array) { + if (array_ && owner_) + mxDestroyArray(array_); + array_ = array; + owner_ = (array != NULL); + } + /** Release managed mxArray* pointer, or clone if not owner. + * @return Unmanaged mxArray*. Always caller must destroy. + */ + mxArray* release() { + MEXPLUS_CHECK_NOTNULL(array_); + mxArray* array = (owner_) ? array_ : clone(); + array_ = NULL; + owner_ = false; + return array; + } + /** Clone mxArray. This always allocates new mxArray*. + * @return Unmanaged mxArray*. Always caller must destroy. + */ + mxArray* clone() const { + MEXPLUS_CHECK_NOTNULL(array_); + mxArray* array = mxDuplicateArray(array_); + MEXPLUS_CHECK_NOTNULL(array); + return array; + } + /** Conversion to const mxArray*. + * @return const mxArray* pointer. + */ + inline const mxArray* get() const { return array_; } + /** Get raw mxArray*. + * @return mxArray* pointer. + */ + inline mxArray* getMutable() { return array_; } + /** Return true if the array is not NULL. + */ + operator bool() const { return array_ != NULL; } + /** Return true if owner. + */ + inline bool isOwner() const { return owner_; } + /** Create a new numeric (real or complex) matrix. + * @param rows Number of rows. + * @param columns Number of cols. + */ + template <typename T> + static mxArray* Numeric(int rows = 1, int columns = 1); + /** Create a new numeric (real or complex) matrix. + * @param ndim Number of dimensions. + * @param dims Dimensions array. Each element in the dimensions array + * contains the size of the array in that dimension. + */ + template <typename T> + static mxArray* Numeric(std::vector<std::size_t> dims); + /** Create a new logical matrix. + * @param rows Number of rows. + * @param columns Number of cols. + */ + static mxArray* Logical(int rows = 1, int columns = 1) { + mxArray* logical_array = mxCreateLogicalMatrix(rows, columns); + MEXPLUS_CHECK_NOTNULL(logical_array); + return logical_array; + } + /** Create a new cell matrix. + * @param rows Number of rows. + * @param columns Number of cols. + * + * Example: + * @code + * MxArray cell_array = MxArray::Cell(1, 2); + * cell_array.set(0, 1); + * cell_array.set(1, "another value"); + * plhs[0] = cell_array.release(); + * @endcode + */ + static mxArray* Cell(int rows = 1, int columns = 1) { + mxArray* cell_array = mxCreateCellMatrix(rows, columns); + MEXPLUS_CHECK_NOTNULL(cell_array); + return cell_array; + } + /** Generic constructor for a struct matrix. + * @param fields field names. + * @param nfields number of field names. + * @param rows size of the first dimension. + * @param columns size of the second dimension. + * + * Example: + * @code + * const char* fields[] = {"field1", "field2"}; + * MxArray struct_array(MxArray::Struct(2, fields)); + * struct_array.set("field1", 1); + * struct_array.set("field2", "field2 value"); + * plhs[0] = struct_array.release(); + * @endcode + */ + static mxArray* Struct(int nfields = 0, + const char** fields = NULL, + int rows = 1, + int columns = 1) { + mxArray* struct_array = mxCreateStructMatrix(rows, + columns, + nfields, + fields); + MEXPLUS_CHECK_NOTNULL(struct_array); + return struct_array; + } + /** mxArray* importer methods. + */ + template <typename T> + static mxArray* from(const T& value) { return fromInternal<T>(value); } + static mxArray* from(const char* value) { + mxArray* array = mxCreateString(value); + MEXPLUS_CHECK_NOTNULL(array); + return array; + } + static mxArray* from(int32_t value) { + mxArray* array = mxCreateNumericMatrix(1, 1, mxINT32_CLASS, mxREAL); + MEXPLUS_CHECK_NOTNULL(array); + *reinterpret_cast<int32_t*>(mxGetData(array)) = value; + return array; + } + /** mxArray* exporter methods. + */ + template <typename T> + static void to(const mxArray* array, T* value) { + toInternal<T>(array, value); + } + template <typename T> + static T to(const mxArray* array) { + T value; + toInternal<T>(array, &value); + return value; + } + /** mxArray* element reader methods. + */ + template <typename T> + static T at(const mxArray* array, mwIndex index) { + T value; + atInternal<T>(array, index, &value); + return value; + } + template <typename T> + static void at(const mxArray* array, mwIndex index, T* value) { + atInternal<T>(array, index, value); + } + static const mxArray* at(const mxArray* array, mwIndex index) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_ASSERT(mxIsCell(array), "Expected a cell array."); + return mxGetCell(array, index); + } + template <typename T> + static void at(const mxArray* array, + const std::string& field, + T* value, + mwIndex index = 0) { + atInternal<T>(array, field, index, value); + } + static const mxArray* at(const mxArray* array, + const std::string& field, + mwIndex index = 0) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_ASSERT(mxIsStruct(array), "Expected a struct array."); + return mxGetField(array, index, field.c_str()); + } + /** mxArray* element writer methods. + */ + template <typename T> + static void set(mxArray* array, mwIndex index, const T& value) { + setInternal<T>(array, index, value); + } + static void set(mxArray* array, mwIndex index, mxArray* value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(mxIsCell(array), "Expected a cell array."); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + mxDestroyArray(mxGetCell(array, index)); + mxSetCell(array, index, value); + } + template <typename T> + static void set(mxArray* array, + const std::string& field, + const T& value, + mwIndex index = 0) { + setInternal<T>(array, field, index, value); + } + static void set(mxArray* array, + const std::string& field, + mxArray* value, + mwIndex index = 0) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(mxIsStruct(array), "Expected a struct array."); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + int field_number = mxGetFieldNumber(array, field.c_str()); + if (field_number < 0) { + field_number = mxAddField(array, field.c_str()); + MEXPLUS_ASSERT(field_number >= 0, + "Failed to create a field '%s'", + field.c_str()); + } + mxDestroyArray(mxGetFieldByNumber(array, index, field_number)); + mxSetFieldByNumber(array, index, field_number, value); + } + + /** Convert MxArray to a specified type. + */ + template <typename T> + T to() const { + T value; + toInternal<T>(array_, &value); + return value; + } + template <typename T> + void to(T* value) const { toInternal<T>(array_, value); } + /** Template for element accessor. + * @param index index of the array element. + * @return value of the element at index. + * + * + * Example: + * @code + * MxArray array(prhs[0]); + * double value = array.at<double>(0); + * @endcode + */ + template <typename T> + T at(mwIndex index) const { + T value; + atInternal<T>(array_, index, &value); + return value; + } + template <typename T> + void at(mwIndex index, T* value) const { + atInternal<T>(array_, index, value); + } + const mxArray* at(mwIndex index) const { + return at(array_, index); + } + /** Template for element accessor. + * @param row index of the first dimension. + * @param column index of the second dimension. + * @return value of the element at (row, column). + */ + template <typename T> + T at(mwIndex row, mwIndex column) const; + /** Template for element accessor. + * @param subscripts subscript indexes of elements. + * @return value of the element at subscript index. + */ + template <typename T> + T at(const std::vector<mwIndex>& subscripts) const; + /** Struct element accessor. + * @param field field name of the struct array. + * @param index index of the struct array. + * @return value of the element at the specified field. + */ + template <typename T> + T at(const std::string& field, mwIndex index = 0) const { + T value; + atInternal<T>(array_, field, index, &value); + return value; + } + template <typename T> + void at(const std::string& field, T* value, mwIndex index = 0) const { + atInternal<T>(array_, field, index, value); + } + const mxArray* at(const std::string& field, mwIndex index = 0) const { + return at(array_, field, index); + } + + /** Template for element write accessor. + * @param index offset of the array element. + * @param value value of the field. + */ + template <typename T> + void set(mwIndex index, const T& value) { + setInternal<T>(array_, index, value); + } + /** Template for element write accessor. + * @param row index of the first dimension of the array element. + * @param column index of the first dimension of the array element. + * @param value value of the field. + */ + template <typename T> + void set(mwIndex row, mwIndex column, const T& value); + /** Template for element write accessor. + * @param subscripts subscript index of the element. + * @param value value of the field. + */ + template <typename T> + void set(const std::vector<mwIndex>& subscripts, const T& value); + /** Cell element write accessor. + * @param index index of the element. + * @param value cell element to be inserted. + */ + void set(mwIndex index, mxArray* value) { + MEXPLUS_ASSERT(isOwner(), "Must be an owner to set."); + set(array_, index, value); + } + /** Cell element write accessor. + * @param row index of the first dimension of the array element. + * @param column index of the first dimension of the array element. + * @param value cell element to be inserted. + */ + void set(mwIndex row, mwIndex column, mxArray* value) { + MEXPLUS_ASSERT(isOwner(), "Must be an owner to set."); + set(array_, subscriptIndex(row, column), value); + } + /** Cell element write accessor. + * @param subscripts subscript index of the element. + * @param value value of the field. + */ + void set(const std::vector<mwIndex>& subscripts, mxArray* value) { + MEXPLUS_ASSERT(isOwner(), "Must be an owner to set."); + set(array_, subscriptIndex(subscripts), value); + } + /** Struct element write accessor. + * @param field field name of the struct array. + * @param value value of the field. + * @param index linear index of the struct array element. + */ + template <typename T> + void set(const std::string& field, const T& value, mwIndex index = 0) { + MEXPLUS_ASSERT(isOwner(), "Must be an owner to set."); + setInternal<T>(array_, field, index, value); + } + /** Struct element write accessor. + * @param field field name of the struct array. + * @param value value of the field to be inserted. + * @param index linear index of the struct array element. + */ + void set(const std::string& field, mxArray* value, mwIndex index = 0) { + MEXPLUS_ASSERT(isOwner(), "Must be an owner to set."); + set(array_, field, value, index); + } + /** Get raw data pointer. + * @return pointer T*. If MxArray is not compatible, return NULL. + */ + template <typename T> + T* getData() const; + /** Get raw data pointer to imaginary part. + * @return pointer T*. If MxArray is not compatible, return NULL. + */ + template <typename T> + T* getImagData() const; + mxLogical* getLogicals() const { + MEXPLUS_CHECK_NOTNULL(array_); + MEXPLUS_ASSERT(isLogical(), + "Expected a logical array but %s.", + className().c_str()); + return mxGetLogicals(array_); + } + mxChar* getChars() const { + MEXPLUS_CHECK_NOTNULL(array_); + MEXPLUS_ASSERT(isChar(), + "Expected a char array but %s.", + className().c_str()); + return mxGetChars(array_); + } + /** Class ID of mxArray. + */ + inline mxClassID classID() const { return mxGetClassID(array_); } + /** Class name of mxArray. + */ + inline const std::string className() const { + return std::string(mxGetClassName(array_)); + } + /** Number of elements in an array. + */ + inline mwSize size() const { + return static_cast<mwSize>(mxGetNumberOfElements(array_)); + } + /** Number of dimensions. + */ + inline mwSize dimensionSize() const { + return mxGetNumberOfDimensions(array_); + } + /** Array of each dimension. + */ + inline std::vector<mwSize> dimensions() const { + const mwSize* dimensions = mxGetDimensions(array_); + return std::vector<mwSize>(dimensions, dimensions + dimensionSize()); + } + /** Number of rows in an array. + */ + inline mwSize rows() const { return static_cast<mwSize>(mxGetM(array_)); } + /** Number of columns in an array. + */ + inline mwSize cols() const { return static_cast<mwSize>(mxGetN(array_)); } + /** Number of fields in a struct array. + */ + inline int fieldSize() const { return mxGetNumberOfFields(array_); } + /** Get field name of a struct array. + * @param index index of the struct array. + * @return std::string. + */ + std::string fieldName(int index) const { + const char* field = mxGetFieldNameByNumber(array_, index); + MEXPLUS_ASSERT(field, "Failed to get field name at %d.", index); + return std::string(field); + } + /** Get field names of a struct array. + * @return std::vector<std::string> of struct field names. + */ + std::vector<std::string> fieldNames() const { + MEXPLUS_ASSERT(isStruct(), "Expected a struct array."); + std::vector<std::string> fields(fieldSize()); + for (size_t i = 0; i < fields.size(); ++i) + fields[i] = fieldName(i); + return fields; + } + /** Number of elements in IR, PR, and PI arrays. + */ + inline mwSize nonZeroMax() const { return mxGetNzmax(array_); } + /** Offset from first element to desired element. + * @param row index of the first dimension of the array. + * @param column index of the second dimension of the array. + * @return linear offset of the specified subscript index. + */ + mwIndex subscriptIndex(mwIndex row, mwIndex column) const { + MEXPLUS_ASSERT(row < rows() && column < cols(), + "Subscript is out of range."); + mwIndex subscripts[] = {row, column}; + return mxCalcSingleSubscript(array_, 2, subscripts); + } + /** Offset from first element to desired element. + * @param subscripts subscript indexes of the array. + * @return linear offset of the specified subscript index. + */ + mwIndex subscriptIndex(const std::vector<mwIndex>& subscripts) const { + return mxCalcSingleSubscript(array_, + static_cast<mwSize>(subscripts.size()), + const_cast<mwIndex*>(&subscripts[0])); + } + /** Determine whether input is cell array. + */ + inline bool isCell() const { return mxIsCell(array_); } + /** Determine whether input is string array. + */ + inline bool isChar() const { return mxIsChar(array_); } + /** Determine whether input is vector array. + */ + inline bool isVector() const { + return mxGetNumberOfDimensions(array_) == 2 && + (mxGetM(array_) == 1 || mxGetN(array_) == 1); + } + /** Determine whether array is integral type. + */ + inline bool isIntegral(const char* name) const { + return mxIsNumeric(array_) && !mxIsDouble(array_); + } + /** Determine whether array is member of specified class. + */ + inline bool isClass(const char* name) const { + return mxIsClass(array_, name); + } + /** Determine whether data is complex. + */ + inline bool isComplex() const { return mxIsComplex(array_); } + /** Determine whether mxArray represents data as double-precision, + * floating-point numbers. + */ + inline bool isDouble() const { return mxIsDouble(array_); } + /** Determine whether array is empty. + */ + inline bool isEmpty() const { return mxIsEmpty(array_); } + /** Determine whether input is finite. + */ + static inline bool IsFinite(double value) { return mxIsFinite(value); } + /** Determine whether array was copied from MATLAB global workspace. + */ + inline bool isFromGlobalWS() const { return mxIsFromGlobalWS(array_); } + /** Determine whether input is infinite. + */ + static inline bool IsInf(double value) { return mxIsInf(value); } + /** Determine whether array represents data as signed 8-bit integers. + */ + inline bool isInt8() const { return mxIsInt8(array_); } + /** Determine whether array represents data as signed 16-bit integers. + */ + inline bool isInt16() const { return mxIsInt16(array_); } + /** Determine whether array represents data as signed 32-bit integers. + */ + inline bool isInt32() const { return mxIsInt32(array_); } + /** Determine whether array represents data as signed 64-bit integers. + */ + inline bool isInt64() const { return mxIsInt64(array_); } + /** Determine whether array is of type mxLogical. + */ + inline bool isLogical() const { return mxIsLogical(array_); } + /** Determine whether scalar array is of type mxLogical. + */ + inline bool isLogicalScalar() const { return mxIsLogicalScalar(array_); } + /** Determine whether scalar array of type mxLogical is true. + */ + inline bool isLogicalScalarTrue() const { + return mxIsLogicalScalarTrue(array_); + } + /** Determine whether array is numeric. + */ + inline bool isNumeric() const { return mxIsNumeric(array_); } + /** Determine whether array represents data as single-precision, + * floating-point numbers. + */ + inline bool isSingle() const { return mxIsSingle(array_); } + /** Determine whether input is sparse array. + */ + inline bool isSparse() const { return mxIsSparse(array_); } + /** Determine whether input is structure array. + */ + inline bool isStruct() const { return mxIsStruct(array_); } + /** Determine whether array represents data as unsigned 8-bit integers. + */ + inline bool isUint8() const { return mxIsUint8(array_); } + /** Determine whether array represents data as unsigned 16-bit integers. + */ + inline bool isUint16() const { return mxIsUint16(array_); } + /** Determine whether array represents data as unsigned 32-bit integers. + */ + inline bool isUint32() const { return mxIsUint32(array_); } + /** Determine whether array represents data as unsigned 64-bit integers. + */ + inline bool isUint64() const { return mxIsUint64(array_); } + /** Determine whether a struct array has a specified field. + */ + bool hasField(const std::string& field_name, mwIndex index = 0) const { + return isStruct() && + mxGetField(array_, index, field_name.c_str()) != NULL; + } + /** Element size. + */ + int elementSize() const { + return static_cast<int>(mxGetElementSize(array_)); + } + /** Determine whether input is NaN (Not-a-Number). + */ + static inline bool IsNaN(double value) { return mxIsNaN(value); } + /** Value of infinity. + */ + static inline double Inf() { return mxGetInf(); } + /** Value of NaN (Not-a-Number). + */ + static inline double NaN() { return mxGetNaN(); } + /** Value of EPS. + */ + static inline double Eps() { return mxGetEps(); } + + private: + /** Copy constructor is prohibited except internally. + */ + MxArray(const MxArray& array); + // MxArray(const MxArray& array) = delete; + /** Copy assignment operator is prohibited. + */ + MxArray& operator=(const MxArray& rhs); + // MxArray& operator=(const MxArray& rhs) = delete; + + /*************************************************************/ + /** Templated mxArray importers **/ + /*************************************************************/ + + /** Fundamental numerics. + */ + template <typename T> + static mxArray* fromInternal(const typename std::enable_if< + MxArithmeticType<T>::value, T>::type& value); + /** Complex types, complex<float> or complex<double>. + */ + template <typename T> + static mxArray* fromInternal(const typename std::enable_if< + MxComplexType<T>::value, T>::type& value); + /** Container with fundamental numerics, i.e. vector<double>. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + MxArithmeticCompound<Container>::value, + Container>::type& value); + /** Container with complex numbers, i.e. vector<complex<double>>. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + MxComplexCompound<Container>::value, Container>::type& value); + /** Char type */ + template <typename T> + static mxArray* fromInternal(const typename std::enable_if< + MxCharType<T>::value, T>::type& value); + /** Containter with signed char. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + (MxCharCompound<Container>::value) && + (std::is_signed<typename Container::value_type>::value), + Container>::type& value); + /** Container with unsigned char. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + (MxCharCompound<Container>::value) && + !(std::is_signed<typename Container::value_type>::value), + Container>::type& value); + /** Logicals. + */ + template <typename T> + static mxArray* fromInternal(const typename std::enable_if< + MxLogicalType<T>::value, T>::type& value); + /** Container with logicals. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + MxLogicalCompound<Container>::value, Container>::type& value); + /** Container with cell type content. + */ + template <typename Container> + static mxArray* fromInternal(const typename std::enable_if< + MxCellCompound<Container>::value, Container>::type& value); + + /*************************************************************/ + /** Templated mxArray exporters **/ + /*************************************************************/ + + /** Singleton types. + */ + template <typename T> + static void toInternal(const mxArray* array, + typename std::enable_if< + MxArithmeticType<T>::value || + MxComplexType<T>::value || + MxLogicalType<T>::value || + MxCharType<T>::value, + T + >::type* value) { + atInternal<T>(array, 0, value); + } + /** Vector types. + */ + template <typename T> + static void toInternal(const mxArray* array, + typename std::enable_if< + MxComplexOrArithmeticCompound<T>::value || + MxLogicalCompound<T>::value || + MxCharCompound<T>::value, + T + >::type* value); + /** Nested types (leads into recursive deduction). + */ + template <typename T> + static void toInternal(const mxArray* array, + typename std::enable_if< + MxCellType<T>::value && + (!std::is_compound<T>::value || + MxCellType<typename T::value_type>::value), + T + >::type* value); + + /*************************************************************/ + /** Templated mxArray getters **/ + /*************************************************************/ + + /** Fundamental numeric types. + */ + template <typename T> + static void atInternal(const mxArray* array, mwIndex index, + typename std::enable_if< + MxComplexOrArithmeticType<T>::value || + MxLogicalType<T>::value || + MxCharType<T>::value, + T>::type* value); + /** Converter for nested types. + */ + template <typename T> + static void atInternal(const mxArray* array, mwIndex index, + typename std::enable_if< + std::is_compound<T>::value && + !MxComplexType<T>::value, + T + >::type* value); + /** Structure access. + */ + template <typename T> + static void atInternal(const mxArray* array, + const std::string& field, + mwIndex index, T* value); + + /*************************************************************/ + /** Templated mxArray element setters **/ + /*************************************************************/ + + /** Fundamental numeric and complex types. + */ + template <typename T> + static void setInternal(mxArray* array, mwIndex index, + const typename std::enable_if< + !std::is_compound<T>::value || + MxComplexType<T>::value, + T + >::type& value); + /** Container types. + */ + template <typename T> + static void setInternal(mxArray* array, mwIndex index, + const typename std::enable_if< + MxCellType<T>::value, + T + >::type& value); + /** Structure access. + */ + template <typename T> + static void setInternal(mxArray* array, const std::string& field, + mwIndex index, const T& value); + + /*************************************************************/ + /** Assignment helpers (for MxArray.to<type>(value)) **/ + /*************************************************************/ + + /** Explicit integer element assignment. + */ + template <typename T, typename R> + static void assignTo(const mxArray* array, + mwIndex index, typename std::enable_if< + std::is_integral<R>::value, + R + >::type* value) { + MEXPLUS_ASSERT(!mxIsComplex(array), "Non-complex array expected!"); + *value = (R)*(reinterpret_cast<T*>(mxGetData(array)) + index); + } + /** Explicit floating point element assignment. + */ + template <typename T, typename R> + static void assignTo(const mxArray* array, + mwIndex index, + typename std::enable_if< + std::is_floating_point<R>::value, + R + >::type* value) { + if (mxIsComplex(array)) { + T real_part = *(reinterpret_cast<T*>(mxGetPr(array)) + index); + T imag_part = *(reinterpret_cast<T*>(mxGetPi(array)) + index); + *value = std::abs(std::complex<R>(real_part, imag_part)); + } else { + *value = *(reinterpret_cast<T*>(mxGetData(array)) + index); + } + } + /** Explicit complex element assignment. + */ + template <typename T, typename R> + static void assignTo(const mxArray* array, + mwIndex index, + typename std::enable_if< + MxComplexType<R>::value, + R + >::type* value) { + typename R::value_type real_part, imag_part; + if (mxIsComplex(array)) { + real_part = *(reinterpret_cast<T*>(mxGetPr(array)) + index); + imag_part = *(reinterpret_cast<T*>(mxGetPi(array)) + index); + } else { + real_part = *(reinterpret_cast<T*>(mxGetData(array)) + index); + imag_part = 0.0; + } + *value = std::complex<typename R::value_type>(real_part, imag_part); + } + /** Explicit char (signed) element assignment. + */ + template <typename R> + static void assignCharTo(const mxArray* array, + mwIndex index, + typename std::enable_if< + std::is_signed<R>::value, + R + >::type* value) { + typedef typename std::make_signed<mxChar>::type SignedMxChar; + *value = *(reinterpret_cast<SignedMxChar*>(mxGetChars(array)) + index); + } + /** Explicit char (unsigned) element assignment. + */ + template <typename R> + static void assignCharTo(const mxArray* array, + mwIndex index, + typename std::enable_if< + !std::is_signed<R>::value, + R + >::type* value) { + *value = *(mxGetChars(array) + index); + } + /** Explicit cell element assignment. + */ + template <typename T> + static void assignCellTo(const mxArray* array, mwIndex index, T* value) { + const mxArray* element = mxGetCell(array, index); + MEXPLUS_CHECK_NOTNULL(element); + toInternal<T>(element, value); // Recursion for nested types. + } + /** Explicit numeric array assignment. + */ + template <typename T, typename R> + static void assignTo(const mxArray* array, + typename std::enable_if< + MxArithmeticCompound<R>::value || + MxLogicalCompound<R>::value || + MxCharCompound<R>::value, + R + >::type* value) { + mwSize array_size = static_cast<mwSize>(mxGetNumberOfElements(array)); + if (!mxIsComplex(array)) { + T* data_pointer = reinterpret_cast<T*>(mxGetData(array)); + value->assign(data_pointer, data_pointer + array_size); + } else { + T* real_part = reinterpret_cast<T*>(mxGetPr(array)); + T* imag_part = reinterpret_cast<T*>(mxGetPi(array)); + value->resize(array_size); + for (mwSize i = 0; i < array_size; ++i) { + double mag = std::abs(std::complex<double>( + static_cast<double>(*(real_part++)), + static_cast<double>(*(imag_part++)))); + (*value)[i] = static_cast<T>(mag); + } + } + } + /** Explicit complex array assigment. + */ + template <typename T, typename R> + static void assignTo(const mxArray* array, + typename std::enable_if< + MxComplexCompound<R>::value, + R + >::type* value) { + mwSize array_size = mxGetNumberOfElements(array); + value->resize(array_size); + if (!mxIsComplex(array)) { + T* data_pointer = reinterpret_cast<T*>(mxGetData(array)); + for (mwSize i = 0; i < array_size; ++i) { + (*value)[i] = typename R::value_type(*(data_pointer++), 0.0f); + } + } else { + T* real_part = reinterpret_cast<T*>(mxGetPr(array)); + T* imag_part = reinterpret_cast<T*>(mxGetPi(array)); + for (mwSize i = 0; i < array_size; ++i) { + (*value)[i] = typename R::value_type(*(real_part++), *(imag_part++)); + } + } + } + /** Explicit char (signed) array assignment. + */ + template <typename R> + static void assignStringTo(const mxArray* array, + typename std::enable_if< + std::is_signed<typename R::value_type>::value, + R + >::type* value) { + typedef typename std::make_signed<mxChar>::type SignedMxChar; + SignedMxChar* data_pointer = reinterpret_cast<SignedMxChar*>( + mxGetChars(array)); + value->assign(data_pointer, data_pointer + mxGetNumberOfElements(array)); + } + /** Explicit char (unsigned) array assignment. + */ + template <typename R> + static void assignStringTo(const mxArray* array, + typename std::enable_if< + !std::is_signed<typename R::value_type>::value, + R>::type* value) { + mxChar* data_pointer = mxGetChars(array); + value->assign(data_pointer, data_pointer + mxGetNumberOfElements(array)); + } + /** Explicit cell array assignment. + */ + template <typename T> + static void assignCellTo(const mxArray* array, T* value) { + mwSize array_size = static_cast<mwSize>(mxGetNumberOfElements(array)); + value->resize(array_size); + for (size_t i = 0; i < array_size; ++i) { + const mxArray* element = mxGetCell(array, i); + MEXPLUS_CHECK_NOTNULL(element); + (*value)[i] = to<typename T::value_type>(element); + } + } + + /*************************************************************/ + /** Assignment helpers (for MxArray.set<type>(i, value)) **/ + /*************************************************************/ + + /** Explicit numeric element assignment. + */ + template <typename R, typename T> + static void assignFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + MxArithmeticType<T>::value || MxCharType<T>::value, + T + >::type& value) { + if (mxIsComplex(array)) { + *(reinterpret_cast<R*>(mxGetPr(array)) + index) = value; + *(reinterpret_cast<R*>(mxGetPi(array)) + index) = 0.0; + } else { + *(reinterpret_cast<R*>(mxGetData(array)) + index) = value; + } + } + /** Explicit complex element assignment. + */ + template <typename R, typename T> + static void assignFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + MxComplexType<T>::value, + T + >::type& value) { + if (mxIsComplex(array)) { + *(reinterpret_cast<R*>(mxGetPr(array)) + index) = value.real(); + *(reinterpret_cast<R*>(mxGetPi(array)) + index) = value.imag(); + } else { + *(reinterpret_cast<R*>(mxGetData(array)) + index) = std::abs(value); + } + } + template <typename T> + static void assignCharFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + std::is_floating_point<T>::value, + T + >::type& value) { + *(mxGetChars(array) + index) = value; // whoever needs this... + } + template <typename T> + static void assignCharFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + std::is_integral<T>::value && + std::is_signed<T>::value, + T + >::type& value) { + *(mxGetChars(array) + index) = reinterpret_cast<const typename + std::make_unsigned<T>::type&>(value); + } + template <typename T> + static void assignCharFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + std::is_integral<T>::value && + !std::is_signed<T>::value, + T + >::type& value) { + *(mxGetChars(array) + index) = value; + } + + template <typename T> + static void assignCharFrom(mxArray* array, + mwIndex index, + const typename std::enable_if< + MxComplexType<T>::value, + T + >::type& value) { + *(mxGetChars(array) + index) = std::abs(value); // whoever needs it... + } + + /** Pointer to the mxArray C object. + */ + mxArray* array_; + /** Flag to enable resource management. + */ + bool owner_; +}; + +/*************************************************************/ +/** Templated mxArray importers **/ +/*************************************************************/ + +/** Fundamental numeric type. + */ +template <typename T> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxArithmeticType<T>::value, T>::type& value) { + mxArray* array = mxCreateNumericMatrix(1, + 1, + MxTypes<T>::class_id, + MxTypes<T>::complexity); + MEXPLUS_CHECK_NOTNULL(array); + *reinterpret_cast<T*>(mxGetData(array)) = value; + return array; +} + +/** Complex type, complex<float> or complex<double>. + */ +template <typename T> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxComplexType<T>::value, T>::type& value) { + mxArray* array = mxCreateNumericMatrix(1, 1, + MxTypes<T>::class_id, + MxTypes<T>::complexity); + MEXPLUS_CHECK_NOTNULL(array); + *reinterpret_cast<typename T::value_type*>(mxGetPr(array)) = value.real(); + *reinterpret_cast<typename T::value_type*>(mxGetPi(array)) = value.imag(); + + return array; +} + +/** Container with fundamental numerics, i.e. vector<double>. + */ +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxArithmeticCompound<Container>::value, Container>::type& value) { + typedef typename Container::value_type ValueType; + mxArray* array = mxCreateNumericMatrix(1, + value.size(), + MxTypes<ValueType>::class_id, + MxTypes<ValueType>::complexity); + MEXPLUS_CHECK_NOTNULL(array); + std::copy(value.begin(), + value.end(), + reinterpret_cast<ValueType*>(mxGetData(array))); + return array; +} + +/** Container with complex numbers, i.e. vector<complex<double>>. + */ +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxComplexCompound<Container>::value, Container>::type& value) { + typedef typename Container::value_type ContainerValueType; + typedef typename ContainerValueType::value_type ValueType; + mxArray* array = mxCreateNumericMatrix(1, + value.size(), + MxTypes<ContainerValueType>::class_id, + mxCOMPLEX); + MEXPLUS_CHECK_NOTNULL(array); + ValueType* real = reinterpret_cast<ValueType*>(mxGetPr(array)); + ValueType* imag = reinterpret_cast<ValueType*>(mxGetPi(array)); + typename Container::const_iterator it; + for (it = value.begin(); it != value.end(); it++) { + *real++ = (*it).real(); + *imag++ = (*it).imag(); + } + return array; +} + +template <typename T> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxCharType<T>::value, T>::type& value) { + const char char_array[] = {static_cast<char>(value), 0}; + mxArray* array = mxCreateString(char_array); + MEXPLUS_CHECK_NOTNULL(array); + return array; +} + +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + (MxCharCompound<Container>::value) && + (std::is_signed<typename Container::value_type>::value), + Container>::type& value) { + typedef typename std::make_unsigned<typename Container::value_type>::type + UnsignedValue; + const mwSize dimensions[] = {1, static_cast<mwSize>(value.size())}; + mxArray* array = mxCreateCharArray(2, dimensions); + MEXPLUS_CHECK_NOTNULL(array); + mxChar* array_data = mxGetChars(array); + for (typename Container::const_iterator it = value.begin(); + it != value.end(); + ++it) { + *(array_data++) = reinterpret_cast<const UnsignedValue&>(*it); + } + return array; +} + +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + (MxCharCompound<Container>::value) && + !(std::is_signed<typename Container::value_type>::value), + Container>::type& value) { + const mwSize dimensions[] = {1, static_cast<mwSize>(value.size())}; + mxArray* array = mxCreateCharArray(2, dimensions); + MEXPLUS_CHECK_NOTNULL(array); + std::copy(value.begin(), value.end(), mxGetChars(array)); + return array; +} + +template <typename T> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxLogicalType<T>::value, T>::type& value) { + mxArray* array = mxCreateLogicalScalar(value); + MEXPLUS_CHECK_NOTNULL(array); + return array; +} + +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxLogicalCompound<Container>::value, Container>::type& value) { + mxArray* array = mxCreateLogicalMatrix(1, value.size()); + MEXPLUS_CHECK_NOTNULL(array); + std::copy(value.begin(), value.end(), mxGetLogicals(array)); + return array; +} + +template <typename Container> +mxArray* MxArray::fromInternal(const typename std::enable_if< + MxCellCompound<Container>::value, Container>::type& value) { + mxArray* array = mxCreateCellMatrix(1, value.size()); + MEXPLUS_CHECK_NOTNULL(array); + mwIndex index = 0; + for (typename Container::const_iterator it = value.begin(); + it != value.end(); + ++it) { + mxArray* new_item = from(*it); // Safe in case if from() fails. + mxDestroyArray(mxGetCell(array, index)); + mxSetCell(array, index++, new_item); + } + return array; +} + +/*************************************************************/ +/** Templated mxArray exporters **/ +/*************************************************************/ + +/** Converter from numeric matrix to container. + */ +template <typename T> +void MxArray::toInternal(const mxArray* array, typename std::enable_if< + MxComplexOrArithmeticCompound<T>::value || + MxLogicalCompound<T>::value || + MxCharCompound<T>::value, T>::type* value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + switch (mxGetClassID(array)) { + case mxINT8_CLASS: assignTo<int8_t, T>(array, value); break; + case mxUINT8_CLASS: assignTo<uint8_t, T>(array, value); break; + case mxINT16_CLASS: assignTo<int16_t, T>(array, value); break; + case mxUINT16_CLASS: assignTo<uint16_t, T>(array, value); break; + case mxINT32_CLASS: assignTo<int32_t, T>(array, value); break; + case mxUINT32_CLASS: assignTo<uint32_t, T>(array, value); break; + case mxINT64_CLASS: assignTo<int64_t, T>(array, value); break; + case mxUINT64_CLASS: assignTo<uint64_t, T>(array, value); break; + case mxSINGLE_CLASS: assignTo<float, T>(array, value); break; + case mxDOUBLE_CLASS: assignTo<double, T>(array, value); break; + case mxLOGICAL_CLASS: assignTo<mxLogical, T>(array, value); break; + case mxCHAR_CLASS: assignStringTo<T>(array, value); break; + case mxCELL_CLASS: assignCellTo<T>(array, value); break; + // case mxSPARSE_CLASS: + default: + MEXPLUS_ERROR("Cannot convert %s.", mxGetClassName(array)); + } +} + +/** Converter from nested types to container. + */ +template <typename T> +void MxArray::toInternal(const mxArray* array, + typename std::enable_if< + MxCellType<T>::value && + (!std::is_compound<T>::value || + MxCellType<typename T::value_type>::value), + T + >::type* value) { + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(mxIsCell(array), "Expected a cell array."); + mwSize array_size = mxGetNumberOfElements(array); + value->resize(array_size); + for (size_t i = 0; i < array_size; ++i) { + const mxArray* element = mxGetCell(array, i); + (*value)[i] = to<typename T::value_type>(element); + } +} + +/*************************************************************/ +/** Templated mxArray getters **/ +/*************************************************************/ + +/** Converter from fundamental numeric or complex types. + */ +template <typename T> +void MxArray::atInternal(const mxArray* array, mwIndex index, + typename std::enable_if< + MxComplexOrArithmeticType<T>::value || + MxLogicalType<T>::value || + MxCharType<T>::value, T>::type* value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + switch (mxGetClassID(array)) { + case mxINT8_CLASS: assignTo<int8_t, T>(array, index, value); break; + case mxUINT8_CLASS: assignTo<uint8_t, T>(array, index, value); break; + case mxINT16_CLASS: assignTo<int16_t, T>(array, index, value); break; + case mxUINT16_CLASS: assignTo<uint16_t, T>(array, index, value); break; + case mxINT32_CLASS: assignTo<int32_t, T>(array, index, value); break; + case mxUINT32_CLASS: assignTo<uint32_t, T>(array, index, value); break; + case mxINT64_CLASS: assignTo<int64_t, T>(array, index, value); break; + case mxUINT64_CLASS: assignTo<uint64_t, T>(array, index, value); break; + case mxSINGLE_CLASS: assignTo<float, T>(array, index, value); break; + case mxDOUBLE_CLASS: assignTo<double, T>(array, index, value); break; + case mxLOGICAL_CLASS: assignTo<mxLogical, T>(array, index, value); break; + case mxCHAR_CLASS: assignCharTo<T>(array, index, value); break; + case mxCELL_CLASS: assignCellTo<T>(array, index, value); break; + // case mxSPARSE_CLASS: + default: + MEXPLUS_ASSERT(true, "Cannot convert %s", mxGetClassName(array)); + } +} + +template <typename T> +void MxArray::atInternal(const mxArray* array, mwIndex index, + typename std::enable_if< + std::is_compound<T>::value && + !MxComplexType<T>::value, T>::type* value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + MEXPLUS_ASSERT(mxIsCell(array), "Expected a cell array."); + const mxArray* element = mxGetCell(array, index); + to<T>(element, value); +} + +template <typename T> +void MxArray::atInternal(const mxArray* array, + const std::string& field, + mwIndex index, + T* value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_CHECK_NOTNULL(value); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + MEXPLUS_ASSERT(mxIsStruct(array), "Expected a struct array."); + const mxArray* element = mxGetField(array, index, field.c_str()); + MEXPLUS_ASSERT(element, "Invalid field name %s.", field.c_str()); + to<T>(element, value); +} + +/*************************************************************/ +/** Templated mxArray setters **/ +/*************************************************************/ + +/** Converter from fundamental numeric or complex types. + */ +template <typename T> +void MxArray::setInternal(mxArray* array, + mwIndex index, + const typename std::enable_if< + !std::is_compound<T>::value || + MxComplexType<T>::value, T>::type& value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + switch (mxGetClassID(array)) { + case mxINT8_CLASS: assignFrom<int8_t, T>(array, index, value); break; + case mxUINT8_CLASS: assignFrom<uint8_t, T>(array, index, value); break; + case mxINT16_CLASS: assignFrom<int16_t, T>(array, index, value); break; + case mxUINT16_CLASS: assignFrom<uint16_t, T>(array, index, value); break; + case mxINT32_CLASS: assignFrom<int32_t, T>(array, index, value); break; + case mxUINT32_CLASS: assignFrom<uint32_t, T>(array, index, value); break; + case mxINT64_CLASS: assignFrom<int64_t, T>(array, index, value); break; + case mxUINT64_CLASS: assignFrom<uint64_t, T>(array, index, value); break; + case mxSINGLE_CLASS: assignFrom<float, T>(array, index, value); break; + case mxDOUBLE_CLASS: assignFrom<double, T>(array, index, value); break; + case mxCHAR_CLASS: assignCharFrom<T>(array, index, value); break; + case mxLOGICAL_CLASS: assignFrom<mxLogical, T>(array, index, value); break; + case mxCELL_CLASS: { + mxArray* new_item = from(value); // Safe in case if from() fails. + + mxDestroyArray(mxGetCell(array, index)); + mxSetCell(array, index, new_item); + break; + } + default: + MEXPLUS_ERROR("Cannot assign to %s array.", mxGetClassName(array)); + } +} + +/** Converter from fundamental numeric or complex types. + */ +template <typename T> +void MxArray::setInternal(mxArray* array, + mwIndex index, + const typename std::enable_if< + MxCellType<T>::value, T>::type& value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + MEXPLUS_ASSERT(mxIsCell(array), "Expected a cell array."); + mxArray* new_item = from(value); // Safe in case if from() fails. + mxDestroyArray(mxGetCell(array, index)); + mxSetCell(array, index, new_item); +} + +template <typename T> +void MxArray::setInternal(mxArray* array, + const std::string& field, + mwIndex index, + const T& value) { + MEXPLUS_CHECK_NOTNULL(array); + MEXPLUS_ASSERT(static_cast<size_t>(index) < mxGetNumberOfElements(array), + "Index out of range: %u.", + index); + MEXPLUS_ASSERT(mxIsStruct(array), "Expected a struct array."); + int field_number = mxGetFieldNumber(array, field.c_str()); + if (field_number < 0) { + field_number = mxAddField(array, field.c_str()); + MEXPLUS_ASSERT(field_number >= 0, + "Failed to create a field '%s'", + field.c_str()); + } + mxArray* new_item = from(value); + mxDestroyArray(mxGetFieldByNumber(array, index, field_number)); + mxSetFieldByNumber(array, index, field_number, new_item); +} + +template <typename T> +mxArray* MxArray::Numeric(int rows, int columns) { + typedef typename std::enable_if< + MxComplexOrArithmeticType<T>::value, T>::type Scalar; + mxArray* numeric = mxCreateNumericMatrix(rows, + columns, + MxTypes<Scalar>::class_id, + MxTypes<Scalar>::complexity); + MEXPLUS_CHECK_NOTNULL(numeric); + return numeric; +} + +template <typename T> +mxArray* MxArray::Numeric(std::vector<std::size_t> dims) { + typedef typename std::enable_if< + MxComplexOrArithmeticType<T>::value, T>::type Scalar; + mxArray* numeric = mxCreateNumericArray(dims.size(), + &dims[0], + MxTypes<Scalar>::class_id, + MxTypes<Scalar>::complexity); + MEXPLUS_CHECK_NOTNULL(numeric); + return numeric; +} + +template <typename T> +T* MxArray::getData() const { + MEXPLUS_CHECK_NOTNULL(array_); + MEXPLUS_ASSERT(MxTypes<T>::class_id == classID(), + "Expected a %s array.", + typeid(T).name()); + return reinterpret_cast<T*>(mxGetData(array_)); +} + +template <typename T> +T* MxArray::getImagData() const { + MEXPLUS_CHECK_NOTNULL(array_); + MEXPLUS_ASSERT(MxTypes<T>::class_id == classID(), + "Expected a %s array.", + typeid(T).name()); + return reinterpret_cast<T*>(mxGetPi(array_)); +} + +template <typename T> +T MxArray::at(mwIndex row, mwIndex column) const { + return at<T>(subscriptIndex(row, column)); +} + +template <typename T> +T MxArray::at(const std::vector<mwIndex>& subscripts) const { + return at<T>(subscriptIndex(subscripts)); +} + +template <typename T> +void MxArray::set(mwIndex row, mwIndex column, const T& value) { + set<T>(subscriptIndex(row, column), value); +} + +template <typename T> +void MxArray::set(const std::vector<mwIndex>& subscripts, const T& value) { + set<T>(subscriptIndex(subscripts), value); +} + +} // namespace mexplus + +#endif // INCLUDE_MEXPLUS_MXARRAY_H_ diff --git a/wrapper_matlab/mxtypes.h b/wrapper_matlab/mxtypes.h new file mode 100644 index 0000000..bc8c1aa --- /dev/null +++ b/wrapper_matlab/mxtypes.h @@ -0,0 +1,345 @@ +/** MxTypes and other type traits for template. + * + * Copyright 2014 Kota Yamaguchi. + */ + +#ifndef INCLUDE_MEXPLUS_MXTYPES_H_ +#define INCLUDE_MEXPLUS_MXTYPES_H_ + +#include <mex.h> +#include <complex> +#include <type_traits> + +namespace mexplus { + +/************************************************************/ +/* Traits for fundamental datatypes. + Don't use with function templates due to type promotion! + (Ignore it and get PITA!) */ +/************************************************************/ + +/** Traits for mxLogical-convertibles. + */ +template <typename T, typename U = T> +struct MxLogicalTy : std::false_type {}; + +template <typename T> +struct MxLogicalTy<T, typename std::enable_if< + std::is_same<typename std::remove_cv<T>::type, bool>::value || + std::is_same<typename std::remove_cv<T>::type, mxLogical>::value, + T>::type> : std::true_type {}; + +/** Traits for mxChar-convertibles. + * + * Treat them as an integer types when they are specified signed or unsigned, + * because uint8_t is exactly unsigned char and there is no way to tell them + * apart. + */ +template <typename T, typename U = T> +struct MxCharTy : std::false_type {}; + +template <typename T> +struct MxCharTy<T, typename std::enable_if< + std::is_same<typename std::remove_cv<T>::type, char>::value || + // Visual Studio cannot distinguish these from uint. + // std::is_same<typename std::remove_cv<T>::type, char16_t>::value || + // std::is_same<typename std::remove_cv<T>::type, char32_t>::value || + std::is_same<typename std::remove_cv<T>::type, mxChar>::value || + std::is_same<typename std::remove_cv<T>::type, wchar_t>::value, + T>::type> : std::true_type {}; + +/** Traits for integer numerics. + */ +template <typename T, typename U = T> +struct MxIntTy : std::false_type {}; +template <typename T> +struct MxIntTy<T, typename std::enable_if< + std::is_integral<T>::value && + !MxLogicalTy<T>::value && + !MxCharTy<T>::value, + T>::type> : std::true_type {}; +/** Traits for arithmetic types. + */ +template <typename T, typename U = T> +struct MxArithmeticTy : std::false_type {}; +template <typename T> +struct MxArithmeticTy<T, typename std::enable_if< + (std::is_floating_point<T>::value) || (MxIntTy<T>::value), + T>::type> : std::true_type {}; + +/**********************************************/ +/* Introducing traits for MATLAB array types. */ +/**********************************************/ + +typedef struct mxNumeric_tag {} mxNumeric; +typedef struct mxCell_tag {} mxCell; +typedef struct mxComplex_tag {} mxComplex; +// mxLogical already defined in MATLAB (matrix.h). + +/** Traits for mxArray. + */ +template <typename T, typename U = T> +struct MxTypes { + typedef T type; + typedef mxCell array_type; + static const mxClassID class_id = mxUNKNOWN_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<MxCharTy<T>::value, T>::type> { + typedef T type; + typedef mxChar array_type; + static const mxClassID class_id = mxCHAR_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<MxLogicalTy<T>::value, T>::type> { + typedef T type; + typedef mxLogical array_type; + static const mxClassID class_id = mxLOGICAL_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_signed<T>::value && + MxIntTy<T>::value && + sizeof(T) == 1, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxINT8_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_unsigned<T>::value && + MxIntTy<T>::value && + sizeof(T) == 1, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxUINT8_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_signed<T>::value && + MxIntTy<T>::value && + sizeof(T) == 2, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxINT16_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_unsigned<T>::value && + MxIntTy<T>::value && + sizeof(T) == 2, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxUINT16_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_signed<T>::value && + MxIntTy<T>::value && + sizeof(T) == 4, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxINT32_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_unsigned<T>::value && + MxIntTy<T>::value && + sizeof(T) == 4, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxUINT32_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_signed<T>::value && + MxIntTy<T>::value && + sizeof(T) == 8, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxINT64_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_unsigned<T>::value && + MxIntTy<T>::value && + sizeof(T) == 8, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxUINT64_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_floating_point<T>::value && + sizeof(T) == 4, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxSINGLE_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if<std::is_floating_point<T>::value && + sizeof(T) == 8, T>::type> { + typedef T type; + typedef mxNumeric array_type; + static const mxClassID class_id = mxDOUBLE_CLASS; + static const mxComplexity complexity = mxREAL; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if< + std::is_same<typename std::remove_cv<T>::type, + std::complex<float>>::value, + T>::type> { + typedef T type; + typedef mxComplex array_type; + static const mxClassID class_id = mxSINGLE_CLASS; + static const mxComplexity complexity = mxCOMPLEX; +}; + +template <typename T> +struct MxTypes<T, typename std::enable_if< + std::is_same<typename std::remove_cv<T>::type, + std::complex<double>>::value, + T>::type> { + typedef T type; + typedef mxComplex array_type; + static const mxClassID class_id = mxDOUBLE_CLASS; + static const mxComplexity complexity = mxCOMPLEX; +}; + +/********************************************/ +/* Type traits for function template usage. */ +/********************************************/ + +/* Traits for logical types. + */ +template <typename T, typename U = T> +struct MxLogicalType : std::false_type {}; +template<typename T> +struct MxLogicalType<T, typename std::enable_if< + std::is_same<typename MxTypes<T>::array_type, mxLogical>::value, + T>::type> : std::true_type {}; + +/* Traits for char types. + */ +template <typename T, typename U = T> +struct MxCharType : std::false_type {}; +template<typename T> +struct MxCharType<T, typename std::enable_if< + std::is_same<typename MxTypes<T>::array_type, mxChar>::value, + T>::type> : std::true_type {}; + +/* Traits for arithmetic types. + */ +template <typename T, typename U = T> +struct MxArithmeticType : std::false_type {}; +template<typename T> +struct MxArithmeticType<T, typename std::enable_if< + std::is_same<typename MxTypes<T>::array_type, mxNumeric>::value, + T>::type> : std::true_type {}; + +/* Traits for complex types. + */ +template <typename T, typename U = T> +struct MxComplexType : std::false_type {}; +template<typename T> +struct MxComplexType<T, typename std::enable_if< + std::is_same<typename MxTypes<T>::array_type, mxComplex>::value, + T>::type> : std::true_type {}; + +/* Traits for complex or arithmetic types. + */ +template <typename T, typename U = T> +struct MxComplexOrArithmeticType : std::false_type {}; +template <typename T> +struct MxComplexOrArithmeticType<T, typename std::enable_if< + MxComplexType<T>::value, + T>::type> : std::true_type {}; +template <typename T> +struct MxComplexOrArithmeticType<T, typename std::enable_if< + MxArithmeticTy<T>::value, + T>::type> : std::true_type {}; + +/* Traits for cell types. + */ +template <typename T, typename U = T> +struct MxCellType : std::false_type {}; +template <typename T> +struct MxCellType<T, typename std::enable_if< + std::is_same<typename MxTypes<T>::array_type, mxCell>::value, + T>::type> : std::true_type {}; + +/* Traits for logical type compounds. + */ +template <typename T, typename U = T> +struct MxLogicalCompound : std::false_type {}; +template <typename T> +struct MxLogicalCompound<T, typename std::enable_if< + MxLogicalType<typename T::value_type>::value, + T>::type> : std::true_type {}; + +/* Traits for char type compounds. + */ +template <typename T, typename U = T> +struct MxCharCompound : std::false_type {}; +template <typename T> +struct MxCharCompound<T, typename std::enable_if< + MxCharType<typename T::value_type>::value, + T>::type> : std::true_type {}; + +/* Traits for arithmetic type compounds. + */ +template <typename T, typename U = T> +struct MxArithmeticCompound : std::false_type {}; +template <typename T> +struct MxArithmeticCompound<T, typename std::enable_if< + (MxArithmeticType<typename T::value_type>::value) && + !(MxComplexType<T>::value), + T>::type> : std::true_type {}; + +/* Traits for complex type compounds. + */ +template <typename T, typename U = T> +struct MxComplexCompound : std::false_type {}; +template <typename T> +struct MxComplexCompound<T, typename std::enable_if< + MxComplexType<typename T::value_type>::value, + T>::type> : std::true_type {}; + +/* Traits for complex or arithmetic type compounds. + */ +template <typename T, typename U = T> +struct MxComplexOrArithmeticCompound : std::false_type {}; +template <typename T> +struct MxComplexOrArithmeticCompound<T, typename std::enable_if< + MxComplexCompound<T>::value || + MxArithmeticCompound<T>::value, + T>::type> : std::true_type {}; + +/* Traits for cell compounds. + */ +template <typename T, typename U = T> +struct MxCellCompound : std::false_type {}; +template <typename T> +struct MxCellCompound<T, typename std::enable_if< + MxCellType<typename T::value_type>::value, + T>::type> : std::true_type {}; + +} // namespace mexplus + +#endif // INCLUDE_MEXPLUS_MXTYPES_H_ diff --git a/wrapper_matlab/run_demo.m b/wrapper_matlab/run_demo.m new file mode 100644 index 0000000..e27174d --- /dev/null +++ b/wrapper_matlab/run_demo.m @@ -0,0 +1,49 @@ +%% Compile the BGSLibrary wrapper +compile; + +%% Run demo +demo; + +%% Run a specific algorithm +demo('FrameDifference') +% demo('StaticFrameDifference') +% demo('WeightedMovingMean') +% demo('WeightedMovingVariance') +% demo('MixtureOfGaussianV1') % only for OpenCV 2.x +% demo('MixtureOfGaussianV2') +% demo('AdaptiveBackgroundLearning') +% demo('AdaptiveSelectiveBackgroundLearning') +% demo('GMG') % only on OpenCV >= 2.4.3 +% demo('KNN') % only on OpenCV 3.x +% demo('DPAdaptiveMedian') +% demo('DPGrimsonGMM') +% demo('DPZivkovicAGMM') +% demo('DPMean') +% demo('DPWrenGA') +% demo('DPPratiMediod') +% demo('DPEigenbackground') +% demo('DPTexture') +% demo('T2FGMM_UM') +% demo('T2FGMM_UV') +% demo('T2FMRF_UM') +% demo('T2FMRF_UV') +% demo('FuzzySugenoIntegral') +% demo('FuzzyChoquetIntegral') +% demo('LBSimpleGaussian') +% demo('LBFuzzyGaussian') +% demo('LBMixtureOfGaussians') +% demo('LBAdaptiveSOM') +% demo('LBFuzzyAdaptiveSOM') +% demo('LBP_MRF') +% demo('MultiLayer') +% demo('PixelBasedAdaptiveSegmenter') +% demo('VuMeter') +% demo('KDE') +% demo('IndependentMultimodal') +% demo('MultiCue') +% demo('SigmaDelta') +% demo('SuBSENSE') +% demo('LOBSTER') +% demo('PAWCS') +% demo('TwoPoints') +% demo('ViBe') \ No newline at end of file diff --git a/wrapper_python/bgslibrary_module.cpp b/wrapper_python/bgslibrary_module.cpp new file mode 100644 index 0000000..edb75a8 --- /dev/null +++ b/wrapper_python/bgslibrary_module.cpp @@ -0,0 +1,265 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <exception> + +#include <opencv2/opencv.hpp> +#include "np_opencv_converter.h" + +#include "../package_bgs/bgslibrary.h" + +namespace py = boost::python; + +cv::Mat test_transpose(const cv::Mat& in) +{ + std::cerr << "Input size: " << in.size() << std::endl; + std::cerr << "Returning transpose" << std::endl; + return in.t(); +} + +namespace fs +{ + namespace python + { + BOOST_PYTHON_MODULE(libbgs) + { + // Main types export + fs::python::init_and_export_converters(); + py::scope scope = py::scope(); + + // Basic test + py::def("test_transpose", &test_transpose); + + py::class_<FrameDifference>("FrameDifference") + .def("apply", &FrameDifference::apply) + .def("getBackgroundModel", &FrameDifference::getBackgroundModel) + ; + + py::class_<StaticFrameDifference>("StaticFrameDifference") + .def("apply", &StaticFrameDifference::apply) + .def("getBackgroundModel", &StaticFrameDifference::getBackgroundModel) + ; + + py::class_<AdaptiveBackgroundLearning>("AdaptiveBackgroundLearning") + .def("apply", &AdaptiveBackgroundLearning::apply) + .def("getBackgroundModel", &AdaptiveBackgroundLearning::getBackgroundModel) + ; + + py::class_<AdaptiveSelectiveBackgroundLearning>("AdaptiveSelectiveBackgroundLearning") + .def("apply", &AdaptiveSelectiveBackgroundLearning::apply) + .def("getBackgroundModel", &AdaptiveSelectiveBackgroundLearning::getBackgroundModel) + ; + + py::class_<DPAdaptiveMedian>("DPAdaptiveMedian") + .def("apply", &DPAdaptiveMedian::apply) + .def("getBackgroundModel", &DPAdaptiveMedian::getBackgroundModel) + ; + + py::class_<DPEigenbackground>("DPEigenbackground") + .def("apply", &DPEigenbackground::apply) + .def("getBackgroundModel", &DPEigenbackground::getBackgroundModel) + ; + + py::class_<DPGrimsonGMM>("DPGrimsonGMM") + .def("apply", &DPGrimsonGMM::apply) + .def("getBackgroundModel", &DPGrimsonGMM::getBackgroundModel) + ; + + py::class_<DPMean>("DPMean") + .def("apply", &DPMean::apply) + .def("getBackgroundModel", &DPMean::getBackgroundModel) + ; + + py::class_<DPPratiMediod>("DPPratiMediod") + .def("apply", &DPPratiMediod::apply) + .def("getBackgroundModel", &DPPratiMediod::getBackgroundModel) + ; + + py::class_<DPTexture>("DPTexture") + .def("apply", &DPTexture::apply) + .def("getBackgroundModel", &DPTexture::getBackgroundModel) + ; + + py::class_<DPWrenGA>("DPWrenGA") + .def("apply", &DPWrenGA::apply) + .def("getBackgroundModel", &DPWrenGA::getBackgroundModel) + ; + + py::class_<DPZivkovicAGMM>("DPZivkovicAGMM") + .def("apply", &DPZivkovicAGMM::apply) + .def("getBackgroundModel", &DPZivkovicAGMM::getBackgroundModel) + ; + + py::class_<FuzzyChoquetIntegral>("FuzzyChoquetIntegral") + .def("apply", &FuzzyChoquetIntegral::apply) + .def("getBackgroundModel", &FuzzyChoquetIntegral::getBackgroundModel) + ; + + py::class_<FuzzySugenoIntegral>("FuzzySugenoIntegral") + .def("apply", &FuzzySugenoIntegral::apply) + .def("getBackgroundModel", &FuzzySugenoIntegral::getBackgroundModel) + ; + +#if CV_MAJOR_VERSION == 2 + py::class_<GMG>("GMG") + .def("apply", &GMG::apply) + .def("getBackgroundModel", &GMG::getBackgroundModel) + ; +#endif + + py::class_<IndependentMultimodal>("IndependentMultimodal") + .def("apply", &IndependentMultimodal::apply) + .def("getBackgroundModel", &IndependentMultimodal::getBackgroundModel) + ; + + py::class_<KDE>("KDE") + .def("apply", &KDE::apply) + .def("getBackgroundModel", &KDE::getBackgroundModel) + ; + +#if CV_MAJOR_VERSION == 3 + py::class_<KNN>("KNN") + .def("apply", &KNN::apply) + .def("getBackgroundModel", &KNN::getBackgroundModel) + ; +#endif + + py::class_<LBAdaptiveSOM>("LBAdaptiveSOM") + .def("apply", &LBAdaptiveSOM::apply) + .def("getBackgroundModel", &LBAdaptiveSOM::getBackgroundModel) + ; + + py::class_<LBFuzzyAdaptiveSOM>("LBFuzzyAdaptiveSOM") + .def("apply", &LBFuzzyAdaptiveSOM::apply) + .def("getBackgroundModel", &LBFuzzyAdaptiveSOM::getBackgroundModel) + ; + + py::class_<LBFuzzyGaussian>("LBFuzzyGaussian") + .def("apply", &LBFuzzyGaussian::apply) + .def("getBackgroundModel", &LBFuzzyGaussian::getBackgroundModel) + ; + + py::class_<LBMixtureOfGaussians>("LBMixtureOfGaussians") + .def("apply", &LBMixtureOfGaussians::apply) + .def("getBackgroundModel", &LBMixtureOfGaussians::getBackgroundModel) + ; + + py::class_<LBSimpleGaussian>("LBSimpleGaussian") + .def("apply", &LBSimpleGaussian::apply) + .def("getBackgroundModel", &LBSimpleGaussian::getBackgroundModel) + ; + + py::class_<LBP_MRF>("LBP_MRF") + .def("apply", &LBP_MRF::apply) + .def("getBackgroundModel", &LBP_MRF::getBackgroundModel) + ; + + py::class_<LOBSTER>("LOBSTER") + .def("apply", &LOBSTER::apply) + .def("getBackgroundModel", &LOBSTER::getBackgroundModel) + ; + +#if CV_MAJOR_VERSION == 2 + py::class_<MixtureOfGaussianV1>("MixtureOfGaussianV1") + .def("apply", &MixtureOfGaussianV1::apply) + .def("getBackgroundModel", &MixtureOfGaussianV1::getBackgroundModel) + ; +#endif + + py::class_<MixtureOfGaussianV2>("MixtureOfGaussianV2") + .def("apply", &MixtureOfGaussianV2::apply) + .def("getBackgroundModel", &MixtureOfGaussianV2::getBackgroundModel) + ; + + py::class_<MultiCue>("MultiCue") + .def("apply", &MultiCue::apply) + .def("getBackgroundModel", &MultiCue::getBackgroundModel) + ; + + py::class_<MultiLayer>("MultiLayer") + .def("apply", &MultiLayer::apply) + .def("getBackgroundModel", &MultiLayer::getBackgroundModel) + ; + + py::class_<PAWCS>("PAWCS") + .def("apply", &PAWCS::apply) + .def("getBackgroundModel", &PAWCS::getBackgroundModel) + ; + + py::class_<PixelBasedAdaptiveSegmenter>("PixelBasedAdaptiveSegmenter") + .def("apply", &PixelBasedAdaptiveSegmenter::apply) + .def("getBackgroundModel", &PixelBasedAdaptiveSegmenter::getBackgroundModel) + ; + + py::class_<SigmaDelta>("SigmaDelta") + .def("apply", &SigmaDelta::apply) + .def("getBackgroundModel", &SigmaDelta::getBackgroundModel) + ; + + py::class_<SuBSENSE>("SuBSENSE") + .def("apply", &SuBSENSE::apply) + .def("getBackgroundModel", &SuBSENSE::getBackgroundModel) + ; + + py::class_<T2FGMM_UM>("T2FGMM_UM") + .def("apply", &T2FGMM_UM::apply) + .def("getBackgroundModel", &T2FGMM_UM::getBackgroundModel) + ; + + py::class_<T2FGMM_UV>("T2FGMM_UV") + .def("apply", &T2FGMM_UV::apply) + .def("getBackgroundModel", &T2FGMM_UV::getBackgroundModel) + ; + + py::class_<T2FMRF_UM>("T2FMRF_UM") + .def("apply", &T2FMRF_UM::apply) + .def("getBackgroundModel", &T2FMRF_UM::getBackgroundModel) + ; + + py::class_<T2FMRF_UV>("T2FMRF_UV") + .def("apply", &T2FMRF_UV::apply) + .def("getBackgroundModel", &T2FMRF_UV::getBackgroundModel) + ; + + py::class_<VuMeter>("VuMeter") + .def("apply", &VuMeter::apply) + .def("getBackgroundModel", &VuMeter::getBackgroundModel) + ; + + py::class_<WeightedMovingMean>("WeightedMovingMean") + .def("apply", &WeightedMovingMean::apply) + .def("getBackgroundModel", &WeightedMovingMean::getBackgroundModel) + ; + + py::class_<WeightedMovingVariance>("WeightedMovingVariance") + .def("apply", &WeightedMovingVariance::apply) + .def("getBackgroundModel", &WeightedMovingVariance::getBackgroundModel) + ; + + py::class_<TwoPoints>("TwoPoints") + .def("apply", &TwoPoints::apply) + .def("getBackgroundModel", &TwoPoints::getBackgroundModel) + ; + + py::class_<ViBe>("ViBe") + .def("apply", &ViBe::apply) + .def("getBackgroundModel", &ViBe::getBackgroundModel) + ; + } + } // namespace fs +} // namespace python diff --git a/wrapper_python/np_opencv_converter.cpp b/wrapper_python/np_opencv_converter.cpp new file mode 100644 index 0000000..6050f6b --- /dev/null +++ b/wrapper_python/np_opencv_converter.cpp @@ -0,0 +1,103 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#include "np_opencv_converter.h" + +namespace fs { namespace python { + +// Static PyInit +static void py_init() { + Py_Initialize(); + import_array(); +} + +// Singleton init and export converters +static bool export_type_conversions_once = false; +bool init_and_export_converters() { + + if (export_type_conversions_once) + return false; + + std::cerr << "PYTHON TYPE CONVERTERS exported" << std::endl; + export_type_conversions_once = true; + + // Py_Init and array import + py_init(); + + // => py::list + expose_template_type<int>(); + expose_template_type<float>(); + expose_template_type<double>(); + + // std::vector => py::list + expose_template_type< std::vector<int> >(); + expose_template_type< std::vector<float> >(); + expose_template_type< std::vector<double> >(); + + expose_template_type< std::vector<cv::Point> >(); + expose_template_type< std::vector<cv::Point2f> >(); + expose_template_type< std::vector<cv::KeyPoint> >(); + + expose_template_type< std::vector<cv::Mat> >(); + expose_template_type< std::vector<cv::Mat1b > >(); + expose_template_type< std::vector<cv::Mat1f > >(); + + // std::map => py::dict + expose_template_type<std::map<int, std::vector<int> > >(); + expose_template_type<std::map<int, std::vector<float> > >(); + expose_template_type<std::map<std::string, float> >(); + + // various converters to cv::Mat + py::to_python_converter<cv::Point, Point_to_mat>(); + py::to_python_converter<cv::Point2f, Point2f_to_mat>(); + py::to_python_converter<cv::Point3f, Point3f_to_mat>(); + py::to_python_converter<cv::Vec3f, Vec3f_to_mat>(); + + // register the to-from-python converter for each of the types + Mat_PyObject_converter< cv::Mat >(); + + // 1-channel + Mat_PyObject_converter< cv::Mat1b >(); + Mat_PyObject_converter< cv::Mat1s >(); + Mat_PyObject_converter< cv::Mat1w >(); + Mat_PyObject_converter< cv::Mat1i >(); + Mat_PyObject_converter< cv::Mat1f >(); + Mat_PyObject_converter< cv::Mat1d >(); + + // 2-channel + Mat_PyObject_converter< cv::Mat2b >(); + Mat_PyObject_converter< cv::Mat2s >(); + Mat_PyObject_converter< cv::Mat2w >(); + Mat_PyObject_converter< cv::Mat2i >(); + Mat_PyObject_converter< cv::Mat2f >(); + Mat_PyObject_converter< cv::Mat2d >(); + + // 3-channel + Mat_PyObject_converter< cv::Mat3b >(); + Mat_PyObject_converter< cv::Mat3s >(); + Mat_PyObject_converter< cv::Mat3w >(); + Mat_PyObject_converter< cv::Mat3i >(); + Mat_PyObject_converter< cv::Mat3f >(); + Mat_PyObject_converter< cv::Mat3d >(); + + // add more if needed + + return true; +} + +} // namespace python +} // namespace fs + diff --git a/wrapper_python/np_opencv_converter.h b/wrapper_python/np_opencv_converter.h new file mode 100644 index 0000000..68386f0 --- /dev/null +++ b/wrapper_python/np_opencv_converter.h @@ -0,0 +1,122 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> + +#include "utils/template.h" +#include "utils/container.h" +#include "utils/conversion.h" + +#include <opencv2/opencv.hpp> + +namespace fs { namespace python { + +// TODO: Template these +// Vec3f => cv::Mat +struct Vec3f_to_mat { + static PyObject* convert(const cv::Vec3f& v){ + NDArrayConverter cvt; + PyObject* ret = cvt.toNDArray(cv::Mat(v)); + return ret; + } +}; + +// cv::Point => cv::Mat +struct Point_to_mat { + static PyObject* convert(const cv::Point& v){ + NDArrayConverter cvt; + PyObject* ret = cvt.toNDArray(cv::Mat(v)); + return ret; + } +}; + +// cv::Point2f => cv::Mat +struct Point2f_to_mat { + static PyObject* convert(const cv::Point2f& v){ + NDArrayConverter cvt; + PyObject* ret = cvt.toNDArray(cv::Mat(v)); + return ret; + } +}; + +// cv::Point3f => cv::Mat +struct Point3f_to_mat { + static PyObject* convert(const cv::Point3f& v){ + NDArrayConverter cvt; + PyObject* ret = cvt.toNDArray(cv::Mat(v)); + return ret; + } +}; + +// cv::Mat_<T> => Numpy PyObject +template <typename T> +struct Mat_to_PyObject { + static PyObject* convert(const T& mat){ + NDArrayConverter cvt; + PyObject* ret = cvt.toNDArray(mat); + return ret; + } +}; + +// Generic templated cv::Mat <=> Numpy PyObject converter +template <typename T> +struct Mat_PyObject_converter +{ + // Register from converter + Mat_PyObject_converter() { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id<T>()); + + // Register to converter + py::to_python_converter<T, Mat_to_PyObject<T> >(); + } + + // Convert from type T to PyObject (numpy array) + // Assume obj_ptr can be converted in a cv::Mat + static void* convertible(PyObject* obj_ptr) + { + // Check validity? + assert(obj_ptr != 0); + return obj_ptr; + } + + // Convert obj_ptr into a cv::Mat + static void construct(PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + using namespace boost::python; + typedef converter::rvalue_from_python_storage< T > storage_t; + + storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + void* memory_chunk = the_storage->storage.bytes; + + NDArrayConverter cvt; + T* newvec = new (memory_chunk) T(cvt.toMat(obj_ptr)); + data->convertible = memory_chunk; + + return; + } +}; + +bool init_and_export_converters(); + +} // namespace python +} // namespace fs diff --git a/wrapper_python/utils/container.h b/wrapper_python/utils/container.h new file mode 100644 index 0000000..3db5613 --- /dev/null +++ b/wrapper_python/utils/container.h @@ -0,0 +1,208 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +// Author: Sudeep Pillai (spillai@csail.mit.edu) +// Note: Stripped from pyxx project + +#pragma once + +#include <boost/python.hpp> +#include <boost/python/class.hpp> +#include <boost/python/module.hpp> +#include <boost/foreach.hpp> + +#include <vector> +#include <string> +#include <stdexcept> +#include <iostream> +#include <map> +#include <list> + +namespace py = boost::python; + +template<typename T> +struct expose_template_type< std::vector<T> > : + public expose_template_type_base< std::vector<T> > +{ + typedef expose_template_type_base< std::vector<T> > base_type; + typedef expose_template_type< std::vector<T> > this_type; + typedef std::vector<T> wrapped_type; + + expose_template_type() + { + ::expose_template_type<T>(); + if( !base_type::wrapped() ) + { + py::to_python_converter< wrapped_type, this_type >(); + py::converter::registry::push_back( + this_type::convertible, + this_type::construct, + py::type_id< wrapped_type >() ); + + } + } + + static PyObject * convert( const wrapped_type & container) + { + py::list l; + for(typename wrapped_type::const_iterator iter = container.begin(); iter != container.end(); iter++) + { + l.append( py::object( *iter ) ); + } + Py_INCREF( l.ptr() ); + return l.ptr(); + } + + static void * convertible( PyObject * py_obj) + { + // we are supposed to indicate whether or not we can convert this + // we don't really know, but we'll try any sequence + if( PySequence_Check(py_obj) ) + return py_obj; + return 0; + } + + static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) + { + using namespace boost::python; + typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; + + storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + void* memory_chunk = the_storage->storage.bytes; + wrapped_type * newvec = new (memory_chunk) wrapped_type; + data->convertible = memory_chunk; + + object sequence(handle<>( borrowed( py_obj ) ) ); + + for(int idx = 0; idx < len(sequence);idx++) + { + newvec->push_back( extract<T>( sequence[idx] )() ); + } + + } + +}; + +template<typename Key, typename Value> + struct expose_template_type< std::map<Key, Value> > : + public expose_template_type_base< std::map<Key, Value> > +{ + typedef std::map<Key, Value> wrapped_type; + typedef expose_template_type_base< wrapped_type > base_type; + typedef expose_template_type< wrapped_type > this_type; + + expose_template_type() + { + if( !base_type::wrapped() ) + { + py::to_python_converter< wrapped_type, this_type >(); + py::converter::registry::push_back( + this_type::convertible, + this_type::construct, + py::type_id< wrapped_type >() ); + + } + } + + static PyObject * convert( const wrapped_type & container) + { + py::dict d; + for(typename wrapped_type::const_iterator iter = container.begin(); iter != container.end(); iter++) + { + d[iter->first] = py::object(iter->second); + } + Py_INCREF( d.ptr() ); + return d.ptr(); + } + + static void * convertible( PyObject * py_obj) + { + // we are supposed to indicate whether or not we can convert this + // we don't really know, but we'll try any sequence + if( PyMapping_Check(py_obj) ) + return py_obj; + return 0; + } + + static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) + { + using namespace boost::python; + typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; + + storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + void* memory_chunk = the_storage->storage.bytes; + wrapped_type * newvec = new (memory_chunk) wrapped_type; + data->convertible = memory_chunk; + + object sequence(handle<>( borrowed( py_obj ) ) ); + sequence = sequence.attr("items")(); + + for(int idx = 0; idx < len(sequence);idx++) + { + Key key = py::extract<Key>(sequence[idx][0])(); + Value value = py::extract<Value>(sequence[idx][1])(); + (*newvec)[key] = value; + } + + } + +}; + +template<typename Key, typename Value> + struct expose_template_type< typename std::pair<Key, Value> > : + public expose_template_type_base< std::pair<Key, Value> > +{ + typedef std::pair<Key, Value> wrapped_type; + typedef expose_template_type_base< wrapped_type > base_type; + typedef expose_template_type< wrapped_type > this_type; + + expose_template_type() + { + if( !base_type::wrapped() ) + { + py::converter::registry::push_back( + this_type::convertible, + this_type::construct, + py::type_id< wrapped_type >() ); + + } + } + + static void * convertible( PyObject * py_obj) + { + // we are supposed to indicate whether or not we can convert this + // we don't really know, but we'll try any sequence + if( PyTuple_Check(py_obj) && PyTuple_Size(py_obj) == 2) + return py_obj; + return 0; + } + + static void construct( PyObject * py_obj, py::converter::rvalue_from_python_stage1_data* data) + { + using namespace boost::python; + typedef converter::rvalue_from_python_storage< wrapped_type > storage_t; + + storage_t* the_storage = reinterpret_cast<storage_t*>( data ); + void* memory_chunk = the_storage->storage.bytes; + wrapped_type * newvec = new (memory_chunk) wrapped_type; + data->convertible = memory_chunk; + + object sequence(handle<>( borrowed( py_obj ) ) ); + newvec->first = extract<Key>(sequence[0])(); + newvec->second = extract<Value>(sequence[1])(); + } + +}; diff --git a/wrapper_python/utils/conversion.cpp b/wrapper_python/utils/conversion.cpp new file mode 100644 index 0000000..7ca21dd --- /dev/null +++ b/wrapper_python/utils/conversion.cpp @@ -0,0 +1,349 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +// Author: Sudeep Pillai (spillai@csail.mit.edu) +// Note: Stripped from Opencv (opencv/modules/python/src2/cv2.cpp) + +# include "conversion.h" +/* + * The following conversion functions are taken/adapted from OpenCV's cv2.cpp file + * inside modules/python/src2 folder. + */ + +static void init() +{ + import_array(); +} + +static int failmsg(const char *fmt, ...) +{ + char str[1000]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + PyErr_SetString(PyExc_TypeError, str); + return 0; +} + +class PyAllowThreads +{ +public: + PyAllowThreads() : _state(PyEval_SaveThread()) {} + ~PyAllowThreads() + { + PyEval_RestoreThread(_state); + } +private: + PyThreadState* _state; +}; + +class PyEnsureGIL +{ +public: + PyEnsureGIL() : _state(PyGILState_Ensure()) {} + ~PyEnsureGIL() + { + PyGILState_Release(_state); + } +private: + PyGILState_STATE _state; +}; + +using namespace cv; +static PyObject* failmsgp(const char *fmt, ...) +{ + char str[1000]; + + va_list ap; + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + PyErr_SetString(PyExc_TypeError, str); + return 0; +} + +#define OPENCV_3 0 +#if OPENCV_3 +class NumpyAllocator : public MatAllocator +{ +public: + NumpyAllocator() { stdAllocator = Mat::getStdAllocator(); } + ~NumpyAllocator() {} + + UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const + { + UMatData* u = new UMatData(this); + u->data = u->origdata = (uchar*)PyArray_DATA((PyArrayObject*) o); + npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); + for( int i = 0; i < dims - 1; i++ ) + step[i] = (size_t)_strides[i]; + step[dims-1] = CV_ELEM_SIZE(type); + u->size = sizes[0]*step[0]; + u->userdata = o; + return u; + } + + UMatData* allocate(int dims0, const int* sizes, int type, void* data, size_t* step, int flags) const + { + if( data != 0 ) + { + CV_Error(Error::StsAssert, "The data should normally be NULL!"); + // probably this is safe to do in such extreme case + return stdAllocator->allocate(dims0, sizes, type, data, step, flags); + } + PyEnsureGIL gil; + + int depth = CV_MAT_DEPTH(type); + int cn = CV_MAT_CN(type); + const int f = (int)(sizeof(size_t)/8); + int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : + depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : + depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : + depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; + int i, dims = dims0; + cv::AutoBuffer<npy_intp> _sizes(dims + 1); + for( i = 0; i < dims; i++ ) + _sizes[i] = sizes[i]; + if( cn > 1 ) + _sizes[dims++] = cn; + PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); + if(!o) + CV_Error_(Error::StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); + return allocate(o, dims0, sizes, type, step); + } + + bool allocate(UMatData* u, int accessFlags) const + { + return stdAllocator->allocate(u, accessFlags); + } + + void deallocate(UMatData* u) const + { + if(u) + { + PyEnsureGIL gil; + PyObject* o = (PyObject*)u->userdata; + Py_XDECREF(o); + delete u; + } + } + + const MatAllocator* stdAllocator; +}; +#else +class NumpyAllocator : public MatAllocator +{ +public: + NumpyAllocator() {} + ~NumpyAllocator() {} + + void allocate(int dims, const int* sizes, int type, int*& refcount, + uchar*& datastart, uchar*& data, size_t* step) + { + PyEnsureGIL gil; + + int depth = CV_MAT_DEPTH(type); + int cn = CV_MAT_CN(type); + const int f = (int)(sizeof(size_t)/8); + int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE : + depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT : + depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT : + depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT; + int i; + npy_intp _sizes[CV_MAX_DIM+1]; + for( i = 0; i < dims; i++ ) + _sizes[i] = sizes[i]; + if( cn > 1 ) + { + /*if( _sizes[dims-1] == 1 ) + _sizes[dims-1] = cn; + else*/ + _sizes[dims++] = cn; + } + PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum); + if(!o) + CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims)); + refcount = refcountFromPyObject(o); + npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); + for( i = 0; i < dims - (cn > 1); i++ ) + step[i] = (size_t)_strides[i]; + datastart = data = (uchar*)PyArray_DATA((PyArrayObject*) o); + } + + void deallocate(int* refcount, uchar*, uchar*) + { + PyEnsureGIL gil; + if( !refcount ) + return; + PyObject* o = pyObjectFromRefcount(refcount); + Py_INCREF(o); + Py_DECREF(o); + } +}; +#endif + + + +NumpyAllocator g_numpyAllocator; + +NDArrayConverter::NDArrayConverter() { init(); } + +void NDArrayConverter::init() +{ + import_array(); +} + +cv::Mat NDArrayConverter::toMat(const PyObject *o) +{ + cv::Mat m; + + if(!o || o == Py_None) + { + if( !m.data ) + m.allocator = &g_numpyAllocator; + } + + if( !PyArray_Check(o) ) + { + failmsg("toMat: Object is not a numpy array"); + } + + int typenum = PyArray_TYPE(o); + int type = typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S : + typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S : + typenum == NPY_INT || typenum == NPY_LONG ? CV_32S : + typenum == NPY_FLOAT ? CV_32F : + typenum == NPY_DOUBLE ? CV_64F : -1; + + if( type < 0 ) + { + failmsg("toMat: Data type = %d is not supported", typenum); + } + + int ndims = PyArray_NDIM(o); + + if(ndims >= CV_MAX_DIM) + { + failmsg("toMat: Dimensionality (=%d) is too high", ndims); + } + + int size[CV_MAX_DIM+1]; + size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type); + const npy_intp* _sizes = PyArray_DIMS(o); + const npy_intp* _strides = PyArray_STRIDES(o); + bool transposed = false; + + for(int i = 0; i < ndims; i++) + { + size[i] = (int)_sizes[i]; + step[i] = (size_t)_strides[i]; + } + + if( ndims == 0 || step[ndims-1] > elemsize ) { + size[ndims] = 1; + step[ndims] = elemsize; + ndims++; + } + + if( ndims >= 2 && step[0] < step[1] ) + { + std::swap(size[0], size[1]); + std::swap(step[0], step[1]); + transposed = true; + } + + // std::cerr << " ndims: " << ndims + // << " size: " << size + // << " type: " << type + // << " step: " << step + // << " size: " << size[2] << std::endl; + + // TODO: Possible bug in multi-dimensional matrices +#if 1 + if( ndims == 3 && size[2] <= CV_CN_MAX && step[1] == elemsize*size[2] ) + { + ndims--; + type |= CV_MAKETYPE(0, size[2]); + } +#endif + + if( ndims > 2) + { + failmsg("toMat: Object has more than 2 dimensions"); + } + + m = Mat(ndims, size, type, PyArray_DATA(o), step); + // m.u = g_numpyAllocator.allocate(o, ndims, size, type, step); + + if( m.data ) + { +#if OPENCV_3 + m.addref(); + Py_INCREF(o); +#else + m.refcount = refcountFromPyObject(o); + m.addref(); // protect the original numpy array from deallocation + // (since Mat destructor will decrement the reference counter) +#endif + }; + m.allocator = &g_numpyAllocator; + + if( transposed ) + { + Mat tmp; + tmp.allocator = &g_numpyAllocator; + transpose(m, tmp); + m = tmp; + } + return m; +} + +PyObject* NDArrayConverter::toNDArray(const cv::Mat& m) +{ +#if OPENCV_3 + if( !m.data ) + Py_RETURN_NONE; + Mat temp, *p = (Mat*)&m; + if(!p->u || p->allocator != &g_numpyAllocator) + { + temp.allocator = &g_numpyAllocator; + m.copyTo(temp); + p = &temp; + } + PyObject* o = (PyObject*)p->u->userdata; + Py_INCREF(o); + // p->addref(); + // pyObjectFromRefcount(p->refcount); + return o; +#else + if( !m.data ) + Py_RETURN_NONE; + Mat temp, *p = (Mat*)&m; + if(!p->refcount || p->allocator != &g_numpyAllocator) + { + temp.allocator = &g_numpyAllocator; + ERRWRAP2(m.copyTo(temp)); + p = &temp; + } + p->addref(); + return pyObjectFromRefcount(p->refcount); +#endif + +} diff --git a/wrapper_python/utils/conversion.h b/wrapper_python/utils/conversion.h new file mode 100644 index 0000000..8ce616d --- /dev/null +++ b/wrapper_python/utils/conversion.h @@ -0,0 +1,75 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +// Author: Sudeep Pillai (spillai@csail.mit.edu) +// Note: Stripped from Opencv (opencv/modules/python/src2/cv2.cpp) + +#pragma once + +#include <Python.h> +#include <opencv2/opencv.hpp> +#include <opencv2/core/core.hpp> +#include <numpy/ndarrayobject.h> + +static PyObject* opencv_error = 0; + +static int failmsg(const char *fmt, ...); + +class PyAllowThreads; + +class PyEnsureGIL; + +#define ERRWRAP2(expr) \ +try \ +{ \ + PyAllowThreads allowThreads; \ + expr; \ +} \ +catch (const cv::Exception &e) \ +{ \ + PyErr_SetString(opencv_error, e.what()); \ + return 0; \ +} + +static PyObject* failmsgp(const char *fmt, ...); + +static size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) + + (0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int); + +static inline PyObject* pyObjectFromRefcount(const int* refcount) +{ + return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET); +} + +static inline int* refcountFromPyObject(const PyObject* obj) +{ + return (int*)((size_t)obj + REFCOUNT_OFFSET); +} + + +class NumpyAllocator; + +enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 }; + +class NDArrayConverter +{ +private: + void init(); +public: + NDArrayConverter(); + cv::Mat toMat(const PyObject* o); + PyObject* toNDArray(const cv::Mat& mat); +}; diff --git a/wrapper_python/utils/template.h b/wrapper_python/utils/template.h new file mode 100644 index 0000000..3f0b535 --- /dev/null +++ b/wrapper_python/utils/template.h @@ -0,0 +1,44 @@ +/* +This file is part of BGSLibrary. + +BGSLibrary is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +BGSLibrary is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with BGSLibrary. If not, see <http://www.gnu.org/licenses/>. +*/ +// Author: Sudeep Pillai (spillai@csail.mit.edu) +// Note: Stripped from pyxx project + +#pragma once + +#include <boost/python.hpp> +/* + * Provides template support + */ + +template<typename TemplateType> +struct expose_template_type +{ + // do nothing! +}; + +template<typename TemplateType> +struct expose_template_type_base +{ + bool wrapped() + { + using namespace boost::python::converter; + using namespace boost::python; + registration const * p = registry::query( type_id<TemplateType>() ); + return p && (p->m_class_object || p->m_to_python); + } + +}; -- GitLab