From f7ac73998a4d518817a81a20e167116617c6b95d Mon Sep 17 00:00:00 2001 From: "marina.kolpakova" Date: Thu, 31 Jan 2013 19:17:56 +0400 Subject: [PATCH] code review fixes --- apps/sft/include/sft/common.hpp | 2 ++ modules/python/src2/cv2.cpp | 3 +- .../include/opencv2/softcascade/softcascade.hpp | 10 +++--- modules/softcascade/misc/sft.py | 2 +- modules/softcascade/perf/perf_softcascade.cpp | 6 ++-- .../softcascade/src/integral_channel_builder.cpp | 32 +++++++++---------- modules/softcascade/src/precomp.hpp | 2 ++ modules/softcascade/src/soft_cascade_octave.cpp | 22 ++++++------- modules/softcascade/src/softcascade.cpp | 36 +++++++++++----------- modules/softcascade/src/softcascade_init.cpp | 4 +-- modules/softcascade/test/test_channel_features.cpp | 4 +-- modules/softcascade/test/test_softcascade.cpp | 18 +++++------ modules/softcascade/test/test_training.cpp | 6 ++-- 13 files changed, 73 insertions(+), 74 deletions(-) diff --git a/apps/sft/include/sft/common.hpp b/apps/sft/include/sft/common.hpp index 1371875..eeca723 100644 --- a/apps/sft/include/sft/common.hpp +++ b/apps/sft/include/sft/common.hpp @@ -46,8 +46,10 @@ #include #include +namespace cv {using namespace scascade;} namespace sft { + using cv::Mat; struct ICF; diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 1eed747..f4ae0a4 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -97,6 +97,7 @@ catch (const cv::Exception &e) \ } using namespace cv; +typedef cv::scascade::ChannelFeatureBuilder scascade_ChannelFeatureBuilder; typedef vector vector_uchar; typedef vector vector_int; @@ -125,7 +126,7 @@ typedef Ptr Ptr_DescriptorExtractor; typedef Ptr Ptr_Feature2D; typedef Ptr Ptr_DescriptorMatcher; -typedef Ptr Ptr_ChannelFeatureBuilder; +typedef Ptr Ptr_ChannelFeatureBuilder; typedef SimpleBlobDetector::Params SimpleBlobDetector_Params; diff --git a/modules/softcascade/include/opencv2/softcascade/softcascade.hpp b/modules/softcascade/include/opencv2/softcascade/softcascade.hpp index 70123c0..ff821ee 100644 --- a/modules/softcascade/include/opencv2/softcascade/softcascade.hpp +++ b/modules/softcascade/include/opencv2/softcascade/softcascade.hpp @@ -45,7 +45,7 @@ #include "opencv2/core/core.hpp" -namespace cv { +namespace cv { namespace scascade { // Representation of detectors result. struct CV_EXPORTS Detection @@ -122,7 +122,7 @@ std::ostream& operator<<(std::ostream& out, const ChannelFeature& m); // Public Interface for Integral Channel Feature. // ========================================================================== // -class CV_EXPORTS_W ChannelFeatureBuilder : public Algorithm +class CV_EXPORTS_W ChannelFeatureBuilder : public cv::Algorithm { public: virtual ~ChannelFeatureBuilder(); @@ -136,7 +136,7 @@ public: // ========================================================================== // // Implementation of soft (stageless) cascaded detector. // ========================================================================== // -class CV_EXPORTS_W SoftCascadeDetector : public Algorithm +class CV_EXPORTS_W SoftCascadeDetector : public cv::Algorithm { public: @@ -186,7 +186,7 @@ private: // ========================================================================== // // Public Interface for singe soft (stageless) cascade octave training. // ========================================================================== // -class CV_EXPORTS SoftCascadeOctave : public Algorithm +class CV_EXPORTS SoftCascadeOctave : public cv::Algorithm { public: enum @@ -211,6 +211,6 @@ public: CV_EXPORTS bool initModule_softcascade(void); -} +} } #endif \ No newline at end of file diff --git a/modules/softcascade/misc/sft.py b/modules/softcascade/misc/sft.py index 019044f..dd098cf 100644 --- a/modules/softcascade/misc/sft.py +++ b/modules/softcascade/misc/sft.py @@ -24,7 +24,7 @@ def convert2detections(rects, confs, crop_factor = 0.125): """ Create new instance of soft cascade.""" def cascade(min_scale, max_scale, nscales, f): # where we use nms cv::SoftCascadeDetector::DOLLAR == 2 - c = cv2.SoftCascadeDetector(min_scale, max_scale, nscales, 2) + c = cv2.scascade_SoftCascadeDetector(min_scale, max_scale, nscales, 2) xml = cv2.FileStorage(f, 0) dom = xml.getFirstTopLevelNode() assert c.load(dom) diff --git a/modules/softcascade/perf/perf_softcascade.cpp b/modules/softcascade/perf/perf_softcascade.cpp index 3810356..683dd57 100644 --- a/modules/softcascade/perf/perf_softcascade.cpp +++ b/modules/softcascade/perf/perf_softcascade.cpp @@ -10,7 +10,7 @@ typedef perf::TestBaseWithParam detect; namespace { -void extractRacts(std::vector objectBoxes, std::vector& rects) +void extractRacts(std::vector objectBoxes, std::vector& rects) { rects.clear(); for (int i = 0; i < (int)objectBoxes.size(); ++i) @@ -26,12 +26,12 @@ PERF_TEST_P(detect, SoftCascadeDetector, cv::Mat colored = cv::imread(getDataPath(get<1>(GetParam()))); ASSERT_FALSE(colored.empty()); - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(getDataPath(get<0>(GetParam())), cv::FileStorage::READ); ASSERT_TRUE(fs.isOpened()); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); - std::vector objectBoxes; + std::vector objectBoxes; cascade.detect(colored, cv::noArray(), objectBoxes); TEST_CYCLE() diff --git a/modules/softcascade/src/integral_channel_builder.cpp b/modules/softcascade/src/integral_channel_builder.cpp index ad5bc7e..86493ff 100644 --- a/modules/softcascade/src/integral_channel_builder.cpp +++ b/modules/softcascade/src/integral_channel_builder.cpp @@ -44,7 +44,7 @@ namespace { -class ICFBuilder : public cv::ChannelFeatureBuilder +class ICFBuilder : public ChannelFeatureBuilder { virtual ~ICFBuilder() {} virtual cv::AlgorithmInfo* info() const; @@ -109,29 +109,29 @@ class ICFBuilder : public cv::ChannelFeatureBuilder CV_INIT_ALGORITHM(ICFBuilder, "ChannelFeatureBuilder.ICFBuilder", ); -cv::ChannelFeatureBuilder::~ChannelFeatureBuilder() {} +cv::scascade::ChannelFeatureBuilder::~ChannelFeatureBuilder() {} -cv::Ptr cv::ChannelFeatureBuilder::create() +cv::Ptr ChannelFeatureBuilder::create() { - cv::Ptr builder(new ICFBuilder()); + cv::Ptr builder(new ICFBuilder()); return builder; } -cv::ChannelFeature::ChannelFeature(int x, int y, int w, int h, int ch) +cv::scascade::ChannelFeature::ChannelFeature(int x, int y, int w, int h, int ch) : bb(cv::Rect(x, y, w, h)), channel(ch) {} -bool cv::ChannelFeature::operator ==(cv::ChannelFeature b) +bool ChannelFeature::operator ==(ChannelFeature b) { return bb == b.bb && channel == b.channel; } -bool cv::ChannelFeature::operator !=(cv::ChannelFeature b) +bool ChannelFeature::operator !=(ChannelFeature b) { return bb != b.bb || channel != b.channel; } -float cv::ChannelFeature::operator() (const cv::Mat& integrals, const cv::Size& model) const +float cv::scascade::ChannelFeature::operator() (const cv::Mat& integrals, const cv::Size& model) const { int step = model.width + 1; @@ -148,22 +148,22 @@ float cv::ChannelFeature::operator() (const cv::Mat& integrals, const cv::Size& return (float)(a - b + c - d); } -void cv::write(cv::FileStorage& fs, const string&, const cv::ChannelFeature& f) +void cv::scascade::write(cv::FileStorage& fs, const string&, const ChannelFeature& f) { fs << "{" << "channel" << f.channel << "rect" << f.bb << "}"; } -std::ostream& cv::operator<<(std::ostream& out, const cv::ChannelFeature& m) +std::ostream& cv::scascade::operator<<(std::ostream& out, const ChannelFeature& m) { out << m.channel << " " << m.bb; return out; } -cv::ChannelFeature::~ChannelFeature(){} +cv::scascade::ChannelFeature::~ChannelFeature(){} namespace { -class ChannelFeaturePool : public cv::FeaturePool +class ChannelFeaturePool : public FeaturePool { public: ChannelFeaturePool(cv::Size m, int n) : FeaturePool(), model(m) @@ -183,7 +183,7 @@ private: void fill(int desired); cv::Size model; - std::vector pool; + std::vector pool; enum { N_CHANNELS = 10 }; }; @@ -235,7 +235,7 @@ void ChannelFeaturePool::fill(int desired) int ch = chRand(eng_ch); - cv::ChannelFeature f(x, y, w, h, ch); + ChannelFeature f(x, y, w, h, ch); if (std::find(pool.begin(), pool.end(),f) == pool.end()) { @@ -246,8 +246,8 @@ void ChannelFeaturePool::fill(int desired) } -cv::Ptr cv::FeaturePool::create(const cv::Size& model, int nfeatures) +cv::Ptr cv::scascade::FeaturePool::create(const cv::Size& model, int nfeatures) { - cv::Ptr pool(new ChannelFeaturePool(model, nfeatures)); + cv::Ptr pool(new ChannelFeaturePool(model, nfeatures)); return pool; } diff --git a/modules/softcascade/src/precomp.hpp b/modules/softcascade/src/precomp.hpp index cb20a26..c373069 100644 --- a/modules/softcascade/src/precomp.hpp +++ b/modules/softcascade/src/precomp.hpp @@ -55,4 +55,6 @@ #include "opencv2/ml/ml.hpp" #include "_random.hpp" +using namespace cv::scascade; + #endif diff --git a/modules/softcascade/src/soft_cascade_octave.cpp b/modules/softcascade/src/soft_cascade_octave.cpp index 41e4a9b..cbad3f1 100644 --- a/modules/softcascade/src/soft_cascade_octave.cpp +++ b/modules/softcascade/src/soft_cascade_octave.cpp @@ -44,19 +44,17 @@ #include #include -using cv::Dataset; -using cv::FeaturePool; using cv::InputArray; using cv::OutputArray; using cv::Mat; -cv::FeaturePool::~FeaturePool(){} -cv::Dataset::~Dataset(){} +cv::scascade::FeaturePool::~FeaturePool(){} +cv::scascade::Dataset::~Dataset(){} namespace { -class BoostedSoftCascadeOctave : public cv::Boost, public cv::SoftCascadeOctave +class BoostedSoftCascadeOctave : public cv::Boost, public SoftCascadeOctave { public: @@ -96,7 +94,7 @@ private: Mat trainData; - cv::Ptr builder; + cv::Ptr builder; }; BoostedSoftCascadeOctave::BoostedSoftCascadeOctave(cv::Rect bb, int np, int nn, int ls, int shr, int poolSize) @@ -128,7 +126,7 @@ BoostedSoftCascadeOctave::BoostedSoftCascadeOctave(cv::Rect bb, int np, int nn, params = _params; - builder = cv::ChannelFeatureBuilder::create(); + builder = ChannelFeatureBuilder::create(); int w = boundingBox.width; int h = boundingBox.height; @@ -195,7 +193,7 @@ void BoostedSoftCascadeOctave::processPositives(const Dataset* dataset) { int h = boundingBox.height; - cv::ChannelFeatureBuilder& _builder = *builder; + ChannelFeatureBuilder& _builder = *builder; int total = 0; for (int curr = 0; curr < dataset->available( Dataset::POSITIVE); ++curr) @@ -228,7 +226,7 @@ void BoostedSoftCascadeOctave::generateNegatives(const Dataset* dataset) int total = 0; Mat sum; - cv::ChannelFeatureBuilder& _builder = *builder; + ChannelFeatureBuilder& _builder = *builder; for (int i = npositives; i < nnegatives + npositives; ++total) { int curr = iRand(idxEng); @@ -441,12 +439,12 @@ void BoostedSoftCascadeOctave::write( CvFileStorage* fs, std::string _name) cons CV_INIT_ALGORITHM(BoostedSoftCascadeOctave, "SoftCascadeOctave.BoostedSoftCascadeOctave", ); -cv::SoftCascadeOctave::~SoftCascadeOctave(){} +cv::scascade::SoftCascadeOctave::~SoftCascadeOctave(){} -cv::Ptr cv::SoftCascadeOctave::create(cv::Rect boundingBox, int npositives, int nnegatives, +cv::Ptr cv::scascade::SoftCascadeOctave::create(cv::Rect boundingBox, int npositives, int nnegatives, int logScale, int shrinkage, int poolSize) { - cv::Ptr octave( + cv::Ptr octave( new BoostedSoftCascadeOctave(boundingBox, npositives, nnegatives, logScale, shrinkage, poolSize)); return octave; } diff --git a/modules/softcascade/src/softcascade.cpp b/modules/softcascade/src/softcascade.cpp index 46811d5..63fcd67 100644 --- a/modules/softcascade/src/softcascade.cpp +++ b/modules/softcascade/src/softcascade.cpp @@ -145,13 +145,13 @@ struct Level scaleshift = static_cast(relScale * (1 << 16)); } - void addDetection(const int x, const int y, float confidence, std::vector& detections) const + void addDetection(const int x, const int y, float confidence, std::vector& detections) const { // fix me int shrinkage = 4;//(*octave).shrinkage; cv::Rect rect(cvRound(x * shrinkage), cvRound(y * shrinkage), objSize.width, objSize.height); - detections.push_back(cv::Detection(rect, confidence)); + detections.push_back(Detection(rect, confidence)); } float rescale(cv::Rect& scaledRect, const float threshold, int idx) const @@ -177,13 +177,13 @@ struct ChannelStorage int step; int model_height; - cv::Ptr builder; + cv::Ptr builder; enum {HOG_BINS = 6, HOG_LUV_BINS = 10}; ChannelStorage(const cv::Mat& colored, int shr) : shrinkage(shr) { - builder = cv::ChannelFeatureBuilder::create(); + builder = ChannelFeatureBuilder::create(); (*builder)(colored, hog); step = hog.step1(); @@ -205,7 +205,7 @@ struct ChannelStorage } -struct cv::SoftCascadeDetector::Fields +struct SoftCascadeDetector::Fields { float minScale; float maxScale; @@ -409,17 +409,17 @@ struct cv::SoftCascadeDetector::Fields } }; -cv::SoftCascadeDetector::SoftCascadeDetector(const double mins, const double maxs, const int nsc, const int rej) +SoftCascadeDetector::SoftCascadeDetector(const double mins, const double maxs, const int nsc, const int rej) : fields(0), minScale(mins), maxScale(maxs), scales(nsc), rejCriteria(rej) {} -cv::SoftCascadeDetector::~SoftCascadeDetector() { delete fields;} +SoftCascadeDetector::~SoftCascadeDetector() { delete fields;} -void cv::SoftCascadeDetector::read(const FileNode& fn) +void SoftCascadeDetector::read(const FileNode& fn) { Algorithm::read(fn); } -bool cv::SoftCascadeDetector::load(const FileNode& fn) +bool SoftCascadeDetector::load(const FileNode& fn) { if (fields) delete fields; @@ -429,12 +429,12 @@ bool cv::SoftCascadeDetector::load(const FileNode& fn) namespace { -typedef std::vector dvector; +typedef std::vector dvector; struct ConfidenceGt { - bool operator()(const cv::Detection& a, const cv::Detection& b) const + bool operator()(const Detection& a, const Detection& b) const { return a.confidence > b.confidence; } @@ -455,10 +455,10 @@ void DollarNMS(dvector& objects) for (dvector::iterator dIt = objects.begin(); dIt != objects.end(); ++dIt) { - const cv::Detection &a = *dIt; + const Detection &a = *dIt; for (dvector::iterator next = dIt + 1; next != objects.end(); ) { - const cv::Detection &b = *next; + const Detection &b = *next; const float ovl = overlap(a.bb, b.bb) / std::min(a.bb.area(), b.bb.area()); @@ -470,15 +470,15 @@ void DollarNMS(dvector& objects) } } -static void suppress(int type, std::vector& objects) +static void suppress(int type, std::vector& objects) { - CV_Assert(type == cv::SoftCascadeDetector::DOLLAR); + CV_Assert(type == SoftCascadeDetector::DOLLAR); DollarNMS(objects); } } -void cv::SoftCascadeDetector::detectNoRoi(const cv::Mat& image, std::vector& objects) const +void SoftCascadeDetector::detectNoRoi(const cv::Mat& image, std::vector& objects) const { Fields& fld = *fields; // create integrals @@ -505,7 +505,7 @@ void cv::SoftCascadeDetector::detectNoRoi(const cv::Mat& image, std::vector& objects) const +void SoftCascadeDetector::detect(cv::InputArray _image, cv::InputArray _rois, std::vector& objects) const { // only color images are suppered cv::Mat image = _image.getMat(); @@ -557,7 +557,7 @@ void cv::SoftCascadeDetector::detect(cv::InputArray _image, cv::InputArray _rois if (rejCriteria != NO_REJECT) suppress(rejCriteria, objects); } -void cv::SoftCascadeDetector::detect(InputArray _image, InputArray _rois, OutputArray _rects, OutputArray _confs) const +void SoftCascadeDetector::detect(InputArray _image, InputArray _rois, OutputArray _rects, OutputArray _confs) const { std::vector objects; detect( _image, _rois, objects); diff --git a/modules/softcascade/src/softcascade_init.cpp b/modules/softcascade/src/softcascade_init.cpp index f9606c1..b1d9e4c 100644 --- a/modules/softcascade/src/softcascade_init.cpp +++ b/modules/softcascade/src/softcascade_init.cpp @@ -42,7 +42,7 @@ #include "precomp.hpp" -namespace cv +namespace cv { namespace scascade { CV_INIT_ALGORITHM(SoftCascadeDetector, "SoftCascade.SoftCascadeDetector", @@ -58,4 +58,4 @@ bool initModule_softcascade(void) return (sc1->info() != 0); } -} \ No newline at end of file +} } \ No newline at end of file diff --git a/modules/softcascade/test/test_channel_features.cpp b/modules/softcascade/test/test_channel_features.cpp index 65249b7..dff99d0 100644 --- a/modules/softcascade/test/test_channel_features.cpp +++ b/modules/softcascade/test/test_channel_features.cpp @@ -44,13 +44,13 @@ TEST(ChannelFeatureBuilderTest, info) { - cv::Ptr builder = cv::ChannelFeatureBuilder::create(); + cv::Ptr builder = cv::scascade::ChannelFeatureBuilder::create(); ASSERT_TRUE(builder->info() != 0); } TEST(ChannelFeatureBuilderTest, compute) { - cv::Ptr builder = cv::ChannelFeatureBuilder::create(); + cv::Ptr builder = cv::scascade::ChannelFeatureBuilder::create(); cv::Mat colored = cv::imread(cvtest::TS::ptr()->get_data_path() + "cascadeandhog/images/image_00000000_0.png"); cv::Mat ints; diff --git a/modules/softcascade/test/test_softcascade.cpp b/modules/softcascade/test/test_softcascade.cpp index 16f122e..1848bf7 100644 --- a/modules/softcascade/test/test_softcascade.cpp +++ b/modules/softcascade/test/test_softcascade.cpp @@ -44,11 +44,12 @@ #include #include "test_precomp.hpp" + typedef cv::scascade::Detection Detection; TEST(SoftCascadeDetector, readCascade) { std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(fs.isOpened()); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); @@ -56,9 +57,8 @@ TEST(SoftCascadeDetector, readCascade) TEST(SoftCascadeDetector, detect) { - typedef cv::Detection Detection; std::string xml = cvtest::TS::ptr()->get_data_path()+ "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); @@ -73,9 +73,8 @@ TEST(SoftCascadeDetector, detect) TEST(SoftCascadeDetector, detectSeparate) { - typedef cv::Detection Detection; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); @@ -90,9 +89,8 @@ TEST(SoftCascadeDetector, detectSeparate) TEST(SoftCascadeDetector, detectRoi) { - typedef cv::Detection Detection; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); @@ -109,9 +107,8 @@ TEST(SoftCascadeDetector, detectRoi) TEST(SoftCascadeDetector, detectNoRoi) { - typedef cv::Detection Detection; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); @@ -128,9 +125,8 @@ TEST(SoftCascadeDetector, detectNoRoi) TEST(SoftCascadeDetector, detectEmptyRoi) { - typedef cv::Detection Detection; std::string xml = cvtest::TS::ptr()->get_data_path() + "cascadeandhog/cascades/inria_caltech-17.01.2013.xml"; - cv::SoftCascadeDetector cascade; + cv::scascade::SoftCascadeDetector cascade; cv::FileStorage fs(xml, cv::FileStorage::READ); ASSERT_TRUE(cascade.load(fs.getFirstTopLevelNode())); diff --git a/modules/softcascade/test/test_training.cpp b/modules/softcascade/test/test_training.cpp index b6a282c..dd8ea93 100644 --- a/modules/softcascade/test/test_training.cpp +++ b/modules/softcascade/test/test_training.cpp @@ -58,7 +58,7 @@ using namespace std; namespace { typedef vector svector; -class ScaledDataset : public cv::Dataset +class ScaledDataset : public cv::scascade::Dataset { public: ScaledDataset(const string& path, const int octave); @@ -210,7 +210,7 @@ TEST(DISABLED_SoftCascade, training) float octave = powf(2.f, (float)(*it)); cv::Size model = cv::Size( cvRound(64 * octave) / shrinkage, cvRound(128 * octave) / shrinkage ); - cv::Ptr pool = cv::FeaturePool::create(model, nfeatures); + cv::Ptr pool = cv::scascade::FeaturePool::create(model, nfeatures); nfeatures = pool->size(); int npositives = 20; int nnegatives = 40; @@ -218,7 +218,7 @@ TEST(DISABLED_SoftCascade, training) cv::Rect boundingBox = cv::Rect( cvRound(20 * octave), cvRound(20 * octave), cvRound(64 * octave), cvRound(128 * octave)); - typedef cv::SoftCascadeOctave Octave; + typedef cv::scascade::SoftCascadeOctave Octave; cv::Ptr boost = Octave::create(boundingBox, npositives, nnegatives, *it, shrinkage, nfeatures); std::string path = cvtest::TS::ptr()->get_data_path() + "softcascade/sample_training_set"; -- 2.7.4