【问题标题】:A matrix with zero rows and 1000 columns?零行 1000 列的矩阵?
【发布时间】:2012-12-02 10:06:30
【问题描述】:

我正在查看CvNormalBayesClassifier::train 的示例,其中输入/输出矩阵将是一维向量。

我正在查看的示例通过使用此行创建一个 0 行和 1000 列的 cv::Mat 矩阵来实现这一点:

Mat trainingData(0, 1000, CV_32FC1);

阅读 opencv 文档中的基本数据类型,这是我为 Mat 找到的:

有许多不同的方法来创建 Mat 对象。这里有一些 热门:

using create(nrows, ncols, type) method or

    the similar constructor

Mat(nrows, ncols, type[, fill_value]) constructor.

无论如何,第一个参数是行。我看它的方式是,即使我们确实创建了一个 1000 列的矩阵,它也至少有 1 行。怎么会有0行?

抱歉,这是一个非常基本的问题。

更新:根据要求,这里是完整的代码。

    #include <vector>
#include <boost/filesystem.hpp>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace boost::filesystem;
using namespace cv;

//location of the training data
#define TRAINING_DATA_DIR "data/train/"
//location of the evaluation data
#define EVAL_DATA_DIR "data/eval/"

//See article on BoW model for details
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("SURF");
Ptr<FeatureDetector> detector = FeatureDetector::create("SURF");

//See article on BoW model for details
int dictionarySize = 1000;
TermCriteria tc(CV_TERMCRIT_ITER, 10, 0.001);
int retries = 1;
int flags = KMEANS_PP_CENTERS;

//See article on BoW model for details
BOWKMeansTrainer bowTrainer(dictionarySize, tc, retries, flags);
//See article on BoW model for details
BOWImgDescriptorExtractor bowDE(extractor, matcher);

/**
 * \brief Recursively traverses a folder hierarchy. Extracts features from the training images and adds them to the bowTrainer.
 */
void extractTrainingVocabulary(const path& basepath) {
    for (directory_iterator iter = directory_iterator(basepath); iter
            != directory_iterator(); iter++) {
        directory_entry entry = *iter;

    if (is_directory(entry.path())) {

        cout << "Processing directory " << entry.path().string() << endl;
        extractTrainingVocabulary(entry.path());

    } else {

        path entryPath = entry.path();
        if (entryPath.extension() == ".jpg") {

            cout << "Processing file " << entryPath.string() << endl;
            Mat img = imread(entryPath.string());
            if (!img.empty()) {
                vector<KeyPoint> keypoints;
                detector->detect(img, keypoints);
                if (keypoints.empty()) {
                    cerr << "Warning: Could not find key points in image: "
                            << entryPath.string() << endl;
                } else {
                    Mat features;
                    extractor->compute(img, keypoints, features);
                    bowTrainer.add(features);
                }
            } else {
                cerr << "Warning: Could not read image: "
                        << entryPath.string() << endl;
            }

        }
    }
}
}

/**
 * \brief Recursively traverses a folder hierarchy. Creates a BoW descriptor for each image encountered.
 */
void extractBOWDescriptor(const path& basepath, Mat& descriptors, Mat& labels) {
    for (directory_iterator iter = directory_iterator(basepath); iter
            != directory_iterator(); iter++) {
        directory_entry entry = *iter;
        if (is_directory(entry.path())) {
            cout << "Processing directory " << entry.path().string() << endl;
            extractBOWDescriptor(entry.path(), descriptors, labels);
        } else {
            path entryPath = entry.path();
            if (entryPath.extension() == ".jpg") {
                cout << "Processing file " << entryPath.string() << endl;
                Mat img = imread(entryPath.string());
                if (!img.empty()) {
                    vector<KeyPoint> keypoints;
                    detector->detect(img, keypoints);
                    if (keypoints.empty()) {
                        cerr << "Warning: Could not find key points in image: "
                                << entryPath.string() << endl;
                    } else {
                        Mat bowDescriptor;
                        bowDE.compute(img, keypoints, bowDescriptor);
                        descriptors.push_back(bowDescriptor);
                        float label=atof(entryPath.filename().c_str());
                        labels.push_back(label);
                    }
                } else {
                    cerr << "Warning: Could not read image: "
                            << entryPath.string() << endl;
                }
            }
        }
    }
}

int main(int argc, char ** argv) {

cout<<"Creating dictionary..."<<endl;
extractTrainingVocabulary(path(TRAINING_DATA_DIR));
vector<Mat> descriptors = bowTrainer.getDescriptors(); //descriptors from training images
int count=0;
for(vector<Mat>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
    count+=iter->rows;
}
cout<<"Clustering "<<count<<" features"<<endl;
Mat dictionary = bowTrainer.cluster();
bowDE.setVocabulary(dictionary);
cout<<"Processing training data..."<<endl;
Mat trainingData(0, dictionarySize, CV_32FC1);
Mat labels(0, 1, CV_32FC1);
extractBOWDescriptor(path(TRAINING_DATA_DIR), trainingData, labels);

NormalBayesClassifier classifier;
cout<<"Training classifier..."<<endl;

classifier.train(trainingData, labels);

cout<<"Processing evaluation data..."<<endl;
Mat evalData(0, dictionarySize, CV_32FC1);
Mat groundTruth(0, 1, CV_32FC1);
extractBOWDescriptor(path(EVAL_DATA_DIR), evalData, groundTruth);

cout<<"Evaluating classifier..."<<endl;
Mat results;
classifier.predict(evalData, &results);

double errorRate = (double) countNonZero(groundTruth - results) / evalData.rows;
        ;
cout << "Error rate: " << errorRate << endl;

}

【问题讨论】:

  • 一维向量有 1 行 N 列(反之亦然)。
  • 0 行的矩阵就像一只手拍手的声音。很有禅意,但不是很有用。要将任何数据放入其中,您至少需要一行。
  • 可能矩阵在那之后扩展了某个地方,例如通过调整大小操作,或者在填充数据时自动调整大小。向我们展示更多代码。
  • 您能发布一个指向您的示例的链接吗?
  • 代码已添加,感谢您迄今为止的回复。

标签: c++ opencv


【解决方案1】:

现在您已经发布了代码,这很有意义。这个 0 行向量被初始化为有 0 行,但它是增量创建的。

0 行矩阵被传递给extractBOWDescriptor(),它自己计算几个描述符并使用cv::Mat.push_back() 向矩阵添加行。

它从 0 行开始,因为一开始我们没有描述符来填充矩阵。

【讨论】:

  • 谢谢,现在这更有意义了。我很困惑,因为我认为 push_back 只能与向量一起使用。我现在知道它们可用于在矩阵的最后一行下方添加元素。
  • 另外@Chris,您能否解释一下我对代码的另一个困惑。如果我能在这里整理出来,而不是为它创建一个新主题,那就太好了。我不知道这一行发生了什么:float label=atof(entryPath.filename().c_str()); labels.push_back(label); 我知道 atof 将字符串转换为双精度,但不是将文件名转换为双精度的代码吗?这有什么帮助?谢谢
  • 它可能特定于正在读取的数据,但是是的,它有一些文件名,然后将其转换为浮点数。我的猜测是这些文件按数字顺序标记,这就是它以这种方式表示的原因。它们也可能由它们的标签(类)命名,因此您在分类期间拥有基本事实。抱歉,我不能确定,因为我不知道数据是什么 :)
  • 感谢您的有用回复。
猜你喜欢
  • 2021-06-24
  • 2016-01-26
  • 2012-03-13
  • 2019-05-21
  • 2016-05-26
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多