2017-06-29 77 views
1

我的機器學習算法已經在MNIST數據庫中學習了70000個圖像。我想在未包含在MNIST數據集中的圖像上進行測試。但是,我的預測函數無法讀取測試圖像的陣列表示。在學習MNIST後對非MNIST圖像進行分類

如何在外部圖像上測試我的算法? 爲什麼我的代碼失敗?

錯誤接收

PS我使用python3:

Traceback (most recent call last): 
    File "hello_world2.py", line 28, in <module> 
    print(sgd_clf.predict(arr)) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sklearn/linear_model/base.py", line 336, in predict 
    scores = self.decision_function(X) 
    File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sklearn/linear_model/base.py", line 317, in decision_function 
    % (X.shape[1], n_features)) 
ValueError: X has 15 features per sample; expecting 784 

代碼:

# Common Imports 
import numpy as np 
from sklearn.datasets import fetch_mldata 
from sklearn.linear_model import SGDClassifier 
from PIL import Image 
from resizeimage import resizeimage 

# loading and learning MNIST data 
mnist = fetch_mldata('MNIST original') 
x, y = mnist["data"], mnist["target"] 
sgd_clf = SGDClassifier(random_state=42) 
sgd_clf.fit(x, y) 

# loading and converting to array a non-MNIST image of a "5", which is in the same folder 
img = Image.open("5.png") 
arr = np.array(img) 

# trying to predict that the image is a "5" 
img = Image.open("5.png") 
img = img.convert('L') #makes it greyscale 
img = resizeimage.resize_thumbnail(img, [28,28]) 
arr = np.array(img) 

print(sgd_clf.predict(arr)) # ERROR... why????????? How do you fix it????? 
+0

該圖像將不得不調整大小。 MNIST圖像是28x28。 –

+0

此外你的圖像似乎是3通道。你必須灰度。 –

+0

如何調整MNIST圖像大小? (注意:請參閱原始代碼進行編輯,謝謝。) – Abicus

回答

0

請試試這個:

img = Image.open("5.png") 
img = img.resize((28,28)) 
img = img.convert('L') #makes it greyscale 
+0

試過了。取得了進展。但我仍然需要調整圖像大小。我很困惑如何調整MNIST圖像的大小。 (注意:請參閱上面的代碼以獲得最新的改進。謝謝。) – Abicus

+0

我更新了我的答案。也許是因爲您在將圖像轉換爲灰色之後重新調整圖像大小,因此它再次向圖像添加了3個圖層。而且您不需要使用另一個庫來調整大小。 –

0

如果你想讀那麼畫面調整它的大小,請嘗試

In [1]: import PIL.Image as Image 

In [2]: img = Image.open('2.jpg', mode='r') 

In [3]: img.mode 
Out[3]: 'RGB' 

In [4]: img.size 
Out[4]: (2880, 1800) 

In [5]: img_new = img.resize([4000, 4000], Image.ANTIALIAS) 

In [6]: img_new2 = img.resize([32, 32], Image.ANTIALIAS) 

文檔是here

這是2.JPG,對不起,這不是一個數字。

enter image description here 這張照片是來自互聯網,對不起,我忘記了來源。

如果遇到模式是「RGBA」,我建議你把它轉移到「RGB」模式,

newimg = Image.new('RGB', img.size) 
newimg.paste(img, mask=img.split()[3]) 
return newimg 
0

這不是簡單地調整大小的問題,圖像所需要的數字中心和白色的黑色等。我一直在爲這項工作開發一個功能。這是使用opencv的當前版本,雖然它可以做進一步的改進,包括使用PIL而不是opencv,但它應該給出所需步驟的概念。

def open_as_mnist(image_path): 
    """ 
    Assume this is a color or grey scale image of a digit which has not so far been preprocessed 

    Black and White 
    Resize to 20 x 20 (digit in center ideally) 
    Sharpen 
    Add white border to make it 28 x 28 
    Convert to white on black 
    """ 
    # open as greyscale 
    image = cv2.imread(image_path, 0) 

    # crop to contour with largest area 
    cropped = do_cropping(image) 

    # resizing the image to 20 x 20 
    resized20 = cv2.resize(cropped, (20, 20), interpolation=cv2.INTER_CUBIC) 

    cv2.imwrite('1_resized.jpg', resized20) 

    # gaussian filtering 
    blurred = cv2.GaussianBlur(resized20, (3, 3), 0) 

    # white digit on black background 
    ret, thresh = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV) 

    padded = to20by20(thresh) 


    resized28 = padded_image(padded, 28) 

    # normalize the image values to fit in the range [0,1] 
    norm_image = np.asarray(resized28, dtype=np.float32)/255. 

    # cv2.imshow('image', norm_image) 
    # cv2.waitKey(0) 

    # # Flatten the image to a 1-D vector and return 
    flat = norm_image.reshape(1, 28 * 28) 
    # return flat 

    # normalize pixels to 0 and 1. 0 is pure white, 1 is pure black. 
    tva = [(255 - x) * 1.0/255.0 for x in flat] 
    return tva 



def padded_image(image, tosize): 
    """ 
    This method adds padding to the image and makes it to a tosize x tosize array, 
    without losing the aspect ratio. 
    Assumes desired image is square 

    :param image: the input image as numpy array 
    :param tosize: the final dimensions 
    """ 

    # image dimensions 
    image_height, image_width = image.shape 


    # if not already square then pad to square 
    if image_height != image_width: 

     # Add padding 
     # The aim is to make an image of different width and height to a sqaure image 
     # For that first the biggest attribute among width and height are determined. 
     max_index = np.argmax([image_height, image_width]) 


     # if height is the biggest one, then add padding to width until width becomes 
     # equal to height 
     if max_index == 0: 
      #order of padding is: top, bottom, left, right 
      left = int((image_height - image_width)/2) 
      right = image_height - image_width - left 
      padded_img = cv2.copyMakeBorder(image, 0, 0, 
              left, 
              right, 
              cv2.BORDER_CONSTANT) 

     # else if width is the biggest one, then add padding to height until height becomes 
     # equal to width 
     else: 
      top = int((image_width - image_height)/2) 
      bottom = image_width - image_height - top 
      padded_img = cv2.copyMakeBorder(image, top, bottom, 0, 0, cv2.BORDER_CONSTANT) 
    else: 
     padded_img = image 


    # now that it's a square, add any additional padding required 
    image_height, image_width = padded_img.shape 
    padding = tosize - image_height 

    # need to handle where padding is not divisiable by 2 
    left = top = int(padding/2) 
    right = bottom = padding - left 
    resized = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT) 


    return resized