From ee50060ebf68f5c69178ad8cebe5ce02293fde8d Mon Sep 17 00:00:00 2001 From: am0ebe <am0ebe@gmx.de> Date: Thu, 27 Jan 2022 21:06:25 +0100 Subject: [PATCH] . --- examples/Demo.c | 680 ++++++++++++++++++++++++++++++++++++++++++++++ examples/Demo.cpp | 8 +- 2 files changed, 684 insertions(+), 4 deletions(-) create mode 100644 examples/Demo.c diff --git a/examples/Demo.c b/examples/Demo.c new file mode 100644 index 0000000..1311d95 --- /dev/null +++ b/examples/Demo.c @@ -0,0 +1,680 @@ +/* +bgs_demo -i ../../dataset/video.tar -a 100 -o ../../output -c ../../config/centerConfigFile.xml -p ../../config/camParam.xml +*/ + +//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 <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> + +#include <regex> //cpp 11X + +#define PROCESS_CENTER_VERSION_MAJOR 2 +#define PROCESS_CENTER_VERSION_MINOR 0 +#define PROCESS_CENTER_VERSION_MINOR_FIXES 1 + +#include <opencv2/opencv.hpp> //opencv +#include "../src/algorithms/algorithms.h" //bgs + +using namespace bgslibrary::algorithms; +using namespace cv; +using namespace std; + +Scalar color_red( 0,0,255,255 ); + +int g_badSignalFlagAbort = 0; + +void my_handler(int signum); + +char* getCmdOption(char ** begin, char ** end, const string & option); + +bool cmdOptionExists(char** begin, char** end, const string& option); + +vector<char> copyDataInBuffer(struct archive *aw); + +//! we convert our actual jpg file number to framenumber +int toFrameNumber(string filename); + +int main(int argc, char * argv[]) +{ + signal(SIGUSR1, my_handler); + + cout << "Using OpenCV " << CV_MAJOR_VERSION << "." << CV_MINOR_VERSION << "." << CV_SUBMINOR_VERSION << endl; + cout << "Using processcenter " << PROCESS_CENTER_VERSION_MAJOR << "." << PROCESS_CENTER_VERSION_MINOR << "." << PROCESS_CENTER_VERSION_MINOR_FIXES << endl << endl; + + //!** parse programm input****************/ + + if( cmdOptionExists(argv, argv+argc, "-h") + || cmdOptionExists(argv, argv+argc, "-?") + || !cmdOptionExists(argv, argv+argc, "-i") + || !cmdOptionExists(argv, argv+argc, "-a") + || !cmdOptionExists(argv, argv+argc, "-o") + || !cmdOptionExists(argv, argv+argc, "-p")) + { + cout << " Usage:" << endl; + cout << " " << argv[0] << " -i in.tar -a amount -c center.xml -o outPath -p camparameterFile.xml" << endl << endl; + cout << " Options:" << endl; + cout << " i - input tarfile/dir containing tars ?" << endl; + cout << " a - amount of files/frames ?" << endl; + cout << " c - exact center xml-conf file" << endl; + cout << " o - output path / dir" << endl; + cout << " p - camparameterFile ?" << endl; + + return EXIT_FAILURE; + } + + char *testFile = getCmdOption(argv, argv + argc, "-i"); + 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"); + 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); + } + + char *camerFile = getCmdOption(argv, argv + argc, "-p"); + string cameraParameterFile("."); + if (camerFile) + { + //test dir exists + cameraParameterFile = string(camerFile); + } + + + cout << "args: -i " << inputFile << " -a " << amountFiles << " -c" << centerFileString << " -o " << outputDir << " -p " << cameraParameterFile << endl; + //!**** 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 ##### + + Codebook is new! + Tapter is TBoy! + + List of all algorithms: + AdaptiveBackgroundLearning,AdaptiveSelectiveBackgroundLearning,CodeBook,DPAdaptiveMedian,DPEigenbackground, + DPGrimsonGMM,DPMean,DPPratiMediod,DPTexture,DPWrenGA,DPZivkovicAGMM,FrameDifference,FuzzyChoquetIntegral, + FuzzySugenoIntegral,GMG,IndependentMultimodal,KDE,KNN,LBAdaptiveSOM,LBFuzzyAdaptiveSOM,LBFuzzyGaussian, + LBMixtureOfGaussians,LBP_MRF,LBSimpleGaussian,LOBSTER,MixtureOfGaussianV2,MixtureOfGaussianV1,MultiCue, + MultiLayer,PAWCS,PixelBasedAdaptiveSegmenter,SigmaDelta,StaticFrameDifference,SuBSENSE,T2FGMM_UM,T2FGMM_UV, + T2FMRF_UM,T2FMRF_UV,TwoPoints,ViBe,VuMeter,WeightedMovingMean,WeightedMovingVariance + + (Note that some of these algorithms are available only for a specific version of OpenCV, see algorithms.h) + */ + IBGS *bgs = new FrameDifference; + // IBGS *bgs = new PixelBasedAdaptiveSegmenter; // TODO + + + //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 (tapter?) + + //init the random number generator + srand (time(NULL)); + + clock_t beginAll = clock(); + + //! read the center config file to 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" << endl; + 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(); + + + cout << "here" << endl; + system("pause"); + + + //open camera config file + cv::String camParam (cameraParameterFile); + Mat intrinsicsCameraMatrix, distortionCoeff; + { + cout << "read cam parameter of: " << cameraParameterFile << endl; + FileStorage fs; + fs.open(camParam, FileStorage::READ); + if (!fs.isOpened()) + { + cerr << "error during open " << cameraParameterFile << " will abort" << endl; + return -1; + } + + fs["camera_matrix"] >> intrinsicsCameraMatrix; + fs["distortion_coefficients"] >> distortionCoeff; + + // intrinsicsCameraMatrix = (int) fs["camera_matrix"]; + // intrinsicsCameraMatrix = fs["camera_matrix"].mat(); + cout << "camera_matrix = " << intrinsicsCameraMatrix << endl; + + // distortionCoeff = (int) fs["distortion_coefficients"]; + // distortionCoeff = fs["distortion_coefficients"].mat(); + cout << "distortion_coefficients = " << distortionCoeff << endl; + } + + cout << "a) process all frames " << endl; + + int everyPic= 60*5; + //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; + + //loop over _all_ pictures in the tar archive + for (;;) + { + + //measure time consumption + //sa opencv tick timer: + // https://docs.opencv.org/4.x/d9/d6f/classcv_1_1TickMeter.html#details + clock_t begin = clock(); //for every single file + vector<char> vec; + + //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); + } + cout << "here2" << endl; + + // get filename + const char *fileNamePtr = archive_entry_pathname(entry); + string filename(fileNamePtr,strlen(fileNamePtr) ); + //cout << "fileName: " << filename << endl; + // convert it to a framenumber + frameCounter = toFrameNumber(filename); + + if(frameCounterOld>frameCounter) + { + cerr << " error during read in the file number, found non-monotonic 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 + } + + 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); + } + + // read the image buffer as a jpg picture and decode it + Mat img_input = imdecode(Mat(vec), 1); + + cout << "\t" << frameCounter << "\tof \t" << amountFiles << " load file :" << filename << endl; + + //of data is present + if(img_input.data ) + { + + //! step 0 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); + + //! step 1) cut out a smaller ROI + img_input = TToolBox::cropImageCircle(imgLenseCorrection,circleCenterX,circleCenterY,circleRadius); + + //! step 2) normal bgs processing + 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) apply 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; + vector<vector<Point> > contours = TToolBox::applyCannyEdgeAndCalcCountours(img_mask,threshholdMin,threshholdMax,apertureSize); + + //define what will be written + 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 contours with area sizes + //****************************** + + //calc all min rotated rectangles for all contour from canny edge detect + //exclude very small/big + 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); + + //we also add the this contour to a selection + contourSelection.push_back(contours[i]); + + } + }//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 ); + + //calc the min circle around + // Point roiCenter; + // float roiRadius; + //minEnclosingCircle(conHull,roiCenter,roiRadius); + + // 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); //fill the picture + + polylines(imgConvexHull, hullComplete, true, color_red, 1, 8); + + //draw circle around + //circle( imgConvexHull, roiCenter, (int) roiRadius, color_red, 2, 8, 0 ); + + //we draw it + cv::String outpath2 = outputDir; + 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 + 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(); + + //! occasionaly write a dbg picture + if(frameCounter%everyPic==0) + { + RNG rng(4344234); + Mat imgDebugPaint2 = Mat::zeros( img_input.size(), CV_8UC3 ); + imgDebugPaint2 = Scalar(255,255,255); //fill the picture white + + // 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 ); + } + + // write the convex hull + if(!conHull.empty()) + { + //the poly + polylines(imgDebugPaint2, conHull, true, color_red, 1, 8); + //the center + circle( imgDebugPaint2,muConvexHullMassCenter, 4, color_red, -1, 8, 0 ); + } + + // copy + Mat imgOverlay2 = img_input.clone(); + // add overlay of paintings + addWeighted( imgDebugPaint2, 0.7, imgOverlay2, 0.3, 0.0, imgOverlay2); + // writeout file + string nameOutPutFileDBGpic = outputDir + TToolBox::mNzero(frameCounter) + string(".jpg"); + + imwrite(nameOutPutFileDBGpic.c_str(),imgOverlay2); + + }//end if dbg picture + + + }//end if the loaded picture has data + else + { + cerr << "error loading file: " << filename << ", will skip this file" << endl; + myFileErrorList.push_back(filename); + } + + //calc the time which we used for a picture //TODO move out of loop + clock_t end = clock(); + double elapsedSecs = double(end - begin) / CLOCKS_PER_SEC; + + + //calc the time which was used for all pictures + 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; // 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 + // 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; + + // write the random file list to a file + string nameOutErrorList = outputDir + "fileErrorList.yml"; + cout << "amount of file errors: " << myFileErrorList.size()<< endl; + FileStorage fs2(nameOutErrorList.c_str(), FileStorage::WRITE); + fs2 << "fileErrorIOs" << myFileErrorList; + + // write error list no contours found in file + cout << "amount contour errors with canny edge: " << myFileListNoContour.size() << endl; + fs2 << "fileErrorNoContours" << myFileListNoContour; + + // write error list no contours found in file + cout << "amount contour errors after selection: " << myFileListAfterContourSelection.size() << endl; + fs2 << "fileErrorNoContoursAfterSelections" << myFileListAfterContourSelection; + + // bgs related things + delete bgs; + + // opencv related things + fs2.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; +} + + + +vector<char> copyDataInBuffer(struct archive *aw) +{ + int r; + const void *buff; + 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 + } + + 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) +{ + if (signum == SIGUSR1) + { + g_badSignalFlagAbort = 1; + cerr << "receive signal to abort" << endl; + } +} + +char* getCmdOption(char ** begin, char ** end, const string & option) +{ + char ** itr = find(begin, end, option); + if (itr != end && ++itr != end) + { + return *itr; + } + return 0; +} + +bool cmdOptionExists(char** begin, char** end, const string& option) +{ + return find(begin, end, option) != end; +} + +int toFrameNumber(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 = stoi( filename ); + + //cout << "filename out:" << filename << " number: " << retVal << endl; + + return retVal; +} diff --git a/examples/Demo.cpp b/examples/Demo.cpp index 14f6278..1311d95 100644 --- a/examples/Demo.cpp +++ b/examples/Demo.cpp @@ -236,7 +236,7 @@ int main(int argc, char * argv[]) cout << "distortion_coefficients = " << distortionCoeff << endl; } - cout << "a) we process all frames " << endl; + cout << "a) process all frames " << endl; int everyPic= 60*5; //string fileName; @@ -247,7 +247,7 @@ int main(int argc, char * argv[]) vector<string> myFileListNoContour; //list for no contours found; vector<string> myFileListAfterContourSelection; //list for no contours found after selection; - //loop over _all_ picture of the tar archive + //loop over _all_ pictures in the tar archive for (;;) { @@ -257,7 +257,7 @@ int main(int argc, char * argv[]) clock_t begin = clock(); //for every single file vector<char> vec; - //we read the next header + //read the next header r = archive_read_next_header(archive, &entry); if (r == ARCHIVE_EOF) break; @@ -277,7 +277,7 @@ int main(int argc, char * argv[]) if(frameCounterOld>frameCounter) { - cerr << " error during read in the file number, we do have non montonic order, will abort"; + cerr << " error during read in the file number, found non-monotonic order, will abort"; exit(1); } -- GitLab