如何训练 libsvm 格式的图像(像素)数据以用于 Java 识别
Posted
技术标签:
【中文标题】如何训练 libsvm 格式的图像(像素)数据以用于 Java 识别【英文标题】:How to train image (pixel) data in libsvm format to use for recognition with Java 【发布时间】:2013-07-14 01:29:08 【问题描述】:我想制作一个使用 libsvm 来识别字符的 Java 应用程序,但是当涉及到这个时,我不明白如何训练图像数据以与 libsvm 一起使用?
最近为了学习,用existing data:做了个测试
我还通过将每个像素转换为0,1
来创建基于32x32
的训练图像数据,但我不知道它是否可以用于创建libsvm 训练数据格式?
还有libsvm的测试数据是怎么产生的?
转换后的图像像素示例(0,1)
:
00000000000001111000000000000000
00000000000011111110000000000000
00000000001111111111000000000000
00000001111111111111100000000000
00000001111111011111100000000000
00000011111110000011110000000000
00000011111110000000111000000000
00000011111110000000111100000000
00000011111110000000011100000000
00000011111110000000011100000000
00000011111100000000011110000000
00000011111100000000001110000000
00000011111100000000001110000000
00000001111110000000000111000000
00000001111110000000000111000000
00000001111110000000000111000000
00000001111110000000000111000000
00000011111110000000001111000000
00000011110110000000001111000000
00000011110000000000011110000000
00000001111000000000001111000000
00000001111000000000011111000000
00000001111000000000111110000000
00000001111000000001111100000000
00000000111000000111111000000000
00000000111100011111110000000000
00000000111111111111110000000000
00000000011111111111110000000000
00000000011111111111100000000000
00000000001111111110000000000000
00000000000111110000000000000000
00000000000011000000000000000000
0
00000000000001111111110000000000
00000000001111111111111000000000
00000000011111111111111100000000
00000000011111111111111100000000
00000000011111111111111110000000
00000001111111111111111100000000
00000000111110000011111100000000
00000000000000000001111100000000
00000000000000000001111100000000
00000000000000000001111100000000
00000000000000000011111000000000
00000000000000000111111000000000
00000000000000000111111000000000
00000000000000000111111000000000
00000000000000001111110000000000
00000000011111111111111111000000
00000000111111111111111111100000
00000000111111111111111111100000
00000000111111111111111111100000
00000001111111111111111110000000
00000001111111111110000000000000
00000001111111111110000000000000
00000000111111111110000000000000
00000000000011111000000000000000
00000000000011111000000000000000
00000000000011111000000000000000
00000000000111111000000000000000
00000000000111111000000000000000
00000000001111110000000000000000
00000000011111110000000000000000
00000000001111100000000000000000
00000000001111100000000000000000
7
libsvm (training, testing data)
如何获得?
【问题讨论】:
【参考方案1】:libsvm
有特定的数据格式,每一行都是一个训练/测试向量,形式为
标签 INDEX0:VALUE0 INDEX1:VALUE1 ... INDEXN:VALUEN
所以在最“幼稚”的方法中,您只需通过连接连续的行将矩阵表示转换为行表示,所以图像像
010
011
000
会变成
010011000
并采用 libsvm 格式(假设我们将其标记为“5”):
5 0:0 1:1 2:0 3:0 4:1 5:1 6:0 7:0 8:0 9:0
由于 libsvm 支持“稀疏”表示,您可以省略带有“0”的值
5 1:1 4:1 5:1
这是手动方式,示例数据位于:http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/a1a
最简单的“自动”方法是将您的数据表示为 .csv 格式(再次将数据转换为类似行的格式,然后转换为 .csv),这是一种非常标准的方法:
标签,PIXEL_0,PIXEL_1,...,PIXEL_N
...
然后用这个程序进行转换
/* convert cvs data to libsvm/svm-light format */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[10000000];
float feature[100000];
int main(int argc, char **argv)
FILE *fp;
if(argc!=2) fprintf(stderr,"Usage %s filename\n",argv[0]);
if((fp=fopen(argv[1],"r"))==NULL)
fprintf(stderr,"Can't open input file %s\n",argv[1]);
while(fscanf(fp,"%[^\n]\n",buf)==1)
int i=0,j;
char *p=strtok(buf,",");
feature[i++]=atof(p);
while((p=strtok(NULL,",")))
feature[i++]=atof(p);
// --i;
/*
if ((int) feature[i]==1)
printf("-1 ");
else
printf("+1 ");
*/
// printf("%f ", feature[1]);
printf("%d ", (int) feature[0]);
for(j=1;j<i;j++)
printf(" %d:%f",j,feature[j]);
printf("\n");
return 0;
训练和测试文件具有完全相同的结构,只需将数据按一定比例(3:1 或 9:1)随机拆分为文件 training
和 testing
,但请记住包含平衡数量的训练向量每个文件中的每个类。
特别是 - 你的数据看起来有点像 MNIST 数据集,如果是这种情况,这已经为 libsvm 准备好了:
http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass.html
MNIST 培训:http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.scale.bz2
MNIST 测试:http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/mnist.scale.t.bz2
如果可以使用您的数据,将您的图像转换为 [0,1] 区间内的实值图像会比二进制数据更有价值(这会丢失很多信息)。
编辑
例如,如果您的图像是 8 位灰度图像,那么每个像素实际上是一个介于 0 和 255 之间的数字 v
。您现在正在做的是一些阈值,将 1 设置为 v > T
和 0对于v <= T
,将这些值映射到实际值将为模型提供更多信息。可以通过简单的挤压v / 255
来完成。因此,所有值都在 [0,1]
区间内,但也有“介于两者之间”的值,例如 0.25
等。
【讨论】:
“将图像转换为 [0,1] 中的实值图像”的方法应该是什么? 更新了答案,我的意思不是映射 v->0,1,而是映射到整个区间 [0,1],例如 - 除原始像素值(0-255如果是 8 位图像)由 255. 谢谢,我会试试看 libsvm 是否可以 我有一个问题,您上面的解决方案是否仅限于训练图像数据的大小(例如:32x32 或),或者我们可以训练到任何大小?因为我的数据训练不能总是 32x32 我的解决方案从未提及图像大小。但是您的数据必须保持恒定大小。因此,如果您有不同的图像尺寸,您需要统一它们(重新缩放为一种格式),这是在机器学习中处理原始像素值的标准过程。以上是关于如何训练 libsvm 格式的图像(像素)数据以用于 Java 识别的主要内容,如果未能解决你的问题,请参考以下文章