-
Thomas Boy authoredThomas Boy authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Demo2.cpp 24.90 KiB
/*
./bgs_demo -i test45/ -a 100 -o test45/results/
based on original demo.cpp
*/
//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>
#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;
}
int main(int argc, char * argv[])
{
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);
}
cout <<"args: -i "<<inputDir<<" -a "<<amountFiles << " -c" << centerFileString<<" -o " << outputDir;
//!**** end parse input***********/
//./program -i pathToInputDir -a amountOfJpgFiles -o outPutPath
//pathToInputDir
//----should have
// centerFile.xml
// -data/
// #which include all jpg and tt files
// first file mus be: 0000000000.jpg
// -bk.jpg
// #is the neutral bk file for training the bgs method
//
// 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 */
//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;
// bgs->setPathOut(outputDir);
// bgs->setInitialFrameCounter(0);
// bgs->setFlagWrite(0);
// bgs->setFlagWriteDBGpic(0);
//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
int i= 0;
cv::Mat img_input;
//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();
// //first the static pic**********
// //std::string fileName = getFileName(begin);
// std::string staticFile = inputDir+"/bk.jpg";
// cout <<"a) load first static background pic :"<< staticFile<<endl;
// img_input = imread(staticFile.c_str(), CV_LOAD_IMAGE_COLOR);
// if(img_input.data )
// {
// //we cut out a smaller ROI
// img_input = TToolBox::cropImageCircle(img_input,circleCenterX,circleCenterY,circleRadius);
// cv::Mat img_mask;
// cv::Mat img_bkgmodel;
// bgs->process(img_input, img_mask, img_bkgmodel);
// }
// else
// {
// cout<<"error loading file: "<< staticFile<<", will abort"<<endl;
// return EXIT_FAILURE;
// }
std::string fileName;
//! we train with first x on random draws
//int amountTrainingSteps = 2;
// //we open the config file and readin
// cv::String configFileName("./config/Tapter.xml");
// {//read the config
// FileStorage fs;
// fs.open(configFileName, FileStorage::READ);
// if (!fs.isOpened())
// {
// cout << "error during open " << configFileName << " will abort " <<endl;
// return EXIT_FAILURE;
// }
// //param
// amountTrainingSteps = (int) fs["trainingSteps"];
// //cout <<"amountTrainingSteps: "<< amountTrainingSteps<< endl;
// fs.release();
// }
cout <<"a) we choose two random file "<< fileName<<endl;
//int j=255;
vector<Mat> picsMask;
vector<Mat> picsOrigin;
int maxTrain = 10;
vector<string> myRandomTrainList; //we save all draws in a list which will save to the results
for(i=0;i<maxTrain;i++)
{
//random index
int index = rand() % amountFiles; //TODO: double check no double draw ??
fileName = inputDir + TToolBox::getFileName(index);
myRandomTrainList.push_back(fileName);
cout <<"\t"<<i <<"\t of \t"<<maxTrain<<" rnd file :"<< fileName<<endl;
img_input = imread(fileName.c_str(), CV_LOAD_IMAGE_COLOR);
if(img_input.data )
{
//we cut out a smaller ROI
img_input = TToolBox::cropImageCircle(img_input,circleCenterX,circleCenterY,circleRadius);
//cv::imshow("input", img_input);
cv::Mat img_mask;
cv::Mat img_bkgmodel;
// //adapter learning rate
// if(j>62)
// bgs->setLearningRate(j);
bgs->process(img_input, img_mask, img_bkgmodel); // by default, it shows automatically the foreground mask image
if(i>=(maxTrain-2))
{
picsMask.push_back(img_mask.clone());
picsOrigin.push_back(img_input.clone());
}
// //we save the bk gmodel
// std::string bkTestFileName = inputDir + "bk_"+TToolBox::mNzero(i)+".jpg";
// imwrite(bkTestFileName.c_str(),img_bkgmodel);
}
else
{
cout<<"error loading file: "<< fileName<<", will abort"<<endl;
return EXIT_FAILURE;
}
}
cout <<"b) we calc the two polygones of the points"<< fileName<<endl;
if(picsMask.empty())
{
cout<<"error no pics loaded"<<endl;
return EXIT_FAILURE;
}
else
cout<<"pics.size(): "<<picsMask.size()<<endl;
int frameCounter = 0;
//vector<vector<vector<Point>>> polyGones;
vector<RotatedRect> rectanglesPicA;//we will save the rectangles for each polygone which was selected
vector<RotatedRect> rectanglesPicB;
for(frameCounter=0;frameCounter<2;frameCounter++)
{
Mat img_mask = picsMask[frameCounter];
//! 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);
// //TODO: we need to order the points to get a nice polygon, otherwise not usefull
// //we also try to find the aproximate polygon*****************
//// vector<Point> aproxiCurve;
//// // //see https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a167a8e0a3a3d86e84b70e33483af4466
//// // if(aproxiCurve::checkVector(10,CV_32F)==-1)
//// // cout<<"error wrong format of vector"<<endl;
//// //calc 0.1 percent of arc length of convex hull
//// double epsilon = 0.1 * cv::arcLength(hullComplete,true);
//// //see https://docs.opencv.org/2.4.13.2/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#approxpolydp
//// cv::approxPolyDP(allContourPoints,aproxiCurve,epsilon,false);
////#ifdef MC_SHOW_STEP_ANALYSE
//// if(aproxiCurve.size()>=2)//we only draw if we have at least a line
//// {
//// Mat imgPolyApr = Mat::zeros( img_input.size(), CV_8UC3 );
//// imgPolyApr = Scalar(255,255,255); //fille the picture
//// Scalar colorC( 0,0,255,255 );//red
//// //for(imgPolyApr)
//// polylines(imgPolyApr, aproxiCurve, true, colorC, 1, 8);
//// cv::String outpath3= "/homes/tb55xemi/work/bugTrainingSet/testRec/rec04379437pp/result/";
//// std::ostringstream convert3;
//// convert3 << outpath3 << frameCounter <<"_appr_poly.jpg";
//// cv::imwrite(convert3.str().c_str(), imgPolyApr);
//// }
//// else
//// cout<<"approximate poly has not enough points will skip file: "<<frameCounter<<endl;
////#endif
//! step 4) we make a selection out of all counters with area sizes******************************
vector<vector<Point> > contourSelection;
//we exlcude very small one and very big ones
//we calc all min rotated rectangles for all contour from candy egde detect
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 = 15000; //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;
//we add the rectangles to the list
if(frameCounter==0)
rectanglesPicA.push_back(minRect[i]);
if(frameCounter==1)
rectanglesPicB.push_back(minRect[i]);
//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
// //! 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:
// vector<Point2f> massCenters( 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 ******************
// vector<Point> conHull(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;
// Point2f muConvexHullMassCenter(0.0,0.0);
// if(!conHull.empty())
// {
// muConvexHull = moments(conHull, true );
// muConvexHullMassCenter= Point2f( muConvexHull.m10/muConvexHull.m00 , muConvexHull.m01/muConvexHull.m00 );
// }
//#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
// //! step 8: we write down all our results in yml file
// std::string nameOutPutFileData = outputDir + TToolBox::mNzero(frameCounter) + ".yml";
// 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) + ".jpg";
// imwrite(nameOutPutFileDBGpic.c_str(),imgOverlay2);
// }
}//end for iterate frame
if(rectanglesPicA.empty()||rectanglesPicB.empty())
cout<<"error no retangles found in pics "<<endl;
Mat picA = picsOrigin[0].clone();
Mat picB = picsOrigin[1].clone();
//now we iterate all rectangles in picA and will produce pictures
for(size_t i=0;i<rectanglesPicA.size();i++)
{
std::string filenName = outputDir + "bk_candidate_a_" + TToolBox::mNzero(i) + ".jpg";
cout << "process picA i"<<i<<" name" <<filenName << endl;
//get the points
RotatedRect rectA= rectanglesPicA[i];
Point2f rectApoints[4];
//get all points of the retange
rectA.points( rectApoints );
//@see https://docs.opencv.org/3.4.0/db/dd6/classcv_1_1RotatedRect.html#a69d648b086f26dbce0029facae9bfb2d
//The points array for storing rectangle vertices.
//The order is bottomLeft, topLeft, topRight, bottomRight.
Point2f corner = rectApoints[1];
//we should add some offset
int offset = 50; //TODO double check offset
Point2f cornerOffset= Point2f((float)( corner.x-offset), (float) (corner.y-offset));
Rect rect = rectA.boundingRect();
//TODO check if out of our area
Rect rectOffset = Rect((float) (cornerOffset.x),(float) (cornerOffset.y),(float)(rect.width + offset) ,(float) (rect.height+offset )) ;
Mat imageRoi = picB(rectOffset);
// std::string filenNameROI = outputDir + "bk_test_a_roi_" + TToolBox::mNzero(i) + ".jpg";
// imwrite(filenNameROI.c_str(),imageRoi);
//imageRoi = Scalar( 255, 0, 0); //fill blue)
// std::cout << "rect size: " << rect.size() << std::endl;
// std::cout << "tempResult cols,rows: " << picB.cols << ", " << picB.rows << endl;
cv::Rect rectROI(cornerOffset.x,cornerOffset.y, imageRoi.cols, imageRoi.rows);
imageRoi.copyTo(picA(rectROI));
cout << "."<<endl;
imwrite(filenName.c_str(),picA);
}
//now we iterate all rectangles and will produce pictures
for(size_t i=0;i<rectanglesPicB.size();i++)
{
std::string filenName = outputDir + "bk_candidate_b_" + TToolBox::mNzero(i) + ".jpg";
cout << "process picB i"<<i<<" name" <<filenName << endl;
//get the points
RotatedRect rectB= rectanglesPicB[i];
Point2f rectBpoints[4];
//get all points of the retange
rectB.points( rectBpoints );
//@see https://docs.opencv.org/3.4.0/db/dd6/classcv_1_1RotatedRect.html#a69d648b086f26dbce0029facae9bfb2d
//The points array for storing rectangle vertices.
//The order is bottomLeft, topLeft, topRight, bottomRight.
Point2f corner = rectBpoints[1];
//we should add some offset
int offset = 50; //TODO double check offset
Point2f cornerOffset= Point2f((float)( corner.x-offset), (float) (corner.y-offset));
Rect rect = rectB.boundingRect();
//TODO check if out of our area
Rect rectOffset = Rect((float) (cornerOffset.x),(float)(cornerOffset.y),(float)(rect.width+offset) ,(float) (rect.height+offset)) ;
Mat imageRoi = picA(rectOffset);
// std::string filenNameROI = outputDir + "bk_test_a_roi_" + TToolBox::mNzero(i) + ".jpg";
// imwrite(filenNameROI.c_str(),imageRoi);
//imageRoi = Scalar( 255, 0, 0); //fill blue)
// std::cout << "rect size: " << rect.size() << std::endl;
// std::cout << "tempResult cols,rows: " << picB.cols << ", " << picB.rows << endl;
cv::Rect rectROI(cornerOffset.x,cornerOffset.y, imageRoi.cols, imageRoi.rows);
imageRoi.copyTo(picB(rectROI));
cout << "."<<endl;
imwrite(filenName.c_str(),picB);
}
// //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;
delete bgs;
// capture.release();
cvDestroyAllWindows();
return 0;
}