Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,80 @@
[![CodeQL](https://github.com/vladiant/CascadeClassifier/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/vladiant/CascadeClassifier/actions/workflows/codeql-analysis.yml)
## About

Haar Cascade Classifier implementation, tools and docs
Haar Cascade Classifier implementation, tools and docs.

This repository revives the classic Viola–Jones cascade trainer that used
to ship with OpenCV (the legacy `opencv_traincascade` program plus its
companion utilities) so it can keep building against modern OpenCV
releases. It contains:

- a stand-alone trainer library and CLI (`traincascade/`) that can train
a multi-stage cascade with Haar, LBP or HOG features;
- the original sample-preparation, annotation, detection and
visualisation utilities (`tools/`);
- documentation on the relevant command-line flags (`docs/`).

## Repository layout

| Path | Contents |
| ---- | -------- |
| `traincascade/` | Cascade trainer library (`lib/`), `traincascade` executable and unit tests (`test/`). |
| `traincascade/lib/include/` | Public headers, fully Doxygen-annotated. |
| `traincascade/lib/src/` | Implementation; the `o_*.cpp` files are extracted from OpenCV's legacy ML module and retain their original copyright headers. |
| `tools/createsamples/` | `opencv_createsamples` — generates `.vec` files of positives. |
| `tools/annotation/` | `opencv_annotation` — interactive bounding-box tool. |
| `tools/detection/Cpp/` | C++ sample that runs a trained cascade on an image. |
| `tools/detection/Python/`| Equivalent Python detection sample. |
| `tools/visualisation/` | `opencv_visualisation` — visualises the stages of a trained cascade. |
| `docs/` | Markdown documentation of CLI parameters. |
| `external/` | CMake helpers (e.g. `FindOpenCV.cmake`). |

## Building

The project uses CMake (>= 3.10) and depends on OpenCV (core, imgproc,
imgcodecs, ml, objdetect, highgui).

```sh
cmake -S . -B build -G Ninja
cmake --build build
```

A coverage-enabled build is also available under `build-coverage/`.

## Architecture overview

The trainer is structured as a small hierarchy of legacy OpenCV ML
classes plus cascade-specific subclasses:

```
CvStatModel
└── CvDTree (CART decision tree, o_cvdtree.h)
└── CvBoostTree (boosting weak learner, o_cvboostree.h)
└── CvCascadeBoostTree (cascade-aware weak tree)

CvStatModel
└── CvBoost (AdaBoost ensemble, o_cvboost.h)
└── CvCascadeBoost (single cascade stage, boost.h)

CvCascadeClassifier (multi-stage trainer, cascadeclassifier.h)
```

Feature evaluation is decoupled through `CvFeatureEvaluator`
(`traincascade_features.h`) with concrete subclasses
`CvHaarEvaluator`, `CvLBPEvaluator` and `CvHOGEvaluator`. Sample
streaming is handled by `CvCascadeImageReader` (`imagestorage.h`).
Refer to the Doxygen comments in `traincascade/lib/include/` for class-
and method-level documentation.

## Documentation

* [Cascade trainer parameters](docs/traincascade_params.md)
* [createsamples parameters](docs/createsamples_params.md)
* [Useful links and references](docs/links.md)
* [Test-suite README](traincascade/test/README.md)

## License

See [LICENSE](LICENSE). Files derived from OpenCV's legacy ML module
(`traincascade/lib/src/o_*.cpp` and the tools under `tools/`) keep their
original Intel / OpenCV Foundation copyright headers.
34 changes: 33 additions & 1 deletion traincascade/lib/include/HOGfeatures.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/**
* @file HOGfeatures.h
* @brief Block-cell Histogram-of-Oriented-Gradients features.
*
* Each HOG feature here is a 2x2 block of cells; per cell the evaluator
* accumulates @c N_BINS oriented-gradient histograms, then L1-normalizes
* the four per-cell histograms by the block sum. The descriptor length
* therefore is @c N_BINS*N_CELLS = 36 floats, exposed by mapping the
* boosting variable index back to (featureIdx, componentIdx).
*/

#ifndef _OPENCV_HOGFEATURES_H_
#define _OPENCV_HOGFEATURES_H_

Expand All @@ -6,15 +17,29 @@
//#define TEST_INTHIST_BUILD
//#define TEST_FEAT_CALC

/// Number of orientation bins per cell histogram.
#define N_BINS 9
/// Number of cells per block (2x2 grid).
#define N_CELLS 4

#define HOGF_NAME "HOGFeatureParams"

/// HOG-specific parameter struct; mostly delegates to @ref CvFeatureParams
/// after setting @c featSize = N_BINS*N_CELLS = 36.
struct CvHOGFeatureParams : public CvFeatureParams
{
CvHOGFeatureParams();
};

/**
* @brief HOG feature evaluator for cascade training.
*
* Stores @c N_BINS integral-histogram channels (@c hist) and an integral
* image of cell magnitudes (@c normSum) per sample. Each abstract
* "variable" the boosting trainer asks for is decoded as
* @c (varIdx / 36, varIdx % 36) into (feature, component) so a single
* feature contributes 36 boosting variables.
*/
class CvHOGEvaluator : public CvFeatureEvaluator
{
public:
Expand All @@ -25,25 +50,32 @@ class CvHOGEvaluator : public CvFeatureEvaluator
float operator()(int varIdx, int sampleIdx) const override;
void writeFeatures( cv::FileStorage &fs, const cv::Mat& featureMap ) const override;
protected:
/// Enumerate every valid 2x2-block HOG feature for the current window.
void generateFeatures() override;
/// Build the @p nbins integral histograms plus the L1-normalization
/// integral image @p norm from the input gray image @p img.
virtual void integralHistogram(const cv::Mat &img, std::vector<cv::Mat> &histogram, cv::Mat &norm, int nbins) const;

/// Geometry of a single HOG feature: a 2x2 grid of cell rectangles.
class Feature
{
public:
Feature();
Feature( int offset, int x, int y, int cellW, int cellH );
/// Read one descriptor component (@p featComponent in [0, N_BINS*N_CELLS)).
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

/// Precomputed corner offsets per cell into the integral histograms.
struct
{
int p0, p1, p2, p3;
} fastRect[N_CELLS]{};
};
std::vector<Feature> features;
std::vector<Feature> features; ///< Generated HOG-feature catalog.

cv::Mat normSum; //for normalization calculation (L1 or L2)
std::vector<cv::Mat> hist;
Expand Down
67 changes: 61 additions & 6 deletions traincascade/lib/include/boost.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
/**
* @file boost.h
* @brief Cascade-stage boosting classifier and its parameter struct.
*
* Hosts the two cascade-specific subclasses derived from the legacy
* @c CvBoost / @c CvBoostParams machinery (see the @c o_cvboost*.h family):
* - @ref CvCascadeBoostParams adds the cascade-only knobs @c minHitRate
* and @c maxFalseAlarm to the boosting parameter set.
* - @ref CvCascadeBoost overrides the boosting training loop so it stops
* when those rates are met and exposes the per-stage decision threshold
* used at runtime.
*/

#ifndef _OPENCV_BOOST_H_
#define _OPENCV_BOOST_H_

Expand All @@ -10,44 +23,86 @@
#include "traincascade_features.h"


// CvCascadeBoostParams <- CvBoostParams <- CvCascadeBoostParams
/**
* @brief Parameters for a single cascade stage trained as a boosted ensemble.
*
* Extends @ref CvBoostParams (boost type, weak-count cap, weight-trim
* threshold, weak-tree max depth) with two cascade-specific targets:
* - @c minHitRate — minimum fraction of positives the stage must keep.
* - @c maxFalseAlarm — maximum fraction of negatives allowed through.
*
* Training stops as soon as both rates are satisfied, even if @c weak_count
* weak learners have not been added yet.
*/
struct CvCascadeBoostParams : CvBoostParams
{
float minHitRate;
float maxFalseAlarm;
float minHitRate; ///< Lower bound on the per-stage true-positive rate.
float maxFalseAlarm; ///< Upper bound on the per-stage false-positive rate.

CvCascadeBoostParams();
CvCascadeBoostParams( int _boostType, float _minHitRate, float _maxFalseAlarm,
double _weightTrimRate, int _maxDepth, int _maxWeakCount );
virtual ~CvCascadeBoostParams() {}
/// Persist parameters to an XML/YAML node (used by @c params.xml).
void write( cv::FileStorage &fs ) const;
/// Restore parameters from a node; returns @c false on malformed input.
bool read( const cv::FileNode &node );
virtual void printDefaults() const;
virtual void printAttrs() const;
/// Parse one @c -name value command-line attribute.
virtual bool scanAttr( const std::string prmName, const std::string val);
};

// CvCascadeBoost <- CvBoost <- CvStatModel
/**
* @brief Boosted ensemble representing a single cascade stage.
*
* Built on top of OpenCV's legacy @c CvBoost; the cascade trainer adds
* weak learners until either @c minHitRate / @c maxFalseAlarm are reached
* or the configured weak-count cap is hit. After training the stage stores
* a real-valued decision @c threshold tuned so the desired hit rate is met
* on the working positive set.
*
* At runtime the stage accepts a sample iff the sum of weak responses
* exceeds @c threshold.
*/
class CvCascadeBoost : public CvBoost
{
public:
/**
* @brief Train one cascade stage on the current working sample set.
* @param _featureEvaluator Feature evaluator already populated with images.
* @param _numSamples Total number of samples (positives + negatives).
* @param _precalcValBufSize Buffer size (MB) for cached feature values.
* @param _precalcIdxBufSize Buffer size (MB) for cached sorted indices.
* @param _params Boosting + cascade rate targets.
* @return @c true once both rate targets are satisfied.
*/
bool train( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples, int _precalcValBufSize, int _precalcIdxBufSize,
const CvCascadeBoostParams& _params=CvCascadeBoostParams() );
/// Evaluate the stage on sample @p sampleIdx. When @p returnSum is true
/// returns the raw weak-response sum, otherwise the binary 0/1 decision.
float predict( int sampleIdx, bool returnSum = false ) const;

/// Decision threshold tuned to satisfy @c minHitRate.
float getThreshold() const { return threshold; }
/// Serialize the stage; @p featureMap remaps used feature indices to compact ids.
void write( cv::FileStorage &fs, const cv::Mat& featureMap ) const;
/// Restore the stage from a previously written XML node.
bool read( const cv::FileNode &node, const CvFeatureEvaluator* _featureEvaluator,
const CvCascadeBoostParams& _params );
/// Mark every feature this stage references as used in @p featureMap.
void markUsedFeaturesInMap( cv::Mat& featureMap );
private:
/// Re-evaluate the stage on the working set and return @c true once
/// the cascade rate targets are met.
bool isErrDesired();
bool set_params( const CvBoostParams& _params ) override;
/// Update boosting sample weights after appending a new weak tree.
void update_weights( CvBoostTree* tree );// override;

float threshold;
float minHitRate, maxFalseAlarm;
float threshold; ///< Decision threshold tuned per stage.
float minHitRate, maxFalseAlarm; ///< Targets copied from CvCascadeBoostParams.
};

#endif
Loading