如何在 OpenCV 和 C++ 中配置 CvSVM 以进行图像分类
Posted
技术标签:
【中文标题】如何在 OpenCV 和 C++ 中配置 CvSVM 以进行图像分类【英文标题】:How to configure CvSVM for image classification in OpenCV and C++ 【发布时间】:2013-05-21 08:29:45 【问题描述】:我正在使用 OpenCV LibSVM 开发一个手写字符识别系统。我已经为特征向量提取了 14 个特征,包括 Hu 矩、仿射不变矩、角数等。对于每个字符,我使用 5 个样本(对于字母“A”,有 5 种类型的 A)。我知道 5 个样本是不够的,但目前我每个角色只有 5 个样本。
我使用 opencv 文档中的基本 LINEAR SVM 示例。我的问题是,出于我的目的,我可以按原样使用该文档示例。我读过关于使用多类 SVM 的 OCR 系统。我的应用程序需要这样的多类 SVM。我不明白这一点。请问有人可以解释吗?这是我的代码。
我有 180 个数字和英文大写字母样本,一个样本有 14 个特征。
float labels[180][1] = 1.0, 2.0, 3.0, 4.0, 5.0, ,,,,, -> 180.0;
Mat matlabesls(180,1, CV_32FC1, labels);
Mat mattrainingDataMat(180, 14, CV_32FC1, ifarr_readtrainingdata);
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
CvSVM SVM;
SVM.train(mattrainingDataMat,matlabesls,Mat(),Mat(),params);
Mat matinput(1,14,CV_32FC1,ifarr_testarray);
is_recognizedcharacter= SVM.predict(matinput);
return is_recognizedcharacter;
【问题讨论】:
【参考方案1】:您的标签设置不正确。您已经定义了 180 个唯一标签,但您只有 26 类数据。标签的长度应该是 180,但它应该只包含值 1..26(任何 26 个不同的值都可以),其顺序与 mattrainingDataMat 中的字符顺序一致。
每个字母需要 5000 个样本,而不仅仅是 5 个。您可以从 MNIST 手写数字数据集开始,直到获得适当的数据。
您的代码似乎训练 svm 只识别 1 个字符。您不应该那样做,因为训练 svm 可能需要 很长 时间。您应该单独训练 svm 并保存模型,以便可以重复使用它,而不必每次都重新训练。
我的理解是 OpenCV 中的 svm 代码是基于一个 old 版本的 Libsvm。所以我只是直接使用最新版本的 libsvm 而不是 OpenCV 版本。
此外,对于您的情况,使用 RBF 内核几乎肯定会比线性内核获得更好的准确度(尽管线性更容易训练)。看起来你有 26 个类,所以你当然需要一个多类 SVM(实际上只是许多二进制 SVM)——Libsvm 会为你处理多类问题。
【讨论】:
您好,非常感谢您考虑我的问题。我将代码更改如下。我有 36 个班级(26 个字母,10 个数字)。目前我只使用 5 个样本(直到我清楚地知道)。一个类有 5 个样本,一个样本有 14 个特征。那么一个类有 70 个特征(5 * 14)。你是这个意思吗 ??请帮助 .. '浮动标签[36][1] = 1.0, 2.0, ... -> 36.0; Mat matlabesls(36,1, CV_32FC1, labels) Mat mattrainingDataMat(36, 70, CV_32FC1, ifarr_readtrainingdata);' 如果您的数据包含“A”的 3 个示例、“C”中的 2 个和“5”中的 3 个示例的特征(按此顺序),那么您的标签将是“浮动标签”[7 ][1] =11.0, 11.0, 11.0, 13.0,13,0, 5.0, 5.0, 5.0 假设 0.0..9.0 用于标记 '0' 到 '9' 并且 11.0..35.0 用于标记 ' A'..'Z'。如果您的数据顺序混乱,则需要将标签混乱起来以匹配。标签告诉 SVM 每个数据项是一个样本。 非常感谢,我了解标签。你能告诉我多类 SVM 在这里的位置吗?我觉得,正如你所说,有 3 个 11.0 的,2 个 13.0 的……等等。这就是所谓的 MultiClass SVM 吗?? 如果你只有 2 个标签,比如 0 和 1,或者 -1 和 1,那么它将是一个二进制 svm。如果您提供超过 2 个不同的值,那么 linsvm(opencv 使用)自动 训练许多二进制 svm 并组合结果,这样您就有了一个多类分类器。实际的 svm 算法本质上是二进制的,它只是寻找一个超平面,将您的数据分成两组(理想情况下,每组中的所有标签都相同)。如果您的数据仅包含两个“A”和三个“C”,您将拥有 'float labels[5][1] =11.0, 11.0, 13.0,13.0 13.0,这将为您提供二进制 svm。 @user2151446- k 然后我将配置我的代码并观察输出。非常感谢您在我的问题中的帮助和努力。HND以上是关于如何在 OpenCV 和 C++ 中配置 CvSVM 以进行图像分类的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Mac 上安装 OpenCV for C++ 并使用 Netbeans 进行配置