Compare commits

...

No commits in common. 'main' and 'dev' have entirely different histories.
main ... dev

@ -1,2 +0,0 @@
# gitproject

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,5 +0,0 @@
ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual -Winconsistent-missing-override -Wsuggest-override)
file(GLOB SRCS *.cpp)
ocv_add_application(opencv_traincascade
MODULES opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d
SRCS ${SRCS})

@ -1,250 +0,0 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "HOGfeatures.h"
#include "cascadeclassifier.h"
using namespace std;
using namespace cv;
CvHOGFeatureParams::CvHOGFeatureParams()
{
maxCatCount = 0;
name = HOGF_NAME;
featSize = N_BINS * N_CELLS;
}
void CvHOGEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)
{
CV_Assert( _maxSampleCount > 0);
int cols = (_winSize.width + 1) * (_winSize.height + 1);
for (int bin = 0; bin < N_BINS; bin++)
{
hist.push_back(Mat(_maxSampleCount, cols, CV_32FC1));
}
normSum.create( (int)_maxSampleCount, cols, CV_32FC1 );
CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
}
void CvHOGEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
{
CV_DbgAssert( !hist.empty());
CvFeatureEvaluator::setImage( img, clsLabel, idx );
vector<Mat> integralHist;
for (int bin = 0; bin < N_BINS; bin++)
{
integralHist.push_back( Mat(winSize.height + 1, winSize.width + 1, hist[bin].type(), hist[bin].ptr<float>((int)idx)) );
}
Mat integralNorm(winSize.height + 1, winSize.width + 1, normSum.type(), normSum.ptr<float>((int)idx));
integralHistogram(img, integralHist, integralNorm, (int)N_BINS);
}
//void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
//{
// _writeFeatures( features, fs, featureMap );
//}
void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
int featIdx;
int componentIdx;
const Mat_<int>& featureMap_ = (const Mat_<int>&)featureMap;
fs << FEATURES << "[";
for ( int fi = 0; fi < featureMap.cols; fi++ )
if ( featureMap_(0, fi) >= 0 )
{
fs << "{";
featIdx = fi / getFeatureSize();
componentIdx = fi % getFeatureSize();
features[featIdx].write( fs, componentIdx );
fs << "}";
}
fs << "]";
}
void CvHOGEvaluator::generateFeatures()
{
int offset = winSize.width + 1;
Size blockStep;
int x, y, t, w, h;
for (t = 8; t <= winSize.width/2; t+=8) //t = size of a cell. blocksize = 4*cellSize
{
blockStep = Size(4,4);
w = 2*t; //width of a block
h = 2*t; //height of a block
for (x = 0; x <= winSize.width - w; x += blockStep.width)
{
for (y = 0; y <= winSize.height - h; y += blockStep.height)
{
features.push_back(Feature(offset, x, y, t, t));
}
}
w = 2*t;
h = 4*t;
for (x = 0; x <= winSize.width - w; x += blockStep.width)
{
for (y = 0; y <= winSize.height - h; y += blockStep.height)
{
features.push_back(Feature(offset, x, y, t, 2*t));
}
}
w = 4*t;
h = 2*t;
for (x = 0; x <= winSize.width - w; x += blockStep.width)
{
for (y = 0; y <= winSize.height - h; y += blockStep.height)
{
features.push_back(Feature(offset, x, y, 2*t, t));
}
}
}
numFeatures = (int)features.size();
}
CvHOGEvaluator::Feature::Feature()
{
for (int i = 0; i < N_CELLS; i++)
{
rect[i] = Rect(0, 0, 0, 0);
}
}
CvHOGEvaluator::Feature::Feature( int offset, int x, int y, int cellW, int cellH )
{
rect[0] = Rect(x, y, cellW, cellH); //cell0
rect[1] = Rect(x+cellW, y, cellW, cellH); //cell1
rect[2] = Rect(x, y+cellH, cellW, cellH); //cell2
rect[3] = Rect(x+cellW, y+cellH, cellW, cellH); //cell3
for (int i = 0; i < N_CELLS; i++)
{
CV_SUM_OFFSETS(fastRect[i].p0, fastRect[i].p1, fastRect[i].p2, fastRect[i].p3, rect[i], offset);
}
}
void CvHOGEvaluator::Feature::write(FileStorage &fs) const
{
fs << CC_RECTS << "[";
for( int i = 0; i < N_CELLS; i++ )
{
fs << "[:" << rect[i].x << rect[i].y << rect[i].width << rect[i].height << "]";
}
fs << "]";
}
//cell and bin idx writing
//void CvHOGEvaluator::Feature::write(FileStorage &fs, int varIdx) const
//{
// int featComponent = varIdx % (N_CELLS * N_BINS);
// int cellIdx = featComponent / N_BINS;
// int binIdx = featComponent % N_BINS;
//
// fs << CC_RECTS << "[:" << rect[cellIdx].x << rect[cellIdx].y <<
// rect[cellIdx].width << rect[cellIdx].height << binIdx << "]";
//}
//cell[0] and featComponent idx writing. By cell[0] it's possible to recover all block
//All block is necessary for block normalization
void CvHOGEvaluator::Feature::write(FileStorage &fs, int featComponentIdx) const
{
fs << CC_RECT << "[:" << rect[0].x << rect[0].y <<
rect[0].width << rect[0].height << featComponentIdx << "]";
}
void CvHOGEvaluator::integralHistogram(const Mat &img, vector<Mat> &histogram, Mat &norm, int nbins) const
{
CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );
int x, y, binIdx;
Size gradSize(img.size());
Size histSize(histogram[0].size());
Mat grad(gradSize, CV_32F);
Mat qangle(gradSize, CV_8U);
AutoBuffer<int> mapbuf(gradSize.width + gradSize.height + 4);
int* xmap = mapbuf.data() + 1;
int* ymap = xmap + gradSize.width + 2;
const int borderType = (int)BORDER_REPLICATE;
for( x = -1; x < gradSize.width + 1; x++ )
xmap[x] = borderInterpolate(x, gradSize.width, borderType);
for( y = -1; y < gradSize.height + 1; y++ )
ymap[y] = borderInterpolate(y, gradSize.height, borderType);
int width = gradSize.width;
AutoBuffer<float> _dbuf(width*4);
float* dbuf = _dbuf.data();
Mat Dx(1, width, CV_32F, dbuf);
Mat Dy(1, width, CV_32F, dbuf + width);
Mat Mag(1, width, CV_32F, dbuf + width*2);
Mat Angle(1, width, CV_32F, dbuf + width*3);
float angleScale = (float)(nbins/CV_PI);
for( y = 0; y < gradSize.height; y++ )
{
const uchar* currPtr = img.ptr(ymap[y]);
const uchar* prevPtr = img.ptr(ymap[y-1]);
const uchar* nextPtr = img.ptr(ymap[y+1]);
float* gradPtr = grad.ptr<float>(y);
uchar* qanglePtr = qangle.ptr(y);
for( x = 0; x < width; x++ )
{
dbuf[x] = (float)(currPtr[xmap[x+1]] - currPtr[xmap[x-1]]);
dbuf[width + x] = (float)(nextPtr[xmap[x]] - prevPtr[xmap[x]]);
}
cartToPolar( Dx, Dy, Mag, Angle, false );
for( x = 0; x < width; x++ )
{
float mag = dbuf[x+width*2];
float angle = dbuf[x+width*3];
angle = angle*angleScale - 0.5f;
int bidx = cvFloor(angle);
angle -= bidx;
if( bidx < 0 )
bidx += nbins;
else if( bidx >= nbins )
bidx -= nbins;
qanglePtr[x] = (uchar)bidx;
gradPtr[x] = mag;
}
}
integral(grad, norm, grad.depth());
float* histBuf;
const float* magBuf;
const uchar* binsBuf;
int binsStep = (int)( qangle.step / sizeof(uchar) );
int histStep = (int)( histogram[0].step / sizeof(float) );
int magStep = (int)( grad.step / sizeof(float) );
for( binIdx = 0; binIdx < nbins; binIdx++ )
{
histBuf = histogram[binIdx].ptr<float>();
magBuf = grad.ptr<float>();
binsBuf = qangle.ptr();
memset( histBuf, 0, histSize.width * sizeof(histBuf[0]) );
histBuf += histStep + 1;
for( y = 0; y < qangle.rows; y++ )
{
histBuf[-1] = 0.f;
float strSum = 0.f;
for( x = 0; x < qangle.cols; x++ )
{
if( binsBuf[x] == binIdx )
strSum += magBuf[x];
histBuf[x] = histBuf[-histStep + x] + strSum;
}
histBuf += histStep;
binsBuf += binsStep;
magBuf += magStep;
}
}
}

@ -1,78 +0,0 @@
#ifndef _OPENCV_HOGFEATURES_H_
#define _OPENCV_HOGFEATURES_H_
#include "traincascade_features.h"
//#define TEST_INTHIST_BUILD
//#define TEST_FEAT_CALC
#define N_BINS 9
#define N_CELLS 4
#define HOGF_NAME "HOGFeatureParams"
struct CvHOGFeatureParams : public CvFeatureParams
{
CvHOGFeatureParams();
};
class CvHOGEvaluator : public CvFeatureEvaluator
{
public:
virtual ~CvHOGEvaluator() {}
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx);
virtual float operator()(int varIdx, int sampleIdx) const;
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
protected:
virtual void generateFeatures();
virtual void integralHistogram(const cv::Mat &img, std::vector<cv::Mat> &histogram, cv::Mat &norm, int nbins) const;
class Feature
{
public:
Feature();
Feature( int offset, int x, int y, int cellW, int cellH );
float calc( const std::vector<cv::Mat> &_hists, const cv::Mat &_normSum, size_t y, int featComponent ) const;
void write( cv::FileStorage &fs ) const;
void write( cv::FileStorage &fs, int varIdx ) const;
cv::Rect rect[N_CELLS]; //cells
struct
{
int p0, p1, p2, p3;
} fastRect[N_CELLS];
};
std::vector<Feature> features;
cv::Mat normSum; //for normalization calculation (L1 or L2)
std::vector<cv::Mat> hist;
};
inline float CvHOGEvaluator::operator()(int varIdx, int sampleIdx) const
{
int featureIdx = varIdx / (N_BINS * N_CELLS);
int componentIdx = varIdx % (N_BINS * N_CELLS);
//return features[featureIdx].calc( hist, sampleIdx, componentIdx);
return features[featureIdx].calc( hist, normSum, sampleIdx, componentIdx);
}
inline float CvHOGEvaluator::Feature::calc( const std::vector<cv::Mat>& _hists, const cv::Mat& _normSum, size_t y, int featComponent ) const
{
float normFactor;
float res;
int binIdx = featComponent % N_BINS;
int cellIdx = featComponent / N_BINS;
const float *phist = _hists[binIdx].ptr<float>((int)y);
res = phist[fastRect[cellIdx].p0] - phist[fastRect[cellIdx].p1] - phist[fastRect[cellIdx].p2] + phist[fastRect[cellIdx].p3];
const float *pnormSum = _normSum.ptr<float>((int)y);
normFactor = (float)(pnormSum[fastRect[0].p0] - pnormSum[fastRect[1].p1] - pnormSum[fastRect[2].p2] + pnormSum[fastRect[3].p3]);
res = (res > 0.001f) ? ( res / (normFactor + 0.001f) ) : 0.f; //for cutting negative values, which appear due to floating precision
return res;
}
#endif // _OPENCV_HOGFEATURES_H_

File diff suppressed because it is too large Load Diff

@ -1,86 +0,0 @@
#ifndef _OPENCV_BOOST_H_
#define _OPENCV_BOOST_H_
#include "traincascade_features.h"
#include "old_ml.hpp"
struct CvCascadeBoostParams : CvBoostParams
{
float minHitRate;
float maxFalseAlarm;
CvCascadeBoostParams();
CvCascadeBoostParams( int _boostType, float _minHitRate, float _maxFalseAlarm,
double _weightTrimRate, int _maxDepth, int _maxWeakCount );
virtual ~CvCascadeBoostParams() {}
void write( cv::FileStorage &fs ) const;
bool read( const cv::FileNode &node );
virtual void printDefaults() const;
virtual void printAttrs() const;
virtual bool scanAttr( const std::string prmName, const std::string val);
};
struct CvCascadeBoostTrainData : CvDTreeTrainData
{
CvCascadeBoostTrainData( const CvFeatureEvaluator* _featureEvaluator,
const CvDTreeParams& _params );
CvCascadeBoostTrainData( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples, int _precalcValBufSize, int _precalcIdxBufSize,
const CvDTreeParams& _params = CvDTreeParams() );
virtual void setData( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples, int _precalcValBufSize, int _precalcIdxBufSize,
const CvDTreeParams& _params=CvDTreeParams() );
void precalculate();
virtual CvDTreeNode* subsample_data( const CvMat* _subsample_idx );
virtual const int* get_class_labels( CvDTreeNode* n, int* labelsBuf );
virtual const int* get_cv_labels( CvDTreeNode* n, int* labelsBuf);
virtual const int* get_sample_indices( CvDTreeNode* n, int* indicesBuf );
virtual void get_ord_var_data( CvDTreeNode* n, int vi, float* ordValuesBuf, int* sortedIndicesBuf,
const float** ordValues, const int** sortedIndices, int* sampleIndicesBuf );
virtual const int* get_cat_var_data( CvDTreeNode* n, int vi, int* catValuesBuf );
virtual float getVarValue( int vi, int si );
virtual void free_train_data();
const CvFeatureEvaluator* featureEvaluator;
cv::Mat valCache; // precalculated feature values (CV_32FC1)
CvMat _resp; // for casting
int numPrecalcVal, numPrecalcIdx;
};
class CvCascadeBoostTree : public CvBoostTree
{
public:
virtual CvDTreeNode* predict( int sampleIdx ) const;
void write( cv::FileStorage &fs, const cv::Mat& featureMap );
void read( const cv::FileNode &node, CvBoost* _ensemble, CvDTreeTrainData* _data );
void markFeaturesInMap( cv::Mat& featureMap );
protected:
virtual void split_node_data( CvDTreeNode* n );
};
class CvCascadeBoost : public CvBoost
{
public:
virtual bool train( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples, int _precalcValBufSize, int _precalcIdxBufSize,
const CvCascadeBoostParams& _params=CvCascadeBoostParams() );
virtual float predict( int sampleIdx, bool returnSum = false ) const;
float getThreshold() const { return threshold; }
void write( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
bool read( const cv::FileNode &node, const CvFeatureEvaluator* _featureEvaluator,
const CvCascadeBoostParams& _params );
void markUsedFeaturesInMap( cv::Mat& featureMap );
protected:
virtual bool set_params( const CvBoostParams& _params );
virtual void update_weights( CvBoostTree* tree );
virtual bool isErrDesired();
float threshold;
float minHitRate, maxFalseAlarm;
};
#endif

@ -1,570 +0,0 @@
#include "opencv2/core.hpp"
#include "cascadeclassifier.h"
#include <queue>
using namespace std;
using namespace cv;
static const char* stageTypes[] = { CC_BOOST };
static const char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
CvCascadeParams::CvCascadeParams() : stageType( defaultStageType ),
featureType( defaultFeatureType ), winSize( cvSize(24, 24) )
{
name = CC_CASCADE_PARAMS;
}
CvCascadeParams::CvCascadeParams( int _stageType, int _featureType ) : stageType( _stageType ),
featureType( _featureType ), winSize( cvSize(24, 24) )
{
name = CC_CASCADE_PARAMS;
}
//---------------------------- CascadeParams --------------------------------------
void CvCascadeParams::write( FileStorage &fs ) const
{
string stageTypeStr = stageType == BOOST ? CC_BOOST : string();
CV_Assert( !stageTypeStr.empty() );
fs << CC_STAGE_TYPE << stageTypeStr;
string featureTypeStr = featureType == CvFeatureParams::HAAR ? CC_HAAR :
featureType == CvFeatureParams::LBP ? CC_LBP :
featureType == CvFeatureParams::HOG ? CC_HOG :
0;
CV_Assert( !stageTypeStr.empty() );
fs << CC_FEATURE_TYPE << featureTypeStr;
fs << CC_HEIGHT << winSize.height;
fs << CC_WIDTH << winSize.width;
}
bool CvCascadeParams::read( const FileNode &node )
{
if ( node.empty() )
return false;
string stageTypeStr, featureTypeStr;
FileNode rnode = node[CC_STAGE_TYPE];
if ( !rnode.isString() )
return false;
rnode >> stageTypeStr;
stageType = !stageTypeStr.compare( CC_BOOST ) ? BOOST : -1;
if (stageType == -1)
return false;
rnode = node[CC_FEATURE_TYPE];
if ( !rnode.isString() )
return false;
rnode >> featureTypeStr;
featureType = !featureTypeStr.compare( CC_HAAR ) ? CvFeatureParams::HAAR :
!featureTypeStr.compare( CC_LBP ) ? CvFeatureParams::LBP :
!featureTypeStr.compare( CC_HOG ) ? CvFeatureParams::HOG :
-1;
if (featureType == -1)
return false;
node[CC_HEIGHT] >> winSize.height;
node[CC_WIDTH] >> winSize.width;
return winSize.height > 0 && winSize.width > 0;
}
void CvCascadeParams::printDefaults() const
{
CvParams::printDefaults();
cout << " [-stageType <";
for( int i = 0; i < (int)(sizeof(stageTypes)/sizeof(stageTypes[0])); i++ )
{
cout << (i ? " | " : "") << stageTypes[i];
if ( i == defaultStageType )
cout << "(default)";
}
cout << ">]" << endl;
cout << " [-featureType <{";
for( int i = 0; i < (int)(sizeof(featureTypes)/sizeof(featureTypes[0])); i++ )
{
cout << (i ? ", " : "") << featureTypes[i];
if ( i == defaultStageType )
cout << "(default)";
}
cout << "}>]" << endl;
cout << " [-w <sampleWidth = " << winSize.width << ">]" << endl;
cout << " [-h <sampleHeight = " << winSize.height << ">]" << endl;
}
void CvCascadeParams::printAttrs() const
{
cout << "stageType: " << stageTypes[stageType] << endl;
cout << "featureType: " << featureTypes[featureType] << endl;
cout << "sampleWidth: " << winSize.width << endl;
cout << "sampleHeight: " << winSize.height << endl;
}
bool CvCascadeParams::scanAttr( const string prmName, const string val )
{
bool res = true;
if( !prmName.compare( "-stageType" ) )
{
for( int i = 0; i < (int)(sizeof(stageTypes)/sizeof(stageTypes[0])); i++ )
if( !val.compare( stageTypes[i] ) )
stageType = i;
}
else if( !prmName.compare( "-featureType" ) )
{
for( int i = 0; i < (int)(sizeof(featureTypes)/sizeof(featureTypes[0])); i++ )
if( !val.compare( featureTypes[i] ) )
featureType = i;
}
else if( !prmName.compare( "-w" ) )
{
winSize.width = atoi( val.c_str() );
}
else if( !prmName.compare( "-h" ) )
{
winSize.height = atoi( val.c_str() );
}
else
res = false;
return res;
}
//---------------------------- CascadeClassifier --------------------------------------
bool CvCascadeClassifier::train( const string _cascadeDirName,
const string _posFilename,
const string _negFilename,
int _numPos, int _numNeg,
int _precalcValBufSize, int _precalcIdxBufSize,
int _numStages,
const CvCascadeParams& _cascadeParams,
const CvFeatureParams& _featureParams,
const CvCascadeBoostParams& _stageParams,
bool baseFormatSave,
double acceptanceRatioBreakValue )
{
// Start recording clock ticks for training time output
double time = (double)getTickCount();
if( _cascadeDirName.empty() || _posFilename.empty() || _negFilename.empty() )
CV_Error( cv::Error::StsBadArg, "_cascadeDirName or _bgfileName or _vecFileName is NULL" );
string dirName;
if (_cascadeDirName.find_last_of("/\\") == (_cascadeDirName.length() - 1) )
dirName = _cascadeDirName;
else
dirName = _cascadeDirName + '/';
numPos = _numPos;
numNeg = _numNeg;
numStages = _numStages;
if ( !imgReader.create( _posFilename, _negFilename, _cascadeParams.winSize ) )
{
cout << "Image reader can not be created from -vec " << _posFilename
<< " and -bg " << _negFilename << "." << endl;
return false;
}
if ( !load( dirName ) )
{
cascadeParams = _cascadeParams;
featureParams = CvFeatureParams::create(cascadeParams.featureType);
featureParams->init(_featureParams);
stageParams = makePtr<CvCascadeBoostParams>();
*stageParams = _stageParams;
featureEvaluator = CvFeatureEvaluator::create(cascadeParams.featureType);
featureEvaluator->init( featureParams, numPos + numNeg, cascadeParams.winSize );
stageClassifiers.reserve( numStages );
}else{
// Make sure that if model parameters are preloaded, that people are aware of this,
// even when passing other parameters to the training command
cout << "---------------------------------------------------------------------------------" << endl;
cout << "Training parameters are pre-loaded from the parameter file in data folder!" << endl;
cout << "Please empty this folder if you want to use a NEW set of training parameters." << endl;
cout << "---------------------------------------------------------------------------------" << endl;
}
cout << "PARAMETERS:" << endl;
cout << "cascadeDirName: " << _cascadeDirName << endl;
cout << "vecFileName: " << _posFilename << endl;
cout << "bgFileName: " << _negFilename << endl;
cout << "numPos: " << _numPos << endl;
cout << "numNeg: " << _numNeg << endl;
cout << "numStages: " << numStages << endl;
cout << "precalcValBufSize[Mb] : " << _precalcValBufSize << endl;
cout << "precalcIdxBufSize[Mb] : " << _precalcIdxBufSize << endl;
cout << "acceptanceRatioBreakValue : " << acceptanceRatioBreakValue << endl;
cascadeParams.printAttrs();
stageParams->printAttrs();
featureParams->printAttrs();
cout << "Number of unique features given windowSize [" << _cascadeParams.winSize.width << "," << _cascadeParams.winSize.height << "] : " << featureEvaluator->getNumFeatures() << "" << endl;
int startNumStages = (int)stageClassifiers.size();
if ( startNumStages > 1 )
cout << endl << "Stages 0-" << startNumStages-1 << " are loaded" << endl;
else if ( startNumStages == 1)
cout << endl << "Stage 0 is loaded" << endl;
double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) /
(double)stageParams->max_depth;
double tempLeafFARate;
for( int i = startNumStages; i < numStages; i++ )
{
cout << endl << "===== TRAINING " << i << "-stage =====" << endl;
cout << "<BEGIN" << endl;
if ( !updateTrainingSet( requiredLeafFARate, tempLeafFARate ) )
{
cout << "Train dataset for temp stage can not be filled. "
"Branch training terminated." << endl;
break;
}
if( tempLeafFARate <= requiredLeafFARate )
{
cout << "Required leaf false alarm rate achieved. "
"Branch training terminated." << endl;
break;
}
if( (tempLeafFARate <= acceptanceRatioBreakValue) && (acceptanceRatioBreakValue >= 0) ){
cout << "The required acceptanceRatio for the model has been reached to avoid overfitting of trainingdata. "
"Branch training terminated." << endl;
break;
}
Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
bool isStageTrained = tempStage->train( featureEvaluator,
curNumSamples, _precalcValBufSize, _precalcIdxBufSize,
*stageParams );
cout << "END>" << endl;
if(!isStageTrained)
break;
stageClassifiers.push_back( tempStage );
// save params
if( i == 0)
{
std::string paramsFilename = dirName + CC_PARAMS_FILENAME;
FileStorage fs( paramsFilename, FileStorage::WRITE);
if ( !fs.isOpened() )
{
cout << "Parameters can not be written, because file " << paramsFilename
<< " can not be opened." << endl;
return false;
}
fs << FileStorage::getDefaultObjectName(paramsFilename) << "{";
writeParams( fs );
fs << "}";
}
// save current stage
char buf[32];
snprintf(buf, sizeof(buf), "%s%d", "stage", i );
string stageFilename = dirName + buf + ".xml";
FileStorage fs( stageFilename, FileStorage::WRITE );
if ( !fs.isOpened() )
{
cout << "Current stage can not be written, because file " << stageFilename
<< " can not be opened." << endl;
return false;
}
fs << FileStorage::getDefaultObjectName(stageFilename) << "{";
tempStage->write( fs, Mat() );
fs << "}";
// Output training time up till now
double seconds = ( (double)getTickCount() - time)/ getTickFrequency();
int days = int(seconds) / 60 / 60 / 24;
int hours = (int(seconds) / 60 / 60) % 24;
int minutes = (int(seconds) / 60) % 60;
int seconds_left = int(seconds) % 60;
cout << "Training until now has taken " << days << " days " << hours << " hours " << minutes << " minutes " << seconds_left <<" seconds." << endl;
}
if(stageClassifiers.size() == 0)
{
cout << "Cascade classifier can't be trained. Check the used training parameters." << endl;
return false;
}
save( dirName + CC_CASCADE_FILENAME, baseFormatSave );
return true;
}
int CvCascadeClassifier::predict( int sampleIdx )
{
CV_DbgAssert( sampleIdx < numPos + numNeg );
for (vector< Ptr<CvCascadeBoost> >::iterator it = stageClassifiers.begin();
it != stageClassifiers.end();++it )
{
if ( (*it)->predict( sampleIdx ) == 0.f )
return 0;
}
return 1;
}
bool CvCascadeClassifier::updateTrainingSet( double minimumAcceptanceRatio, double& acceptanceRatio)
{
int64 posConsumed = 0, negConsumed = 0;
imgReader.restart();
int posCount = fillPassedSamples( 0, numPos, true, 0, posConsumed );
if( !posCount )
return false;
cout << "POS count : consumed " << posCount << " : " << (int)posConsumed << endl;
int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible
int negCount = fillPassedSamples( posCount, proNumNeg, false, minimumAcceptanceRatio, negConsumed );
if ( !negCount )
if ( !(negConsumed > 0 && ((double)negCount+1)/(double)negConsumed <= minimumAcceptanceRatio) )
return false;
curNumSamples = posCount + negCount;
acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed );
cout << "NEG count : acceptanceRatio " << negCount << " : " << acceptanceRatio << endl;
return true;
}
int CvCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, double minimumAcceptanceRatio, int64& consumed )
{
int getcount = 0;
Mat img(cascadeParams.winSize, CV_8UC1);
for( int i = first; i < first + count; i++ )
{
for( ; ; )
{
if( consumed != 0 && ((double)getcount+1)/(double)(int64)consumed <= minimumAcceptanceRatio )
return getcount;
bool isGetImg = isPositive ? imgReader.getPos( img ) :
imgReader.getNeg( img );
if( !isGetImg )
return getcount;
consumed++;
featureEvaluator->setImage( img, isPositive ? 1 : 0, i );
if( predict( i ) == 1 )
{
getcount++;
printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount);
fflush(stdout);
break;
}
}
}
return getcount;
}
void CvCascadeClassifier::writeParams( FileStorage &fs ) const
{
cascadeParams.write( fs );
fs << CC_STAGE_PARAMS << "{"; stageParams->write( fs ); fs << "}";
fs << CC_FEATURE_PARAMS << "{"; featureParams->write( fs ); fs << "}";
}
void CvCascadeClassifier::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
featureEvaluator->writeFeatures( fs, featureMap );
}
void CvCascadeClassifier::writeStages( FileStorage &fs, const Mat& featureMap ) const
{
char cmnt[30];
int i = 0;
fs << CC_STAGES << "[";
for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
it != stageClassifiers.end();++it, ++i )
{
snprintf( cmnt, sizeof(cmnt), "stage %d", i );
fs.writeComment(cmnt);
fs << "{";
(*it)->write( fs, featureMap );
fs << "}";
}
fs << "]";
}
bool CvCascadeClassifier::readParams( const FileNode &node )
{
if ( !node.isMap() || !cascadeParams.read( node ) )
return false;
stageParams = makePtr<CvCascadeBoostParams>();
FileNode rnode = node[CC_STAGE_PARAMS];
if ( !stageParams->read( rnode ) )
return false;
featureParams = CvFeatureParams::create(cascadeParams.featureType);
rnode = node[CC_FEATURE_PARAMS];
if ( !featureParams->read( rnode ) )
return false;
return true;
}
bool CvCascadeClassifier::readStages( const FileNode &node)
{
FileNode rnode = node[CC_STAGES];
if (!rnode.empty() || !rnode.isSeq())
return false;
stageClassifiers.reserve(numStages);
FileNodeIterator it = rnode.begin();
for( int i = 0; i < min( (int)rnode.size(), numStages ); i++, it++ )
{
Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
if ( !tempStage->read( *it, featureEvaluator, *stageParams) )
return false;
stageClassifiers.push_back(tempStage);
}
return true;
}
// For old Haar Classifier file saving
#define ICV_HAAR_TYPE_ID "opencv-haar-classifier"
#define ICV_HAAR_SIZE_NAME "size"
#define ICV_HAAR_STAGES_NAME "stages"
#define ICV_HAAR_TREES_NAME "trees"
#define ICV_HAAR_FEATURE_NAME "feature"
#define ICV_HAAR_RECTS_NAME "rects"
#define ICV_HAAR_TILTED_NAME "tilted"
#define ICV_HAAR_THRESHOLD_NAME "threshold"
#define ICV_HAAR_LEFT_NODE_NAME "left_node"
#define ICV_HAAR_LEFT_VAL_NAME "left_val"
#define ICV_HAAR_RIGHT_NODE_NAME "right_node"
#define ICV_HAAR_RIGHT_VAL_NAME "right_val"
#define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
#define ICV_HAAR_PARENT_NAME "parent"
#define ICV_HAAR_NEXT_NAME "next"
void CvCascadeClassifier::save( const string filename, bool baseFormat )
{
FileStorage fs( filename, FileStorage::WRITE );
if ( !fs.isOpened() )
return;
fs << FileStorage::getDefaultObjectName(filename);
if ( !baseFormat )
{
Mat featureMap;
getUsedFeaturesIdxMap( featureMap );
fs << "{";
writeParams( fs );
fs << CC_STAGE_NUM << (int)stageClassifiers.size();
writeStages( fs, featureMap );
writeFeatures( fs, featureMap );
}
else
{
//char buf[256];
CvSeq* weak;
if ( cascadeParams.featureType != CvFeatureParams::HAAR )
CV_Error( cv::Error::StsBadFunc, "old file format is used for Haar-like features only");
fs << "{:" ICV_HAAR_TYPE_ID;
fs << ICV_HAAR_SIZE_NAME << "[:" << cascadeParams.winSize.width <<
cascadeParams.winSize.height << "]";
fs << ICV_HAAR_STAGES_NAME << "[";
for( size_t si = 0; si < stageClassifiers.size(); si++ )
{
fs << "{"; //stage
/*snprintf( buf, sizeof(buf), "stage %d", si );
CV_CALL( cvWriteComment( fs, buf, 1 ) );*/
weak = stageClassifiers[si]->get_weak_predictors();
fs << ICV_HAAR_TREES_NAME << "[";
for( int wi = 0; wi < weak->total; wi++ )
{
int total_inner_node_idx = -1;
queue<const CvDTreeNode*> inner_nodes_queue;
CvCascadeBoostTree* tree = *((CvCascadeBoostTree**) cvGetSeqElem( weak, wi ));
fs << "[";
/*snprintf( buf, sizeof(buf), "tree %d", wi );
CV_CALL( cvWriteComment( fs, buf, 1 ) );*/
const CvDTreeNode* tempNode;
inner_nodes_queue.push( tree->get_root() );
total_inner_node_idx++;
while (!inner_nodes_queue.empty())
{
tempNode = inner_nodes_queue.front();
fs << "{";
fs << ICV_HAAR_FEATURE_NAME << "{";
((CvHaarEvaluator*)featureEvaluator.get())->writeFeature( fs, tempNode->split->var_idx );
fs << "}";
fs << ICV_HAAR_THRESHOLD_NAME << tempNode->split->ord.c;
if( tempNode->left->left || tempNode->left->right )
{
inner_nodes_queue.push( tempNode->left );
total_inner_node_idx++;
fs << ICV_HAAR_LEFT_NODE_NAME << total_inner_node_idx;
}
else
fs << ICV_HAAR_LEFT_VAL_NAME << tempNode->left->value;
if( tempNode->right->left || tempNode->right->right )
{
inner_nodes_queue.push( tempNode->right );
total_inner_node_idx++;
fs << ICV_HAAR_RIGHT_NODE_NAME << total_inner_node_idx;
}
else
fs << ICV_HAAR_RIGHT_VAL_NAME << tempNode->right->value;
fs << "}"; // ICV_HAAR_FEATURE_NAME
inner_nodes_queue.pop();
}
fs << "]";
}
fs << "]"; //ICV_HAAR_TREES_NAME
fs << ICV_HAAR_STAGE_THRESHOLD_NAME << stageClassifiers[si]->getThreshold();
fs << ICV_HAAR_PARENT_NAME << (int)si-1 << ICV_HAAR_NEXT_NAME << -1;
fs << "}"; //stage
} /* for each stage */
fs << "]"; //ICV_HAAR_STAGES_NAME
}
fs << "}";
}
bool CvCascadeClassifier::load( const string cascadeDirName )
{
FileStorage fs( cascadeDirName + CC_PARAMS_FILENAME, FileStorage::READ );
if ( !fs.isOpened() )
return false;
FileNode node = fs.getFirstTopLevelNode();
if ( !readParams( node ) )
return false;
featureEvaluator = CvFeatureEvaluator::create(cascadeParams.featureType);
featureEvaluator->init( featureParams, numPos + numNeg, cascadeParams.winSize );
fs.release();
char buf[5+10+1] = {0};
for ( int si = 0; si < numStages; si++ )
{
snprintf( buf, sizeof(buf), "%s%d", "stage", si);
fs.open( cascadeDirName + buf + ".xml", FileStorage::READ );
node = fs.getFirstTopLevelNode();
if ( !fs.isOpened() )
break;
Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
if ( !tempStage->read( node, featureEvaluator, *stageParams ))
{
fs.release();
break;
}
stageClassifiers.push_back(tempStage);
}
return true;
}
void CvCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap )
{
int varCount = featureEvaluator->getNumFeatures() * featureEvaluator->getFeatureSize();
featureMap.create( 1, varCount, CV_32SC1 );
featureMap.setTo(Scalar(-1));
for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
it != stageClassifiers.end();++it )
(*it)->markUsedFeaturesInMap( featureMap );
for( int fi = 0, idx = 0; fi < varCount; fi++ )
if ( featureMap.at<int>(0, fi) >= 0 )
featureMap.ptr<int>(0)[fi] = idx++;
}

@ -1,125 +0,0 @@
#ifndef _OPENCV_CASCADECLASSIFIER_H_
#define _OPENCV_CASCADECLASSIFIER_H_
#include <ctime>
#include "traincascade_features.h"
#include "haarfeatures.h"
#include "lbpfeatures.h"
#include "HOGfeatures.h" //new
#include "boost.h"
#define CC_CASCADE_FILENAME "cascade.xml"
#define CC_PARAMS_FILENAME "params.xml"
#define CC_CASCADE_PARAMS "cascadeParams"
#define CC_STAGE_TYPE "stageType"
#define CC_FEATURE_TYPE "featureType"
#define CC_HEIGHT "height"
#define CC_WIDTH "width"
#define CC_STAGE_NUM "stageNum"
#define CC_STAGES "stages"
#define CC_STAGE_PARAMS "stageParams"
#define CC_BOOST "BOOST"
#define CC_BOOST_TYPE "boostType"
#define CC_DISCRETE_BOOST "DAB"
#define CC_REAL_BOOST "RAB"
#define CC_LOGIT_BOOST "LB"
#define CC_GENTLE_BOOST "GAB"
#define CC_MINHITRATE "minHitRate"
#define CC_MAXFALSEALARM "maxFalseAlarm"
#define CC_TRIM_RATE "weightTrimRate"
#define CC_MAX_DEPTH "maxDepth"
#define CC_WEAK_COUNT "maxWeakCount"
#define CC_STAGE_THRESHOLD "stageThreshold"
#define CC_WEAK_CLASSIFIERS "weakClassifiers"
#define CC_INTERNAL_NODES "internalNodes"
#define CC_LEAF_VALUES "leafValues"
#define CC_FEATURES FEATURES
#define CC_FEATURE_PARAMS "featureParams"
#define CC_MAX_CAT_COUNT "maxCatCount"
#define CC_FEATURE_SIZE "featSize"
#define CC_HAAR "HAAR"
#define CC_MODE "mode"
#define CC_MODE_BASIC "BASIC"
#define CC_MODE_CORE "CORE"
#define CC_MODE_ALL "ALL"
#define CC_RECTS "rects"
#define CC_TILTED "tilted"
#define CC_LBP "LBP"
#define CC_RECT "rect"
#define CC_HOG "HOG"
#ifdef _WIN32
#define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC)
#else
#define TIME( arg ) (time( arg ))
#endif
class CvCascadeParams : public CvParams
{
public:
enum { BOOST = 0 };
static const int defaultStageType = BOOST;
static const int defaultFeatureType = CvFeatureParams::HAAR;
CvCascadeParams();
CvCascadeParams( int _stageType, int _featureType );
void write( cv::FileStorage &fs ) const;
bool read( const cv::FileNode &node );
void printDefaults() const;
void printAttrs() const;
bool scanAttr( const std::string prmName, const std::string val );
int stageType;
int featureType;
cv::Size winSize;
};
class CvCascadeClassifier
{
public:
bool train( const std::string _cascadeDirName,
const std::string _posFilename,
const std::string _negFilename,
int _numPos, int _numNeg,
int _precalcValBufSize, int _precalcIdxBufSize,
int _numStages,
const CvCascadeParams& _cascadeParams,
const CvFeatureParams& _featureParams,
const CvCascadeBoostParams& _stageParams,
bool baseFormatSave = false,
double acceptanceRatioBreakValue = -1.0 );
private:
int predict( int sampleIdx );
void save( const std::string cascadeDirName, bool baseFormat = false );
bool load( const std::string cascadeDirName );
bool updateTrainingSet( double minimumAcceptanceRatio, double& acceptanceRatio );
int fillPassedSamples( int first, int count, bool isPositive, double requiredAcceptanceRatio, int64& consumed );
void writeParams( cv::FileStorage &fs ) const;
void writeStages( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
bool readParams( const cv::FileNode &node );
bool readStages( const cv::FileNode &node );
void getUsedFeaturesIdxMap( cv::Mat& featureMap );
CvCascadeParams cascadeParams;
cv::Ptr<CvFeatureParams> featureParams;
cv::Ptr<CvCascadeBoostParams> stageParams;
cv::Ptr<CvFeatureEvaluator> featureEvaluator;
std::vector< cv::Ptr<CvCascadeBoost> > stageClassifiers;
CvCascadeImageReader imgReader;
int numStages, curNumSamples;
int numPos, numNeg;
};
#endif

@ -1,93 +0,0 @@
#include "opencv2/core.hpp"
#include "traincascade_features.h"
#include "cascadeclassifier.h"
using namespace std;
using namespace cv;
float calcNormFactor( const Mat& sum, const Mat& sqSum )
{
CV_DbgAssert( sum.cols > 3 && sqSum.rows > 3 );
Rect normrect( 1, 1, sum.cols - 3, sum.rows - 3 );
size_t p0, p1, p2, p3;
CV_SUM_OFFSETS( p0, p1, p2, p3, normrect, sum.step1() )
double area = normrect.width * normrect.height;
const int *sp = sum.ptr<int>();
int valSum = sp[p0] - sp[p1] - sp[p2] + sp[p3];
const double *sqp = sqSum.ptr<double>();
double valSqSum = sqp[p0] - sqp[p1] - sqp[p2] + sqp[p3];
return (float) sqrt( (double) (area * valSqSum - (double)valSum * valSum) );
}
CvParams::CvParams() : name( "params" ) {}
void CvParams::printDefaults() const
{ cout << "--" << name << "--" << endl; }
void CvParams::printAttrs() const {}
bool CvParams::scanAttr( const string, const string ) { return false; }
//---------------------------- FeatureParams --------------------------------------
CvFeatureParams::CvFeatureParams() : maxCatCount( 0 ), featSize( 1 )
{
name = CC_FEATURE_PARAMS;
}
void CvFeatureParams::init( const CvFeatureParams& fp )
{
maxCatCount = fp.maxCatCount;
featSize = fp.featSize;
}
void CvFeatureParams::write( FileStorage &fs ) const
{
fs << CC_MAX_CAT_COUNT << maxCatCount;
fs << CC_FEATURE_SIZE << featSize;
}
bool CvFeatureParams::read( const FileNode &node )
{
if ( node.empty() )
return false;
maxCatCount = node[CC_MAX_CAT_COUNT];
featSize = node[CC_FEATURE_SIZE];
return ( maxCatCount >= 0 && featSize >= 1 );
}
Ptr<CvFeatureParams> CvFeatureParams::create( int featureType )
{
return featureType == HAAR ? Ptr<CvFeatureParams>(new CvHaarFeatureParams) :
featureType == LBP ? Ptr<CvFeatureParams>(new CvLBPFeatureParams) :
featureType == HOG ? Ptr<CvFeatureParams>(new CvHOGFeatureParams) :
Ptr<CvFeatureParams>();
}
//------------------------------------- FeatureEvaluator ---------------------------------------
void CvFeatureEvaluator::init(const CvFeatureParams *_featureParams,
int _maxSampleCount, Size _winSize )
{
CV_Assert(_maxSampleCount > 0);
featureParams = (CvFeatureParams *)_featureParams;
winSize = _winSize;
numFeatures = 0;
cls.create( (int)_maxSampleCount, 1, CV_32FC1 );
generateFeatures();
}
void CvFeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
{
CV_Assert(img.cols == winSize.width);
CV_Assert(img.rows == winSize.height);
CV_Assert(idx < cls.rows);
cls.ptr<float>(idx)[0] = clsLabel;
}
Ptr<CvFeatureEvaluator> CvFeatureEvaluator::create(int type)
{
return type == CvFeatureParams::HAAR ? Ptr<CvFeatureEvaluator>(new CvHaarEvaluator) :
type == CvFeatureParams::LBP ? Ptr<CvFeatureEvaluator>(new CvLBPEvaluator) :
type == CvFeatureParams::HOG ? Ptr<CvFeatureEvaluator>(new CvHOGEvaluator) :
Ptr<CvFeatureEvaluator>();
}

@ -1,312 +0,0 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "haarfeatures.h"
#include "cascadeclassifier.h"
using namespace std;
using namespace cv;
CvHaarFeatureParams::CvHaarFeatureParams() : mode(BASIC)
{
name = HFP_NAME;
}
CvHaarFeatureParams::CvHaarFeatureParams( int _mode ) : mode( _mode )
{
name = HFP_NAME;
}
void CvHaarFeatureParams::init( const CvFeatureParams& fp )
{
CvFeatureParams::init( fp );
mode = ((const CvHaarFeatureParams&)fp).mode;
}
void CvHaarFeatureParams::write( FileStorage &fs ) const
{
CvFeatureParams::write( fs );
string modeStr = mode == BASIC ? CC_MODE_BASIC :
mode == CORE ? CC_MODE_CORE :
mode == ALL ? CC_MODE_ALL : string();
CV_Assert( !modeStr.empty() );
fs << CC_MODE << modeStr;
}
bool CvHaarFeatureParams::read( const FileNode &node )
{
if( !CvFeatureParams::read( node ) )
return false;
FileNode rnode = node[CC_MODE];
if( !rnode.isString() )
return false;
string modeStr;
rnode >> modeStr;
mode = !modeStr.compare( CC_MODE_BASIC ) ? BASIC :
!modeStr.compare( CC_MODE_CORE ) ? CORE :
!modeStr.compare( CC_MODE_ALL ) ? ALL : -1;
return (mode >= 0);
}
void CvHaarFeatureParams::printDefaults() const
{
CvFeatureParams::printDefaults();
cout << " [-mode <" CC_MODE_BASIC << "(default) | "
<< CC_MODE_CORE <<" | " << CC_MODE_ALL << endl;
}
void CvHaarFeatureParams::printAttrs() const
{
CvFeatureParams::printAttrs();
string mode_str = mode == BASIC ? CC_MODE_BASIC :
mode == CORE ? CC_MODE_CORE :
mode == ALL ? CC_MODE_ALL : 0;
cout << "mode: " << mode_str << endl;
}
bool CvHaarFeatureParams::scanAttr( const string prmName, const string val)
{
if ( !CvFeatureParams::scanAttr( prmName, val ) )
{
if( !prmName.compare("-mode") )
{
mode = !val.compare( CC_MODE_CORE ) ? CORE :
!val.compare( CC_MODE_ALL ) ? ALL :
!val.compare( CC_MODE_BASIC ) ? BASIC : -1;
if (mode == -1)
return false;
}
return false;
}
return true;
}
//--------------------- HaarFeatureEvaluator ----------------
void CvHaarEvaluator::init(const CvFeatureParams *_featureParams,
int _maxSampleCount, Size _winSize )
{
CV_Assert(_maxSampleCount > 0);
int cols = (_winSize.width + 1) * (_winSize.height + 1);
sum.create((int)_maxSampleCount, cols, CV_32SC1);
tilted.create((int)_maxSampleCount, cols, CV_32SC1);
normfactor.create(1, (int)_maxSampleCount, CV_32FC1);
CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
}
void CvHaarEvaluator::setImage(const Mat& img, uchar clsLabel, int idx)
{
CV_DbgAssert( !sum.empty() && !tilted.empty() && !normfactor.empty() );
CvFeatureEvaluator::setImage( img, clsLabel, idx);
Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));
Mat innSqSum;
if (((const CvHaarFeatureParams*)featureParams)->mode == CvHaarFeatureParams::ALL)
{
Mat innTilted(winSize.height + 1, winSize.width + 1, tilted.type(), tilted.ptr<int>((int)idx));
integral(img, innSum, innSqSum, innTilted);
}
else
integral(img, innSum, innSqSum);
normfactor.ptr<float>(0)[idx] = calcNormFactor( innSum, innSqSum );
}
void CvHaarEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
_writeFeatures( features, fs, featureMap );
}
void CvHaarEvaluator::writeFeature(FileStorage &fs, int fi) const
{
CV_DbgAssert( fi < (int)features.size() );
features[fi].write(fs);
}
void CvHaarEvaluator::generateFeatures()
{
int mode = ((const CvHaarFeatureParams*)((CvFeatureParams*)featureParams))->mode;
int offset = winSize.width + 1;
for( int x = 0; x < winSize.width; x++ )
{
for( int y = 0; y < winSize.height; y++ )
{
for( int dx = 1; dx <= winSize.width; dx++ )
{
for( int dy = 1; dy <= winSize.height; dy++ )
{
// haar_x2
if ( (x+dx*2 <= winSize.width) && (y+dy <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx*2, dy, -1,
x+dx, y, dx , dy, +2 ) );
}
// haar_y2
if ( (x+dx <= winSize.width) && (y+dy*2 <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx, dy*2, -1,
x, y+dy, dx, dy, +2 ) );
}
// haar_x3
if ( (x+dx*3 <= winSize.width) && (y+dy <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx*3, dy, -1,
x+dx, y, dx , dy, +2 ) );
}
// haar_y3
if ( (x+dx <= winSize.width) && (y+dy*3 <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx, dy*3, -1,
x, y+dy, dx, dy, +2 ) );
}
if( mode != CvHaarFeatureParams::BASIC )
{
// haar_x4
if ( (x+dx*4 <= winSize.width) && (y+dy <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx*4, dy, -1,
x+dx, y, dx*2, dy, +2 ) );
}
// haar_y4
if ( (x+dx <= winSize.width ) && (y+dy*4 <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx, dy*4, -1,
x, y+dy, dx, dy*2, +2 ) );
}
}
// x2_y2
if ( (x+dx*2 <= winSize.width) && (y+dy*2 <= winSize.height) )
{
features.push_back( Feature( offset, false,
x, y, dx*2, dy*2, -1,
x, y, dx, dy, +2,
x+dx, y+dy, dx, dy, +2 ) );
}
if (mode != CvHaarFeatureParams::BASIC)
{
if ( (x+dx*3 <= winSize.width) && (y+dy*3 <= winSize.height) )
{
features.push_back( Feature( offset, false,
x , y , dx*3, dy*3, -1,
x+dx, y+dy, dx , dy , +9) );
}
}
if (mode == CvHaarFeatureParams::ALL)
{
// tilted haar_x2
if ( (x+2*dx <= winSize.width) && (y+2*dx+dy <= winSize.height) && (x-dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx*2, dy, -1,
x, y, dx, dy, +2 ) );
}
// tilted haar_y2
if ( (x+dx <= winSize.width) && (y+dx+2*dy <= winSize.height) && (x-2*dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx, 2*dy, -1,
x, y, dx, dy, +2 ) );
}
// tilted haar_x3
if ( (x+3*dx <= winSize.width) && (y+3*dx+dy <= winSize.height) && (x-dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx*3, dy, -1,
x+dx, y+dx, dx, dy, +3 ) );
}
// tilted haar_y3
if ( (x+dx <= winSize.width) && (y+dx+3*dy <= winSize.height) && (x-3*dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx, 3*dy, -1,
x-dy, y+dy, dx, dy, +3 ) );
}
// tilted haar_x4
if ( (x+4*dx <= winSize.width) && (y+4*dx+dy <= winSize.height) && (x-dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx*4, dy, -1,
x+dx, y+dx, dx*2, dy, +2 ) );
}
// tilted haar_y4
if ( (x+dx <= winSize.width) && (y+dx+4*dy <= winSize.height) && (x-4*dy>= 0) )
{
features.push_back( Feature( offset, true,
x, y, dx, 4*dy, -1,
x-dy, y+dy, dx, 2*dy, +2 ) );
}
}
}
}
}
}
numFeatures = (int)features.size();
}
CvHaarEvaluator::Feature::Feature()
{
tilted = false;
rect[0].r = rect[1].r = rect[2].r = Rect(0,0,0,0);
rect[0].weight = rect[1].weight = rect[2].weight = 0;
}
CvHaarEvaluator::Feature::Feature( int offset, bool _tilted,
int x0, int y0, int w0, int h0, float wt0,
int x1, int y1, int w1, int h1, float wt1,
int x2, int y2, int w2, int h2, float wt2 )
{
tilted = _tilted;
rect[0].r.x = x0;
rect[0].r.y = y0;
rect[0].r.width = w0;
rect[0].r.height = h0;
rect[0].weight = wt0;
rect[1].r.x = x1;
rect[1].r.y = y1;
rect[1].r.width = w1;
rect[1].r.height = h1;
rect[1].weight = wt1;
rect[2].r.x = x2;
rect[2].r.y = y2;
rect[2].r.width = w2;
rect[2].r.height = h2;
rect[2].weight = wt2;
if( !tilted )
{
for( int j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
{
if( rect[j].weight == 0.0F )
break;
CV_SUM_OFFSETS( fastRect[j].p0, fastRect[j].p1, fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )
}
}
else
{
for( int j = 0; j < CV_HAAR_FEATURE_MAX; j++ )
{
if( rect[j].weight == 0.0F )
break;
CV_TILTED_OFFSETS( fastRect[j].p0, fastRect[j].p1, fastRect[j].p2, fastRect[j].p3, rect[j].r, offset )
}
}
}
void CvHaarEvaluator::Feature::write( FileStorage &fs ) const
{
fs << CC_RECTS << "[";
for( int ri = 0; ri < CV_HAAR_FEATURE_MAX && rect[ri].r.width != 0; ++ri )
{
fs << "[:" << rect[ri].r.x << rect[ri].r.y <<
rect[ri].r.width << rect[ri].r.height << rect[ri].weight << "]";
}
fs << "]" << CC_TILTED << tilted;
}

@ -1,89 +0,0 @@
#ifndef _OPENCV_HAARFEATURES_H_
#define _OPENCV_HAARFEATURES_H_
#include "traincascade_features.h"
#define CV_HAAR_FEATURE_MAX 3
#define HFP_NAME "haarFeatureParams"
class CvHaarFeatureParams : public CvFeatureParams
{
public:
enum { BASIC = 0, CORE = 1, ALL = 2 };
/* 0 - BASIC = Viola
* 1 - CORE = All upright
* 2 - ALL = All features */
CvHaarFeatureParams();
CvHaarFeatureParams( int _mode );
virtual void init( const CvFeatureParams& fp );
virtual void write( cv::FileStorage &fs ) const;
virtual bool read( const cv::FileNode &node );
virtual void printDefaults() const;
virtual void printAttrs() const;
virtual bool scanAttr( const std::string prm, const std::string val);
int mode;
};
class CvHaarEvaluator : public CvFeatureEvaluator
{
public:
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx);
virtual float operator()(int featureIdx, int sampleIdx) const;
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
void writeFeature( cv::FileStorage &fs, int fi ) const; // for old file fornat
protected:
virtual void generateFeatures();
class Feature
{
public:
Feature();
Feature( int offset, bool _tilted,
int x0, int y0, int w0, int h0, float wt0,
int x1, int y1, int w1, int h1, float wt1,
int x2 = 0, int y2 = 0, int w2 = 0, int h2 = 0, float wt2 = 0.0F );
float calc( const cv::Mat &sum, const cv::Mat &tilted, size_t y) const;
void write( cv::FileStorage &fs ) const;
bool tilted;
struct
{
cv::Rect r;
float weight;
} rect[CV_HAAR_FEATURE_MAX];
struct
{
int p0, p1, p2, p3;
} fastRect[CV_HAAR_FEATURE_MAX];
};
std::vector<Feature> features;
cv::Mat sum; /* sum images (each row represents image) */
cv::Mat tilted; /* tilted sum images (each row represents image) */
cv::Mat normfactor; /* normalization factor */
};
inline float CvHaarEvaluator::operator()(int featureIdx, int sampleIdx) const
{
float nf = normfactor.at<float>(0, sampleIdx);
return !nf ? 0.0f : (features[featureIdx].calc( sum, tilted, sampleIdx)/nf);
}
inline float CvHaarEvaluator::Feature::calc( const cv::Mat &_sum, const cv::Mat &_tilted, size_t y) const
{
const int* img = tilted ? _tilted.ptr<int>((int)y) : _sum.ptr<int>((int)y);
float ret = rect[0].weight * (img[fastRect[0].p0] - img[fastRect[0].p1] - img[fastRect[0].p2] + img[fastRect[0].p3] ) +
rect[1].weight * (img[fastRect[1].p0] - img[fastRect[1].p1] - img[fastRect[1].p2] + img[fastRect[1].p3] );
if( rect[2].weight != 0.0f )
ret += rect[2].weight * (img[fastRect[2].p0] - img[fastRect[2].p1] - img[fastRect[2].p2] + img[fastRect[2].p3] );
return ret;
}
#endif

@ -1,186 +0,0 @@
#include "opencv2/core.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "imagestorage.h"
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
bool CvCascadeImageReader::create( const string _posFilename, const string _negFilename, Size _winSize )
{
return posReader.create(_posFilename) && negReader.create(_negFilename, _winSize);
}
CvCascadeImageReader::NegReader::NegReader()
{
src.create( 0, 0 , CV_8UC1 );
img.create( 0, 0, CV_8UC1 );
point = offset = Point( 0, 0 );
scale = 1.0F;
scaleFactor = 1.4142135623730950488016887242097F;
stepFactor = 0.5F;
}
bool CvCascadeImageReader::NegReader::create( const string _filename, Size _winSize )
{
string str;
std::ifstream file(_filename.c_str());
if ( !file.is_open() )
return false;
while( !file.eof() )
{
std::getline(file, str);
str.erase(str.find_last_not_of(" \n\r\t")+1);
if (str.empty()) break;
if (str.at(0) == '#' ) continue; /* comment */
imgFilenames.push_back(str);
}
file.close();
winSize = _winSize;
last = round = 0;
return true;
}
bool CvCascadeImageReader::NegReader::nextImg()
{
Point _offset = Point(0,0);
size_t count = imgFilenames.size();
for( size_t i = 0; i < count; i++ )
{
src = imread( imgFilenames[last++], IMREAD_GRAYSCALE );
if( src.empty() ){
last %= count;
continue;
}
round += last / count;
round = round % (winSize.width * winSize.height);
last %= count;
_offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width );
_offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height );
if( !src.empty() && src.type() == CV_8UC1
&& _offset.x >= 0 && _offset.y >= 0 )
break;
}
if( src.empty() )
return false; // no appropriate image
point = offset = _offset;
scale = max( ((float)winSize.width + point.x) / ((float)src.cols),
((float)winSize.height + point.y) / ((float)src.rows) );
Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) );
resize( src, img, sz, 0, 0, INTER_LINEAR_EXACT );
return true;
}
bool CvCascadeImageReader::NegReader::get( Mat& _img )
{
CV_Assert( !_img.empty() );
CV_Assert( _img.type() == CV_8UC1 );
CV_Assert( _img.cols == winSize.width );
CV_Assert( _img.rows == winSize.height );
if( img.empty() )
if ( !nextImg() )
return false;
Mat mat( winSize.height, winSize.width, CV_8UC1,
(void*)(img.ptr(point.y) + point.x * img.elemSize()), img.step );
mat.copyTo(_img);
if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols )
point.x += (int)(stepFactor * winSize.width);
else
{
point.x = offset.x;
if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows )
point.y += (int)(stepFactor * winSize.height);
else
{
point.y = offset.y;
scale *= scaleFactor;
if( scale <= 1.0F )
resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ), 0, 0, INTER_LINEAR_EXACT );
else
{
if ( !nextImg() )
return false;
}
}
}
return true;
}
CvCascadeImageReader::PosReader::PosReader()
{
file = 0;
vec = 0;
}
bool CvCascadeImageReader::PosReader::create( const string _filename )
{
if ( file )
fclose( file );
file = fopen( _filename.c_str(), "rb" );
if( !file )
return false;
short tmp = 0;
if( fread( &count, sizeof( count ), 1, file ) != 1 ||
fread( &vecSize, sizeof( vecSize ), 1, file ) != 1 ||
fread( &tmp, sizeof( tmp ), 1, file ) != 1 ||
fread( &tmp, sizeof( tmp ), 1, file ) != 1 )
CV_Error_( cv::Error::StsParseError, ("wrong file format for %s\n", _filename.c_str()) );
base = sizeof( count ) + sizeof( vecSize ) + 2*sizeof( tmp );
if( feof( file ) )
return false;
last = 0;
vec = (short*) cvAlloc( sizeof( *vec ) * vecSize );
CV_Assert( vec );
return true;
}
bool CvCascadeImageReader::PosReader::get( Mat &_img )
{
CV_Assert( _img.rows * _img.cols == vecSize );
uchar tmp = 0;
size_t elements_read = fread( &tmp, sizeof( tmp ), 1, file );
if( elements_read != 1 )
CV_Error( cv::Error::StsBadArg, "Can not get new positive sample. The most possible reason is "
"insufficient count of samples in given vec-file.\n");
elements_read = fread( vec, sizeof( vec[0] ), vecSize, file );
if( elements_read != (size_t)(vecSize) )
CV_Error( cv::Error::StsBadArg, "Can not get new positive sample. Seems that vec-file has incorrect structure.\n");
if( feof( file ) || last++ >= count )
CV_Error( cv::Error::StsBadArg, "Can not get new positive sample. vec-file is over.\n");
for( int r = 0; r < _img.rows; r++ )
{
for( int c = 0; c < _img.cols; c++ )
_img.ptr(r)[c] = (uchar)vec[r * _img.cols + c];
}
return true;
}
void CvCascadeImageReader::PosReader::restart()
{
CV_Assert( file );
last = 0;
fseek( file, base, SEEK_SET );
}
CvCascadeImageReader::PosReader::~PosReader()
{
if (file)
fclose( file );
cvFree( &vec );
}

@ -1,50 +0,0 @@
#ifndef _OPENCV_IMAGESTORAGE_H_
#define _OPENCV_IMAGESTORAGE_H_
class CvCascadeImageReader
{
public:
bool create( const std::string _posFilename, const std::string _negFilename, cv::Size _winSize );
void restart() { posReader.restart(); }
bool getNeg(cv::Mat &_img) { return negReader.get( _img ); }
bool getPos(cv::Mat &_img) { return posReader.get( _img ); }
private:
class PosReader
{
public:
PosReader();
virtual ~PosReader();
bool create( const std::string _filename );
bool get( cv::Mat &_img );
void restart();
short* vec;
FILE* file;
int count;
int vecSize;
int last;
int base;
} posReader;
class NegReader
{
public:
NegReader();
bool create( const std::string _filename, cv::Size _winSize );
bool get( cv::Mat& _img );
bool nextImg();
cv::Mat src, img;
std::vector<std::string> imgFilenames;
cv::Point offset, point;
float scale;
float scaleFactor;
float stepFactor;
size_t last, round;
cv::Size winSize;
} negReader;
};
#endif

@ -1,67 +0,0 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "lbpfeatures.h"
#include "cascadeclassifier.h"
using namespace cv;
CvLBPFeatureParams::CvLBPFeatureParams()
{
maxCatCount = 256;
name = LBPF_NAME;
}
void CvLBPEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)
{
CV_Assert( _maxSampleCount > 0);
sum.create((int)_maxSampleCount, (_winSize.width + 1) * (_winSize.height + 1), CV_32SC1);
CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
}
void CvLBPEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
{
CV_DbgAssert( !sum.empty() );
CvFeatureEvaluator::setImage( img, clsLabel, idx );
Mat innSum(winSize.height + 1, winSize.width + 1, sum.type(), sum.ptr<int>((int)idx));
integral( img, innSum );
}
void CvLBPEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
{
_writeFeatures( features, fs, featureMap );
}
void CvLBPEvaluator::generateFeatures()
{
int offset = winSize.width + 1;
for( int x = 0; x < winSize.width; x++ )
for( int y = 0; y < winSize.height; y++ )
for( int w = 1; w <= winSize.width / 3; w++ )
for( int h = 1; h <= winSize.height / 3; h++ )
if ( (x+3*w <= winSize.width) && (y+3*h <= winSize.height) )
features.push_back( Feature(offset, x, y, w, h ) );
numFeatures = (int)features.size();
}
CvLBPEvaluator::Feature::Feature()
{
rect = cvRect(0, 0, 0, 0);
}
CvLBPEvaluator::Feature::Feature( int offset, int x, int y, int _blockWidth, int _blockHeight )
{
Rect tr = rect = cvRect(x, y, _blockWidth, _blockHeight);
CV_SUM_OFFSETS( p[0], p[1], p[4], p[5], tr, offset )
tr.x += 2*rect.width;
CV_SUM_OFFSETS( p[2], p[3], p[6], p[7], tr, offset )
tr.y +=2*rect.height;
CV_SUM_OFFSETS( p[10], p[11], p[14], p[15], tr, offset )
tr.x -= 2*rect.width;
CV_SUM_OFFSETS( p[8], p[9], p[12], p[13], tr, offset )
}
void CvLBPEvaluator::Feature::write(FileStorage &fs) const
{
fs << CC_RECT << "[:" << rect.x << rect.y << rect.width << rect.height << "]";
}

@ -1,57 +0,0 @@
#ifndef _OPENCV_LBPFEATURES_H_
#define _OPENCV_LBPFEATURES_H_
#include "traincascade_features.h"
#define LBPF_NAME "lbpFeatureParams"
struct CvLBPFeatureParams : CvFeatureParams
{
CvLBPFeatureParams();
};
class CvLBPEvaluator : public CvFeatureEvaluator
{
public:
virtual ~CvLBPEvaluator() {}
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx);
virtual float operator()(int featureIdx, int sampleIdx) const
{ return (float)features[featureIdx].calc( sum, sampleIdx); }
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
protected:
virtual void generateFeatures();
class Feature
{
public:
Feature();
Feature( int offset, int x, int y, int _block_w, int _block_h );
uchar calc( const cv::Mat& _sum, size_t y ) const;
void write( cv::FileStorage &fs ) const;
cv::Rect rect;
int p[16];
};
std::vector<Feature> features;
cv::Mat sum;
};
inline uchar CvLBPEvaluator::Feature::calc(const cv::Mat &_sum, size_t y) const
{
const int* psum = _sum.ptr<int>((int)y);
int cval = psum[p[5]] - psum[p[6]] - psum[p[9]] + psum[p[10]];
return (uchar)((psum[p[0]] - psum[p[1]] - psum[p[4]] + psum[p[5]] >= cval ? 128 : 0) | // 0
(psum[p[1]] - psum[p[2]] - psum[p[5]] + psum[p[6]] >= cval ? 64 : 0) | // 1
(psum[p[2]] - psum[p[3]] - psum[p[6]] + psum[p[7]] >= cval ? 32 : 0) | // 2
(psum[p[6]] - psum[p[7]] - psum[p[10]] + psum[p[11]] >= cval ? 16 : 0) | // 5
(psum[p[10]] - psum[p[11]] - psum[p[14]] + psum[p[15]] >= cval ? 8 : 0) | // 8
(psum[p[9]] - psum[p[10]] - psum[p[13]] + psum[p[14]] >= cval ? 4 : 0) | // 7
(psum[p[8]] - psum[p[9]] - psum[p[12]] + psum[p[13]] >= cval ? 2 : 0) | // 6
(psum[p[4]] - psum[p[5]] - psum[p[8]] + psum[p[9]] >= cval ? 1 : 0)); // 3
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,792 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "old_ml_precomp.hpp"
#include <ctype.h>
#define MISS_VAL FLT_MAX
#define CV_VAR_MISS 0
CvTrainTestSplit::CvTrainTestSplit()
{
train_sample_part_mode = CV_COUNT;
train_sample_part.count = -1;
mix = false;
}
CvTrainTestSplit::CvTrainTestSplit( int _train_sample_count, bool _mix )
{
train_sample_part_mode = CV_COUNT;
train_sample_part.count = _train_sample_count;
mix = _mix;
}
CvTrainTestSplit::CvTrainTestSplit( float _train_sample_portion, bool _mix )
{
train_sample_part_mode = CV_PORTION;
train_sample_part.portion = _train_sample_portion;
mix = _mix;
}
////////////////
CvMLData::CvMLData()
{
values = missing = var_types = var_idx_mask = response_out = var_idx_out = var_types_out = 0;
train_sample_idx = test_sample_idx = 0;
header_lines_number = 0;
sample_idx = 0;
response_idx = -1;
train_sample_count = -1;
delimiter = ',';
miss_ch = '?';
//flt_separator = '.';
rng = &cv::theRNG();
}
CvMLData::~CvMLData()
{
clear();
}
void CvMLData::free_train_test_idx()
{
cvReleaseMat( &train_sample_idx );
cvReleaseMat( &test_sample_idx );
sample_idx = 0;
}
void CvMLData::clear()
{
class_map.clear();
cvReleaseMat( &values );
cvReleaseMat( &missing );
cvReleaseMat( &var_types );
cvReleaseMat( &var_idx_mask );
cvReleaseMat( &response_out );
cvReleaseMat( &var_idx_out );
cvReleaseMat( &var_types_out );
free_train_test_idx();
total_class_count = 0;
response_idx = -1;
train_sample_count = -1;
}
void CvMLData::set_header_lines_number( int idx )
{
header_lines_number = std::max(0, idx);
}
int CvMLData::get_header_lines_number() const
{
return header_lines_number;
}
static char *fgets_chomp(char *str, int n, FILE *stream)
{
char *head = fgets(str, n, stream);
if( head )
{
for(char *tail = head + strlen(head) - 1; tail >= head; --tail)
{
if( *tail != '\r' && *tail != '\n' )
break;
*tail = '\0';
}
}
return head;
}
int CvMLData::read_csv(const char* filename)
{
const int M = 1000000;
const char str_delimiter[3] = { ' ', delimiter, '\0' };
FILE* file = 0;
CvMemStorage* storage;
CvSeq* seq;
char *ptr;
float* el_ptr;
CvSeqReader reader;
int cols_count = 0;
uchar *var_types_ptr = 0;
clear();
file = fopen( filename, "rt" );
if( !file )
return -1;
std::vector<char> _buf(M);
char* buf = &_buf[0];
// skip header lines
for( int i = 0; i < header_lines_number; i++ )
{
if( fgets( buf, M, file ) == 0 )
{
fclose(file);
return -1;
}
}
// read the first data line and determine the number of variables
if( !fgets_chomp( buf, M, file ))
{
fclose(file);
return -1;
}
ptr = buf;
while( *ptr == ' ' )
ptr++;
for( ; *ptr != '\0'; )
{
if(*ptr == delimiter || *ptr == ' ')
{
cols_count++;
ptr++;
while( *ptr == ' ' ) ptr++;
}
else
ptr++;
}
cols_count++;
if ( cols_count == 0)
{
fclose(file);
return -1;
}
// create temporary memory storage to store the whole database
el_ptr = new float[cols_count];
storage = cvCreateMemStorage();
seq = cvCreateSeq( 0, sizeof(*seq), cols_count*sizeof(float), storage );
var_types = cvCreateMat( 1, cols_count, CV_8U );
cvZero( var_types );
var_types_ptr = var_types->data.ptr;
for(;;)
{
char *token = NULL;
int type;
token = strtok(buf, str_delimiter);
if (!token)
break;
for (int i = 0; i < cols_count-1; i++)
{
str_to_flt_elem( token, el_ptr[i], type);
var_types_ptr[i] |= type;
token = strtok(NULL, str_delimiter);
if (!token)
{
fclose(file);
delete [] el_ptr;
return -1;
}
}
str_to_flt_elem( token, el_ptr[cols_count-1], type);
var_types_ptr[cols_count-1] |= type;
cvSeqPush( seq, el_ptr );
if( !fgets_chomp( buf, M, file ) )
break;
}
fclose(file);
values = cvCreateMat( seq->total, cols_count, CV_32FC1 );
missing = cvCreateMat( seq->total, cols_count, CV_8U );
var_idx_mask = cvCreateMat( 1, values->cols, CV_8UC1 );
cvSet( var_idx_mask, cvRealScalar(1) );
train_sample_count = seq->total;
cvStartReadSeq( seq, &reader );
for(int i = 0; i < seq->total; i++ )
{
const float* sdata = (float*)reader.ptr;
float* ddata = values->data.fl + cols_count*i;
uchar* dm = missing->data.ptr + cols_count*i;
for( int j = 0; j < cols_count; j++ )
{
ddata[j] = sdata[j];
dm[j] = ( fabs( MISS_VAL - sdata[j] ) <= FLT_EPSILON );
}
CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
}
if ( cvNorm( missing, 0, CV_L1 ) <= FLT_EPSILON )
cvReleaseMat( &missing );
cvReleaseMemStorage( &storage );
delete []el_ptr;
return 0;
}
const CvMat* CvMLData::get_values() const
{
return values;
}
const CvMat* CvMLData::get_missing() const
{
CV_FUNCNAME( "CvMLData::get_missing" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
__END__;
return missing;
}
const std::map<cv::String, int>& CvMLData::get_class_labels_map() const
{
return class_map;
}
void CvMLData::str_to_flt_elem( const char* token, float& flt_elem, int& type)
{
char* stopstring = NULL;
flt_elem = (float)strtod( token, &stopstring );
assert( stopstring );
type = CV_VAR_ORDERED;
if ( *stopstring == miss_ch && strlen(stopstring) == 1 ) // missed value
{
flt_elem = MISS_VAL;
type = CV_VAR_MISS;
}
else
{
if ( (*stopstring != 0) && (*stopstring != '\n') && (strcmp(stopstring, "\r\n") != 0) ) // class label
{
int idx = class_map[token];
if ( idx == 0)
{
total_class_count++;
idx = total_class_count;
class_map[token] = idx;
}
flt_elem = (float)idx;
type = CV_VAR_CATEGORICAL;
}
}
}
void CvMLData::set_delimiter(char ch)
{
CV_FUNCNAME( "CvMLData::set_delimited" );
__BEGIN__;
if (ch == miss_ch /*|| ch == flt_separator*/)
CV_ERROR(cv::Error::StsBadArg, "delimited, miss_character and flt_separator must be different");
delimiter = ch;
__END__;
}
char CvMLData::get_delimiter() const
{
return delimiter;
}
void CvMLData::set_miss_ch(char ch)
{
CV_FUNCNAME( "CvMLData::set_miss_ch" );
__BEGIN__;
if (ch == delimiter/* || ch == flt_separator*/)
CV_ERROR(cv::Error::StsBadArg, "delimited, miss_character and flt_separator must be different");
miss_ch = ch;
__END__;
}
char CvMLData::get_miss_ch() const
{
return miss_ch;
}
void CvMLData::set_response_idx( int idx )
{
CV_FUNCNAME( "CvMLData::set_response_idx" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
if ( idx >= values->cols)
CV_ERROR( cv::Error::StsBadArg, "idx value is not correct" );
if ( response_idx >= 0 )
chahge_var_idx( response_idx, true );
if ( idx >= 0 )
chahge_var_idx( idx, false );
response_idx = idx;
__END__;
}
int CvMLData::get_response_idx() const
{
CV_FUNCNAME( "CvMLData::get_response_idx" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
__END__;
return response_idx;
}
void CvMLData::change_var_type( int var_idx, int type )
{
CV_FUNCNAME( "CvMLData::change_var_type" );
__BEGIN__;
int var_count = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
var_count = values->cols;
if ( var_idx < 0 || var_idx >= var_count)
CV_ERROR( cv::Error::StsBadArg, "var_idx is not correct" );
if ( type != CV_VAR_ORDERED && type != CV_VAR_CATEGORICAL)
CV_ERROR( cv::Error::StsBadArg, "type is not correct" );
assert( var_types );
if ( var_types->data.ptr[var_idx] == CV_VAR_CATEGORICAL && type == CV_VAR_ORDERED)
CV_ERROR( cv::Error::StsBadArg, "it`s impossible to assign CV_VAR_ORDERED type to categorical variable" );
var_types->data.ptr[var_idx] = (uchar)type;
__END__;
return;
}
void CvMLData::set_var_types( const char* str )
{
CV_FUNCNAME( "CvMLData::set_var_types" );
__BEGIN__;
const char* ord = 0, *cat = 0;
int var_count = 0, set_var_type_count = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
var_count = values->cols;
assert( var_types );
ord = strstr( str, "ord" );
cat = strstr( str, "cat" );
if ( !ord && !cat )
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
if ( !ord && strlen(cat) == 3 ) // str == "cat"
{
cvSet( var_types, cvScalarAll(CV_VAR_CATEGORICAL) );
return;
}
if ( !cat && strlen(ord) == 3 ) // str == "ord"
{
cvSet( var_types, cvScalarAll(CV_VAR_ORDERED) );
return;
}
if ( ord ) // parse ord str
{
char* stopstring = NULL;
if ( ord[3] != '[')
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
ord += 4; // pass "ord["
do
{
int b1 = (int)strtod( ord, &stopstring );
if ( *stopstring == 0 || (*stopstring != ',' && *stopstring != ']' && *stopstring != '-') )
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
ord = stopstring + 1;
if ( (stopstring[0] == ',') || (stopstring[0] == ']'))
{
if ( var_types->data.ptr[b1] == CV_VAR_CATEGORICAL)
CV_ERROR( cv::Error::StsBadArg, "it`s impossible to assign CV_VAR_ORDERED type to categorical variable" );
var_types->data.ptr[b1] = CV_VAR_ORDERED;
set_var_type_count++;
}
else
{
if ( stopstring[0] == '-')
{
int b2 = (int)strtod( ord, &stopstring);
if ( (*stopstring == 0) || (*stopstring != ',' && *stopstring != ']') )
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
ord = stopstring + 1;
for (int i = b1; i <= b2; i++)
{
if ( var_types->data.ptr[i] == CV_VAR_CATEGORICAL)
CV_ERROR( cv::Error::StsBadArg, "it`s impossible to assign CV_VAR_ORDERED type to categorical variable" );
var_types->data.ptr[i] = CV_VAR_ORDERED;
}
set_var_type_count += b2 - b1 + 1;
}
else
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
}
}
while (*stopstring != ']');
if ( stopstring[1] != '\0' && stopstring[1] != ',')
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
}
if ( cat ) // parse cat str
{
char* stopstring = NULL;
if ( cat[3] != '[')
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
cat += 4; // pass "cat["
do
{
int b1 = (int)strtod( cat, &stopstring );
if ( *stopstring == 0 || (*stopstring != ',' && *stopstring != ']' && *stopstring != '-') )
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
cat = stopstring + 1;
if ( (stopstring[0] == ',') || (stopstring[0] == ']'))
{
var_types->data.ptr[b1] = CV_VAR_CATEGORICAL;
set_var_type_count++;
}
else
{
if ( stopstring[0] == '-')
{
int b2 = (int)strtod( cat, &stopstring);
if ( (*stopstring == 0) || (*stopstring != ',' && *stopstring != ']') )
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
cat = stopstring + 1;
for (int i = b1; i <= b2; i++)
var_types->data.ptr[i] = CV_VAR_CATEGORICAL;
set_var_type_count += b2 - b1 + 1;
}
else
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
}
}
while (*stopstring != ']');
if ( stopstring[1] != '\0' && stopstring[1] != ',')
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
}
if (set_var_type_count != var_count)
CV_ERROR( cv::Error::StsBadArg, "types string is not correct" );
__END__;
}
const CvMat* CvMLData::get_var_types()
{
CV_FUNCNAME( "CvMLData::get_var_types" );
__BEGIN__;
uchar *var_types_out_ptr = 0;
int avcount, vt_size;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
assert( var_idx_mask );
avcount = cvFloor( cvNorm( var_idx_mask, 0, CV_L1 ) );
vt_size = avcount + (response_idx >= 0);
if ( avcount == values->cols || (avcount == values->cols-1 && response_idx == values->cols-1) )
return var_types;
if ( !var_types_out || ( var_types_out && var_types_out->cols != vt_size ) )
{
cvReleaseMat( &var_types_out );
var_types_out = cvCreateMat( 1, vt_size, CV_8UC1 );
}
var_types_out_ptr = var_types_out->data.ptr;
for( int i = 0; i < var_types->cols; i++)
{
if (i == response_idx || !var_idx_mask->data.ptr[i]) continue;
*var_types_out_ptr = var_types->data.ptr[i];
var_types_out_ptr++;
}
if ( response_idx >= 0 )
*var_types_out_ptr = var_types->data.ptr[response_idx];
__END__;
return var_types_out;
}
int CvMLData::get_var_type( int var_idx ) const
{
return var_types->data.ptr[var_idx];
}
const CvMat* CvMLData::get_responses()
{
CV_FUNCNAME( "CvMLData::get_responses_ptr" );
__BEGIN__;
int var_count = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
var_count = values->cols;
if ( response_idx < 0 || response_idx >= var_count )
return 0;
if ( !response_out )
response_out = cvCreateMatHeader( values->rows, 1, CV_32FC1 );
else
cvInitMatHeader( response_out, values->rows, 1, CV_32FC1);
cvGetCol( values, response_out, response_idx );
__END__;
return response_out;
}
void CvMLData::set_train_test_split( const CvTrainTestSplit * spl)
{
CV_FUNCNAME( "CvMLData::set_division" );
__BEGIN__;
int sample_count = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
sample_count = values->rows;
float train_sample_portion;
if (spl->train_sample_part_mode == CV_COUNT)
{
train_sample_count = spl->train_sample_part.count;
if (train_sample_count > sample_count)
CV_ERROR( cv::Error::StsBadArg, "train samples count is not correct" );
train_sample_count = train_sample_count<=0 ? sample_count : train_sample_count;
}
else // dtype.train_sample_part_mode == CV_PORTION
{
train_sample_portion = spl->train_sample_part.portion;
if ( train_sample_portion > 1)
CV_ERROR( cv::Error::StsBadArg, "train samples count is not correct" );
train_sample_portion = train_sample_portion <= FLT_EPSILON ||
1 - train_sample_portion <= FLT_EPSILON ? 1 : train_sample_portion;
train_sample_count = std::max(1, cvFloor( train_sample_portion * sample_count ));
}
if ( train_sample_count == sample_count )
{
free_train_test_idx();
return;
}
if ( train_sample_idx && train_sample_idx->cols != train_sample_count )
free_train_test_idx();
if ( !sample_idx)
{
int test_sample_count = sample_count- train_sample_count;
sample_idx = (int*)cvAlloc( sample_count * sizeof(sample_idx[0]) );
for (int i = 0; i < sample_count; i++ )
sample_idx[i] = i;
train_sample_idx = cvCreateMatHeader( 1, train_sample_count, CV_32SC1 );
*train_sample_idx = cvMat( 1, train_sample_count, CV_32SC1, &sample_idx[0] );
CV_Assert(test_sample_count > 0);
test_sample_idx = cvCreateMatHeader( 1, test_sample_count, CV_32SC1 );
*test_sample_idx = cvMat( 1, test_sample_count, CV_32SC1, &sample_idx[train_sample_count] );
}
mix = spl->mix;
if ( mix )
mix_train_and_test_idx();
__END__;
}
const CvMat* CvMLData::get_train_sample_idx() const
{
CV_FUNCNAME( "CvMLData::get_train_sample_idx" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
__END__;
return train_sample_idx;
}
const CvMat* CvMLData::get_test_sample_idx() const
{
CV_FUNCNAME( "CvMLData::get_test_sample_idx" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
__END__;
return test_sample_idx;
}
void CvMLData::mix_train_and_test_idx()
{
CV_FUNCNAME( "CvMLData::mix_train_and_test_idx" );
__BEGIN__;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
__END__;
if ( !sample_idx)
return;
if ( train_sample_count > 0 && train_sample_count < values->rows )
{
int n = values->rows;
for (int i = 0; i < n; i++)
{
int a = (*rng)(n);
int b = (*rng)(n);
int t;
CV_SWAP( sample_idx[a], sample_idx[b], t );
}
}
}
const CvMat* CvMLData::get_var_idx()
{
CV_FUNCNAME( "CvMLData::get_var_idx" );
__BEGIN__;
int avcount = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
assert( var_idx_mask );
avcount = cvFloor( cvNorm( var_idx_mask, 0, CV_L1 ) );
int* vidx;
if ( avcount == values->cols )
return 0;
if ( !var_idx_out || ( var_idx_out && var_idx_out->cols != avcount ) )
{
cvReleaseMat( &var_idx_out );
var_idx_out = cvCreateMat( 1, avcount, CV_32SC1);
if ( response_idx >=0 )
var_idx_mask->data.ptr[response_idx] = 0;
}
vidx = var_idx_out->data.i;
for(int i = 0; i < var_idx_mask->cols; i++)
if ( var_idx_mask->data.ptr[i] )
{
*vidx = i;
vidx++;
}
__END__;
return var_idx_out;
}
void CvMLData::chahge_var_idx( int vi, bool state )
{
change_var_idx( vi, state );
}
void CvMLData::change_var_idx( int vi, bool state )
{
CV_FUNCNAME( "CvMLData::change_var_idx" );
__BEGIN__;
int var_count = 0;
if ( !values )
CV_ERROR( cv::Error::StsInternal, "data is empty" );
var_count = values->cols;
if ( vi < 0 || vi >= var_count)
CV_ERROR( cv::Error::StsBadArg, "variable index is not correct" );
assert( var_idx_mask );
var_idx_mask->data.ptr[vi] = state;
__END__;
}
/* End of file. */

@ -1,376 +0,0 @@
/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef OPENCV_PRECOMP_H
#define OPENCV_PRECOMP_H
#include "opencv2/core.hpp"
#include "old_ml.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/private.hpp"
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define ML_IMPL CV_IMPL
#define __BEGIN__ __CV_BEGIN__
#define __END__ __CV_END__
#define EXIT __CV_EXIT__
#define CV_MAT_ELEM_FLAG( mat, type, comp, vect, tflag ) \
(( tflag == CV_ROW_SAMPLE ) \
? (CV_MAT_ELEM( mat, type, comp, vect )) \
: (CV_MAT_ELEM( mat, type, vect, comp )))
/* Convert matrix to vector */
#define ICV_MAT2VEC( mat, vdata, vstep, num ) \
if( MIN( (mat).rows, (mat).cols ) != 1 ) \
CV_ERROR( cv::Error::StsBadArg, "" ); \
(vdata) = ((mat).data.ptr); \
if( (mat).rows == 1 ) \
{ \
(vstep) = CV_ELEM_SIZE( (mat).type ); \
(num) = (mat).cols; \
} \
else \
{ \
(vstep) = (mat).step; \
(num) = (mat).rows; \
}
/* get raw data */
#define ICV_RAWDATA( mat, flags, rdata, sstep, cstep, m, n ) \
(rdata) = (mat).data.ptr; \
if( CV_IS_ROW_SAMPLE( flags ) ) \
{ \
(sstep) = (mat).step; \
(cstep) = CV_ELEM_SIZE( (mat).type ); \
(m) = (mat).rows; \
(n) = (mat).cols; \
} \
else \
{ \
(cstep) = (mat).step; \
(sstep) = CV_ELEM_SIZE( (mat).type ); \
(n) = (mat).rows; \
(m) = (mat).cols; \
}
#define ICV_IS_MAT_OF_TYPE( mat, mat_type) \
(CV_IS_MAT( mat ) && CV_MAT_TYPE( mat->type ) == (mat_type) && \
(mat)->cols > 0 && (mat)->rows > 0)
/*
uchar* data; int sstep, cstep; - trainData->data
uchar* classes; int clstep; int ncl;- trainClasses
uchar* tmask; int tmstep; int ntm; - typeMask
uchar* missed;int msstep, mcstep; -missedMeasurements...
int mm, mn; == m,n == size,dim
uchar* sidx;int sistep; - sampleIdx
uchar* cidx;int cistep; - compIdx
int k, l; == n,m == dim,size (length of cidx, sidx)
int m, n; == size,dim
*/
#define ICV_DECLARE_TRAIN_ARGS() \
uchar* data; \
int sstep, cstep; \
uchar* classes; \
int clstep; \
int ncl; \
uchar* tmask; \
int tmstep; \
int ntm; \
uchar* missed; \
int msstep, mcstep; \
int mm, mn; \
uchar* sidx; \
int sistep; \
uchar* cidx; \
int cistep; \
int k, l; \
int m, n; \
\
data = classes = tmask = missed = sidx = cidx = NULL; \
sstep = cstep = clstep = ncl = tmstep = ntm = msstep = mcstep = mm = mn = 0; \
sistep = cistep = k = l = m = n = 0;
#define ICV_TRAIN_DATA_REQUIRED( param, flags ) \
if( !ICV_IS_MAT_OF_TYPE( (param), CV_32FC1 ) ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
else \
{ \
ICV_RAWDATA( *(param), (flags), data, sstep, cstep, m, n ); \
k = n; \
l = m; \
}
#define ICV_TRAIN_CLASSES_REQUIRED( param ) \
if( !ICV_IS_MAT_OF_TYPE( (param), CV_32FC1 ) ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
else \
{ \
ICV_MAT2VEC( *(param), classes, clstep, ncl ); \
if( m != ncl ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Unmatched sizes" ); \
} \
}
#define ICV_ARG_NULL( param ) \
if( (param) != NULL ) \
{ \
CV_ERROR( cv::Error::StsBadArg, #param " parameter must be NULL" ); \
}
#define ICV_MISSED_MEASUREMENTS_OPTIONAL( param, flags ) \
if( param ) \
{ \
if( !ICV_IS_MAT_OF_TYPE( param, CV_8UC1 ) ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
else \
{ \
ICV_RAWDATA( *(param), (flags), missed, msstep, mcstep, mm, mn ); \
if( mm != m || mn != n ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Unmatched sizes" ); \
} \
} \
}
#define ICV_COMP_IDX_OPTIONAL( param ) \
if( param ) \
{ \
if( !ICV_IS_MAT_OF_TYPE( param, CV_32SC1 ) ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
else \
{ \
ICV_MAT2VEC( *(param), cidx, cistep, k ); \
if( k > n ) \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
}
#define ICV_SAMPLE_IDX_OPTIONAL( param ) \
if( param ) \
{ \
if( !ICV_IS_MAT_OF_TYPE( param, CV_32SC1 ) ) \
{ \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
else \
{ \
ICV_MAT2VEC( *sampleIdx, sidx, sistep, l ); \
if( l > m ) \
CV_ERROR( cv::Error::StsBadArg, "Invalid " #param " parameter" ); \
} \
}
/****************************************************************************************/
#define ICV_CONVERT_FLOAT_ARRAY_TO_MATRICE( array, matrice ) \
{ \
CvMat a, b; \
int dims = (matrice)->cols; \
int nsamples = (matrice)->rows; \
int type = CV_MAT_TYPE((matrice)->type); \
int i, offset = dims; \
\
CV_ASSERT( type == CV_32FC1 || type == CV_64FC1 ); \
offset *= ((type == CV_32FC1) ? sizeof(float) : sizeof(double));\
\
b = cvMat( 1, dims, CV_32FC1 ); \
cvGetRow( matrice, &a, 0 ); \
for( i = 0; i < nsamples; i++, a.data.ptr += offset ) \
{ \
b.data.fl = (float*)array[i]; \
CV_CALL( cvConvert( &b, &a ) ); \
} \
}
/****************************************************************************************\
* Auxiliary functions declarations *
\****************************************************************************************/
/* Generates a set of classes centers in quantity <num_of_clusters> that are generated as
uniform random vectors in parallelepiped, where <data> is concentrated. Vectors in
<data> should have horizontal orientation. If <centers> != NULL, the function doesn't
allocate any memory and stores generated centers in <centers>, returns <centers>.
If <centers> == NULL, the function allocates memory and creates the matrice. Centers
are supposed to be oriented horizontally. */
CvMat* icvGenerateRandomClusterCenters( int seed,
const CvMat* data,
int num_of_clusters,
CvMat* centers CV_DEFAULT(0));
/* Fills the <labels> using <probs> by choosing the maximal probability. Outliers are
fixed by <oulier_tresh> and have cluster label (-1). Function also controls that there
weren't "empty" clusters by filling empty clusters with the maximal probability vector.
If probs_sums != NULL, fills it with the sums of probabilities for each sample (it is
useful for normalizing probabilities' matrice of FCM) */
void icvFindClusterLabels( const CvMat* probs, float outlier_thresh, float r,
const CvMat* labels );
typedef struct CvSparseVecElem32f
{
int idx;
float val;
}
CvSparseVecElem32f;
/* Prepare training data and related parameters */
#define CV_TRAIN_STATMODEL_DEFRAGMENT_TRAIN_DATA 1
#define CV_TRAIN_STATMODEL_SAMPLES_AS_ROWS 2
#define CV_TRAIN_STATMODEL_SAMPLES_AS_COLUMNS 4
#define CV_TRAIN_STATMODEL_CATEGORICAL_RESPONSE 8
#define CV_TRAIN_STATMODEL_ORDERED_RESPONSE 16
#define CV_TRAIN_STATMODEL_RESPONSES_ON_OUTPUT 32
#define CV_TRAIN_STATMODEL_ALWAYS_COPY_TRAIN_DATA 64
#define CV_TRAIN_STATMODEL_SPARSE_AS_SPARSE 128
int
cvPrepareTrainData( const char* /*funcname*/,
const CvMat* train_data, int tflag,
const CvMat* responses, int response_type,
const CvMat* var_idx,
const CvMat* sample_idx,
bool always_copy_data,
const float*** out_train_samples,
int* _sample_count,
int* _var_count,
int* _var_all,
CvMat** out_responses,
CvMat** out_response_map,
CvMat** out_var_idx,
CvMat** out_sample_idx=0 );
void
cvSortSamplesByClasses( const float** samples, const CvMat* classes,
int* class_ranges, const uchar** mask CV_DEFAULT(0) );
void
cvCombineResponseMaps (CvMat* _responses,
const CvMat* old_response_map,
CvMat* new_response_map,
CvMat** out_response_map);
void
cvPreparePredictData( const CvArr* sample, int dims_all, const CvMat* comp_idx,
int class_count, const CvMat* prob, float** row_sample,
int as_sparse CV_DEFAULT(0) );
/* copies clustering [or batch "predict"] results
(labels and/or centers and/or probs) back to the output arrays */
void
cvWritebackLabels( const CvMat* labels, CvMat* dst_labels,
const CvMat* centers, CvMat* dst_centers,
const CvMat* probs, CvMat* dst_probs,
const CvMat* sample_idx, int samples_all,
const CvMat* comp_idx, int dims_all );
#define cvWritebackResponses cvWritebackLabels
#define XML_FIELD_NAME "_name"
cv::FileNode icvFileNodeGetChild( cv::FileNode& father, const char* name );
cv::FileNode icvFileNodeGetChildArrayElem( cv::FileNode& father, const char* name,int index );
cv::FileNode icvFileNodeGetNext( cv::FileNode& n, const char* name );
void cvCheckTrainData( const CvMat* train_data, int tflag,
const CvMat* missing_mask,
int* var_all, int* sample_all );
CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, bool check_for_duplicates=false );
CvMat* cvPreprocessVarType( const CvMat* type_mask, const CvMat* var_idx,
int var_all, int* response_type );
CvMat* cvPreprocessOrderedResponses( const CvMat* responses,
const CvMat* sample_idx, int sample_all );
CvMat* cvPreprocessCategoricalResponses( const CvMat* responses,
const CvMat* sample_idx, int sample_all,
CvMat** out_response_map, CvMat** class_counts=0 );
const float** cvGetTrainSamples( const CvMat* train_data, int tflag,
const CvMat* var_idx, const CvMat* sample_idx,
int* _var_count, int* _sample_count,
bool always_copy_data=false );
namespace cv
{
struct DTreeBestSplitFinder
{
DTreeBestSplitFinder(){ splitSize = 0, tree = 0; node = 0; }
DTreeBestSplitFinder( CvDTree* _tree, CvDTreeNode* _node);
DTreeBestSplitFinder( const DTreeBestSplitFinder& finder, Split );
virtual ~DTreeBestSplitFinder() {}
virtual void operator()(const BlockedRange& range);
void join( DTreeBestSplitFinder& rhs );
Ptr<CvDTreeSplit> bestSplit;
Ptr<CvDTreeSplit> split;
int splitSize;
CvDTree* tree;
CvDTreeNode* node;
};
struct ForestTreeBestSplitFinder : DTreeBestSplitFinder
{
ForestTreeBestSplitFinder() : DTreeBestSplitFinder() {}
ForestTreeBestSplitFinder( CvForestTree* _tree, CvDTreeNode* _node );
ForestTreeBestSplitFinder( const ForestTreeBestSplitFinder& finder, Split );
virtual void operator()(const BlockedRange& range);
};
}
#endif /* __ML_H__ */

File diff suppressed because it is too large Load Diff

@ -1,129 +0,0 @@
#include "opencv2/core.hpp"
#include "cascadeclassifier.h"
using namespace std;
using namespace cv;
/*
traincascade.cpp is the source file of the program used for cascade training.
User has to provide training input in form of positive and negative training images,
and other data related to training in form of command line argument.
*/
int main( int argc, char* argv[] )
{
CvCascadeClassifier classifier;
string cascadeDirName, vecName, bgName;
int numPos = 2000;
int numNeg = 1000;
int numStages = 20;
int numThreads = getNumThreads();
int precalcValBufSize = 1024,
precalcIdxBufSize = 1024;
bool baseFormatSave = false;
double acceptanceRatioBreakValue = -1.0;
CvCascadeParams cascadeParams;
CvCascadeBoostParams stageParams;
Ptr<CvFeatureParams> featureParams[] = { makePtr<CvHaarFeatureParams>(),
makePtr<CvLBPFeatureParams>(),
makePtr<CvHOGFeatureParams>()
};
int fc = sizeof(featureParams)/sizeof(featureParams[0]);
if( argc == 1 )
{
cout << "Usage: " << argv[0] << endl;
cout << " -data <cascade_dir_name>" << endl;
cout << " -vec <vec_file_name>" << endl;
cout << " -bg <background_file_name>" << endl;
cout << " [-numPos <number_of_positive_samples = " << numPos << ">]" << endl;
cout << " [-numNeg <number_of_negative_samples = " << numNeg << ">]" << endl;
cout << " [-numStages <number_of_stages = " << numStages << ">]" << endl;
cout << " [-precalcValBufSize <precalculated_vals_buffer_size_in_Mb = " << precalcValBufSize << ">]" << endl;
cout << " [-precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb = " << precalcIdxBufSize << ">]" << endl;
cout << " [-baseFormatSave]" << endl;
cout << " [-numThreads <max_number_of_threads = " << numThreads << ">]" << endl;
cout << " [-acceptanceRatioBreakValue <value> = " << acceptanceRatioBreakValue << ">]" << endl;
cascadeParams.printDefaults();
stageParams.printDefaults();
for( int fi = 0; fi < fc; fi++ )
featureParams[fi]->printDefaults();
return 0;
}
for( int i = 1; i < argc; i++ )
{
bool set = false;
if( !strcmp( argv[i], "-data" ) )
{
cascadeDirName = argv[++i];
}
else if( !strcmp( argv[i], "-vec" ) )
{
vecName = argv[++i];
}
else if( !strcmp( argv[i], "-bg" ) )
{
bgName = argv[++i];
}
else if( !strcmp( argv[i], "-numPos" ) )
{
numPos = atoi( argv[++i] );
}
else if( !strcmp( argv[i], "-numNeg" ) )
{
numNeg = atoi( argv[++i] );
}
else if( !strcmp( argv[i], "-numStages" ) )
{
numStages = atoi( argv[++i] );
}
else if( !strcmp( argv[i], "-precalcValBufSize" ) )
{
precalcValBufSize = atoi( argv[++i] );
}
else if( !strcmp( argv[i], "-precalcIdxBufSize" ) )
{
precalcIdxBufSize = atoi( argv[++i] );
}
else if( !strcmp( argv[i], "-baseFormatSave" ) )
{
baseFormatSave = true;
}
else if( !strcmp( argv[i], "-numThreads" ) )
{
numThreads = atoi(argv[++i]);
}
else if( !strcmp( argv[i], "-acceptanceRatioBreakValue" ) )
{
acceptanceRatioBreakValue = atof(argv[++i]);
}
else if ( cascadeParams.scanAttr( argv[i], argv[i+1] ) ) { i++; }
else if ( stageParams.scanAttr( argv[i], argv[i+1] ) ) { i++; }
else if ( !set )
{
for( int fi = 0; fi < fc; fi++ )
{
set = featureParams[fi]->scanAttr(argv[i], argv[i+1]);
if ( !set )
{
i++;
break;
}
}
}
}
setNumThreads( numThreads );
classifier.train( cascadeDirName,
vecName,
bgName,
numPos, numNeg,
precalcValBufSize, precalcIdxBufSize,
numStages,
cascadeParams,
*featureParams[cascadeParams.featureType],
stageParams,
baseFormatSave,
acceptanceRatioBreakValue );
return 0;
}

@ -1,101 +0,0 @@
#ifndef _OPENCV_FEATURES_H_
#define _OPENCV_FEATURES_H_
#include "imagestorage.h"
#include <stdio.h>
#define FEATURES "features"
#define CV_SUM_OFFSETS( p0, p1, p2, p3, rect, step ) \
/* (x, y) */ \
(p0) = (rect).x + (step) * (rect).y; \
/* (x + w, y) */ \
(p1) = (rect).x + (rect).width + (step) * (rect).y; \
/* (x + w, y) */ \
(p2) = (rect).x + (step) * ((rect).y + (rect).height); \
/* (x + w, y + h) */ \
(p3) = (rect).x + (rect).width + (step) * ((rect).y + (rect).height);
#define CV_TILTED_OFFSETS( p0, p1, p2, p3, rect, step ) \
/* (x, y) */ \
(p0) = (rect).x + (step) * (rect).y; \
/* (x - h, y + h) */ \
(p1) = (rect).x - (rect).height + (step) * ((rect).y + (rect).height);\
/* (x + w, y + w) */ \
(p2) = (rect).x + (rect).width + (step) * ((rect).y + (rect).width); \
/* (x + w - h, y + w + h) */ \
(p3) = (rect).x + (rect).width - (rect).height \
+ (step) * ((rect).y + (rect).width + (rect).height);
float calcNormFactor( const cv::Mat& sum, const cv::Mat& sqSum );
template<class Feature>
void _writeFeatures( const std::vector<Feature> features, cv::FileStorage &fs, const cv::Mat& featureMap )
{
fs << FEATURES << "[";
const cv::Mat_<int>& featureMap_ = (const cv::Mat_<int>&)featureMap;
for ( int fi = 0; fi < featureMap.cols; fi++ )
if ( featureMap_(0, fi) >= 0 )
{
fs << "{";
features[fi].write( fs );
fs << "}";
}
fs << "]";
}
class CvParams
{
public:
CvParams();
virtual ~CvParams() {}
// from|to file
virtual void write( cv::FileStorage &fs ) const = 0;
virtual bool read( const cv::FileNode &node ) = 0;
// from|to screen
virtual void printDefaults() const;
virtual void printAttrs() const;
virtual bool scanAttr( const std::string prmName, const std::string val );
std::string name;
};
class CvFeatureParams : public CvParams
{
public:
enum { HAAR = 0, LBP = 1, HOG = 2 };
CvFeatureParams();
virtual void init( const CvFeatureParams& fp );
virtual void write( cv::FileStorage &fs ) const;
virtual bool read( const cv::FileNode &node );
static cv::Ptr<CvFeatureParams> create( int featureType );
int maxCatCount; // 0 in case of numerical features
int featSize; // 1 in case of simple features (HAAR, LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features
};
class CvFeatureEvaluator
{
public:
virtual ~CvFeatureEvaluator() {}
virtual void init(const CvFeatureParams *_featureParams,
int _maxSampleCount, cv::Size _winSize );
virtual void setImage(const cv::Mat& img, uchar clsLabel, int idx);
virtual void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const = 0;
virtual float operator()(int featureIdx, int sampleIdx) const = 0;
static cv::Ptr<CvFeatureEvaluator> create(int type);
int getNumFeatures() const { return numFeatures; }
int getMaxCatCount() const { return featureParams->maxCatCount; }
int getFeatureSize() const { return featureParams->featSize; }
const cv::Mat& getCls() const { return cls; }
float getCls(int si) const { return cls.at<float>(si, 0); }
protected:
virtual void generateFeatures() = 0;
int npos, nneg;
int numFeatures;
cv::Size winSize;
CvFeatureParams *featureParams;
cv::Mat cls;
};
#endif

@ -1,19 +0,0 @@
import csv
def add_quotes_to_first_column(input_file, output_file):
with open(input_file, mode='r', newline='', encoding='utf-8') as infile, \
open(output_file, mode='w', newline='', encoding='utf-8') as outfile:
reader = csv.reader(infile)
writer = csv.writer(outfile)
for row in reader:
# 在第一列的每个内容两边加上引号
row[0] = f'"{row[0]}"'
writer.writerow(row)
# 使用示例
input_csv = 'E:\机器\论文分类.csv' # 输入的CSV文件名
output_csv = 'F:\桌面\论文分类1.csv' # 输出的CSV文件名
add_quotes_to_first_column(input_csv, output_csv)

@ -1,60 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'CAM.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(690, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 111, 41))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(280, 130, 111, 41))
self.pushButton_2.setObjectName("pushButton_2")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(280, 250, 111, 41))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.currentIndexChanged.connect(self.on_camera_selected) # 添加信号
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setGeometry(QtCore.QRect(280, 310, 111, 41))
self.pushButton_3.setObjectName("pushButton_3")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 690, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def on_camera_selected(self, index):
# 这个函数会在下拉列表的选项改变时被调用
self.camera_index = index # 保存选择的索引值
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "打开摄像头"))
self.pushButton_2.setText(_translate("MainWindow", "设置"))
self.comboBox.setItemText(0, _translate("MainWindow", "本地相机"))
self.comboBox.setItemText(1, _translate("MainWindow", "外置相机"))
self.comboBox.setItemText(2, _translate("MainWindow", "其他"))
self.pushButton_3.setText(_translate("MainWindow", "退出登录"))

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>690</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>280</x>
<y>190</y>
<width>111</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>打开摄像头</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>280</x>
<y>130</y>
<width>111</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>设置</string>
</property>
</widget>
<widget class="QComboBox" name="comboBox">
<property name="geometry">
<rect>
<x>280</x>
<y>250</y>
<width>111</width>
<height>41</height>
</rect>
</property>
<item>
<property name="text">
<string>本地相机</string>
</property>
</item>
<item>
<property name="text">
<string>外置相机</string>
</property>
</item>
<item>
<property name="text">
<string>其他</string>
</property>
</item>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>280</x>
<y>310</y>
<width>111</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>退出登录</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>690</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -1,21 +0,0 @@
import cv2
import matplotlib.pyplot as plt
# 读取图像
image_path = r"F:\photos\p2.jpg"
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 使用 Canny 算子进行边缘检测
canny = cv2.Canny(image, 100, 200)
# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.subplot(1, 2, 2)
plt.title('Canny Edge Detection')
plt.imshow(canny, cmap='gray')
plt.show()

@ -1,24 +0,0 @@
import cv2
import numpy as np
# 读取图像
img = cv2.imread( r"F:\photos\p2.jpg") # 替换为你的图像文件名
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 将图像转换为浮点型
gray = np.float32(gray)
# Harris 角点检测
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
# 结果进行膨胀,便于显示
dst = cv2.dilate(dst, None)
# 设定阈值
threshold = 0.01 * dst.max()
img[dst > threshold] = [0, 0, 255] # 将角点标记为红色
# 显示结果
cv2.imshow('Harris Corners', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

@ -1,25 +0,0 @@
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
image_path = r"F:\photos\p2.jpg"
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 使用 Laplacian 算子进行边缘检测
laplacian = cv2.Laplacian(image, cv2.CV_64F)
# 将结果转换为 8 位无符号整数
laplacian = np.uint8(np.absolute(laplacian))
# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.subplot(1, 2, 2)
plt.title('Laplacian Edge Detection')
plt.imshow(laplacian, cmap='gray')
plt.show()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

@ -1,5 +0,0 @@
<RCC>
<qresource prefix="aaa">
<file>MainWindow.jpg</file>
</qresource>
</RCC>

@ -1,13 +0,0 @@
import csv
# 打开 TSV 文件进行读取
with open('F:\passage\savedrecs (1).txt', mode='r', encoding='utf-8') as tsv_file:
tsv_reader = csv.reader(tsv_file, delimiter='\t')
# 打开 CSV 文件进行写入
with open('D:\out\output.csv', mode='w', encoding='utf-8', newline='') as csv_file:
csv_writer = csv.writer(csv_file, delimiter=',')
# 逐行读取 TSV 数据并写入 CSV 文件
for row in tsv_reader:
csv_writer.writerow(row)

@ -1,35 +0,0 @@
import pandas as pd
import numpy as np
# 读取CSV文件
df = pd.read_csv("F:\机器学习\output2.csv")
# 获取数据(去掉最后一列作为标签)
data = df.iloc[:, :-1]
# 获取标签(最后一列)
labels = df.iloc[:, -1]
# 定义裁剪函数
def reshape_and_crop(row):
# 将行数据转换为32x30的矩阵
image_32x30 = np.array(row).reshape(32, 30)
# 裁剪为28x26的矩阵
cropped_image = image_32x30[14:18, 13:16]
# 将裁剪后的矩阵展平为一维数组
cropped_image_flat = cropped_image.flatten()
return cropped_image_flat
# 对每一行应用裁剪函数
df_cropped = data.apply(reshape_and_crop, axis=1)
# 将降维后的数据与标签合并
df_result = pd.DataFrame(df_cropped.tolist())
df_result['Label'] = labels.values # 添加标签作为新一列
# 保存降维后的数据到新的CSV文件
df_result.to_csv("E:\机器\out4.csv", index=False)

@ -1,92 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# 摄像头实时人脸特征描述子计算 / Real-time face descriptor computing
import dlib # 人脸识别的库 Dlib
import cv2 # 图像处理的库 OpenCV
import time
# 1. Dlib 正向人脸检测器
detector = dlib.get_frontal_face_detector()
# 2. Dlib 人脸 landmark 特征点检测器
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# 3. Dlib Resnet 人脸识别模型,提取 128D 的特征矢量
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
class Face_Descriptor:
def __init__(self):
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.frame_cnt = 0
def update_fps(self):
now = time.time()
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
def run(self):
cap = cv2.VideoCapture(0)
cap.set(3, 480)
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def process(self, stream):
while stream.isOpened():
flag, img_rd = stream.read()
self.frame_cnt+=1
k = cv2.waitKey(1)
print('- Frame ', self.frame_cnt, " starts:")
timestamp1 = time.time()
faces = detector(img_rd, 0)
timestamp2 = time.time()
print("--- Time used to `detector`: %s seconds ---" % (timestamp2 - timestamp1))
font = cv2.FONT_HERSHEY_SIMPLEX
# 检测到人脸
if len(faces) != 0:
for face in faces:
timestamp3 = time.time()
face_shape = predictor(img_rd, face)
timestamp4 = time.time()
print("--- Time used to `predictor`: %s seconds ---" % (timestamp4 - timestamp3))
timestamp5 = time.time()
face_desc = face_reco_model.compute_face_descriptor(img_rd, face_shape)
timestamp6 = time.time()
print("--- Time used to `compute_face_descriptor` %s seconds ---" % (timestamp6 - timestamp5))
# 添加说明
cv2.putText(img_rd, "Face descriptor", (20, 40), font, 1, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps.__round__(2)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 140), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "S: Save current face", (20, 400), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
# 按下 'q' 键退出
if k == ord('q'):
break
self.update_fps()
cv2.namedWindow("camera", 1)
cv2.imshow("camera", img_rd)
print('\n')
def main():
Face_Descriptor_con = Face_Descriptor()
Face_Descriptor_con.run()
if __name__ == '__main__':
main()

@ -1,225 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 摄像头实时人脸识别 / Real-time face detection and recognition
import dlib
import numpy as np
import cv2
import pandas as pd
import os
import time
import logging
from PIL import Image, ImageDraw, ImageFont
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# Dlib Resnet 人脸识别模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
class Face_Recognizer:
def __init__(self):
self.face_feature_known_list = [] # 用来存放所有录入人脸特征的数组 / Save the features of faces in database
self.face_name_known_list = [] # 存储录入人脸名字 / Save the name of faces in database
self.current_frame_face_cnt = 0 # 存储当前摄像头中捕获到的人脸数 / Counter for faces in current frame
self.current_frame_face_feature_list = [] # 存储当前摄像头中捕获到的人脸特征 / Features of faces in current frame
self.current_frame_face_name_list = [] # 存储当前摄像头中捕获到的所有人脸的名字 / Names of faces in current frame
self.current_frame_face_name_position_list = [] # 存储当前摄像头中捕获到的所有人脸的名字坐标 / Positions of faces in current frame
# Update FPS
self.fps = 0 # FPS of current frame
self.fps_show = 0 # FPS per second
self.frame_start_time = 0
self.frame_cnt = 0
self.start_time = time.time()
self.font = cv2.FONT_ITALIC
self.font_chinese = ImageFont.truetype("simsun.ttc", 30)
# 从 "features_all.csv" 读取录入人脸特征 / Read known faces from "features_all.csv"
def get_face_database(self):
if os.path.exists("data/features_all.csv"):
path_features_known_csv = "data/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
for i in range(csv_rd.shape[0]):
features_someone_arr = []
self.face_name_known_list.append(csv_rd.iloc[i][0])
for j in range(1, 129):
if csv_rd.iloc[i][j] == '':
features_someone_arr.append('0')
else:
features_someone_arr.append(csv_rd.iloc[i][j])
self.face_feature_known_list.append(features_someone_arr)
logging.info("Faces in Database%d", len(self.face_feature_known_list))
return 1
else:
logging.warning("'features_all.csv' not found!")
logging.warning("Please run 'get_faces_from_camera.py' "
"and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'")
return 0
# 计算两个128D向量间的欧式距离 / Compute the e-distance between two 128D features
@staticmethod
def return_euclidean_distance(feature_1, feature_2):
feature_1 = np.array(feature_1)
feature_2 = np.array(feature_2)
dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
return dist
# 更新 FPS / Update FPS of Video stream
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
# 生成的 cv2 window 上面添加说明文字 / PutText on cv2 window
def draw_note(self, img_rd):
cv2.putText(img_rd, "Face Recognizer", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 130), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 160), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
def draw_name(self, img_rd):
# 在人脸框下面写人脸名字 / Write names under rectangle
img = Image.fromarray(cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
for i in range(self.current_frame_face_cnt):
# cv2.putText(img_rd, self.current_frame_face_name_list[i], self.current_frame_face_name_position_list[i], self.font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
draw.text(xy=self.current_frame_face_name_position_list[i], text=self.current_frame_face_name_list[i], font=self.font_chinese,
fill=(255, 255, 0))
img_rd = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
return img_rd
# 修改显示人名 / Show names in chinese
def show_chinese_name(self):
# Default known name: person_1, person_2, person_3
if self.current_frame_face_cnt >= 1:
# 修改录入的人脸姓名 / Modify names in face_name_known_list to chinese name
self.face_name_known_list[0] = '张三'.encode('utf-8').decode()
# self.face_name_known_list[1] = '张四'.encode('utf-8').decode()
# 处理获取的视频流,进行人脸识别 / Face detection and recognition from input video stream
def process(self, stream):
# 1. 读取存放所有人脸特征的 csv / Read known faces from "features.all.csv"
if self.get_face_database():
while stream.isOpened():
self.frame_cnt += 1
logging.debug("Frame %d starts", self.frame_cnt)
flag, img_rd = stream.read()
faces = detector(img_rd, 0)
kk = cv2.waitKey(1)
# 按下 q 键退出 / Press 'q' to quit
if kk == ord('q'):
break
else:
self.draw_note(img_rd)
self.current_frame_face_feature_list = []
self.current_frame_face_cnt = 0
self.current_frame_face_name_position_list = []
self.current_frame_face_name_list = []
# 2. 检测到人脸 / Face detected in current frame
if len(faces) != 0:
# 3. 获取当前捕获到的图像的所有人脸的特征 / Compute the face descriptors for faces in current frame
for i in range(len(faces)):
shape = predictor(img_rd, faces[i])
self.current_frame_face_feature_list.append(face_reco_model.compute_face_descriptor(img_rd, shape))
# 4. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
logging.debug("For face %d in camera:", k+1)
# 先默认所有人不认识,是 unknown / Set the default names of faces with "unknown"
self.current_frame_face_name_list.append("unknown")
# 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_frame_face_name_position_list.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
# 5. 对于某张人脸,遍历所有存储的人脸特征
# For every faces detected, compare the faces in the database
current_frame_e_distance_list = []
for i in range(len(self.face_feature_known_list)):
# 如果 person_X 数据不为空
if str(self.face_feature_known_list[i][0]) != '0.0':
e_distance_tmp = self.return_euclidean_distance(self.current_frame_face_feature_list[k],
self.face_feature_known_list[i])
logging.debug(" With person %s, the e-distance is %f", str(i + 1), e_distance_tmp)
current_frame_e_distance_list.append(e_distance_tmp)
else:
# 空数据 person_X
current_frame_e_distance_list.append(999999999)
# 6. 寻找出最小的欧式距离匹配 / Find the one with minimum e-distance
similar_person_num = current_frame_e_distance_list.index(min(current_frame_e_distance_list))
logging.debug("Minimum e-distance with %s: %f", self.face_name_known_list[similar_person_num], min(current_frame_e_distance_list))
if min(current_frame_e_distance_list) < 0.4:
self.current_frame_face_name_list[k] = self.face_name_known_list[similar_person_num]
logging.debug("Face recognition result: %s", self.face_name_known_list[similar_person_num])
else:
logging.debug("Face recognition result: Unknown person")
logging.debug("\n")
# 矩形框 / Draw rectangle
for kk, d in enumerate(faces):
# 绘制矩形框
cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]),
(255, 255, 255), 2)
self.current_frame_face_cnt = len(faces)
# 7. 在这里更改显示的人名 / Modify name if needed
# self.show_chinese_name()
# 8. 写名字 / Draw name
img_with_name = self.draw_name(img_rd)
else:
img_with_name = img_rd
logging.debug("Faces in camera now: %s", self.current_frame_face_name_list)
cv2.imshow("camera", img_with_name)
# 9. 更新 FPS / Update stream FPS
self.update_fps()
logging.debug("Frame ends\n\n")
# OpenCV 调用摄像头并进行 process
def run(self):
# cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
cap = cv2.VideoCapture(0) # Get video stream from camera
cap.set(3, 480) # 640x480
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def main():
# logging.basicConfig(level=logging.DEBUG) # Set log level to 'logging.DEBUG' to print debug info of every frame
logging.basicConfig(level=logging.INFO)
Face_Recognizer_con = Face_Recognizer()
Face_Recognizer_con.run()
if __name__ == '__main__':
main()

@ -1,306 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 利用 OT 人脸追踪, 进行人脸实时识别 / Real-time face detection and recognition via OT for multi faces
# 检测 -> 识别人脸, 新人脸出现 -> 不需要识别, 而是利用质心追踪来判断识别结果 / Do detection -> recognize face, new face -> not do re-recognition
# 人脸进行再识别需要花费大量时间, 这里用 OT 做跟踪 / Do re-recognition for multi faces will cost much time, OT will be used to instead it
import dlib
import numpy as np
import cv2
import os
import pandas as pd
import time
import logging
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# Dlib Resnet 人脸识别模型, 提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
class Face_Recognizer:
def __init__(self):
self.font = cv2.FONT_ITALIC
# FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
# cnt for frame
self.frame_cnt = 0
# 用来存放所有录入人脸特征的数组 / Save the features of faces in the database
self.face_features_known_list = []
# 存储录入人脸名字 / Save the name of faces in the database
self.face_name_known_list = []
# 用来存储上一帧和当前帧 ROI 的质心坐标 / List to save centroid positions of ROI in frame N-1 and N
self.last_frame_face_centroid_list = []
self.current_frame_face_centroid_list = []
# 用来存储上一帧和当前帧检测出目标的名字 / List to save names of objects in frame N-1 and N
self.last_frame_face_name_list = []
self.current_frame_face_name_list = []
# 上一帧和当前帧中人脸数的计数器 / cnt for faces in frame N-1 and N
self.last_frame_face_cnt = 0
self.current_frame_face_cnt = 0
# 用来存放进行识别时候对比的欧氏距离 / Save the e-distance for faceX when recognizing
self.current_frame_face_X_e_distance_list = []
# 存储当前摄像头中捕获到的所有人脸的坐标名字 / Save the positions and names of current faces captured
self.current_frame_face_position_list = []
# 存储当前摄像头中捕获到的人脸特征 / Save the features of people in current frame
self.current_frame_face_feature_list = []
# e distance between centroid of ROI in last and current frame
self.last_current_frame_centroid_e_distance = 0
# 控制再识别的后续帧数 / Reclassify after 'reclassify_interval' frames
# 如果识别出 "unknown" 的脸, 将在 reclassify_interval_cnt 计数到 reclassify_interval 后, 对于人脸进行重新识别
self.reclassify_interval_cnt = 0
self.reclassify_interval = 10
# 从 "features_all.csv" 读取录入人脸特征 / Get known faces from "features_all.csv"
def get_face_database(self):
if os.path.exists("data/features_all.csv"):
path_features_known_csv = "data/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
for i in range(csv_rd.shape[0]):
features_someone_arr = []
self.face_name_known_list.append(csv_rd.iloc[i][0])
for j in range(1, 129):
if csv_rd.iloc[i][j] == '':
features_someone_arr.append('0')
else:
features_someone_arr.append(csv_rd.iloc[i][j])
self.face_features_known_list.append(features_someone_arr)
logging.info("Faces in Database %d", len(self.face_features_known_list))
return 1
else:
logging.warning("'features_all.csv' not found!")
logging.warning("Please run 'get_faces_from_camera.py' "
"and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'")
return 0
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
@staticmethod
# 计算两个128D向量间的欧式距离 / Compute the e-distance between two 128D features
def return_euclidean_distance(feature_1, feature_2):
feature_1 = np.array(feature_1)
feature_2 = np.array(feature_2)
dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
return dist
# 使用质心追踪来识别人脸 / Use centroid tracker to link face_x in current frame with person_x in last frame
def centroid_tracker(self):
for i in range(len(self.current_frame_face_centroid_list)):
e_distance_current_frame_person_x_list = []
# 对于当前帧中的人脸1, 和上一帧中的 人脸1/2/3/4/.. 进行欧氏距离计算 / For object 1 in current_frame, compute e-distance with object 1/2/3/4/... in last frame
for j in range(len(self.last_frame_face_centroid_list)):
self.last_current_frame_centroid_e_distance = self.return_euclidean_distance(
self.current_frame_face_centroid_list[i], self.last_frame_face_centroid_list[j])
e_distance_current_frame_person_x_list.append(
self.last_current_frame_centroid_e_distance)
last_frame_num = e_distance_current_frame_person_x_list.index(
min(e_distance_current_frame_person_x_list))
self.current_frame_face_name_list[i] = self.last_frame_face_name_list[last_frame_num]
# 生成的 cv2 window 上面添加说明文字 / putText on cv2 window
def draw_note(self, img_rd):
# 添加说明 / Add some info on windows
cv2.putText(img_rd, "Face Recognizer with OT", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps.__round__(2)), (20, 130), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 160), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
for i in range(len(self.current_frame_face_name_list)):
img_rd = cv2.putText(img_rd, "Face_" + str(i + 1), tuple(
[int(self.current_frame_face_centroid_list[i][0]), int(self.current_frame_face_centroid_list[i][1])]),
self.font,
0.8, (255, 190, 0),
1,
cv2.LINE_AA)
# 处理获取的视频流, 进行人脸识别 / Face detection and recognition wit OT from input video stream
def process(self, stream):
# 1. 读取存放所有人脸特征的 csv / Get faces known from "features.all.csv"
if self.get_face_database():
while stream.isOpened():
self.frame_cnt += 1
logging.debug("Frame " + str(self.frame_cnt) + " starts")
flag, img_rd = stream.read()
kk = cv2.waitKey(1)
# 2. 检测人脸 / Detect faces for frame X
faces = detector(img_rd, 0)
# 3. 更新人脸计数器 / Update cnt for faces in frames
self.last_frame_face_cnt = self.current_frame_face_cnt
self.current_frame_face_cnt = len(faces)
# 4. 更新上一帧中的人脸列表 / Update the face name list in last frame
self.last_frame_face_name_list = self.current_frame_face_name_list[:]
# 5. 更新上一帧和当前帧的质心列表 / update frame centroid list
self.last_frame_face_centroid_list = self.current_frame_face_centroid_list
self.current_frame_face_centroid_list = []
# 6.1 如果当前帧和上一帧人脸数没有变化 / if cnt not changes
if (self.current_frame_face_cnt == self.last_frame_face_cnt) and (
self.reclassify_interval_cnt != self.reclassify_interval):
logging.debug("scene 1: 当前帧和上一帧相比没有发生人脸数变化 / No face cnt changes in this frame!!!")
self.current_frame_face_position_list = []
if "unknown" in self.current_frame_face_name_list:
logging.debug(" 有未知人脸, 开始进行 reclassify_interval_cnt 计数")
self.reclassify_interval_cnt += 1
if self.current_frame_face_cnt != 0:
for k, d in enumerate(faces):
self.current_frame_face_position_list.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
self.current_frame_face_centroid_list.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
img_rd = cv2.rectangle(img_rd,
tuple([d.left(), d.top()]),
tuple([d.right(), d.bottom()]),
(255, 255, 255), 2)
# 如果当前帧中有多个人脸, 使用质心追踪 / Multi-faces in current frame, use centroid-tracker to track
if self.current_frame_face_cnt != 1:
self.centroid_tracker()
for i in range(self.current_frame_face_cnt):
# 6.2 Write names under ROI
img_rd = cv2.putText(img_rd, self.current_frame_face_name_list[i],
self.current_frame_face_position_list[i], self.font, 0.8, (0, 255, 255), 1,
cv2.LINE_AA)
self.draw_note(img_rd)
# 6.2 如果当前帧和上一帧人脸数发生变化 / If cnt of faces changes, 0->1 or 1->0 or ...
else:
logging.debug("scene 2: 当前帧和上一帧相比人脸数发生变化 / Faces cnt changes in this frame")
self.current_frame_face_position_list = []
self.current_frame_face_X_e_distance_list = []
self.current_frame_face_feature_list = []
self.reclassify_interval_cnt = 0
# 6.2.1 人脸数减少 / Face cnt decreases: 1->0, 2->1, ...
if self.current_frame_face_cnt == 0:
logging.debug(" scene 2.1 人脸消失, 当前帧中没有人脸 / No faces in this frame!!!")
# clear list of names and features
self.current_frame_face_name_list = []
# 6.2.2 人脸数增加 / Face cnt increase: 0->1, 0->2, ..., 1->2, ...
else:
logging.debug(" scene 2.2 出现人脸, 进行人脸识别 / Get faces in this frame and do face recognition")
self.current_frame_face_name_list = []
for i in range(len(faces)):
shape = predictor(img_rd, faces[i])
self.current_frame_face_feature_list.append(
face_reco_model.compute_face_descriptor(img_rd, shape))
self.current_frame_face_name_list.append("unknown")
# 6.2.2.1 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
logging.debug(" For face %d in current frame:", k + 1)
self.current_frame_face_centroid_list.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
self.current_frame_face_X_e_distance_list = []
# 6.2.2.2 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_frame_face_position_list.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
# 6.2.2.3 对于某张人脸, 遍历所有存储的人脸特征
# For every faces detected, compare the faces in the database
for i in range(len(self.face_features_known_list)):
# 如果 q 数据不为空
if str(self.face_features_known_list[i][0]) != '0.0':
e_distance_tmp = self.return_euclidean_distance(
self.current_frame_face_feature_list[k],
self.face_features_known_list[i])
logging.debug(" with person %d, the e-distance: %f", i + 1, e_distance_tmp)
self.current_frame_face_X_e_distance_list.append(e_distance_tmp)
else:
# 空数据 person_X
self.current_frame_face_X_e_distance_list.append(999999999)
# 6.2.2.4 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
similar_person_num = self.current_frame_face_X_e_distance_list.index(
min(self.current_frame_face_X_e_distance_list))
if min(self.current_frame_face_X_e_distance_list) < 0.4:
self.current_frame_face_name_list[k] = self.face_name_known_list[similar_person_num]
logging.debug(" Face recognition result: %s",
self.face_name_known_list[similar_person_num])
else:
logging.debug(" Face recognition result: Unknown person")
# 7. 生成的窗口添加说明文字 / Add note on cv2 window
self.draw_note(img_rd)
# cv2.imwrite("debug/debug_" + str(self.frame_cnt) + ".png", img_rd) # Dump current frame image if needed
# 8. 按下 'q' 键退出 / Press 'q' to exit
if kk == ord('q'):
break
self.update_fps()
cv2.namedWindow("camera", 1)
cv2.imshow("camera", img_rd)
logging.debug("Frame ends\n\n")
def run(self):
# cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
cap = cv2.VideoCapture(0) # Get video stream from camera
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def main():
# logging.basicConfig(level=logging.DEBUG) # Set log level to 'logging.DEBUG' to print debug info of every frame
logging.basicConfig(level=logging.INFO)
Face_Recognizer_con = Face_Recognizer()
Face_Recognizer_con.run()
if __name__ == '__main__':
main()

@ -1,329 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 单张人脸实时识别 / Real-time face detection and recognition for single face
# 检测 -> 识别人脸, 新人脸出现 -> 再识别, 不会对于每一帧都进行识别 / Do detection -> recognize face, new face -> do re-recognition
# 其实对于单张人脸, 不需要 OT 进行跟踪, 对于新出现的人脸, 再识别一次就好了 / No OT here, OT will be used only for multi faces
import dlib
import numpy as np
import cv2
import os
import pandas as pd
import time
from PIL import Image, ImageDraw, ImageFont
import logging
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# Dlib Resnet 人脸识别模型, 提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
class Face_Recognizer:
def __init__(self):
self.font = cv2.FONT_ITALIC
self.font_chinese = ImageFont.truetype("simsun.ttc", 30)
# 统计 FPS / For FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
# 统计帧数 / cnt for frame
self.frame_cnt = 0
# 用来存储所有录入人脸特征的数组 / Save the features of faces in the database
self.features_known_list = []
# 用来存储录入人脸名字 / Save the name of faces in the database
self.face_name_known_list = []
# 用来存储上一帧和当前帧 ROI 的质心坐标 / List to save centroid positions of ROI in frame N-1 and N
self.last_frame_centroid_list = []
self.current_frame_centroid_list = []
# 用来存储当前帧检测出目标的名字 / List to save names of objects in current frame
self.current_frame_name_list = []
# 上一帧和当前帧中人脸数的计数器 / cnt for faces in frame N-1 and N
self.last_frame_faces_cnt = 0
self.current_frame_face_cnt = 0
# 用来存放进行识别时候对比的欧氏距离 / Save the e-distance for faceX when recognizing
self.current_frame_face_X_e_distance_list = []
# 存储当前摄像头中捕获到的所有人脸的坐标名字 / Save the positions and names of current faces captured
self.current_frame_face_position_list = []
# 存储当前摄像头中捕获到的人脸特征 / Save the features of people in current frame
self.current_frame_face_feature_list = []
# 控制再识别的后续帧数 / Reclassify after 'reclassify_interval' frames
# 如果识别出 "unknown" 的脸, 将在 reclassify_interval_cnt 计数到 reclassify_interval 后, 对于人脸进行重新识别
self.reclassify_interval_cnt = 0
self.reclassify_interval = 10
# 从 "features_all.csv" 读取录入人脸特征 / Get known faces from "features_all.csv"
def get_face_database(self):
if os.path.exists("data/features_all.csv"):
path_features_known_csv = "data/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
for i in range(csv_rd.shape[0]):
features_someone_arr = []
self.face_name_known_list.append(csv_rd.iloc[i][0])
for j in range(1, 129):
if csv_rd.iloc[i][j] == '':
features_someone_arr.append('0')
else:
features_someone_arr.append(csv_rd.iloc[i][j])
self.features_known_list.append(features_someone_arr)
logging.info("Faces in Database %d", len(self.features_known_list))
return 1
else:
logging.warning("'features_all.csv' not found!")
logging.warning("Please run 'get_faces_from_camera.py' "
"and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'")
return 0
# 获取处理之后 stream 的帧数 / Update FPS of video stream
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
# 计算两个128D向量间的欧式距离 / Compute the e-distance between two 128D features
@staticmethod
def return_euclidean_distance(feature_1, feature_2):
feature_1 = np.array(feature_1)
feature_2 = np.array(feature_2)
dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
return dist
# 生成的 cv2 window 上面添加说明文字 / putText on cv2 window
def draw_note(self, img_rd):
# 添加说明 (Add some statements
cv2.putText(img_rd, "Face Recognizer for single face", (20, 40), self.font, 1, (255, 255, 255), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 130), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 160), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
def draw_name(self, img_rd):
# 在人脸框下面写人脸名字 / Write names under ROI
logging.debug(self.current_frame_name_list)
img = Image.fromarray(cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
draw.text(xy=self.current_frame_face_position_list[0], text=self.current_frame_name_list[0], font=self.font_chinese,
fill=(255, 255, 0))
img_rd = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
return img_rd
def show_chinese_name(self):
if self.current_frame_face_cnt >= 1:
logging.debug(self.face_name_known_list)
# 修改录入的人脸姓名 / Modify names in face_name_known_list to chinese name
self.face_name_known_list[0] = '张三'.encode('utf-8').decode()
# self.face_name_known_list[1] = '张四'.encode('utf-8').decode()
# 处理获取的视频流, 进行人脸识别 / Face detection and recognition wit OT from input video stream
def process(self, stream):
# 1. 读取存放所有人脸特征的 csv / Get faces known from "features.all.csv"
if self.get_face_database():
while stream.isOpened():
self.frame_cnt += 1
logging.debug("Frame " + str(self.frame_cnt) + " starts")
flag, img_rd = stream.read()
kk = cv2.waitKey(1)
# 2. 检测人脸 / Detect faces for frame X
faces = detector(img_rd, 0)
# 3. 更新帧中的人脸数 / Update cnt for faces in frames
self.last_frame_faces_cnt = self.current_frame_face_cnt
self.current_frame_face_cnt = len(faces)
# 4.1 当前帧和上一帧相比没有发生人脸数变化 / If cnt not changes, 1->1 or 0->0
if self.current_frame_face_cnt == self.last_frame_faces_cnt:
logging.debug("scene 1: 当前帧和上一帧相比没有发生人脸数变化 / No face cnt changes in this frame!!!")
if "unknown" in self.current_frame_name_list:
logging.debug(" >>> 有未知人脸, 开始进行 reclassify_interval_cnt 计数")
self.reclassify_interval_cnt += 1
# 4.1.1 当前帧一张人脸 / One face in this frame
if self.current_frame_face_cnt == 1:
if self.reclassify_interval_cnt == self.reclassify_interval:
logging.debug(" scene 1.1 需要对于当前帧重新进行人脸识别 / Re-classify for current frame")
self.reclassify_interval_cnt = 0
self.current_frame_face_feature_list = []
self.current_frame_face_X_e_distance_list = []
self.current_frame_name_list = []
for i in range(len(faces)):
shape = predictor(img_rd, faces[i])
self.current_frame_face_feature_list.append(
face_reco_model.compute_face_descriptor(img_rd, shape))
# a. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
self.current_frame_name_list.append("unknown")
# b. 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_frame_face_position_list.append(tuple(
[faces[k].left(),
int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
# c. 对于某张人脸, 遍历所有存储的人脸特征 / For every face detected, compare it with all the faces in the database
for i in range(len(self.features_known_list)):
# 如果 person_X 数据不为空 / If the data of person_X is not empty
if str(self.features_known_list[i][0]) != '0.0':
e_distance_tmp = self.return_euclidean_distance(
self.current_frame_face_feature_list[k],
self.features_known_list[i])
logging.debug(" with person %d, the e-distance: %f", i + 1, e_distance_tmp)
self.current_frame_face_X_e_distance_list.append(e_distance_tmp)
else:
# 空数据 person_X / For empty data
self.current_frame_face_X_e_distance_list.append(999999999)
# d. 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
similar_person_num = self.current_frame_face_X_e_distance_list.index(
min(self.current_frame_face_X_e_distance_list))
if min(self.current_frame_face_X_e_distance_list) < 0.4:
# 在这里更改显示的人名 / Modify name if needed
self.show_chinese_name()
self.current_frame_name_list[k] = self.face_name_known_list[similar_person_num]
logging.debug(" recognition result for face %d: %s", k + 1,
self.face_name_known_list[similar_person_num])
else:
logging.debug(" recognition result for face %d: %s", k + 1, "unknown")
else:
logging.debug(
" scene 1.2 不需要对于当前帧重新进行人脸识别 / No re-classification needed for current frame")
# 获取特征框坐标 / Get ROI positions
for k, d in enumerate(faces):
cv2.rectangle(img_rd,
tuple([d.left(), d.top()]),
tuple([d.right(), d.bottom()]),
(255, 255, 255), 2)
self.current_frame_face_position_list[k] = tuple(
[faces[k].left(),
int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)])
img_rd = self.draw_name(img_rd)
# 4.2 当前帧和上一帧相比发生人脸数变化 / If face cnt changes, 1->0 or 0->1
else:
logging.debug("scene 2: 当前帧和上一帧相比人脸数发生变化 / Faces cnt changes in this frame")
self.current_frame_face_position_list = []
self.current_frame_face_X_e_distance_list = []
self.current_frame_face_feature_list = []
# 4.2.1 人脸数从 0->1 / Face cnt 0->1
if self.current_frame_face_cnt == 1:
logging.debug(" scene 2.1 出现人脸, 进行人脸识别 / Get faces in this frame and do face recognition")
self.current_frame_name_list = []
for i in range(len(faces)):
shape = predictor(img_rd, faces[i])
self.current_frame_face_feature_list.append(
face_reco_model.compute_face_descriptor(img_rd, shape))
# a. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
self.current_frame_name_list.append("unknown")
# b. 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_frame_face_position_list.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
# c. 对于某张人脸, 遍历所有存储的人脸特征 / For every face detected, compare it with all the faces in database
for i in range(len(self.features_known_list)):
# 如果 person_X 数据不为空 / If data of person_X is not empty
if str(self.features_known_list[i][0]) != '0.0':
e_distance_tmp = self.return_euclidean_distance(
self.current_frame_face_feature_list[k],
self.features_known_list[i])
logging.debug(" with person %d, the e-distance: %f", i + 1, e_distance_tmp)
self.current_frame_face_X_e_distance_list.append(e_distance_tmp)
else:
# 空数据 person_X / Empty data for person_X
self.current_frame_face_X_e_distance_list.append(999999999)
# d. 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
similar_person_num = self.current_frame_face_X_e_distance_list.index(
min(self.current_frame_face_X_e_distance_list))
if min(self.current_frame_face_X_e_distance_list) < 0.4:
# 在这里更改显示的人名 / Modify name if needed
self.show_chinese_name()
self.current_frame_name_list[k] = self.face_name_known_list[similar_person_num]
logging.debug(" recognition result for face %d: %s", k + 1,
self.face_name_known_list[similar_person_num])
else:
logging.debug(" recognition result for face %d: %s", k + 1, "unknown")
if "unknown" in self.current_frame_name_list:
self.reclassify_interval_cnt += 1
# 4.2.1 人脸数从 1->0 / Face cnt 1->0
elif self.current_frame_face_cnt == 0:
logging.debug(" scene 2.2 人脸消失, 当前帧中没有人脸 / No face in this frame!!!")
self.reclassify_interval_cnt = 0
self.current_frame_name_list = []
self.current_frame_face_feature_list = []
# 5. 生成的窗口添加说明文字 / Add note on cv2 window
self.draw_note(img_rd)
if kk == ord('q'):
break
self.update_fps()
cv2.namedWindow("camera", 1)
cv2.imshow("camera", img_rd)
logging.debug("Frame ends\n\n")
def run(self):
# cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
cap = cv2.VideoCapture(0) # Get video stream from camera
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def main():
# logging.basicConfig(level=logging.DEBUG) # Set log level to 'logging.DEBUG' to print debug info of every frame
logging.basicConfig(level=logging.INFO)
Face_Recognizer_con = Face_Recognizer()
Face_Recognizer_con.run()
if __name__ == '__main__':
main()

@ -1,106 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 从人脸图像文件中提取人脸特征存入 "features_all.csv" / Extract features from images and save into "features_all.csv"
import os
import dlib
import csv
import numpy as np
import logging
import cv2
# 要读取人脸图像文件的路径 / Path of cropped faces
path_images_from_camera = "data/data_faces_from_camera/"
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# Dlib Resnet 人脸识别模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
# 返回单张图像的 128D 特征 / Return 128D features for single image
# Input: path_img <class 'str'>
# Output: face_descriptor <class 'dlib.vector'>
def return_128d_features(path_img):
img_rd = cv2.imread(path_img)
faces = detector(img_rd, 1)
logging.info("%-40s %-20s", "检测到人脸的图像 / Image with faces detected:", path_img)
# 因为有可能截下来的人脸再去检测,检测不出来人脸了, 所以要确保是 检测到人脸的人脸图像拿去算特征
# For photos of faces saved, we need to make sure that we can detect faces from the cropped images
if len(faces) != 0:
shape = predictor(img_rd, faces[0])
face_descriptor = face_reco_model.compute_face_descriptor(img_rd, shape)
else:
face_descriptor = 0
logging.warning("no face")
return face_descriptor
# 返回 personX 的 128D 特征均值 / Return the mean value of 128D face descriptor for person X
# Input: path_face_personX <class 'str'>
# Output: features_mean_personX <class 'numpy.ndarray'>
def return_features_mean_personX(path_face_personX):
features_list_personX = []
photos_list = os.listdir(path_face_personX)
if photos_list:
for i in range(len(photos_list)):
# 调用 return_128d_features() 得到 128D 特征 / Get 128D features for single image of personX
logging.info("%-40s %-20s", "正在读的人脸图像 / Reading image:", path_face_personX + "/" + photos_list[i])
features_128d = return_128d_features(path_face_personX + "/" + photos_list[i])
# 遇到没有检测出人脸的图片跳过 / Jump if no face detected from image
if features_128d == 0:
i += 1
else:
features_list_personX.append(features_128d)
else:
logging.warning("文件夹内图像文件为空 / Warning: No images in%s/", path_face_personX)
# 计算 128D 特征的均值 / Compute the mean
# personX 的 N 张图像 x 128D -> 1 x 128D
if features_list_personX:
features_mean_personX = np.array(features_list_personX, dtype=object).mean(axis=0)
else:
features_mean_personX = np.zeros(128, dtype=object, order='C')
return features_mean_personX
def main():
logging.basicConfig(level=logging.INFO)
# 获取已录入的最后一个人脸序号 / Get the order of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_list.sort()
with open("data/features_all.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile)
for person in person_list:
# Get the mean/average features of face/personX, it will be a list with a length of 128D
logging.info("%sperson_%s", path_images_from_camera, person)
features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
if len(person.split('_', 2)) == 2:
# "person_x"
person_name = person
else:
# "person_x_tom"
person_name = person.split('_', 2)[-1]
features_mean_personX = np.insert(features_mean_personX, 0, person_name, axis=0)
# features_mean_personX will be 129D, person name + 128 features
writer.writerow(features_mean_personX)
logging.info('\n')
logging.info("所有录入人脸数据存入 / Save all the features of faces registered into: data/features_all.csv")
if __name__ == '__main__':
main()

@ -1,198 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 进行人脸录入 / Face register
import dlib
import numpy as np
import cv2
import os
import shutil
import time
import logging
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
class Face_Register:
def __init__(self):
self.path_photos_from_camera = "data/data_faces_from_camera/"
self.font = cv2.FONT_ITALIC
self.existing_faces_cnt = 0 # 已录入的人脸计数器 / cnt for counting saved faces
self.ss_cnt = 0 # 录入 personX 人脸时图片计数器 / cnt for screen shots
self.current_frame_faces_cnt = 0 # 录入人脸计数器 / cnt for counting faces in current frame
self.save_flag = 1 # 之后用来控制是否保存图像的 flag / The flag to control if save
self.press_n_flag = 0 # 之后用来检查是否先按 'n' 再按 's' / The flag to check if press 'n' before 's'
# FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
# 新建保存人脸图像文件和数据 CSV 文件夹 / Mkdir for saving photos and csv
def pre_work_mkdir(self):
# 新建文件夹 / Create folders to save face images and csv
if os.path.isdir(self.path_photos_from_camera):
pass
else:
os.mkdir(self.path_photos_from_camera)
# 删除之前存的人脸数据文件夹 / Delete old face folders
def pre_work_del_old_face_folders(self):
# 删除之前存的人脸数据文件夹, 删除 "/data_faces_from_camera/person_x/"...
folders_rd = os.listdir(self.path_photos_from_camera)
for i in range(len(folders_rd)):
shutil.rmtree(self.path_photos_from_camera+folders_rd[i])
if os.path.isfile("data/features_all.csv"):
os.remove("data/features_all.csv")
# 如果有之前录入的人脸, 在之前 person_x 的序号按照 person_x+1 开始录入 / Start from person_x+1
def check_existing_faces_cnt(self):
if os.listdir("data/data_faces_from_camera/"):
# 获取已录入的最后一个人脸序号 / Get the order of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_num_list = []
for person in person_list:
person_num_list.append(int(person.split('_')[-1]))
self.existing_faces_cnt = max(person_num_list)
# 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入 / Start from person_1
else:
self.existing_faces_cnt = 0
# 更新 FPS / Update FPS of Video stream
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
# 生成的 cv2 window 上面添加说明文字 / PutText on cv2 window
def draw_note(self, img_rd):
# 添加说明 / Add some notes
cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "N: Create 创建 face folder", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "S: Save current face", (20, 400), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
# 获取人脸 / Main process of face detection and saving
def process(self, stream):
# 1. 新建储存人脸图像文件目录 / Create folders to save photos
self.pre_work_mkdir()
# 2. 删除 "/data/data_faces_from_camera" 中已有人脸图像文件
# / Uncomment if want to delete the saved faces and start from person_1
# if os.path.isdir(self.path_photos_from_camera):
# self.pre_work_del_old_face_folders()
# 3. 检查 "/data/data_faces_from_camera" 中已有人脸文件
self.check_existing_faces_cnt()
while stream.isOpened():
flag, img_rd = stream.read() # Get camera video stream
kk = cv2.waitKey(1)
faces = detector(img_rd, 0) # Use Dlib face detector
# 4. 按下 'n' 新建存储人脸的文件夹 / Press 'n' to create the folders for saving faces
if kk == ord('n'):
self.existing_faces_cnt += 1
current_face_dir = self.path_photos_from_camera + "person_" + str(self.existing_faces_cnt)
os.makedirs(current_face_dir)
logging.info("\n%-40s %s", "新建的人脸文件夹 / Create folders:", current_face_dir)
self.ss_cnt = 0 # 将人脸计数器清零 / Clear the cnt of screen shots
self.press_n_flag = 1 # 已经按下 'n' / Pressed 'n' already
# 5. 检测到人脸 / Face detected
if len(faces) != 0:
# 矩形框 / Show the ROI of faces
for k, d in enumerate(faces):
# 计算矩形框大小 / Compute the size of rectangle box
height = (d.bottom() - d.top())
width = (d.right() - d.left())
hh = int(height/2)
ww = int(width/2)
# 6. 判断人脸矩形框是否超出 480x640 / If the size of ROI > 480x640
if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0):
cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
color_rectangle = (0, 0, 255)
save_flag = 0
if kk == ord('s'):
logging.warning("请调整位置 / Please adjust your position")
else:
color_rectangle = (255, 255, 255)
save_flag = 1
cv2.rectangle(img_rd,
tuple([d.left() - ww, d.top() - hh]),
tuple([d.right() + ww, d.bottom() + hh]),
color_rectangle, 2)
# 7. 根据人脸大小生成空的图像 / Create blank image according to the size of face detected
img_blank = np.zeros((int(height*2), width*2, 3), np.uint8)
if save_flag:
# 8. 按下 's' 保存摄像头中的人脸到本地 / Press 's' to save faces into local images
if kk == ord('s'):
# 检查有没有先按'n'新建文件夹 / Check if you have pressed 'n'
if self.press_n_flag:
self.ss_cnt += 1
for ii in range(height*2):
for jj in range(width*2):
img_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
cv2.imwrite(current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", img_blank)
logging.info("%-40s %s/img_face_%s.jpg", "写入本地 / Save into",
str(current_face_dir), str(self.ss_cnt))
else:
logging.warning("请先按 'N' 来建文件夹, 按 'S' / Please press 'N' and press 'S'")
self.current_frame_faces_cnt = len(faces)
# 9. 生成的窗口添加说明文字 / Add note on cv2 window
self.draw_note(img_rd)
# 10. 按下 'q' 键退出 / Press 'q' to exit
if kk == ord('q'):
break
# 11. Update FPS
self.update_fps()
cv2.namedWindow("camera", 1)
cv2.imshow("camera", img_rd)
def run(self):
# cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
cap = cv2.VideoCapture(0) # Get video stream from camera
self.process(cap)
cap.release()
cv2.destroyAllWindows()
def main():
logging.basicConfig(level=logging.INFO)
Face_Register_con = Face_Register()
Face_Register_con.run()
if __name__ == '__main__':
main()

@ -1,305 +0,0 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# 人脸录入 Tkinter GUI / Face register GUI with tkinter
#改代码为简易ui界面暂时无法运行
import dlib
import numpy as np
import cv2
import os
import shutil
import time
import logging
import tkinter as tk
from tkinter import font as tkFont
from PIL import Image, ImageTk
# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
detector = dlib.get_frontal_face_detector()
class Face_Register:
def __init__(self):
self.current_frame_faces_cnt = 0 # 当前帧中人脸计数器 / cnt for counting faces in current frame
self.existing_faces_cnt = 0 # 已录入的人脸计数器 / cnt for counting saved faces
self.ss_cnt = 0 # 录入 person_n 人脸时图片计数器 / cnt for screen shots
# Tkinter GUI
self.win = tk.Tk()
self.win.title("Face Register @coneypo")
# PLease modify window size here if needed
self.win.geometry("1300x550")
# GUI left part
self.frame_left_camera = tk.Frame(self.win)
self.label = tk.Label(self.win)
self.label.pack(side=tk.LEFT)
self.frame_left_camera.pack()
# GUI right part
self.frame_right_info = tk.Frame(self.win)
self.label_cnt_face_in_database = tk.Label(self.frame_right_info, text=str(self.existing_faces_cnt))
self.label_fps_info = tk.Label(self.frame_right_info, text="")
self.input_name = tk.Entry(self.frame_right_info)
self.input_name_char = ""
self.label_warning = tk.Label(self.frame_right_info)
self.label_face_cnt = tk.Label(self.frame_right_info, text="Faces in current frame: ")
self.log_all = tk.Label(self.frame_right_info)
self.font_title = tkFont.Font(family='Helvetica', size=20, weight='bold')
self.font_step_title = tkFont.Font(family='Helvetica', size=15, weight='bold')
self.font_warning = tkFont.Font(family='Helvetica', size=15, weight='bold')
self.path_photos_from_camera = "data/data_faces_from_camera/"
self.current_face_dir = ""
self.font = cv2.FONT_ITALIC
# Current frame and face ROI position
self.current_frame = np.ndarray
self.face_ROI_image = np.ndarray
self.face_ROI_width_start = 0
self.face_ROI_height_start = 0
self.face_ROI_width = 0
self.face_ROI_height = 0
self.ww = 0
self.hh = 0
self.out_of_range_flag = False
self.face_folder_created_flag = False
# FPS
self.frame_time = 0
self.frame_start_time = 0
self.fps = 0
self.fps_show = 0
self.start_time = time.time()
self.cap = cv2.VideoCapture(0) # Get video stream from camera
# self.cap = cv2.VideoCapture("test.mp4") # Input local video
# 删除之前存的人脸数据文件夹 / Delete old face folders
def GUI_clear_data(self):
# 删除之前存的人脸数据文件夹, 删除 "/data_faces_from_camera/person_x/"...
folders_rd = os.listdir(self.path_photos_from_camera)
for i in range(len(folders_rd)):
shutil.rmtree(self.path_photos_from_camera + folders_rd[i])
if os.path.isfile("data/features_all.csv"):
os.remove("data/features_all.csv")
self.label_cnt_face_in_database['text'] = "0"
self.existing_faces_cnt = 0
self.log_all["text"] = "Face images and `features_all.csv` removed!"
def GUI_get_input_name(self):
self.input_name_char = self.input_name.get()
self.create_face_folder()
self.label_cnt_face_in_database['text'] = str(self.existing_faces_cnt)
def GUI_info(self):
tk.Label(self.frame_right_info,
text="Face register",
font=self.font_title).grid(row=0, column=0, columnspan=3, sticky=tk.W, padx=2, pady=20)
tk.Label(self.frame_right_info,
text="FPS: ").grid(row=1, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2)
self.label_fps_info.grid(row=1, column=2, sticky=tk.W, padx=5, pady=2)
tk.Label(self.frame_right_info,
text="Faces in database: ").grid(row=2, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2)
self.label_cnt_face_in_database.grid(row=2, column=2, columnspan=3, sticky=tk.W, padx=5, pady=2)
tk.Label(self.frame_right_info,
text="Faces in current frame: ").grid(row=3, column=0, columnspan=2, sticky=tk.W, padx=5, pady=2)
self.label_face_cnt.grid(row=3, column=2, columnspan=3, sticky=tk.W, padx=5, pady=2)
self.label_warning.grid(row=4, column=0, columnspan=3, sticky=tk.W, padx=5, pady=2)
# Step 1: Clear old data
tk.Label(self.frame_right_info,
font=self.font_step_title,
text="Step 1: Clear face photos").grid(row=5, column=0, columnspan=2, sticky=tk.W, padx=5, pady=20)
tk.Button(self.frame_right_info,
text='Clear',
command=self.GUI_clear_data).grid(row=6, column=0, columnspan=3, sticky=tk.W, padx=5, pady=2)
# Step 2: Input name and create folders for face
tk.Label(self.frame_right_info,
font=self.font_step_title,
text="Step 2: Input name").grid(row=7, column=0, columnspan=2, sticky=tk.W, padx=5, pady=20)
tk.Label(self.frame_right_info, text="Name: ").grid(row=8, column=0, sticky=tk.W, padx=5, pady=0)
self.input_name.grid(row=8, column=1, sticky=tk.W, padx=0, pady=2)
tk.Button(self.frame_right_info,
text='Input',
command=self.GUI_get_input_name).grid(row=8, column=2, padx=5)
# Step 3: Save current face in frame
tk.Label(self.frame_right_info,
font=self.font_step_title,
text="Step 3: Save face image").grid(row=9, column=0, columnspan=2, sticky=tk.W, padx=5, pady=20)
tk.Button(self.frame_right_info,
text='Save current face',
command=self.save_current_face).grid(row=10, column=0, columnspan=3, sticky=tk.W)
# Show log in GUI
self.log_all.grid(row=11, column=0, columnspan=20, sticky=tk.W, padx=5, pady=20)
self.frame_right_info.pack()
# 新建保存人脸图像文件和数据 CSV 文件夹 / Mkdir for saving photos and csv
def pre_work_mkdir(self):
# 新建文件夹 / Create folders to save face images and csv
if os.path.isdir(self.path_photos_from_camera):
pass
else:
os.mkdir(self.path_photos_from_camera)
# 如果有之前录入的人脸, 在之前 person_x 的序号按照 person_x+1 开始录入 / Start from person_x+1
def check_existing_faces_cnt(self):
if os.listdir("data/data_faces_from_camera/"):
# 获取已录入的最后一个人脸序号 / Get the order of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_num_list = []
for person in person_list:
person_order = person.split('_')[1].split('_')[0]
person_num_list.append(int(person_order))
self.existing_faces_cnt = max(person_num_list)
# 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入 / Start from person_1
else:
self.existing_faces_cnt = 0
# 更新 FPS / Update FPS of Video stream
def update_fps(self):
now = time.time()
# 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
self.frame_time = now - self.frame_start_time
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
self.label_fps_info["text"] = str(self.fps.__round__(2))
def create_face_folder(self):
# 新建存储人脸的文件夹 / Create the folders for saving faces
self.existing_faces_cnt += 1
if self.input_name_char:
self.current_face_dir = self.path_photos_from_camera + \
"person_" + str(self.existing_faces_cnt) + "_" + \
self.input_name_char
else:
self.current_face_dir = self.path_photos_from_camera + \
"person_" + str(self.existing_faces_cnt)
os.makedirs(self.current_face_dir)
self.log_all["text"] = "\"" + self.current_face_dir + "/\" created!"
logging.info("\n%-40s %s", "新建的人脸文件夹 / Create folders:", self.current_face_dir)
self.ss_cnt = 0 # 将人脸计数器清零 / Clear the cnt of screen shots
self.face_folder_created_flag = True # Face folder already created
def save_current_face(self):
if self.face_folder_created_flag:
if self.current_frame_faces_cnt == 1:
if not self.out_of_range_flag:
self.ss_cnt += 1
# 根据人脸大小生成空的图像 / Create blank image according to the size of face detected
self.face_ROI_image = np.zeros((int(self.face_ROI_height * 2), self.face_ROI_width * 2, 3),
np.uint8)
for ii in range(self.face_ROI_height * 2):
for jj in range(self.face_ROI_width * 2):
self.face_ROI_image[ii][jj] = self.current_frame[self.face_ROI_height_start - self.hh + ii][
self.face_ROI_width_start - self.ww + jj]
self.log_all["text"] = "\"" + self.current_face_dir + "/img_face_" + str(
self.ss_cnt) + ".jpg\"" + " saved!"
self.face_ROI_image = cv2.cvtColor(self.face_ROI_image, cv2.COLOR_BGR2RGB)
cv2.imwrite(self.current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", self.face_ROI_image)
logging.info("%-40s %s/img_face_%s.jpg", "写入本地 / Save into",
str(self.current_face_dir), str(self.ss_cnt) + ".jpg")
else:
self.log_all["text"] = "Please do not out of range!"
else:
self.log_all["text"] = "No face in current frame!"
else:
self.log_all["text"] = "Please run step 2!"
def get_frame(self):
try:
if self.cap.isOpened():
ret, frame = self.cap.read()
return ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
except:
print("Error: No video input!!!")
# 获取人脸 / Main process of face detection and saving
def process(self):
ret, self.current_frame = self.get_frame()
faces = detector(self.current_frame, 0)
# Get frame
if ret:
self.update_fps()
self.label_face_cnt["text"] = str(len(faces))
# 检测到人脸 / Face detected
if len(faces) != 0:
# 矩形框 / Show the ROI of faces
for k, d in enumerate(faces):
self.face_ROI_width_start = d.left()
self.face_ROI_height_start = d.top()
# 计算矩形框大小 / Compute the size of rectangle box
self.face_ROI_height = (d.bottom() - d.top())
self.face_ROI_width = (d.right() - d.left())
self.hh = int(self.face_ROI_height / 2)
self.ww = int(self.face_ROI_width / 2)
# 判断人脸矩形框是否超出 480x640 / If the size of ROI > 480x640
if (d.right() + self.ww) > 640 or (d.bottom() + self.hh > 480) or (d.left() - self.ww < 0) or (
d.top() - self.hh < 0):
self.label_warning["text"] = "OUT OF RANGE"
self.label_warning['fg'] = 'red'
self.out_of_range_flag = True
color_rectangle = (255, 0, 0)
else:
self.out_of_range_flag = False
self.label_warning["text"] = ""
color_rectangle = (255, 255, 255)
self.current_frame = cv2.rectangle(self.current_frame,
tuple([d.left() - self.ww, d.top() - self.hh]),
tuple([d.right() + self.ww, d.bottom() + self.hh]),
color_rectangle, 2)
self.current_frame_faces_cnt = len(faces)
# Convert PIL.Image.Image to PIL.Image.PhotoImage
img_Image = Image.fromarray(self.current_frame)
img_PhotoImage = ImageTk.PhotoImage(image=img_Image)
self.label.img_tk = img_PhotoImage
self.label.configure(image=img_PhotoImage)
# Refresh frame
self.win.after(20, self.process)
def run(self):
self.pre_work_mkdir()
self.check_existing_faces_cnt()
self.GUI_info()
self.process()
self.win.mainloop()
def main():
logging.basicConfig(level=logging.INFO)
Face_Register_con = Face_Register()
Face_Register_con.run()
if __name__ == '__main__':
main()

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>image</class>
<widget class="QMainWindow" name="image">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>706</width>
<height>575</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>40</x>
<y>30</y>
<width>621</width>
<height>401</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(0, 0, 0);</string>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>40</x>
<y>490</y>
<width>111</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>打开文件</string>
</property>
</widget>
<widget class="QTextBrowser" name="textBrowser">
<property name="geometry">
<rect>
<x>230</x>
<y>490</y>
<width>256</width>
<height>21</height>
</rect>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -1,40 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\pythonProjects\pyqt\image.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_image(object):
def setupUi(self, image):
image.setObjectName("image")
image.resize(706, 575)
image.setStyleSheet("")
self.centralwidget = QtWidgets.QWidget(image)
self.centralwidget.setObjectName("centralwidget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(40, 30, 621, 401))
self.label.setStyleSheet("background-color: rgb(0, 0, 0);")
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(40, 490, 75, 21))
self.pushButton.setObjectName("pushButton")
self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.textBrowser.setGeometry(QtCore.QRect(140, 490, 256, 21))
self.textBrowser.setObjectName("textBrowser")
image.setCentralWidget(self.centralwidget)
self.retranslateUi(image)
QtCore.QMetaObject.connectSlotsByName(image)
def retranslateUi(self, image):
_translate = QtCore.QCoreApplication.translate
image.setWindowTitle(_translate("image", "MainWindow"))
self.label.setText(_translate("image", "TextLabel"))
self.pushButton.setText(_translate("image", "打开文件"))

@ -1,111 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoginWindow</class>
<widget class="QMainWindow" name="LoginWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>60</x>
<y>40</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>600</width>
<height>500</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(217, 217, 217);</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="placeholderText">
<string>账号</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit_2">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="placeholderText">
<string>密码</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton_2">
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 251, 208);</string>
</property>
<property name="text">
<string>登录</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton">
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 251, 208);
</string>
</property>
<property name="text">
<string>注册账号</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton_3">
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 251, 208);</string>
</property>
<property name="text">
<string>找回密码</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -1,64 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'login.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_LoginWindow(object):
def setupUi(self, LoginWindow):
LoginWindow.setObjectName("LoginWindow")
LoginWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(LoginWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(60, 40, 600, 500))
self.frame.setMinimumSize(QtCore.QSize(600, 500))
self.frame.setStyleSheet("background-color: rgb(217, 217, 217);")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.frame)
self.lineEdit.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit.setStyleSheet("background-color: rgb(255, 255, 255);")
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit, 0, QtCore.Qt.AlignHCenter)
self.lineEdit_2 = QtWidgets.QLineEdit(self.frame)
self.lineEdit_2.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit_2.setStyleSheet("background-color: rgb(255, 255, 255);")
self.lineEdit_2.setObjectName("lineEdit_2")
self.verticalLayout.addWidget(self.lineEdit_2, 0, QtCore.Qt.AlignHCenter)
self.pushButton_2 = QtWidgets.QPushButton(self.frame)
self.pushButton_2.setStyleSheet("background-color: rgb(255, 251, 208);")
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2, 0, QtCore.Qt.AlignHCenter)
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setStyleSheet("background-color: rgb(255, 251, 208);\n"
"")
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton, 0, QtCore.Qt.AlignHCenter)
self.pushButton_3 = QtWidgets.QPushButton(self.frame)
self.pushButton_3.setStyleSheet("background-color: rgb(255, 251, 208);")
self.pushButton_3.setObjectName("pushButton_3")
self.verticalLayout.addWidget(self.pushButton_3, 0, QtCore.Qt.AlignHCenter)
LoginWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(LoginWindow)
QtCore.QMetaObject.connectSlotsByName(LoginWindow)
def retranslateUi(self, LoginWindow):
_translate = QtCore.QCoreApplication.translate
LoginWindow.setWindowTitle(_translate("LoginWindow", "MainWindow"))
self.lineEdit.setPlaceholderText(_translate("LoginWindow", "账号"))
self.lineEdit_2.setPlaceholderText(_translate("LoginWindow", "密码"))
self.pushButton_2.setText(_translate("LoginWindow", "登录"))
self.pushButton.setText(_translate("LoginWindow", "注册账号"))
self.pushButton_3.setText(_translate("LoginWindow", "找回密码"))

@ -1,463 +0,0 @@
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from login_ui import Ui_LoginWindow # 这里需要根据实际的文件名字与类的名字导入
from image_ui import Ui_image # 这里需要根据实际的文件名字与类的名字导入
from register_ui import Ui_RegWindow # 这里需要根据实际的文件名字与类的名字导入
from reset_ui import Ui_RetWindow # 这里需要根据实际的文件名字与类的名字导入
from PyQt5.QtWidgets import QMessageBox, QFileDialog, QLineEdit
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from CAM import Ui_MainWindow
import cv2
import sqlite3
from PyQt5.QtWidgets import QMessageBox
from start import Ui_MainWindow as start_ui
import time
import os
from datetime import datetime, timedelta
from set import Ui_MainWindow as set_ui
from test4 import calculate_required_time, is_within_time_range, create_training_directory
from io import BytesIO
class LoginWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_LoginWindow()
self.ui.setupUi(self)
self.show()
self.ui.pushButton.clicked.connect(self.register)
self.ui.pushButton_2.clicked.connect(self.login)
self.ui.pushButton_3.clicked.connect(self.reset)
# 登录函数
def login(self):
# 连接数据库
conn1 = sqlite3.connect("F:\BaiduNetdiskDownload\pyqt\pyqt\mrsoft.db")
cursor1 = conn1.cursor()
user_id = self.ui.lineEdit.text() # 获取账号
password = self.ui.lineEdit_2.text() # 获取密码
# sql语句判断数据库中是否拥有这账号和密码
sql = 'select user_id, password from user where user_id=? and password =?'
cursor1.execute(sql, (user_id, password))
# 获取一致的部分,存在表示输入正确,不存在提示错误
data = cursor1.fetchall()
conn1.commit()
cursor1.close()
conn1.close()
# 账号和密码不为空时候,才进入
if data :
self.close()
MainWindow.show()
else:
QMessageBox.information(self, "提示", "您的登录账号/密码错误或为空!",
QMessageBox.Close)
# 跳转至注册函数
def register(self):
RegisterWindow.show()
self.close()
# 跳转至重置函数
def reset(self):
ResetWindow.show()
self.close()
def video264(self):
MainWindow.show()
self.close()
class RegisterWindow(QMainWindow, Ui_RegWindow):
def __init__(self, parent=None):
super(RegisterWindow, self).__init__(parent)
self.ui = Ui_RegWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.reg)
self.ui.pushButton_2.clicked.connect(self.back1)
def open(self):
self.show()
def back1(self):
self.close()
LoginWindow.show()
def reg(self):
conn2 = sqlite3.connect("F:\BaiduNetdiskDownload\pyqt\pyqt\mrsoft.db")
cursor2 = conn2.cursor()
user_id = self.ui.lineEdit.text()
password = self.ui.lineEdit_2.text()
confirm = self.ui.lineEdit_3.text()
if password == confirm and password and user_id:
# sql语句符合条件的给数据库中加入新的账号和密码
sql = 'insert into user (user_id, password) values (?, ?)'
cursor2.execute(sql, (user_id, password))
self.back1()
# 如果两次输入密码不一致,发出提示
elif password != confirm:
QMessageBox.information(self, "提示", "两次输入的密码不一致,请重新输入!",
QMessageBox.Close)
else:
QMessageBox.information(self, "提示", "输入错误!",
QMessageBox.Close)
conn2.commit()
cursor2.close()
conn2.close()
class ResetWindow(QMainWindow, Ui_RetWindow):
def __init__(self, parent=None):
super(ResetWindow, self).__init__(parent)
self.ui = Ui_RetWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.ret)
self.ui.pushButton_2.clicked.connect(self.back2)
def open(self):
self.show()
def back2(self):
self.close()
LoginWindow.show()
def ret(self):
conn3 = sqlite3.connect("F:\BaiduNetdiskDownload\pyqt\pyqt\mrsoft.db")
cursor3 = conn3.cursor()
user_id = self.ui.lineEdit.text()
password = self.ui.lineEdit_2.text()
confirm = self.ui.lineEdit_3.text()
if password == confirm and password and user_id:
sql = 'update user set password=? where user_id=?'
cursor3.execute(sql, (password, user_id))
self.back2()
elif password != confirm:
QMessageBox.information(self, "提示", "两次输入的密码不一致,请重新输入!",
QMessageBox.Close)
else:
QMessageBox.information(self, "提示", "输入错误!",
QMessageBox.Close)
conn3.commit()
cursor3.close()
conn3.close()
global_background_image = None
class StartWindow(QMainWindow, start_ui):
def __init__(self):
super(StartWindow, self).__init__()
self.setupUi(self)
self.startButton.clicked.connect(self.main)
self.closeButton.clicked.connect(self.back2)
def back2(self):
self.close()
MainWindow.show() # 请确保 MainWindow 已经被实例化并可以显示
def main(self): # 方法参数改为 self
# 获取输入值
start_time_str = self.lineEdit.text()
end_time_str = self.lineEdit_2.text()
percentage = float(self.lineEdit_3.text()) # 转换为浮点数
# 创建训练数据目录
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
# 判断当前时间是否在指定的时间范围内
def is_within_time_range(start_time_str, end_time_str):
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
# 计算所需的最少时间(分钟)
def calculate_required_time(start_time_str, end_time_str, percentage):
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
# 捕获人脸并计时
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str,
end_time_str):
cv2.namedWindow(window_name)
cap = cv2.VideoCapture(camera_id)
face_cascade = cv2.CascadeClassifier(
r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml"
)
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
create_training_directory(path_name)
# 使用生成的唯一文件名
video_name = self.generate_unique_filename() + '.mp4'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(video_name, fourcc, 20.0, (640, 480))
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示倒计时
cv2.putText(frame, f'Time Left: {remaining_time // 60}m {remaining_time % 60}s', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
if remaining_time <= 0:
break
else:
countdown_started = False
remaining_time = required_time * 60
cv2.putText(frame, 'Outside of specified time range', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,
(0, 0, 255), 2)
cv2.imshow(window_name, frame)
out.write(frame) # 写入视频帧
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
print('Finished capturing faces and video.')
# 将视频写入数据库
self.save_video_to_folder(video_name)
# 检查是否在规定时间内完成了任务
if countdown_started and remaining_time <= 0:
self.show_message_box("学习完成")
else:
self.show_message_box("学习未完成")
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
print(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', MainWindow.CAM_NUM, 'training_data_faces/', 1000, required_time, start_time_str,
end_time_str)
def save_video_to_folder(self, video_name):
print(f"Saving video: {video_name}")
save_directory = "F:\\BaiduNetdiskDownload\\pyqt\\pyqt\\videos"
video_path = os.path.join(save_directory, video_name)
if not os.path.exists(save_directory):
print("Directory does not exist. Creating...")
os.makedirs(save_directory)
# 使用cv2.VideoWriter将视频写入
os.rename(video_name, video_path) # 将视频文件重命名并移动到目标路径
print(f"Video saved to {video_path}")
def generate_unique_filename(self):
# 生成唯一的文件名,例如使用时间戳
import time
return f"video_{int(time.time())}"
def show_message_box(self, message):
QMessageBox.information(self, "任务完成情况", message)
# 请确保 MainWindow 已经被实例化并可以显示
# 例如: MainWindow = QMainWindow()
def set_background_image(window, image_path):
if os.path.exists(image_path):
pixmap = QPixmap(image_path)
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(pixmap))
window.setPalette(palette)
print(f"背景图片已设置: {image_path}")
else:
print(f"图片文件不存在: {image_path}")
class SetWindow(QMainWindow, set_ui):
def __init__(self, MainWindow):
super(SetWindow, self).__init__()
self.setupUi(self)
self.MainWindow = MainWindow # 保存 MainWindow 实例
self.backButton.clicked.connect(self.back2)
self.videoButton.clicked.connect(self.open_recorded_videos_folder)
self.fontButton.clicked.connect(self.change_font)
self.background.clicked.connect(self.change_background) # 连接到改变背景的方法
def open_recorded_videos_folder(self):
# 定义文件夹路径
folder_path = r'F:\BaiduNetdiskDownload\pyqt\pyqt\videos'
try:
if isinstance(folder_path, str):
if os.path.exists(folder_path):
os.startfile(folder_path) # 打开指定的文件夹
print(f"已打开文件夹: {folder_path}")
else:
print(f"文件夹不存在: {folder_path}")
else:
print(f"传入的路径类型错误: {type(folder_path)}")
except Exception as e:
print(f"打开文件夹时出错: {e}")
def change_font(self):
# 打开字体选择对话框
font, ok = QFontDialog.getFont()
if ok:
# 应用字体到所有控件
self.apply_font_to_all_widgets(self, font)
def apply_font_to_all_widgets(self, widget, font):
# 遍历当前控件的所有子控件
for child in widget.findChildren(QWidget):
# 检查子控件是否支持设置字体
if hasattr(child, 'setFont'):
child.setFont(font)
print(f"字体已更改为: {font.toString()} 应用于: {child.objectName()}")
# 递归应用到子控件的子控件
self.apply_font_to_all_widgets(child, font)
def back2(self):
self.close()
MainWindow.show()
def change_background(self):
# 选择背景图片文件
options = QFileDialog.Options()
file_name, _ = QFileDialog.getOpenFileName(self, "选择背景图片", "",
"Images (*.png *.xpm *.jpg);;All Files (*)", options=options)
if file_name:
# 设置窗口背景图片
set_background_image(self, file_name)
# 如果 MainWindow 存在,也设置背景图片
if hasattr(self, 'MainWindow'):
set_background_image(self.MainWindow, file_name)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
# UI界面
self.setupUi(self)
self.CAM_NUM = 0 # 默认camera_id为0
self.cap = cv2.VideoCapture()
self.background()
self.pushButton_2.clicked.connect(self.back2)
# 在label中播放视频
self.init_timer()
self.pushButton_3.clicked.connect(self.back3)
# 加载人脸检测分类器
self.face_cascade = cv2.CascadeClassifier(r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml")
def background(self):
self.pushButton.clicked.connect(self.open_camera)
self.pushButton_2.clicked.connect(self.back2)
self.pushButton.setEnabled(True)
def back3(self):
LoginWindow.show()
self.close()
def back2(self):
SetWindow.show()
self.close()
def on_camera_selected(self, index):
# 根据下拉列表的选择设置camera_id
if index == 0: # 本地相机
self.CAM_NUM = 0
elif index == 1: # 外置相机
self.CAM_NUM = 1
# 打开相机采集视频
def open_camera(self):
StartWindow.show()
self.close()
# 关闭相机
def close_camera(self):
self.cap.release()
self.pushButton.setEnabled(True)
self.pushButton_2.setEnabled(False)
self.timer.stop()
# 播放视频画面
def init_timer(self):
self.timer = QTimer(self)
self.timer.timeout.connect(self.show_pic)
# 显示视频图像
def show_pic(self):
ret, img = self.cap.read()
if ret:
# 人脸检测
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)
# 在人脸上画框
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cur_frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width = cur_frame.shape[:2]
pixmap = QImage(cur_frame, width, height, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(pixmap)
ratio = max(width / self.label.width(), height / self.label.height())
pixmap.setDevicePixelRatio(ratio)
self.label.setAlignment(Qt.AlignCenter)
self.label.setPixmap(pixmap)
if __name__ == '__main__':
# 连接到SQLite数据库建立数据库文件,如果文件不存在,自动建立。
conn = sqlite3.connect('F:\BaiduNetdiskDownload\pyqt\pyqt\mrsoft.db')
# 创建一个cursor游标
cursor = conn.cursor()
# 执行一条SQL语句创建user包括账号user_id与密码password只能执行一次执行一次以后会报错提示 table user已经存在所以需要用#注释掉,但第一运行时请删除注释符#
# cursor.execute('create table user (user_id varchar(30) primary key, password varchar)')
# 关闭游标
cursor.close()
# 提交事务
conn.commit()
# 关闭connection
conn.close()
# 将按钮与页面打开或者相应的功能函数连接起来,分别是注册账号按钮,注册按钮,登录按钮
app = QApplication(sys.argv)
MainWindow = MainWindow()
# 将CAM.py中的信号连接到main.py中的槽函数
MainWindow.comboBox.currentIndexChanged.connect(MainWindow.on_camera_selected)
ResetWindow = ResetWindow()
RegisterWindow = RegisterWindow()
StartWindow = StartWindow()
LoginWindow = LoginWindow()
LoginWindow.show()
SetWindow = SetWindow(MainWindow)
sys.exit(app.exec_())

@ -1,38 +0,0 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['main.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='main',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

File diff suppressed because it is too large Load Diff

@ -1,128 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RegWindow</class>
<widget class="QMainWindow" name="RegWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>650</width>
<height>500</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>20</x>
<y>40</y>
<width>631</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>631</width>
<height>500</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(174, 200, 199);</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="placeholderText">
<string>账号:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit_2">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="placeholderText">
<string>密码:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit_3">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<property name="placeholderText">
<string>确认密码</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton">
<property name="minimumSize">
<size>
<width>100</width>
<height>25</height>
</size>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>确认注册</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>返回</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\pythonProjects\pyqt\register.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_RegWindow(object):
def setupUi(self, RegWindow):
RegWindow.setObjectName("RegWindow")
RegWindow.resize(800, 600)
RegWindow.setMinimumSize(QtCore.QSize(650, 500))
self.centralwidget = QtWidgets.QWidget(RegWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(20, 40, 631, 500))
self.frame.setMinimumSize(QtCore.QSize(631, 500))
self.frame.setStyleSheet("background-color: rgb(174, 200, 199);")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.frame)
self.lineEdit.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit.setStyleSheet("background-color: rgb(255, 255, 255);")
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit, 0, QtCore.Qt.AlignHCenter)
self.lineEdit_2 = QtWidgets.QLineEdit(self.frame)
self.lineEdit_2.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit_2.setStyleSheet("background-color: rgb(255, 255, 255);")
self.lineEdit_2.setObjectName("lineEdit_2")
self.verticalLayout.addWidget(self.lineEdit_2, 0, QtCore.Qt.AlignHCenter)
self.lineEdit_3 = QtWidgets.QLineEdit(self.frame)
self.lineEdit_3.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit_3.setStyleSheet("background-color: rgb(255, 255, 255);")
self.lineEdit_3.setObjectName("lineEdit_3")
self.verticalLayout.addWidget(self.lineEdit_3, 0, QtCore.Qt.AlignHCenter)
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setMinimumSize(QtCore.QSize(100, 25))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton, 0, QtCore.Qt.AlignHCenter)
self.pushButton_2 = QtWidgets.QPushButton(self.frame)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2, 0, QtCore.Qt.AlignHCenter)
RegWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(RegWindow)
QtCore.QMetaObject.connectSlotsByName(RegWindow)
def retranslateUi(self, RegWindow):
_translate = QtCore.QCoreApplication.translate
RegWindow.setWindowTitle(_translate("RegWindow", "MainWindow"))
self.lineEdit.setPlaceholderText(_translate("RegWindow", "账号:"))
self.lineEdit_2.setPlaceholderText(_translate("RegWindow", "密码:"))
self.lineEdit_3.setPlaceholderText(_translate("RegWindow", "确认密码"))
self.pushButton.setText(_translate("RegWindow", "确认注册"))
self.pushButton_2.setText(_translate("RegWindow", "返回"))

@ -1,128 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RetWindow</class>
<widget class="QMainWindow" name="RetWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>600</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QFrame" name="frame">
<property name="geometry">
<rect>
<x>40</x>
<y>40</y>
<width>600</width>
<height>500</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>600</width>
<height>500</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(187, 200, 190);</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="placeholderText">
<string>账号:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit_2">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="placeholderText">
<string>密码:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QLineEdit" name="lineEdit_3">
<property name="minimumSize">
<size>
<width>250</width>
<height>25</height>
</size>
</property>
<property name="placeholderText">
<string>确认密码:</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton">
<property name="minimumSize">
<size>
<width>80</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>密码重置</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignHCenter">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>返回</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -1,63 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'D:\pythonProjects\pyqt\reset.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_RetWindow(object):
def setupUi(self, RetWindow):
RetWindow.setObjectName("RetWindow")
RetWindow.resize(800, 600)
RetWindow.setMinimumSize(QtCore.QSize(600, 0))
self.centralwidget = QtWidgets.QWidget(RetWindow)
self.centralwidget.setObjectName("centralwidget")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(40, 40, 600, 500))
self.frame.setMinimumSize(QtCore.QSize(600, 500))
self.frame.setStyleSheet("background-color: rgb(187, 200, 190);")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.lineEdit = QtWidgets.QLineEdit(self.frame)
self.lineEdit.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit, 0, QtCore.Qt.AlignHCenter)
self.lineEdit_2 = QtWidgets.QLineEdit(self.frame)
self.lineEdit_2.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit_2.setObjectName("lineEdit_2")
self.verticalLayout.addWidget(self.lineEdit_2, 0, QtCore.Qt.AlignHCenter)
self.lineEdit_3 = QtWidgets.QLineEdit(self.frame)
self.lineEdit_3.setMinimumSize(QtCore.QSize(250, 25))
self.lineEdit_3.setObjectName("lineEdit_3")
self.verticalLayout.addWidget(self.lineEdit_3, 0, QtCore.Qt.AlignHCenter)
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setMinimumSize(QtCore.QSize(80, 25))
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton, 0, QtCore.Qt.AlignHCenter)
self.pushButton_2 = QtWidgets.QPushButton(self.frame)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2, 0, QtCore.Qt.AlignHCenter)
RetWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(RetWindow)
QtCore.QMetaObject.connectSlotsByName(RetWindow)
def retranslateUi(self, RetWindow):
_translate = QtCore.QCoreApplication.translate
RetWindow.setWindowTitle(_translate("RetWindow", "MainWindow"))
self.lineEdit.setPlaceholderText(_translate("RetWindow", "账号:"))
self.lineEdit_2.setPlaceholderText(_translate("RetWindow", "密码:"))
self.lineEdit_3.setPlaceholderText(_translate("RetWindow", "确认密码:"))
self.pushButton.setText(_translate("RetWindow", "密码重置"))
self.pushButton_2.setText(_translate("RetWindow", "返回"))

@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'set.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1045, 640)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.fontButton = QtWidgets.QPushButton(self.centralwidget)
self.fontButton.setGeometry(QtCore.QRect(390, 150, 91, 31))
self.fontButton.setObjectName("fontButton")
self.background = QtWidgets.QPushButton(self.centralwidget)
self.background.setGeometry(QtCore.QRect(390, 210, 91, 31))
self.background.setObjectName("pushButton_2")
self.backButton = QtWidgets.QPushButton(self.centralwidget)
self.backButton.setGeometry(QtCore.QRect(390, 320, 91, 31))
self.backButton.setObjectName("pushButton_3")
self.videoButton = QtWidgets.QPushButton(self.centralwidget)
self.videoButton.setGeometry(QtCore.QRect(390, 270, 91, 31))
self.videoButton.setObjectName("pushButton_4")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.fontButton.setText(_translate("MainWindow", "字体"))
self.background.setText(_translate("MainWindow", "背景图片"))
self.backButton.setText(_translate("MainWindow", "退回"))
self.videoButton.setText(_translate("MainWindow", "本地视频"))

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1045</width>
<height>640</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>390</x>
<y>150</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>字体</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>390</x>
<y>210</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>背景图片</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>390</x>
<y>320</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>退回</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_4">
<property name="geometry">
<rect>
<x>390</x>
<y>270</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>本地视频</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -1,29 +0,0 @@
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
image_path = r"F:\photos\p2.jpg"
image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
# 使用 Sobel 算子进行边缘检测
sobel_x = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
sobel_y = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
# 计算梯度幅值
sobel_magnitude = np.sqrt(sobel_x**2 + sobel_y**2)
# 将结果转换为 8 位无符号整数
sobel_magnitude = np.uint8(sobel_magnitude)
# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('Original Image')
plt.imshow(image, cmap='gray')
plt.subplot(1, 2, 2)
plt.title('Sobel Edge Detection')
plt.imshow(sobel_magnitude, cmap='gray')
plt.show()

@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'start.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(698, 640)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(190, 160, 71, 20))
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(190, 200, 71, 21))
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(190, 250, 71, 31))
self.label_3.setObjectName("label_3")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(280, 160, 161, 20))
self.lineEdit.setObjectName("lineEdit")
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_2.setGeometry(QtCore.QRect(280, 200, 161, 20))
self.lineEdit_2.setObjectName("lineEdit_2")
self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_3.setGeometry(QtCore.QRect(280, 260, 161, 20))
self.lineEdit_3.setObjectName("lineEdit_3")
self.startButton = QtWidgets.QPushButton(self.centralwidget)
self.startButton.setGeometry(QtCore.QRect(200, 320, 91, 31))
self.startButton.setObjectName("startButton")
self.closeButton = QtWidgets.QPushButton(self.centralwidget)
self.closeButton.setGeometry(QtCore.QRect(360, 320, 91, 31))
self.closeButton.setObjectName("closeButton")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "开始时间:"))
self.label_2.setText(_translate("MainWindow", "结束时间:"))
self.label_3.setText(_translate("MainWindow", "学习比例:"))
self.startButton.setText(_translate("MainWindow", "开始学习"))
self.closeButton.setText(_translate("MainWindow", "取消"))

@ -1,116 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>698</width>
<height>640</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>190</x>
<y>160</y>
<width>71</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>开始时间:</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>190</x>
<y>200</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>结束时间:</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>190</x>
<y>250</y>
<width>71</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>学习时间:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>280</x>
<y>160</y>
<width>161</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_2">
<property name="geometry">
<rect>
<x>280</x>
<y>200</y>
<width>161</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_3">
<property name="geometry">
<rect>
<x>280</x>
<y>260</y>
<width>161</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="startButton">
<property name="geometry">
<rect>
<x>200</x>
<y>320</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>开始学习</string>
</property>
</widget>
<widget class="QPushButton" name="closeButton">
<property name="geometry">
<rect>
<x>360</x>
<y>320</y>
<width>91</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>取消</string>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

@ -1,25 +0,0 @@
import sqlite3
# 连接到SQLite数据库
conn = sqlite3.connect('mrsoft.db')
# 创建一个游标
cursor = conn.cursor()
# 查询所有用户账户
cursor.execute('SELECT * FROM user')
# 获取所有结果
users = cursor.fetchall()
# 检查是否有用户
if users:
print("已创建的账户如下:")
for user in users:
print(f"User ID: {user[0]}, Password: {user[1]}")
else:
print("没有找到任何账户。")
# 关闭游标和连接
cursor.close()
conn.close()

@ -1,82 +0,0 @@
import sys
from PyQt5.QtWidgets import QMessageBox, QFileDialog, QLineEdit
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from CAM import Ui_MainWindow
import cv2
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
# UI界面
self.setupUi(self)
self.CAM_NUM = 0
self.cap = cv2.VideoCapture()
self.background()
# 在label中播放视频
self.init_timer()
# 加载人脸检测分类器
self.face_cascade = cv2.CascadeClassifier(r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_default.xml")
def background(self):
self.pushButton.clicked.connect(self.open_camera)
self.pushButton_2.clicked.connect(self.close_camera)
self.pushButton.setEnabled(True)
self.pushButton_2.setEnabled(False)
# 打开相机采集视频
def open_camera(self):
index = self.comboBox.currentIndex()
self.CAM_NUM = index
flag = self.cap.open(self.CAM_NUM)
if flag is False:
QMessageBox.information(self, "警告", "该设备未正常连接", QMessageBox.Ok)
else:
self.label.setEnabled(True)
self.pushButton.setEnabled(False)
self.pushButton_2.setEnabled(True)
self.timer.start()
print("beginning")
# 关闭相机
def close_camera(self):
self.cap.release()
self.pushButton.setEnabled(True)
self.pushButton_2.setEnabled(False)
self.timer.stop()
# 播放视频画面
def init_timer(self):
self.timer = QTimer(self)
self.timer.timeout.connect(self.show_pic)
# 显示视频图像
def show_pic(self):
ret, img = self.cap.read()
if ret:
# 人脸检测
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5)
# 在人脸上画框
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cur_frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width = cur_frame.shape[:2]
pixmap = QImage(cur_frame, width, height, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(pixmap)
ratio = max(width / self.label.width(), height / self.label.height())
pixmap.setDevicePixelRatio(ratio)
self.label.setAlignment(Qt.AlignCenter)
self.label.setPixmap(pixmap)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

@ -1,69 +0,0 @@
import cv2
import time
import os
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, monitor_time):
cv2.namedWindow(window_name)
cap = cv2.VideoCapture(camera_id)
pathf = r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml"
# 载入人脸检测器,眼睛检测器,微笑检测器
face_cascade = cv2.CascadeClassifier(pathf)
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = monitor_time
create_training_directory(path_name)
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
if len(faces) > 0:
if not countdown_started:
countdown_started = True
start_time = time.time()
remaining_time = monitor_time - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# Display countdown timer
cv2.putText(frame, f'Time Left: {remaining_time}s', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
else:
# If no faces detected, keep countdown paused
if countdown_started:
remaining_time = max(0, remaining_time)
cv2.imshow(window_name, frame)
if remaining_time <= 0 or (cv2.waitKey(10) & 0xFF == ord('q')):
break
cap.release()
cv2.destroyAllWindows()
print('Finished capturing faces.')
if __name__ == '__main__':
monitor_time = int(input('Enter monitoring time in seconds: '))
print('Starting face capture...')
capture_faces_with_timer('FaceCapture', 0, 'training_data_faces/', 1000, monitor_time)

@ -1,96 +0,0 @@
import cv2
import time
import os
from datetime import datetime, timedelta
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
def is_within_time_range(start_time_str, end_time_str):
"""判断当前时间是否在指定的时间范围内"""
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
def calculate_required_time(start_time_str, end_time_str, percentage):
"""计算所需的最少时间(分钟)"""
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str, end_time_str):
cv2.namedWindow(window_name)
cap = cv2.VideoCapture(camera_id)
face_cascade = cv2.CascadeClassifier(
r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml")
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
create_training_directory(path_name)
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示倒计时
cv2.putText(frame, f'Time Left: {remaining_time // 60}m {remaining_time % 60}s', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
if remaining_time <= 0:
break
else:
countdown_started = False
remaining_time = required_time * 60
cv2.putText(frame, 'Outside of specified time range', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
print('Finished capturing faces.')
if __name__ == '__main__':
start_time_str = input("Enter the start time (e.g., 17:00 for 5pm): ")
end_time_str = input("Enter the end time (e.g., 18:00 for 6pm): ")
percentage = int(input("Enter the minimum percentage of the time to monitor (0-100): "))
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
print(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', 0, 'training_data_faces/', 1000, required_time, start_time_str,
end_time_str)

@ -1,94 +0,0 @@
import cv2
import time
import os
from datetime import datetime, timedelta
def main(start_time_str, end_time_str, percentage):
# 创建训练数据目录
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
# 判断当前时间是否在指定的时间范围内
def is_within_time_range(start_time_str, end_time_str):
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
# 计算所需的最少时间(分钟)
def calculate_required_time(start_time_str, end_time_str, percentage):
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
# 捕获人脸并计时
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str, end_time_str):
cv2.namedWindow(window_name)
cap = cv2.VideoCapture(camera_id)
face_cascade = cv2.CascadeClassifier(
r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml")
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
create_training_directory(path_name)
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示倒计时
cv2.putText(frame, f'Time Left: {remaining_time // 60}m {remaining_time % 60}s', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
if remaining_time <= 0:
break
else:
countdown_started = False
remaining_time = required_time * 60
cv2.putText(frame, 'Outside of specified time range', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
print('Finished capturing faces.')
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
print(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', 0, 'training_data_faces/', 1000, required_time, start_time_str, end_time_str)
if __name__ == '__main__':
start_time_str = input("Enter the start time (e.g., 17:00 for 5pm): ")
end_time_str = input("Enter the end time (e.g., 18:00 for 6pm): ")
percentage = int(input("Enter the minimum percentage of the time to monitor (0-100): "))
main(start_time_str, end_time_str, percentage)

@ -1,199 +0,0 @@
import cv2
import time
import os
from datetime import datetime, timedelta
import logging
import yaml
from PIL import Image, ImageFont, ImageDraw
import numpy as np # 添加导入
# 初始化日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
def is_within_time_range(start_time_str, end_time_str):
"""判断当前时间是否在指定的时间范围内"""
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
def calculate_required_time(start_time_str, end_time_str, percentage):
"""计算所需的最少时间(分钟)"""
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
def load_config(config_path='config.yaml'):
base_dir = os.path.dirname(os.path.abspath(__file__)) # 获取脚本所在目录
config_full_path = os.path.join(base_dir, config_path) # 构建配置文件的绝对路径
with open(config_full_path, 'r', encoding='utf-8') as file:
return yaml.safe_load(file)
def put_chinese_text(frame, text, position, font_path, font_size, color, font_cache={}):
"""
使用 PIL 绘制中文文本并转换回 OpenCV 图像
"""
# 检查字体文件是否存在
if not os.path.exists(font_path):
logging.error(f"字体文件未找到: {font_path}")
return frame
# 使用缓存的字体对象
if font_path in font_cache:
font = font_cache[font_path]
else:
try:
font = ImageFont.truetype(font_path, font_size)
font_cache[font_path] = font
except Exception as e:
logging.error(f"加载字体失败: {e}")
return frame
# 将 OpenCV 的 BGR 图像转换为 RGB
img_pil = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
# 绘制文本
draw.text(position, text, font=font, fill=color)
# 将 PIL 图像转换回 OpenCV 的 BGR 图像
frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
return frame
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str, end_time_str, font_path):
cv2.namedWindow(window_name)
try:
cap = cv2.VideoCapture(camera_id) # 直接初始化 VideoCapture
face_cascade = cv2.CascadeClassifier(
config['face_cascade_path']) # 使用配置文件中的路径
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
pause_time = None # 初始化暂停时间
create_training_directory(path_name)
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
if pause_time is not None:
# 调整 start_time 以考虑暂停的时长
start_time += time.time() - pause_time
else:
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示剩余学习时长
text = f'剩余学习时长: {remaining_time // 60}m {remaining_time % 60}s'
frame = put_chinese_text(
frame,
text,
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
if remaining_time <= 0:
break
else:
# 如果计时器已经暂停,继续显示剩余时间
text = f'剩余学习时长: {remaining_time // 60}m {remaining_time % 60}s'
frame = put_chinese_text(
frame,
text,
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
else:
if countdown_started:
logging.info('未检测到人脸,暂停计时。')
countdown_started = False
pause_time = time.time() # 记录暂停时间
# 显示外部时间范围提示
frame = put_chinese_text(
frame,
'不在指定的时间范围内',
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
except Exception as e:
logging.error(f"发生错误: {e}")
finally:
cap.release() # 确保摄像头资源被释放
cv2.destroyAllWindows()
logging.info('人脸捕捉完成。')
def get_time_input(prompt):
while True:
time_str = input(prompt)
try:
datetime.strptime(time_str, "%H:%M")
return time_str
except ValueError:
print("时间格式错误,请输入如 17:00 这样的24小时制时间。")
if __name__ == '__main__':
config = load_config()
start_time_str = get_time_input("Enter the start time (e.g., 17:00 for 5pm): ")
end_time_str = get_time_input("Enter the end time (e.g., 18:00 for 6pm): ")
while True:
try:
percentage = int(input("Enter the minimum percentage of the time to monitor (0-100): "))
if 0 <= percentage <= 100:
break
else:
print("请输入 0 到 100 之间的整数。")
except ValueError:
print("请输入有效的整数。")
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
# 指定中文字体的路径
font_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fonts', 'SimHei.ttf') # 确保路径正确
logging.info(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', config['camera_id'], config['path_name'], 1000, required_time, start_time_str,
end_time_str, font_path)

@ -1,37 +0,0 @@
import os
import csv
from PIL import Image
def pgm_to_csv(pgm_dir, csv_file):
# 初始化CSV文件并写入头部
with open(csv_file, 'w', newline='') as file:
writer = csv.writer(file)
# 假设图像大小为32x30这里可根据实际情况调整
pixel_count = 960 # 32 * 30
# 写入CSV头部其中filename是文件名列后面是像素值列
header = ['filename'] + [f'pixel_{i}' for i in range(pixel_count)]
writer.writerow(header)
# 遍历文件夹中的所有PGM文件
for filename in os.listdir(pgm_dir):
if os.path.isdir(os.path.join(pgm_dir, filename)): # 仅处理文件夹
for people in os.listdir(os.path.join(pgm_dir, filename)):
if people.endswith('.pgm'):
img_path = os.path.join(pgm_dir, filename, people)
# 读取PGM图像
with Image.open(img_path) as img:
img = img.convert('L') # 转换为灰度图像
pixels = list(img.getdata())
# 将像素值写入CSV文件
with open(csv_file, 'a', newline='') as file:
writer = csv.writer(file)
# 在每一行前添加文件名
writer.writerow([people] + pixels) # 写入文件名和像素值
pgm_dir = 'F:\pr\orange' # PGM文件所在的文件夹路径
csv_file = 'F:\pr\change\change.csv' # 输出CSV文件的路径
pgm_to_csv(pgm_dir, csv_file)

@ -1,42 +0,0 @@
import os
import csv
from PIL import Image
def png_to_pgm_and_csv(png_dir, pgm_dir, csv_file):
# 初始化CSV文件并写入头部
with open(csv_file, 'w', newline='') as file:
writer = csv.writer(file)
# 假设图像大小为32x30写入CSV头部
writer.writerow(['pixel_values'] + list(range(0, 4*3)) + ['filename'])
# 遍历文件夹中的所有PNG文件
for filename in os.listdir(png_dir):
if filename.endswith('.png'):
img_path = os.path.join(png_dir, filename)
# 读取PNG图像
with Image.open(img_path) as img:
img = img.convert('L') # 转换为灰度图像
# 调整图像大小为32x30
img = img.resize((4, 3), resample=Image.Resampling.LANCZOS)
# 构造PGM文件路径
pgm_filename = filename.replace('.png', '.pgm')
pgm_path = os.path.join(pgm_dir, pgm_filename)
# 保存为PGM文件
img.save(pgm_path, format='PPM') # 保存为PGM格式PPM是PGM的一种
# 获取像素值
pixels = list(img.getdata())
# 将像素值写入CSV文件
with open(csv_file, 'a', newline='') as file:
writer = csv.writer(file)
# 确保每一行有962个值960个像素值 + 1个文件名
writer.writerow(pixels + [filename])
# 使用示例
png_dir = 'F:\\self' # PNG文件所在的文件夹路径
pgm_dir = 'F:\\self2\\43' # 输出PGM文件的文件夹路径
csv_file = 'F:\\self3\\43.csv' # 输出CSV文件的路径
# 确保PGM文件夹存在
os.makedirs(pgm_dir, exist_ok=True)
png_to_pgm_and_csv(png_dir, pgm_dir, csv_file)

@ -1,199 +0,0 @@
import cv2
import time
import os
from datetime import datetime, timedelta
import logging
import yaml
from PIL import Image, ImageFont, ImageDraw
import numpy as np # 添加导入
# 初始化日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
def is_within_time_range(start_time_str, end_time_str):
"""判断当前时间是否在指定的时间范围内"""
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
def calculate_required_time(start_time_str, end_time_str, percentage):
"""计算所需的最少时间(分钟)"""
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
def load_config(config_path='config.yaml'):
base_dir = os.path.dirname(os.path.abspath(__file__)) # 获取脚本所在目录
config_full_path = os.path.join(base_dir, config_path) # 构建配置文件的绝对路径
with open(config_full_path, 'r', encoding='utf-8') as file:
return yaml.safe_load(file)
def put_chinese_text(frame, text, position, font_path, font_size, color, font_cache={}):
"""
使用 PIL 绘制中文文本并转换回 OpenCV 图像
"""
# 检查字体文件是否存在
if not os.path.exists(font_path):
logging.error(f"字体文件未找到: {font_path}")
return frame
# 使用缓存的字体对象
if font_path in font_cache:
font = font_cache[font_path]
else:
try:
font = ImageFont.truetype(font_path, font_size)
font_cache[font_path] = font
except Exception as e:
logging.error(f"加载字体失败: {e}")
return frame
# 将 OpenCV 的 BGR 图像转换为 RGB
img_pil = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
# 绘制文本
draw.text(position, text, font=font, fill=color)
# 将 PIL 图像转换回 OpenCV 的 BGR 图像
frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
return frame
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str, end_time_str, font_path):
cv2.namedWindow(window_name)
try:
cap = cv2.VideoCapture(camera_id) # 直接初始化 VideoCapture
face_cascade = cv2.CascadeClassifier(
config['face_cascade_path']) # 使用配置文件中的路径
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
pause_time = None # 初始化暂停时间
create_training_directory(path_name)
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
if pause_time is not None:
# 调整 start_time 以考虑暂停的时长
start_time += time.time() - pause_time
else:
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示剩余学习时长
text = f'剩余学习时长: {remaining_time // 60}m {remaining_time % 60}s'
frame = put_chinese_text(
frame,
text,
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
if remaining_time <= 0:
break
else:
# 如果计时器已经暂停,继续显示剩余时间
text = f'剩余学习时长: {remaining_time // 60}m {remaining_time % 60}s'
frame = put_chinese_text(
frame,
text,
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
else:
if countdown_started:
logging.info('未检测到人脸,暂停计时。')
countdown_started = False
pause_time = time.time() # 记录暂停时间
# 显示外部时间范围提示
frame = put_chinese_text(
frame,
'不在指定的时间范围内',
(10, 30),
font_path,
30, # 字体大小
(0, 0, 255) # 颜色
)
cv2.imshow(window_name, frame)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
except Exception as e:
logging.error(f"发生错误: {e}")
finally:
cap.release() # 确保摄像头资源被释放
cv2.destroyAllWindows()
logging.info('人脸捕捉完成。')
def get_time_input(prompt):
while True:
time_str = input(prompt)
try:
datetime.strptime(time_str, "%H:%M")
return time_str
except ValueError:
print("时间格式错误,请输入如 17:00 这样的24小时制时间。")
if __name__ == '__main__':
config = load_config()
start_time_str = get_time_input("Enter the start time (e.g., 17:00 for 5pm): ")
end_time_str = get_time_input("Enter the end time (e.g., 18:00 for 6pm): ")
while True:
try:
percentage = int(input("Enter the minimum percentage of the time to monitor (0-100): "))
if 0 <= percentage <= 100:
break
else:
print("请输入 0 到 100 之间的整数。")
except ValueError:
print("请输入有效的整数。")
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
# 指定中文字体的路径
font_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'fonts', 'SimHei.ttf') # 确保路径正确
logging.info(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', config['camera_id'], config['path_name'], 1000, required_time, start_time_str,
end_time_str, font_path)

@ -1,21 +0,0 @@
# 示例代码:使用数据增强
from sklearn.utils import resample
import pandas as pd
# 加载你自己的数据集
data = pd.read_csv("F:\机器学习\\28-26.csv")
# 假设 `data` 是包含所有类别的数据集
# `self_data` 是 `self` 类别的数据
self_data = data[data['a961'] == 'self']
# 使用 resample 增加样本数量
self_data_upsampled = resample(self_data,
replace=True, # 放回采样
n_samples=20, # 增加到10个样本
random_state=42) # 设置随机种子
# 将增强后的数据合并回原始数据集
data_upsampled = pd.concat([data[data['a961'] != 'self'], self_data_upsampled])
# 查看每类样本的数量
class_counts = data_upsampled['a961'].value_counts()
print(class_counts)

@ -1,20 +0,0 @@
import pandas as pd
from scipy.io import arff
# 读取 CSV 文件
data = pd.read_csv('F:\test\test2.csv')
# 保存为 ARFF 文件
with open('F:\test\test2.arff', 'w') as f:
# 写入 @relation
f.write("@RELATION your_relation_name\n\n")
# 写入 @attribute
for column in data.columns:
f.write(f"@ATTRIBUTE {column} STRING\n") # 可以根据需要调整属性类型
f.write("\n@DATA\n")
# 写入数据
for index, row in data.iterrows():
f.write(','.join(map(str, row.values)) + '\n')

@ -1,152 +0,0 @@
import os
import sqlite3
import time
from datetime import datetime
import cv2
from PyQt5.QtWidgets import QMainWindow
class StartWindow(QMainWindow, start_ui):
def __init__(self):
super(StartWindow, self).__init__()
self.setupUi(self)
self.startButton.clicked.connect(self.main)
self.closeButton.clicked.connect(self.back2)
def back2(self):
self.close()
MainWindow.show() # 请确保 MainWindow 已经被实例化并可以显示
def main(self): # 方法参数改为 self
# 获取输入值
start_time_str = self.lineEdit.text()
end_time_str = self.lineEdit_2.text()
percentage = float(self.lineEdit_3.text()) # 转换为浮点数
# 创建训练数据目录
def create_training_directory(path_name):
if not os.path.exists(path_name):
os.makedirs(path_name)
# 判断当前时间是否在指定的时间范围内
def is_within_time_range(start_time_str, end_time_str):
now = datetime.now().time()
start_time = datetime.strptime(start_time_str, "%H:%M").time() # 24小时制
end_time = datetime.strptime(end_time_str, "%H:%M").time()
return start_time <= now <= end_time
# 计算所需的最少时间(分钟)
def calculate_required_time(start_time_str, end_time_str, percentage):
start_time = datetime.strptime(start_time_str, "%H:%M")
end_time = datetime.strptime(end_time_str, "%H:%M")
total_time = (end_time - start_time).total_seconds() / 60 # 总时长(分钟)
return total_time * (percentage / 100)
# 捕获人脸并计时
def capture_faces_with_timer(window_name, camera_id, path_name, max_num, required_time, start_time_str, end_time_str):
cv2.namedWindow(window_name)
cap = cv2.VideoCapture(camera_id)
face_cascade = cv2.CascadeClassifier(
r"C:\Users\a'su's\AppData\Local\Programs\Python\Python310\Lib\site-packages\cv2\data\haarcascade_frontalface_alt.xml"
)
color = (0, 255, 0)
face_count = 0
countdown_started = False
remaining_time = required_time * 60 # 转换为秒
create_training_directory(path_name)
# 视频存储设置
video_name = 'captured_video.mp4'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(video_name, fourcc, 20.0, (640, 480))
while cap.isOpened() and face_count < max_num:
ret, frame = cap.read()
if not ret:
break
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray_frame, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 检查当前时间是否在指定的时间范围内
if is_within_time_range(start_time_str, end_time_str):
if len(faces) > 0:
if not countdown_started:
countdown_started = True
start_time = time.time()
remaining_time = required_time * 60 - int(time.time() - start_time)
for (x, y, w, h) in faces:
face_image = frame[y:y + h, x:x + w]
image_name = os.path.join(path_name, f'face_{face_count}.jpg')
cv2.imwrite(image_name, face_image)
face_count += 1
cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
# 显示倒计时
cv2.putText(frame, f'Time Left: {remaining_time // 60}m {remaining_time % 60}s', (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
if remaining_time <= 0:
break
else:
countdown_started = False
remaining_time = required_time * 60
cv2.putText(frame, 'Outside of specified time range', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1,
(0, 0, 255), 2)
cv2.imshow(window_name, frame)
out.write(frame) # 写入视频帧
if cv2.waitKey(10) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
print('Finished capturing faces and video.')
# 将视频写入数据库
self.save_video_to_db(video_name)
required_time = calculate_required_time(start_time_str, end_time_str, percentage)
print(f'Starting face capture, will monitor for at least {required_time} minutes...')
capture_faces_with_timer('FaceCapture', 0, 'training_data_faces/', 1000, required_time, start_time_str, end_time_str)
def save_video_to_db(self, video_file_path):
db_path = r'F:\BaiduNetdiskDownload\pyqt\pyqt\user.db'
# 连接到SQLite数据库
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# 创建表(如果尚未创建)
cursor.execute('''
CREATE TABLE IF NOT EXISTS videos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
data BLOB NOT NULL
)
''')
# 读取视频文件
with open(video_file_path, 'rb') as video_file:
video_data = video_file.read()
# 获取文件名
video_name = video_file_path.split('\\')[-1] # Windows路径分隔符
# 插入数据
cursor.execute('''
INSERT INTO videos (name, data) VALUES (?, ?)
''', (video_name, video_data))
# 提交更改并关闭连接
conn.commit()
conn.close()
print(f"视频 '{video_name}' 已成功插入到数据库中。")
# 请确保 MainWindow 已经被实例化并可以显示
# 例如: MainWindow = QMainWindow()

@ -1 +1 @@
Subproject commit fe6b02d92d839f094d2e8a0e9c71b8c30b15c7cb
Subproject commit ed300fd741015b5fe0411443cc4f4527b6421290

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save