質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

【Python/SVM】画像の分類を行いたい

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 8,087

nnahito

score 1858

 前提

機械学習初心者です。
サポートベクターマシーン(SVM)の使い方を勉強中です。

 質問概要

サポートベクターマシーン(SVM)とPythonを用いて、
膨大な量の画像を「好き」or「嫌い」に分けたいが、以下のエラーが出てしまう。
なぜでしょうか?

ValueError: Found array with dim 3. Estimator expected <= 2.

 質問詳細

サポートベクターマシーン(SVM)とPythonを用いて、
膨大な量の画像を「好き」or「嫌い」に分けたいが、以下のエラーが出てしまいます。

ValueError: Found array with dim 3. Estimator expected <= 2.

これの意味がよく分かりませんが、調べてみたところ、入力値に問題があると……
……それは調べなくとも何となくわかりますが、その整形の仕方が分かりません。

以下、私が書いたコードと、フォルダ構成です。

 フォルダ構成

イメージ説明

  • img:分類したい画像データ
  • ng:嫌いな画像の教師群
  • ok:好きな画像の教師群
  • out:グレースケール、エッジ抽出、ダウンサイジングを行った後の画像を出力するフォルダ

 コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
from PIL import Image
import ImageFilter
import numpy as np
from sklearn import svm


# 定数定義場
STANDARD_SIZE = (300, 167)
CONST_NUM = 50100


# 変数定義場
Images = []                    # 教師画像
Labels = []                    # ラベル(ok = 0, ng = 1とする)


# 学習用画像データ(OK)を読み込む
for f in os.listdir("./ok/"):
    # 画像を読み込む
    img = Image.open("./ok/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # データを追加
    Images.append(np.asarray(img))

    # ラベルを設定
    Labels.append(0)

    print "Images, Labels = " + str(len(Images)) + ", " + str(len(Labels))

    #print "0, " + f

    img.save('./out/ok_' + f)



# 学習用画像データ(NG)を読み込む
for f in os.listdir("./ng/"):
    # 画像を読み込む
    img = Image.open("./ng/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # データを追加
    Images.append(np.asarray(img))

    img.save('./out/ng_' + f)

    # ラベルを設定
    Labels.append(1)
    #print "1, " + f
    print "Images, Labels = " + str(len(Images)) + ", " + str(len(Labels))

print Images

# ガウシアンカーネルによる SVM インスタンス生成
clf = svm.SVC(C=100, kernel="rbf")

# 教師データで学習 (データに対するフィッティング)
print "----------------"
print "TRAINING NOW..."
print "----------------"

print "画像数:" + str(len(Images))
print "ラベル数:" + str(len(Labels))

# トレーニング
clf.fit(Images, Labels)


# 分類する画像データを入れる変数
studentImages = []

# 分類する画像を読み込む
for f in os.listdir("./img/"):
    print "filename: " + f

    # 画像を読み込む
    img = Image.open("./img/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # データを追加
    studentImages.append(np.asarray(img))

    img.save('./out/student_' + f)


print "-------------------"
print "CLUSTERING NOW..."
print "-------------------"

# 画像データを分類する
results = clf.predict(studentImages)

for r in results:
    if r == 0:
        print "ok"
    elif r == 1:
        print "ng"
    else:
        print "error"

このやり方であっているのでしょうか?
画像の読み込み方や、配列の指定方法はあっていますでしょうか?

何かお気づきの点などございましたら、ご教示頂けますと幸いです。
よろしくお願いいたします。

 参考サイト様

 環境

  • MacOSX Yosemite 10.10.5
  • Python 2.7.10

 追記1

ベクトルの1次元変換は、このような感じでは無いでしょうか?

# 次元を1次元に変換
    img_np = np.asarray(img)
    img_np = img_np.shape[0] * img_np.shape[1]

以下、全文

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import os
from PIL import Image
import ImageFilter
import numpy as np
from sklearn import svm


# 定数定義場
STANDARD_SIZE = (300, 167)
CONST_NUM = 50100


# 変数定義場
Images = []                    # 教師画像
Labels = []                    # ラベル(ok = 0, ng = 1とする)


# 学習用画像データ(OK)を読み込む
for f in os.listdir("./ok/"):
    # 画像を読み込む
    img = Image.open("./ok/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # 次元を1次元に変換
    img_np = np.asarray(img)
    img_np = img_np.shape[0] * img_np.shape[1]

    # データを追加
    Images.append(img_np)

    # ラベルを設定
    Labels.append(0)

    print "Images, Labels = " + str(len(Images)) + ", " + str(len(Labels))

    img.save('./out/ok_' + f)



# 学習用画像データ(NG)を読み込む
for f in os.listdir("./ng/"):
    # 画像を読み込む
    img = Image.open("./ng/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # 次元を1次元に変換
    img_np = np.asarray(img)
    img_np = img_np.shape[0] * img_np.shape[1]

    # データを追加
    Images.append(img_np)

    img.save('./out/ng_' + f)

    print "Images, Labels = " + str(len(Images)) + ", " + str(len(Labels))

    # ラベルを設定
    Labels.append(1)



# ガウシアンカーネルによる SVM インスタンス生成
clf = svm.SVC(C=100, kernel="rbf")

# 教師データで学習 (データに対するフィッティング)
print "----------------"
print "TRAINING NOW..."
print "----------------"

print "画像数:" + str(len(Images))
print "ラベル数:" + str(len(Labels))

# トレーニング
clf.fit(Images, Labels)


# 分類する画像データを入れる変数
studentImages = []

# 分類する画像を読み込む
for f in os.listdir("./img/"):
    print "filename: " + f

    # 画像を読み込む
    img = Image.open("./img/" + f)

    # グレースケール化
    img = img.convert('L')

    # エッジ抽出
    img = img.filter(ImageFilter.FIND_EDGES)

    # ダウンサイジング
    img = img.resize(STANDARD_SIZE)

    # 次元を1次元に変換
    img_np = np.asarray(img)
    img_np = img_np.shape[0] * img_np.shape[1]

    # データを追加
    studentImages.append(img_np)

    img.save('./out/student_' + f)


print "-------------------"
print "CLUSTERING NOW..."
print "-------------------"

# 画像データを分類する
results = clf.predict(studentImages)

for r in results:
    if r == 0:
        print "ok"
    elif r == 1:
        print "ng"
    else:
        print "error"

 追記2

/Library/Python/2.7/site-packages/sklearn/utils/validation.py:386: DeprecationWarning:
Passing 1d arrays as data is deprecated in 0.17 and willraise ValueError in 0.19.
Reshape your data either using X.reshape(-1, 1) if your data has a single feature or X.reshape(1, -1) if it contains a single sample.

ValueError: X and y have incompatible shapes.
X has 1 samples, but y has 170.
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

+1

2次元画像をスタックして、3次元配列を作成しているようです。

># データを追加
>Images.append(np.asarray(img))

svmで画像を分類するには、画像を1次元のベクトルに変換する必要があります。それらを画像の枚数だけ並べて
行列を作り、それをsvmに渡します。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/13 11:04

    ご回答ありがとうございます。
    ベクトルの変換が必要ということなのですが、どのように行うのでしょうか。

    一応調べて見たところ、「追記1」のようにすればいいと載っているサイト様があったのですが、
    「追記2」のようなエラーが出ます。

    お手数をおかけいたしますが、もう少し詳しく教えて頂けませんでしょうか。

    キャンセル

  • 2016/12/15 07:54

    >> # 次元を1次元に変換
    >> img_np = np.asarray(img)
    >> img_np = img_np.shape[0] * img_np.shape[1]

    img_npガスカラーになっています。

    svmに渡すデータの構造を知るには、例えば
    from sklearn import datasets
    digits = datasets.load_digits()
    print(digits.data)
    を実行してみてください。何をどのようにならべればよいかわかるはずです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る