2016-07-22 76 views
5

我想制作一个程序到识别图像中的数字。我遵循scikit learn的教程。Scikit-learn SVM数字识别

我可以列车和适合svm分类器如下所示。

首先,我导入库和数据集

from sklearn import datasets, svm, metrics 

digits = datasets.load_digits() 
n_samples = len(digits.images) 
data = digits.images.reshape((n_samples, -1)) 

其次,我创建了SVM模型和数据集训练它。

classifier = svm.SVC(gamma = 0.001) 
classifier.fit(data[:n_samples], digits.target[:n_samples]) 

然后,我尝试阅读我自己的图像并使用函数predict()来识别数字。

这是我的图像: enter image description here

重塑图像划分成(8,8),然后将其转换为1D阵列。

img = misc.imread("w1.jpg") 
img = misc.imresize(img, (8, 8)) 
img = img[:, :, 0] 

最后,当我打印出预测,它返回[1]

predicted = classifier.predict(img.reshape((1,img.shape[0]*img.shape[1]))) 
print predicted 

无论我用户他人图像时,它仍返回[1]

enter image description here enter image description here

当我打印出“默认”号的数据集 “9”,它看起来像:enter image description here

我的形象数字 “9”:

enter image description here

你可以看到非零数字是相当大的我的形象。

我不知道为什么。我正在寻求帮助来解决我的问题。由于

回答

5

我最好打赌会是你的数据类型和数组形状有问题。

看起来你是在numpy的数组,其类型np.float64(或可能np.float32在32位系统上,我不记得了)和每个图像具有形状(64,)的训练。

同时,在代码调整大小后,预测输入图像的类型为uint8,形状为(1, 64)

我先试试改变你的输入图像的形状,因为D型转换往往只是工作,你所期望的。因此,改变这一行:

predicted = classifier.predict(img.reshape((1,img.shape[0]*img.shape[1])))

这样:

predicted = classifier.predict(img.reshape(img.shape[0]*img.shape[1]))

如果不解决这个问题,你可以总是试图用

img = img.astype(digits.images.dtype)重铸的数据类型,以及。

我希望有帮助。通过代理进行调试比坐在电脑前困难得多:)

编辑:根据SciPy文档,训练数据包含从0到16的整数值。输入图像中的值应该缩放到适合相同的时间间隔。 (http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html#sklearn.datasets.load_digits

+0

谢谢你的回复。我试过你的方法,它不起作用。我发现我的图像的数组元素比训练数据集要大得多。我已更新 – VICTOR

+1

这个问题啊,看起来你必须将它们缩放到0-16范围内:http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html#sklearn。 datasets.load_digits –

+0

@CLWONG - 这是否解决了您的问题? –

1

这只是一种猜测,但...从SK-学习训练集是黑色数字白色背景。你试图预测黑色背景上的白色数字...

我认为你应该在你的训练集上训练,或者训练你的图片的负面版本。

我希望这个帮助!

+0

感谢您的回复。我试过黑色背景,白色号码,它仍然返回1. – VICTOR

3

1)你必须创建自己的训练集 - 基于类似于您将作出的预测数据。在scikit-learn中调用datasets.load_digits()正在加载MNIST Digits数据集的预处理版本,我们知道,该数据集可能与您尝试识别的图像有非常不同的图像。

2)您需要正确设置你的分类的参数。对svm.SVC(gamma = 0.001)的调用只是在SVC中选择一个任意的gamma参数值,这可能不是最佳选择。另外,您没有配置C参数 - 这对于SVM非常重要。我敢打赌,这是你的输出“​​总是1”的原因之一。

3)您选择适合您的机型无论最终的设置,则需要使用交叉验证计划,以确保该算法有效地学习

有很多机器学习这背后的理论,但是,作为一个良好的开端,我真的建议看看SVM - scikit-learn对于如何在SVC实现sickit学习作品更深入的说明,并GridSearchCV为参数设置一个简单的技术。

1

如果你看看: http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html#sklearn.datasets.load_digits

,你可以看到,在矩阵为0-16之间的值,每个点。

你可以尝试将图像的值转化为0-16之间。我做到了,现在预测数字9的效果很好,但不适用于8和6.它不会再给1了。

from sklearn import datasets, svm, metrics 
import cv2 
import numpy as np 

# Load digit database 
digits = datasets.load_digits() 
n_samples = len(digits.images) 
data = digits.images.reshape((n_samples, -1)) 

# Train SVM classifier 
classifier = svm.SVC(gamma = 0.001) 
classifier.fit(data[:n_samples], digits.target[:n_samples]) 

# Read image "9" 
img = cv2.imread("w1.jpg") 
img = img[:,:,0]; 
img = cv2.resize(img, (8, 8)) 

# Normalize the values in the image to 0-16 
minValueInImage = np.min(img) 
maxValueInImage = np.max(img) 
normaliizeImg = np.floor(np.divide((img - minValueInImage).astype(np.float),(maxValueInImage-minValueInImage).astype(np.float))*16) 

# Predict 
predicted = classifier.predict(normaliizeImg.reshape((1,normaliizeImg.shape[0]*normaliizeImg.shape[1]))) 
print predicted 
0

嗨除了@carrdelling反应,我会加你可以使用相同的训练集,如果你的正常化图像具有相同的范围内的值。例如,您可以对您的数据进行二进制码处理(如果> 0,其他情况下为1),或者可以将图像中的最大强度除以具有任意间隔[0; 1]。

0

您可能想要从图像中提取与数据集相关的特征并训练模型。 一个例子,我从here.

surf = cv2.SURF(400) kp, des = surf.detectAndCompute(img,None)

复制但SURF功能可能无法使用你的数据集和训练任务的最有用的或相关的。你应该尝试其他人,如HOG或其他人。

记住这个更高级别的功能,您可以提取更一般/容错您的模型将看不见的图像。但是,您可能会牺牲已知样本和测试用例的准确性。

1

我已经解决了通过以下方法解决此问题:

  1. 检查属性的数量,过大或过小。

  2. 检查你的灰度值的比例,我改变为[0,16]。

  3. 检查数据类型,我将其更改为uint8。

  4. 检查训练数据的数量是否太少。

我希望它有帮助。 ^。^