diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 03296d9d08ca4a14eb58df37cceb5d9af5ac15fc..d668f260fc04479100b0fb447cad7c730397af16 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,21 +1,20 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 2.8) -project(bgslibrary-examples) +project(bgslibrary) -set(CMAKE_CXX_STANDARD 14) +# 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") - set(CMAKE_MACOSX_RPATH 1) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x") endif(UNIX) -# Avoid cmake warnings about changes in behavior of some Mac OS X path -# variable we don't care about. -if (POLICY CMP0042) - cmake_policy(SET CMP0042 NEW) -endif() - -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") #set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) # compilation mode setup @@ -23,15 +22,8 @@ set(CMAKE_BUILD_TYPE Release) #set(CMAKE_BUILD_TYPE Debug) if(WIN32) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) - set(BUILD_SHARED_LIBS TRUE) - #if(BGS_PYTHON_SUPPORT) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") - #else() - # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") - # set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") - #endif() + 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 ".") @@ -41,104 +33,121 @@ 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}) + 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) + # 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) - # -ansi does not compile with sjn module - #ADD_DEFINITIONS(-ansi) + # -ansi does not compile with sjn module + #ADD_DEFINITIONS(-ansi) - # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare - #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) + # if you like to have warinings about conversions, e.g. double->int or double->float etc., or float compare + #ADD_DEFINITIONS(-Wconversion -Wfloat-equal) endif(UNIX) set(OpenCV_STATIC OFF) find_package(OpenCV REQUIRED) -if(OpenCV_FOUND) - message(STATUS "") - message(STATUS "OpenCV library status:") - message(STATUS " version: ${OpenCV_VERSION}") - message(STATUS " libraries: ${OpenCV_LIBS}") - message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}\n") -endif() + +message(STATUS "OpenCV library status:") +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}") +# 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}") + message(FATAL_ERROR "OpenCV version is not compatible: ${OpenCV_VERSION}") endif() +find_package(LibArchive REQUIRED) +message(STATUS "LibArchive library status:") +message(STATUS " version: ${LibArchive_VERSION}") +message(STATUS " libraries: ${LibArchive_LIBRARIES}") +message(STATUS " include path: ${LibArchive_INCLUDE_DIRS}") + + +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) -file(GLOB_RECURSE tools_src ../src/tools/*.cpp ../src/tools/*.c) -file(GLOB_RECURSE tools_inc ../src/tools/*.h ../src/tools/*.hpp) - -file(GLOB_RECURSE utils_src ../src/utils/*.cpp ../src/utils/*.c) -file(GLOB_RECURSE utils_inc ../src/utils/*.h ../src/utils/*.hpp) - -file(GLOB_RECURSE bgs_src ../src/algorithms/*.cpp ../src/algorithms/*.c) -file(GLOB_RECURSE bgs_inc ../src/algorithms/*.h ../src/algorithms/*.hpp) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${OpenCV_INCLUDE_DIRS}) +# list(REMOVE_ITEM sources ${demo} ${demo2}) + +file(GLOB_RECURSE analysis_src package_analysis/*.cpp) +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} ${LibArchive_INCLUDE_DIRS}) +endif() # GMG is not available in older OpenCV versions if(${OpenCV_VERSION} VERSION_LESS 2.4.3) - file(GLOB gmg ../src/algorithms/GMG.cpp) - list(REMOVE_ITEM bgs_src ${gmg}) + file(GLOB gmg package_bgs/GMG.cpp) + list(REMOVE_ITEM bgs_src ${gmg}) endif() -add_library(bgslibrary_core SHARED ${bgs_src} ${tools_src} ${utils_src} ${bgs_inc} ${tools_inc} ${utils_inc}) -# generates the export header bgslibrary_core_EXPORTS.h automatically -include(GenerateExportHeader) -GENERATE_EXPORT_HEADER(bgslibrary_core - BASE_NAME bgslibrary_core - EXPORT_MACRO_NAME bgslibrary_core_EXPORTS - EXPORT_FILE_NAME bgslibrary_core_EXPORTS.h - STATIC_DEFINE BGSLIBRARY_CORE_EXPORTS_BUILT_AS_STATIC) -target_link_libraries(bgslibrary_core ${OpenCV_LIBS}) -set_property(TARGET bgslibrary_core PROPERTY PUBLIC_HEADER ${bgs_inc} ${tools_inc} ${utils_inc}) - -#if(WIN32) -# # set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".lib") -# #if(BGS_PYTHON_SUPPORT) -# # set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".pyd") -# #endif() -#else() -# set_property(TARGET bgslibrary_core PROPERTY OUTPUT_NAME "bgs") -#endif() - -#if(APPLE) -# if(BGS_PYTHON_SUPPORT) -# set_property(TARGET bgslibrary_core PROPERTY SUFFIX ".so") -# set_target_properties(bgslibrary_core PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") -# endif() -#endif() +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") +else() + set_property(TARGET libbgs PROPERTY OUTPUT_NAME "bgs") +endif() + +add_executable(bgslibrary ${main}) +target_link_libraries(bgslibrary ${OpenCV_LIBS} libbgs) +# set_target_properties(bgslibrary PROPERTIES OUTPUT_NAME bgs) add_executable(bgs_demo ${demo}) -target_link_libraries(bgs_demo ${OpenCV_LIBS} bgslibrary_core) +target_link_libraries(bgs_demo ${OpenCV_LIBS} ${LibArchive_LIBRARIES} libbgs) add_executable(bgs_demo2 ${demo2}) -target_link_libraries(bgs_demo2 ${OpenCV_LIBS} bgslibrary_core) - -if(UNIX) - # to avoid: error while loading shared libraries: libbgslibrary_core.so - message(STATUS "You might need to run:") - message(STATUS "$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib") - message(STATUS "$ export LD_LIBRARY_PATH") - message(STATUS "after 'make install' to avoid error while loading libbgslibrary_core\n") -endif() - -if(WIN32) - message(STATUS "You might need to add ${CMAKE_CURRENT_BINARY_DIR} to your PATH to be able to run your applications.") - message(STATUS "> set PATH=%PATH%;${CMAKE_CURRENT_BINARY_DIR}\n") -endif() +target_link_libraries(bgs_demo2 ${OpenCV_LIBS} ${LibArchive_LIBRARIES} libbgs) + +install(TARGETS libbgs + bgslibrary + RUNTIME DESTINATION bin COMPONENT app + LIBRARY DESTINATION lib COMPONENT runtime + ARCHIVE DESTINATION lib COMPONENT runtime + PUBLIC_HEADER DESTINATION include/package_bgs COMPONENT dev + FRAMEWORK DESTINATION "/Library/Frameworks" +) diff --git a/examples/Demo.cpp b/examples/Demo.cpp index 2bfec63b297acb1f1ec796f5349a9137d0674512..67ac83ec0d3ace39be9fdeacc809589167885cb2 100644 --- a/examples/Demo.cpp +++ b/examples/Demo.cpp @@ -1,92 +1,714 @@ +/* +./bgs_demo -i test45/ -a 100 -o test45/results +*/ + +//cpp c #include <iostream> #include <algorithm> -#include <iterator> -#include <vector> +#include <cstdlib> +#include <stdio.h> /* printf, scanf, puts, NULL */ +#include <stdlib.h> /* srand, rand */ +#include <time.h> /* time */ +#include <ctime> +#include <signal.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <archive.h> +#include <archive_entry.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +//cpp 11X +#include <regex> + + +#define PROCESS_CENTER_VERSION_MAJOR 2 +#define PROCESS_CENTER_VERSION_MINOR 0 +#define PROCESS_CENTER_VERSION_MINOR_FIXES 1 + +//opencv #include <opencv2/opencv.hpp> +//bgslibrary +#include "package_bgs/bgslibrary.h" +//my class +#include "package_bgs/Tapter.h" +#include "package_bgs/ttoolbox.h" + +using namespace cv; +using namespace std; + +int g_badSignalFlagAbort = 0; + +void my_handler(int signum); + +char* getCmdOption(char ** begin, char ** end, const std::string & option); + +bool cmdOptionExists(char** begin, char** end, const std::string& option); + +std::vector<char> copyDataInBuffer(struct archive *aw); + +//! we convert our actual jpg file number to framenumber +int toFrameNumber(std::string filename); + +int main(int argc, char * argv[]) +{ + signal(SIGUSR1, my_handler); + + std::cout << "using processcenter " <<PROCESS_CENTER_VERSION_MAJOR <<"."<< PROCESS_CENTER_VERSION_MINOR<<"."<<PROCESS_CENTER_VERSION_MINOR_FIXES<< endl; + std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; + //!** parse programm input****************/ + if(cmdOptionExists(argv, argv+argc, "-h")) + { + cout <<" error: please use command as\n./bgs_demo -i inputTarFile -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath -p camparameterFile.xml"<<endl; + return EXIT_FAILURE; + } + if(!cmdOptionExists(argv, argv+argc, "-i")||!cmdOptionExists(argv, argv+argc, "-a")||!cmdOptionExists(argv, argv+argc, "-o") ||!cmdOptionExists(argv, argv+argc, "-p")) + { + cout <<" error: please use command as\n./bgs_demo -i inputTarFile -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath -p camparameterFile.xml"<<endl; + return EXIT_FAILURE; + } + + char *testFile = getCmdOption(argv, argv + argc, "-i"); + std::string inputFile("."); + if (testFile) + { + //test dir exists + inputFile = string(testFile); + } + int amountFiles = -1; + char *testFileAmount = getCmdOption(argv, argv + argc, "-a"); + if (testFileAmount) + { + string s(testFileAmount); + stringstream foo(s); + foo >> amountFiles; + } + + + char *centerFile = getCmdOption(argv, argv + argc, "-c"); + std::string centerFileString("."); + if (centerFile) + { + //test dir exists + centerFileString = string(centerFile); + } + + char *testOutputDir = getCmdOption(argv, argv + argc, "-o"); + std::string outputDir("."); + if (testOutputDir) + { + //test dir exists + outputDir = string(testOutputDir); + } + + char *camerFile = getCmdOption(argv, argv + argc, "-p"); + std::string cameraParameterFile("."); + if (camerFile) + { + //test dir exists + cameraParameterFile = string(camerFile); + } + + + cout <<"args: -i "<<inputFile<<" -a "<<amountFiles << " -c" << centerFileString<<" -o " << outputDir <<" -p " << cameraParameterFile ; + //!**** end parse input***********/ + + //libarchive things + + struct archive *archive; + struct archive *ext; + struct archive_entry *entry; + int r; + int flags = ARCHIVE_EXTRACT_TIME; // see https://linux.die.net/man/3/archive_write_disk for more flags + const char *filename = testFile; + + archive = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, flags); + + archive_read_support_format_tar(archive); + + //we get the filename + if (filename != NULL && strcmp(filename, "-") == 0) + filename = NULL; + + //and open the handler + if ((r = archive_read_open_filename(archive, filename, 10240))) + { + cerr<<"archive_read_open_filename: error: "<< archive_error_string(archive) <<" will abort"<< endl; + exit(1); + } + + /* Background Subtraction Methods */ + IBGS *bgs; + + //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; // 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; + //bgs = new MultiLayer; + bgs = new PixelBasedAdaptiveSegmenter; + //bgs = new LBSimpleGaussian; + //bgs = new LBFuzzyGaussian; + //bgs = new LBMixtureOfGaussians; + //bgs = new LBAdaptiveSOM; + //bgs = new LBFuzzyAdaptiveSOM; + //bgs = new LBP_MRF; + //bgs = new VuMeter; + //bgs = new KDE; + //bgs = new IndependentMultimodal; + //bgs = new MultiCue; + //bgs = new SigmaDelta; + //bgs = new SuBSENSE; + //bgs = new LOBSTER; + //bgs = new PAWCS; + //bgs = new TwoPoints; + //bgs = new ViBe; + //bgs = new Tapter; + + //Tapter *bgs = new Tapter; + + //see paper https://dl.acm.org/citation.cfm?id=2321600 + //https://ieeexplore.ieee.org/document/4527178/ + //was in benchmark on top https://www.researchgate.net/publication/259340906_A_comprehensive_review_of_background_subtraction_algorithms_evaluated_with_synthetic_and_real_videos + //my own adapter to use the model + + //init the random number generator + srand (time(NULL)); + + clock_t beginAll = clock(); + + //! we read the center config file for cut out the ROI + //TODO merge this config with the Tapter.xml ?? + //circle param + int circleCenterX = 880; + int circleCenterY = 750; + int circleRadius = 700; + cv::String configFileNameCenter(centerFileString); + //read the config + cout << "parameter of centerConfigFile.xml"<<endl; + FileStorage fsCen; + fsCen.open(configFileNameCenter, FileStorage::READ); + if (!fsCen.isOpened()) + { + cout << "error during open " <<centerFileString << " will abort\n "; + return EXIT_FAILURE; + } + + circleCenterX = (int) fsCen["circleCenterX"]; + cout <<"circleCenterX: "<< circleCenterX<<endl; + + circleCenterY = (int) fsCen["circleCenterY"]; + cout <<"circleCenterY: "<< circleCenterY<<endl; + + circleRadius = (int) fsCen["circleRadius"]; + cout <<"circleRadius: "<< circleRadius<<endl; + fsCen.release(); + + + //we open the camera config file + cv::String camParam (cameraParameterFile); + Mat intrinsicsCameraMatrix, distortionCoeff; + { + cout << "read cam parameter of: "<< cameraParameterFile ; + FileStorage fs; + fs.open(camParam, FileStorage::READ); + if (!fs.isOpened()) + { + cerr << "error during open " << cameraParameterFile << " will abort\n "; + return -1; + } + fs["camera_matrix"] >> intrinsicsCameraMatrix; + std::cout << "camera_matrix = "<< intrinsicsCameraMatrix<<endl; + fs["distortion_coefficients"] >> distortionCoeff; + std::cout << "distortion_coefficients"<< distortionCoeff<<endl; + } + + + cout <<"a) we process all frames "<<endl; + + int everyPic= 60*5; + //std::string fileName; + int frameCounter=0; + int myFileTarWriterHeaderCounter = 0; + int frameCounterOld = -1; + vector<string> myFileErrorList;//list for pure io error + vector<string> myFileListNoContour; //list for no contours found; + vector<string> myFileListAfterContourSelection; //list for no contours found after selection; + + //the corruption check is done beforehand + //vector<string> myFileListCorrupted; //list all corrupted jpg files + + + //here we loop over all picture of the tar archive, independing how many this are + for (;;) + { + + //measure time consumption + clock_t begin = clock(); //for every single file + std::vector<char> vec; + + //we read the next header + r = archive_read_next_header(archive, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) + { + cerr<<"archive_read_next_header: error: "<< archive_error_string(archive) <<" will abort"<< endl; + exit(1); + } + + //we get the filename + const char *fileNamePtr = archive_entry_pathname(entry); + std::string filename(fileNamePtr,strlen(fileNamePtr) ); + //cout << "fileName: "<< filename <<endl; + //we convert it to a framenumber + frameCounter = toFrameNumber(filename); + + if(frameCounterOld>frameCounter) + { + cerr <<" error during read in the file number, we do have non montonic order, will abort"; + exit(1); + } + + frameCounterOld = frameCounter; + + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + { + cerr<<"archive_write_header() error: "<< archive_error_string(ext)<<endl; + myFileTarWriterHeaderCounter++; + continue; //we overjump all in our for loop + } + //else + //{ + //we copy all data to the buffer vector + vec = copyDataInBuffer(archive); + if(vec.empty()) + cerr << "error during load data into buffer"; + + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + { + cerr<<"archive_write_finish_entry: error: "<< archive_error_string(ext) <<" will abort"<< endl; + exit(1); + } + //} + //we read the image buffer as a jpg picture and decode it + Mat img_input = imdecode(Mat(vec), 1); + + // //we define the type better to prevent error + // fileName = std::string(inputFile + TToolBox::getFileName(frameCounter)); + // cv::String fileNameCV(fileName); + + cout <<"\t"<<frameCounter<<"\tof \t"<<amountFiles<<" load file :"<< filename<<endl; + + //of data is present + if(img_input.data ) + { + + //! step 0 we take care about the lense distortion + //! correct lense distortion + Mat imgLenseCorrection = img_input.clone(); + //see https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#undistort + cv::undistort(img_input, imgLenseCorrection, intrinsicsCameraMatrix, distortionCoeff); + + //! we cut out a smaller ROI, + //! step 1) + img_input = TToolBox::cropImageCircle(imgLenseCorrection,circleCenterX,circleCenterY,circleRadius); + + //! normal bgs processing + //! step 2) + 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 + + //! step 3) we make we apply a edge detection + //TODO make this in a function, how many times is this listed ?? + //TODO read from tapter config + //TODO all parameter from applyCannyEdgeAndCalcCountours also !! + double threshholdMin = 150; + double threshholdMax = 200; + int apertureSize = 3; + std::vector<vector<Point> > contours = TToolBox::applyCannyEdgeAndCalcCountours(img_mask,threshholdMin,threshholdMax,apertureSize); + + //define what we will write down + std::vector<vector<Point> > contourSelection; + vector<Point2f> massCenters; + vector<Point> conHull; + Point2f muConvexHullMassCenter(0.0,0.0); + + if(!contours.empty()) + { + + //! step 4) we make a selection out of all counters with area sizes****************************** + + //we calc all min rotated rectangles for all contour from candy egde detect + //we exlcude very small one and very big ones + vector<RotatedRect> minRect( contours.size() ); + + //calc boxes around the contours + for( size_t i = 0; i < contours.size(); i++ ) + minRect[i] = minAreaRect( Mat(contours[i]) ); //may use boundingRect ?? to use fix non rotated rectangles ? + + vector<Point2f> recCenterPoints; + float areaMinThreshold = 150; + float areaMaxThreshold = 300000; //old max threshold was to small //TODO apply moving filter ??, an more adaptive approach + + //iterate all rectangles + for( size_t i = 0; i< minRect.size(); i++ ) + { + Point2f rect_points[4]; + //get all points of the retange + minRect[i].points( rect_points ); + + //construct contour based on rectangle points because contour != rectangle with points + vector<Point> contourRect; + for(int j=0;j<4;j++) + contourRect.push_back(rect_points[j]); + + //calc the area of the contour + double area0 = contourArea(contourRect); + //over stepp all small areas + if(area0<areaMinThreshold||area0>areaMaxThreshold) + { + //cout<<i<<":area0:"<<area0<<" dismissed "<<endl; + //skipe if the area is too small + continue; + } + else + { + //cout<<i<<":area0:"<<area0<<" choose "<<endl; + + //get the center of this rectangle + Point2f center = minRect[i].center; + recCenterPoints.push_back(center); -#include "../src/algorithms/algorithms.h" + //we also add the this contour to a selection + contourSelection.push_back(contours[i]); -#if CV_MAJOR_VERSION >= 4 -#define CV_CAP_PROP_POS_FRAMES cv::CAP_PROP_POS_FRAMES -#define CV_CAP_PROP_FRAME_COUNT cv::CAP_PROP_FRAME_COUNT + } + }//end iterate all min rectangle + + if(!contourSelection.empty()) + { + //! step 5) we calc the moments from the contour selection + vector<Moments> mu(contourSelection.size() ); + for( size_t i = 0; i < contourSelection.size(); i++ ) + { + mu[i] = moments( contourSelection[i], false ); + } + + // Get the mass centers: + massCenters = vector<Point2f>( contourSelection.size() ); + for( size_t i = 0; i < contourSelection.size(); i++ ) + { + massCenters[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); + } + + //! step 6) calc convex hull of all points of the contour selection ********* + //TODO produce center of convex hull of all polygones + //TODO double check if ne contour sharing a center point ? nearby ?? + + //we merge all points + vector<Point> allContourPoints; + for (size_t cC = 0; cC < contourSelection.size(); ++cC) + for(size_t cP =0; cP < contourSelection[cC].size(); cP++) + { + Point currentContourPixel = contourSelection[cC][cP]; + allContourPoints.push_back(currentContourPixel); + } + + // calc the hull ****************** + conHull = vector<Point>(allContourPoints.size()); + convexHull( Mat(allContourPoints), conHull, false ); + // Point roiCenter; + // float roiRadius; + + //calc the min circle around + //minEnclosingCircle(conHull,roiCenter,roiRadius); + //we calc the mass center of the convex hull + + ///we calc the mass center of the convex hull + Moments muConvexHull; + if(!conHull.empty()) + { + muConvexHull = moments(conHull, true ); + muConvexHullMassCenter= Point2f( muConvexHull.m10/muConvexHull.m00 , muConvexHull.m01/muConvexHull.m00 ); + } + } + else //end after selection is empty + { + cerr<<"error, no contour found after selection in file: "<< filename<<endl; + myFileListAfterContourSelection.push_back(filename); + } + }//end if contours are empty, to canny edge found nothing + else + { + cerr<<"error, no contour found at all in file: "<< filename<<endl; + myFileListNoContour.push_back(filename); + + } +#ifdef MC_SHOW_STEP_ANALYSE + + if(!conHull.empty())//if we any elements, we process further + { + Mat imgConvexHull = Mat::zeros( img_input.size(), CV_8UC3 ); + imgConvexHull = Scalar(255,255,255); //fille the picture + + Scalar colorB( 0,0,255,255 );//red + polylines(imgConvexHull, hullComplete, true, colorB, 1, 8); + + //draw circle around + //circle( imgConvexHull, roiCenter, (int) roiRadius, colorB, 2, 8, 0 ); + + //we draw it + cv::String outpath2= outputDir; + std::ostringstream convert2; + convert2 << outpath2 <<TToolBox::mNzero(frameCounter) <<"_convex_hull.jpg"; + cv::imwrite(convert2.str().c_str(), imgConvexHull); + } + else + cout<<"convex hull has no points will skip file: "<<i<<endl; + +#endif + + //cout <<" found center at : "<< massCenters.at(0).x<< ";"<<massCenters.at(0).y<<endl; + //! step 8: we write down all our results in yml file + std::string nameOutPutFileData = outputDir + TToolBox::mNzero(frameCounter) + ".yml"; + + //cout <<"output file:" << nameOutPutFileData; + + FileStorage fs(nameOutPutFileData.c_str(), FileStorage::WRITE); + fs << "masscenters" << massCenters; + fs << "polygonselection"<< contourSelection; + fs << "convexhull"<<conHull; + fs << "masscenterconvexhull"<<muConvexHullMassCenter; + fs.release(); + + //! we write from time to time a dbg picture + if(frameCounter%everyPic==0) + { + Scalar colorRed( 0,0,255,255 );//red + RNG rng(4344234); + Mat imgDebugPaint2 = Mat::zeros( img_input.size(), CV_8UC3 ); + imgDebugPaint2 = Scalar(255,255,255); //fill the picture white + + //we write all polyies of the selection and the mass centers with a random color + for( size_t i = 0; i< contourSelection.size(); i++ ) + { + //random color + Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + //contour + drawContours( imgDebugPaint2, contourSelection, i, color, 1, LINE_AA); + //draw the center + circle( imgDebugPaint2, massCenters[i], 4, color, -1, 8, 0 ); + } + + //we write the convex hull + if(!conHull.empty()) + { + //the poly + polylines(imgDebugPaint2, conHull, true, colorRed, 1, 8); + //the center + circle( imgDebugPaint2,muConvexHullMassCenter, 4, colorRed, -1, 8, 0 ); + } + + //we make a copy + Mat imgOverlay2 = img_input.clone(); + //we add a overlay of our paitings + addWeighted( imgDebugPaint2, 0.7, imgOverlay2, 0.3, 0.0, imgOverlay2); + //we write the file down + std::string nameOutPutFileDBGpic = outputDir + TToolBox::mNzero(frameCounter) + std::string(".jpg"); + + imwrite(nameOutPutFileDBGpic.c_str(),imgOverlay2); + + }//end if we write a dbg picture + + + }//end if the loaded picture has data + else + { + cerr<<"error loading file: "<< filename<<", will skip this file"<<endl; + myFileErrorList.push_back(filename); + } + + // }//end if not corrupted picture + // else + // { + // cerr<<"error file: "<< fileName<<" is corrupted, will ignore it"<<endl; + // myFileListCorrupted.push_back(fileName); + + // } + + + //we calc the time which we used for a picture + clock_t end = clock(); + double elapsedSecs = double(end - begin) / CLOCKS_PER_SEC; + + + //we calc the time which was used for all picture + clock_t endAll = clock(); + double elapsedSecTotal = double(endAll - beginAll) / CLOCKS_PER_SEC; + cout <<"process single pic:\t"<<elapsedSecs<<" s - \t\t"<<(int)(elapsedSecTotal/60)<<" min -\t"<<(int)(elapsedSecTotal/60/60)<<" h"<<endl; + + if(g_badSignalFlagAbort) + frameCounter = amountFiles; //we abort + + //if(frameCounter>10)exit(0); //the test abort function + + }//end for ever loop + + //finishing time + clock_t endAll = clock(); + double elapsed = double(endAll - beginAll) / CLOCKS_PER_SEC; + cout <<"process : "<<amountFiles<<" files took:\t"<<(int)(elapsed/60)<<" min -\t"<<(int)(elapsed/60/60)<<" h \n in total"<<endl; + + // //we write the random file list to a file + // std::string nameOutRandomFile = outputDir + "randlist.yml"; + // FileStorage fs(nameOutRandomFile.c_str(), FileStorage::WRITE); + // fs << "randomlist" << myRandomTrainList; + // fs.release(); + + //TODO we should merge the file + + cout<< "amount of libarchive read header errors :"<< myFileTarWriterHeaderCounter; + + //we write the random file list to a file + std::string nameOutErrorList = outputDir + "fileErrorList.yml"; + cout <<"amount of file errors: "<< myFileErrorList.size()<<endl; + FileStorage fs2(nameOutErrorList.c_str(), FileStorage::WRITE); + fs2 << "fileErrorIOs" << myFileErrorList; + + //we write error list no contours found in file + cout <<"amount contour errors with canny edge: "<< myFileListNoContour.size()<<endl; + fs2 << "fileErrorNoContours" << myFileListNoContour; + + //we write error list no contours found in file + cout <<"amount contour errors after selection: "<< myFileListAfterContourSelection.size()<<endl; + fs2 << "fileErrorNoContoursAfterSelections" << myFileListAfterContourSelection; + + + // //we write error list no contours found in file + // cout <<"amount of corrupted jpg files: "<< myFileListCorrupted.size()<<endl; + // fs2 << "fileErrorIOcorruptFiles" << myFileListCorrupted; + + //the bgs related things + delete bgs; + + //opencv related things + fs2.release(); + // capture.release(); + cvDestroyAllWindows(); + + //close lib archive related things + archive_read_close(archive); + archive_read_free(archive); + + archive_write_close(ext); + archive_write_free(ext); + + return 0; +} + + + +std::vector<char> copyDataInBuffer(struct archive *aw) +{ + int r; + const void *buff; + std::vector<char> vec; + size_t size; +#if ARCHIVE_VERSION_NUMBER >= 3000000 + int64_t offset; +#else + off_t offset; #endif + //forever till we get a specific return + for (;;) { + r = archive_read_data_block(aw, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + { + return vec; // everything fine, were are just at the end + } -int main(int argc, char **argv) + if (r != ARCHIVE_OK) + { + cerr << "error during read archive "<<endl; + return vec; + } + + //a good discussion : https://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping + // Method 4: vector::insert + { + //we rename our pointer to avoid a weird compiler warning + char *foo = (char*) buff; + vec.insert(vec.end(), &foo[0], &foo[size]); + } + + } + + return vec; +} +void my_handler(int signum) { - std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - - cv::VideoCapture capture; - - if (argc > 1) - { - std::cout << "Openning: " << argv[1] << std::endl; - capture.open(argv[1]); - } - else - capture.open(0); - - if (!capture.isOpened()) - { - std::cerr << "Cannot initialize video!" << std::endl; - return -1; - } - - /* Background Subtraction Methods */ - auto algorithmsName = BGS_Factory::Instance()->GetRegisteredAlgorithmsName(); - - std::cout << "List of available algorithms:" << std::endl; - std::copy(algorithmsName.begin(), algorithmsName.end(), std::ostream_iterator<std::string>(std::cout, "\n")); - - for (const std::string& algorithmName : algorithmsName) - { - std::cout << "Running " << algorithmName << std::endl; - auto bgs = BGS_Factory::Instance()->Create(algorithmName); - - cv::Mat img_input; - - capture.set(CV_CAP_PROP_POS_FRAMES, 0); // Set index to 0 (start frame) - auto frame_counter = 0; - std::cout << "Press 's' to stop:" << std::endl; - auto key = 0; - while (key != 's') - { - // Capture frame-by-frame - capture >> img_input; - frame_counter += 1; - - if (img_input.empty()) break; - - cv::resize(img_input, img_input, cv::Size(380, 240), 0, 0, CV_INTER_LINEAR); - cv::imshow("input", img_input); - - cv::Mat img_mask; - cv::Mat img_bkgmodel; - try - { - 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 - } - catch (std::exception& e) - { - std::cout << "Exception occurred" << std::endl; - std::cout << e.what() << std::endl; - } - - key = cv::waitKey(33); - } - - std::cout << "Press 'q' to exit, or anything else to move to the next algorithm:" << std::endl; - key = cv::waitKey(0); - if (key == 'q') - break; - - cv::destroyAllWindows(); - } - - capture.release(); - - return 0; + if (signum == SIGUSR1) + { + g_badSignalFlagAbort = 1; + cerr << "receive signal to abort"<<endl; + } +} + +char* getCmdOption(char ** begin, char ** end, const std::string & option) +{ + char ** itr = std::find(begin, end, option); + if (itr != end && ++itr != end) + { + return *itr; + } + return 0; +} + +bool cmdOptionExists(char** begin, char** end, const std::string& option) +{ + return std::find(begin, end, option) != end; +} + +int toFrameNumber(std::string filename) +{ + int retVal = -1; + + //we cut out all non needed substrings + filename = regex_replace(filename, regex("/"), ""); + filename = regex_replace(filename, regex("data_sized"), ""); + filename = regex_replace(filename, regex("jpg"), ""); + filename = regex_replace(filename, regex("\\."), ""); + + retVal = std::stoi( filename ); + + //cout <<"filename out:" << filename << " number: "<< retVal << endl; + + return retVal; } diff --git a/examples/Demo2.cpp b/examples/Demo2.cpp index 8b4f69839d141345a01c423d1bd98d3d34b287bb..eef22d47c9fcc7ae707e4e0313c65b497db5fa48 100644 --- a/examples/Demo2.cpp +++ b/examples/Demo2.cpp @@ -1,80 +1,303 @@ +/* +./bgs_demo -i test45/ -a 100 -o test45/results/ +based on original demo.cpp +*/ + +// c +#include <sys/types.h> +#include <sys/stat.h> +#include <archive.h> +#include <archive_entry.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +//cpp c #include <iostream> #include <algorithm> -#include <iterator> #include <vector> +#include <cstdlib> +#include <stdio.h> /* printf, scanf, puts, NULL */ +#include <stdlib.h> /* srand, rand */ +#include <time.h> /* time */ +#include <ctime> + +#define PROCESS_CENTER_VERSION_MAJOR 0 +#define PROCESS_CENTER_VERSION_MINOR 2 + +//opencv #include <opencv2/opencv.hpp> +//bgslibrary +#include "package_bgs/bgslibrary.h" +//my class +#include "package_bgs/Tapter.h" +#include "package_bgs/ttoolbox.h" + +using namespace cv; +using namespace std; + +char* getCmdOption(char ** begin, char ** end, const std::string & option) +{ + char ** itr = std::find(begin, end, option); + if (itr != end && ++itr != end) + { + return *itr; + } + return 0; +} + +bool cmdOptionExists(char** begin, char** end, const std::string& option) +{ + return std::find(begin, end, option) != end; +} + + +static std::vector<char> copyDataInBuffer(struct archive *aw); + +//static void errmsg(const char *); +//static void fail(const char *, const char *, int); +//static void msg(const char *); +//static void warn(const char *, const char *); -#include "../src/algorithms/algorithms.h" -#if CV_MAJOR_VERSION >= 4 -#define CV_LOAD_IMAGE_COLOR cv::IMREAD_COLOR -#endif -int main(int argc, char **argv) +int main(int argc, char * argv[]) { - std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; - - std::string baseDir = "./dataset/frames"; - if (argc > 1) - baseDir = argv[1]; - std::cout << "Openning: " << baseDir << std::endl; - - /* Background Subtraction Methods */ - auto algorithmsName = BGS_Factory::Instance()->GetRegisteredAlgorithmsName(); - - std::cout << "List of available algorithms:" << std::endl; - std::copy(algorithmsName.begin(), algorithmsName.end(), std::ostream_iterator<std::string>(std::cout, "\n")); - - for (const std::string& algorithmName : algorithmsName) - { - std::cout << "Running " << algorithmName << std::endl; - auto bgs = BGS_Factory::Instance()->Create(algorithmName); - - auto frame_counter = 0; - std::cout << "Press 's' to stop:" << std::endl; - auto key = 0; - while (key != 's') + std::cout << "using produce bk " <<PROCESS_CENTER_VERSION_MAJOR <<"."<< PROCESS_CENTER_VERSION_MINOR << endl; + std::cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << std::endl; + //!** parse programm input****************/ + if(cmdOptionExists(argv, argv+argc, "-h")) + { + cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; + return EXIT_FAILURE; + } + if(!cmdOptionExists(argv, argv+argc, "-i")||!cmdOptionExists(argv, argv+argc, "-a")||!cmdOptionExists(argv, argv+argc, "-o") ) + { + cout <<" error: please use command as\n./bgs_demo -i pathToInputDir -a amountOfJpgFiles -c exactCenterConfFile.xml -o outPutPath"<<endl; + return EXIT_FAILURE; + } + + char *testInputDir = getCmdOption(argv, argv + argc, "-i"); + string inputDir("."); + if (testInputDir) + { + //test dir exists + inputDir = string(testInputDir); + } + int amountFiles = -1; + char *testFileAmount = getCmdOption(argv, argv + argc, "-a"); + if (testFileAmount) + { + string s(testFileAmount); + stringstream foo(s); + foo >> amountFiles; + } + + + char *centerFile = getCmdOption(argv, argv + argc, "-c"); + string centerFileString("."); + if (centerFile) + { + //test dir exists + centerFileString = string(centerFile); + } + + char *testOutputDir = getCmdOption(argv, argv + argc, "-o"); + string outputDir("."); + if (testOutputDir) + { + //test dir exists + outputDir = string(testOutputDir); + } + + struct archive *archive; + struct archive *ext; + struct archive_entry *entry; + int r; + int flags = ARCHIVE_EXTRACT_TIME; // see https://linux.die.net/man/3/archive_write_disk for more flags + const char *filename = "data_sized.tar"; + + archive = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, flags); + + archive_read_support_format_tar(archive); + + //we get the filename + if (filename != NULL && strcmp(filename, "-") == 0) + filename = NULL; + + //and open the handler + if ((r = archive_read_open_filename(archive, filename, 10240))) { - // Capture frame-by-frame - frame_counter++; - std::stringstream ss; - ss << frame_counter; - auto fileName = baseDir + "/" + ss.str() + ".png"; - std::cout << "reading " << fileName << std::endl; - - auto img_input = cv::imread(fileName, CV_LOAD_IMAGE_COLOR); - - if (img_input.empty()) - break; - - cv::imshow("input", img_input); - - cv::Mat img_mask; - cv::Mat img_bkgmodel; - try - { - 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 - } - catch (std::exception& e) - { - std::cout << "Exception occurred" << std::endl; - std::cout << e.what() << std::endl; - } - - key = cv::waitKey(33); + cerr<<"archive_read_open_filename: error: "<< archive_error_string(archive) <<" will abort"<< endl; + exit(1); + // fail("archive_read_open_filename()", + // archive_error_string(a), r); + } + + int counter = 0; + for (;;) { + r = archive_read_next_header(archive, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) + { + cerr<<"archive_read_next_header: error: "<< archive_error_string(archive) <<" will abort"<< endl; + exit(1); + // fail("archive_read_next_header()", + // archive_error_string(a), 1); + } + //msg("x "); + ///char *buffer = malloc (sizeof(char) * 400000); + //Mat img =Mat::zeros(1936,1456,CV_8UC3); + + //new way + //std::ifstream file("img.jpg"); + std::vector<char> vec; + + // file >> std::noskipws; + // std::copy(std::istream_iterator<char>(file), std::istream_iterator<char>(), std::back_inserter(data)); + + const char *fileNamePtr = archive_entry_pathname(entry); + std::string filename(fileNamePtr,strlen(fileNamePtr) ); + cout << "fileName: "<< filename <<endl; + + //TODO we should test what file we have, this filenumber n = n - 1 ?? + + //msg(archive_entry_pathname(entry)); + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + { + cerr<<"archive_write_header() error: "<< archive_error_string(ext)<<endl; + } + else + { + vec = copyDataInBuffer(archive);//no // we cast the data pointer to void, because we know what we do ?? + if(vec.empty()) + cerr << "error during load data into buffer"; + + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + { + cerr<<"archive_write_finish_entry: error: "<< archive_error_string(ext) <<" will abort"<< endl; + exit(1); + +// fail("archive_write_finish_entry()", +// archive_error_string(ext), 1); + } + } + //we read the image buffer as a jpg picture and decode it + Mat img2 = imdecode(Mat(vec), 1); + +// //here we could use our image +// //we show what we got +// namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display. +// imshow( "Display window", img2 ); // Show our image inside it. +// cv::imwrite("foo.jpg", img2); + +// //msg("\n"); + if(counter > 10) exit(1); + counter ++; + +// waitKey(0); + + } + archive_read_close(archive); + archive_read_free(archive); + + archive_write_close(ext); + archive_write_free(ext); + + return 0; +} + +static std::vector<char> copyDataInBuffer(struct archive *aw) +{ + int r; + const void *buff; + std::vector<char> vec; + size_t size; +#if ARCHIVE_VERSION_NUMBER >= 3000000 + int64_t offset; +#else + off_t offset; +#endif + // unsigned int myOffsetCounter = 0; + // int counterIteration = 0; + + // ofstream myfile; + // myfile.open ("tmpPicture.jpg", ios::out | ios::binary); + // if (!myfile.is_open()) + // return vec; + + for (;;) { + r = archive_read_data_block(aw, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + { + return vec; // everything fine, were are just at the end + } - std::cout << "Press 'q' to exit, or anything else to move to the next algorithm:" << std::endl; - key = cv::waitKey(0); - if (key == 'q') - break; + if (r != ARCHIVE_OK) + { + cerr << "error during read archive "<<endl; + return vec; + } + //r = archive_write_data_block(aw, buff, size, offset); + //we mem copy the buffer + //cout <<counterIteration++<< " offset: "<< offset<< " size: "<< size<<endl; - cv::destroyAllWindows(); - } + //memcpy( &buffer[myOffsetCounter], (char*) buff, size * sizeof( char ) ); + //we simply copy it to the end + //std::copy ( buff, buff+size, vec.end() ); + //myOffsetCounter += size; - return 0; + //a good discussion : https://stackoverflow.com/questions/259297/how-do-you-copy-the-contents-of-an-array-to-a-stdvector-in-c-without-looping + // Method 4: vector::insert + { + //we rename our pointer to avoid a weird compiler warning + char *foo = (char*) buff; + vec.insert(vec.end(), &foo[0], &foo[size]); + } + + + //myfile.write ((char*)buff,size); + // if (r != ARCHIVE_OK) { + // warn("archive_write_data_block()", + // archive_error_string(aw)); + // return (r); + // } + } + //myfile.close(); + + return vec; } + +//static void +//msg(const char *m) +//{ +// write(1, m, strlen(m)); +//} + +//static void +//errmsg(const char *m) +//{ +// write(2, m, strlen(m)); +//} + +//static void +//warn(const char *f, const char *m) +//{ +// errmsg(f); +// errmsg(" failed: "); +// errmsg(m); +// errmsg("\n"); +//} + +//static void +//fail(const char *f, const char *m, int r) +//{ +// warn(f, m); +// exit(r); +//} diff --git a/examples/README.md b/examples/README.md index f4486ec8029e0ba872ffb873e0848c22ebe52ba1..e5ec9a9ca9bd9bb757b7086e8ccaf7a4a53824a4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,27 +1,103 @@ -### BGS Library Examples +## BGSLibrary -#### CMake on Linux or MacOS -``` -cd build -cmake .. -make -cd .. -``` +thomas fork of + +for the records of 2018 and preprocessed records please use: +tag v.0.9.9 alias: 415d967eccf7b8f541cb647c99a2f26be2f3ddc7 + +i updated the version to include the lense correction in 2019 + + + +A Background Subtraction Library + +[](https://youtu.be/_UbERwuQ0OU) + +Last Page Update: **18/03/2017** + +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 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 [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) +* [Which algorithms really matter?](https://github.com/andrewssobral/bgslibrary/wiki/Which-algorithms-really-matter%3F) +* [Library architecture](https://github.com/andrewssobral/bgslibrary/wiki/Library-architecture) + +* Installation instructions + +* * [Windows installation](https://github.com/andrewssobral/bgslibrary/wiki/Installation-instructions---Windows) + +* * [Ubuntu / OS X installation](https://github.com/andrewssobral/bgslibrary/wiki/Installation-instructions-Ubuntu-or-OSX) + +* Graphical User Interface: -#### Running +* * [C++ MFC (Microsoft Foundation Class)](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-MFC) +* * [Java](https://github.com/andrewssobral/bgslibrary/wiki/Graphical-User-Interface:-Java) + +* [Docker images](https://github.com/andrewssobral/bgslibrary/wiki/Docker-images) +* [How to integrate BGSLibrary in your own CPP code](https://github.com/andrewssobral/bgslibrary/wiki/How-to-integrate-BGSLibrary-in-your-own-CPP-code) +* [How to contribute](https://github.com/andrewssobral/bgslibrary/wiki/How-to-contribute) +* [List of collaborators](https://github.com/andrewssobral/bgslibrary/wiki/List-of-collaborators) +* [Release notes](https://github.com/andrewssobral/bgslibrary/wiki/Release-notes) + + +Citation +-------- + +If you use this library for your publications, please cite it as: ``` -chmod +x *.sh -./run_demo.sh -./run_demo2.sh +@inproceedings{bgslibrary, +author = {Sobral, Andrews}, +title = {{BGSLibrary}: An OpenCV C++ Background Subtraction Library}, +booktitle = {IX Workshop de Visão Computacional (WVC'2013)}, +address = {Rio de Janeiro, Brazil}, +year = {2013}, +month = {Jun}, +url = {https://github.com/andrewssobral/bgslibrary} +} ``` -or +A chapter about the BGSLibrary has been published in the handbook on [Background Modeling and Foreground Detection for Video Surveillance](https://sites.google.com/site/backgroundmodeling/). +``` +@incollection{bgslibrarychapter, +author = {Sobral, Andrews and Bouwmans, Thierry}, +title = {BGS Library: A Library Framework for Algorithm’s Evaluation in Foreground/Background Segmentation}, +booktitle = {Background Modeling and Foreground Detection for Video Surveillance}, +publisher = {CRC Press, Taylor and Francis Group.} +year = {2014}, +} ``` -# using a web camera -./build/bgs_demo -# using a video file -./build/bgs_demo ../dataset/video.avi -# using a sequence of images -./build/bgs_demo2 ../dataset/frames -``` +Download PDF: +* Sobral, Andrews. BGSLibrary: An OpenCV C++ Background Subtraction Library. IX Workshop de Visão Computacional (WVC'2013), Rio de Janeiro, Brazil, Jun. 2013. ([PDF](http://www.researchgate.net/publication/257424214_BGSLibrary_An_OpenCV_C_Background_Subtraction_Library) in brazilian-portuguese containing an english abstract). + +* Sobral, Andrews; Bouwmans, Thierry. "BGS Library: A Library Framework for Algorithm’s Evaluation in Foreground/Background Segmentation". Chapter on the handbook "Background Modeling and Foreground Detection for Video Surveillance", CRC Press, Taylor and Francis Group, 2014. ([PDF](http://www.researchgate.net/publication/257424214_BGSLibrary_An_OpenCV_C_Background_Subtraction_Library) in english). + + +Some references +--------------- + +Some algorithms of the BGSLibrary were used successfully in the following papers: + +* (2014) Sobral, Andrews; Vacavant, Antoine. A comprehensive review of background subtraction algorithms evaluated with synthetic and real videos. Computer Vision and Image Understanding (CVIU), 2014. ([Online](http://dx.doi.org/10.1016/j.cviu.2013.12.005)) ([PDF](http://www.researchgate.net/publication/259340906_A_comprehensive_review_of_background_subtraction_algorithms_evaluated_with_synthetic_and_real_videos)) + +* (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 +------ + +<p align="center"> +<a href="https://www.youtube.com/watch?v=_UbERwuQ0OU" target="_blank"> +<img src="https://sites.google.com/site/andrewssobral/bgslibrary_qt_gui_video.png?width=600" border="0" /> +</a> +</p> + +<p align="center"> +<a href="https://www.youtube.com/watch?v=Ccqa9KBO9_U" target="_blank"> +<img src="https://sites.google.com/site/andrewssobral/bgslibrary_youtube.png?width=600" border="0" /> +</a> +</p> diff --git a/src/algorithms/Tapter.cpp b/src/algorithms/Tapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d2425af5f13eeb785a889d05e045276f77b64e8 --- /dev/null +++ b/src/algorithms/Tapter.cpp @@ -0,0 +1,139 @@ +/* +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 "Tapter.h" + +using namespace bgslibrary::algorithms; + +Tapter::Tapter() : + sensitivity(75), trainingSensitivity(245), learningRate(62), trainingLearningRate(255), trainingSteps(55) +{ + std::cout << "Tapter()" << std::endl; + setup("./config/Tapter.xml"); +// frameCounter = 0; +// //inputPath = "."; +// //centerFile = "."; +// outputPath = "."; +// flagWrite = -1; +// writeDbgPic = -1; + +} + +Tapter::~Tapter() +{ + delete m_pBGModel; + std::cout << "~Tapter()" << std::endl; +} + +//void Tapter::setFlagWrite(short flag) +//{ +// flagWrite = flag; +//} + +//void Tapter::setFlagWriteDBGpic(short flag) +//{ +// writeDbgPic = flag; +//} + +//void Tapter::setPathOut(std::string outPath) +//{ +// outputPath = outPath; +//} + + +//void Tapter::setLearningRate(int rate) +//{ +// learningRate = rate; + +//} +//void Tapter::setInitialFrameCounter(int counter) +//{ +// frameCounter = counter; +//} + +void Tapter::process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel) +{ + + //! continue the normal + init(img_input, img_output, img_bgmodel); + + IplImage *frame = new IplImage(img_input); + + if (firstTime) + { + int w = cvGetSize(frame).width; + int h = cvGetSize(frame).height; + + 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->UpdateModel(frame); + + 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 Tapter::saveConfig() +{ + 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); +} + +void Tapter::loadConfig() +{ + 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); +} + + diff --git a/src/algorithms/Tapter.h b/src/algorithms/Tapter.h new file mode 100644 index 0000000000000000000000000000000000000000..ae4ef5eca2114f95390f6a17c7900d7049a3cece --- /dev/null +++ b/src/algorithms/Tapter.h @@ -0,0 +1,88 @@ +/* +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 + +//std lib +#include <sstream> +#include <vector> +//opencv +#include "opencv2/opencv.hpp" +#include "opencv2/imgproc/imgproc.hpp" +//bgslib +#include "lb/BGModelSom.h" +#include "IBGS.h" + +#include "ttoolbox.h" + +//#define MC_SHOW_STEP_ANALYSE + +using namespace lb_library; +using namespace lb_library::AdaptiveSOM; +using namespace cv; +using namespace std; + +namespace bgslibrary +{ + namespace algorithms + { + class Tapter : public IBGS + { + private: + BGModel* m_pBGModel; + int sensitivity; + int trainingSensitivity; + int learningRate; + int trainingLearningRate; + int trainingSteps; + +// int frameCounter; // +// std::string inputPath; +//// std::string centerFile; +// short flagWrite; +// short writeDbgPic; +// std::string outputPath; + + public: + Tapter(); + ~Tapter(); + + void setInitialFrameCounter(int counter); + +// void setPaths(std::string inPath,std::string outPath); + void setPathOut(std::string outPath); + +// //! 1 is on +// //! other no write +// void setFlagWrite(short flag); + +// //! set learning rate +// void setLearningRate(int rate); + +// //! 1 is on +// //! other no write +// void setFlagWriteDBGpic(short flag); + + void process(const cv::Mat &img_input, cv::Mat &img_output, cv::Mat &img_bgmodel); + + private: + void saveConfig(); + void loadConfig(); + + + }; + } +} diff --git a/src/algorithms/ttoolbox.cpp b/src/algorithms/ttoolbox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1734221196f4b002065fff5d46f0b3a76d4fb30 --- /dev/null +++ b/src/algorithms/ttoolbox.cpp @@ -0,0 +1,152 @@ +#include "ttoolbox.h" + +std::string TToolBox::mNzero(int i) +{ + std::ostringstream convert; + convert << i ; + std::string numberString = convert.str(); + std::string newNumberString = std::string(10 - numberString.length(), '0') + numberString; + return newNumberString; +} +std::string TToolBox::getFileName(int i) +{ + std::string fileName =std::string ( std::string ("/data/")+ mNzero(i) + std::string (".jpg")); + return fileName; +} + +std::vector<std::vector<cv::Point>> TToolBox::applyCannyEdgeAndCalcCountours(cv::Mat imgSource, double threshholdMin, double threshholdMax, int apertureSize) +{ + cv::Mat imgCannyEdge; + std::vector<std::vector<cv::Point> > contours; + std::vector<cv::Vec4i> hierarchy; + + //! 2 make a copy + cv::Mat imgBinary = imgSource.clone(); + //imgMarkBinary = Scalar(255,255,255); //fill white + + //! 3 apply binary filter not reduce noise + //method to threshold important changes + int binaryThreshold = 80; //TODO as parameter + imgBinary = imgSource > binaryThreshold; + + + //! 4 smooth with gaussian filter to suppress no connected lines + //add a gaussian filter //see http://docs.opencv.org/2.4/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html + cv::Mat imgSmoothed = imgBinary.clone(); + int exclusPara3 = 3; //TODO as parameter + cv::GaussianBlur(imgBinary,imgSmoothed,cv::Size(exclusPara3,exclusPara3),0); //0 = BORDER_CONSTANT + + //! 5 we make the canny edge detect + // Detect edges using canny + cv::Canny( imgSmoothed, imgCannyEdge, threshholdMin, threshholdMax, apertureSize ); + + // Find contours, use RETR_EXTERNAL ignore inner child structures, TREE more usefull ? + cv::findContours( imgCannyEdge, contours, hierarchy, cv::RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); + +#define MC_SHOW_STEP_ANALYSE +#ifdef MC_SHOW_STEP_ANALYSE + // Draw contours on extra mat + cv::Mat imgContour = cv::Mat::zeros( imgCannyEdge.size(), CV_8UC3 ); + imgContour = cv::Scalar(255,255,255); //fille the picture + cv::RNG rng(232323); + for( size_t i = 0; i< contours.size(); i++ ) + { + //random color + cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); + //contour + cv::drawContours( imgContour, contours, i, color, 1, cv::LINE_AA, hierarchy, 0, cv::Point() ); + } + + cv::String outpath= "/homes/tb55xemi/work/dev/bgslibrary-bgslib_qtgui_2.0.0/build/test0815/results"; + std::ostringstream convert; + convert << outpath << "test_countour_canny_edge.jpg"; + cv::imwrite(convert.str().c_str(), imgContour); + +#endif + + // return minRect; + return contours; +} + + +cv::Mat TToolBox::cropImageCircle(cv::Mat image, int x, int y, int r) +{ + + // Your Hough circle + cv::Vec3f circ(x,y,r); + + // Draw the mask: white circle on black background + cv::Mat1b mask(image.size(), uchar(0)); + cv::circle(mask, cv::Point(circ[0], circ[1]), circ[2], cv::Scalar(255), CV_FILLED); + + //NO CROP NEEDED + + // Compute the bounding box + //Rect bbox(circ[0] - circ[2], circ[1] - circ[2], 2 * circ[2], 2 * circ[2]); + + // Create a black image + cv::Mat res = cv::Mat::zeros( image.size(), CV_8UC3 ); + res = cv::Scalar(0,0,0); //fill with black color + + + // Copy only the image under the white circle to black image + image.copyTo(res, mask); + + // Crop according to the roi + //res = res(bbox); + + return res; +} + +int TToolBox::checkFileCorrupted(std::string filename) +{ + int retVal = 1;//is as long Corrupted as we dont find it in another way + char command[] = "identify "; + const char *fileNameArr = filename.c_str(); + char command2[] = " > /dev/null 2>&1 ; echo $?"; + char *cmd = new char[std::strlen(command)+std::strlen(fileNameArr) + std::strlen(command2) +1]; + //we put all peaces together + std::strcpy(cmd,command); + std::strcat(cmd,fileNameArr); + std::strcat(cmd,command2); + + //std:: cout <<"cmd is: "<< cmd<< std::endl; + //execute the command + std::string result = TToolBox::execCMD((const char* ) cmd); + + //std:: cout <<"results is: "<< result<< std::endl; + + if(!result.empty()) + { + try { + retVal = std::stoi(result); + } + catch(std::invalid_argument& e) + { + std::cerr <<"wrong argument for stoi"<<std::endl; + // if no conversion could be performed + } + catch (const std::exception& e) + { + std::cerr <<"error during use stoi"<<std::endl; + } + + }//end if + return retVal; +} + + +std::string TToolBox::execCMD(const char* cmd) { + std::array<char, 128> buffer; + std::string result; + std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose); + if (!pipe) throw std::runtime_error("popen() failed!"); + while (!feof(pipe.get())) { + if (fgets(buffer.data(), 128, pipe.get()) != nullptr) + result += buffer.data(); + //std::cout<<result<<std::endl; + + } + //std::cout<<"call: " <<result<<std::endl; + return result; +} diff --git a/src/algorithms/ttoolbox.h b/src/algorithms/ttoolbox.h new file mode 100644 index 0000000000000000000000000000000000000000..ee2ca9b194ff94b72a7c73bf7382b640c556bb8d --- /dev/null +++ b/src/algorithms/ttoolbox.h @@ -0,0 +1,54 @@ +#ifndef TTOOLBOX_H +#define TTOOLBOX_H + +//cpp,c +#include <iostream> +#include <algorithm> +#include <cstdlib> +#include <stdio.h> /* printf, scanf, puts, NULL */ +#include <stdlib.h> /* srand, rand */ +#include <time.h> /* time */ +#include <ctime> +#include <sstream> +#include <cstdio> +#include <memory> +#include <stdexcept> +#include <string> +#include <array> + +//open cv +#include "opencv2/core/core.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" + +class TToolBox +{ +public: + + //! return the number as string with 10 digits and '0' leading ones + static std::string mNzero(int i); + + //! return string plus data path and jpg suffix + static std::string getFileName(int i); + + //! returns a image, which is resulting circle + //! return roi of image which is cloned + //! without resize the image + //! will fill rest outer bound black + static cv::Mat cropImageCircle(cv::Mat image, int x, int y, int r); + + //! canny edge detect + static std::vector<std::vector<cv::Point>> applyCannyEdgeAndCalcCountours(cv::Mat imgSource, double threshholdMin, double threshholdMax, int apertureSize); + + //! will test if file is not corrupted + //! @return 1 if corrupted + //! @return 0 if not + static int checkFileCorrupted(std::string filename); + + //! will try to execute the cmd on the bash + static std::string execCMD(const char* cmd); + +}; + +#endif // TTOOLBOX_H