1

我正在尝试使用 scikit-learn 构建一个简单的图像分类器。我希望避免在训练之前调整每个图像的大小和转换。

问题

给定两个不同格式和大小的图像(1.jpg2.png),我怎样才能避免ValueError拟合模型?

  • 我有一个例子,我只使用 训练1.jpg,它很适合。
  • 我有另一个例子,我使用1.jpgand2.png和 aValueError进行训练。

此示例将成功拟合:

import numpy as np
from sklearn import svm 
import matplotlib.image as mpimg

target = [1, 2]
images = np.array([
    # target 1
    [mpimg.imread('./1.jpg'), mpimg.imread('./1.jpg')],
    # target 2
    [mpimg.imread('./1.jpg'), mpimg.imread('./1.jpg')],
])
n_samples = len(images)
data = images.reshape((n_samples, -1))
model = svm.SVC()
model.fit(data, target)

此示例将引发值错误。

观察目标 2 中不同的 2.png 图像。

import numpy as np
from sklearn import svm 
import matplotlib.image as mpimg

target = [1, 2]
images = np.array([
    # target 1
    [mpimg.imread('./1.jpg'), mpimg.imread('./1.jpg')],
    # target 2
    [mpimg.imread('./2.png'), mpimg.imread('./1.jpg')],
])
n_samples = len(images)
data = images.reshape((n_samples, -1))
model = svm.SVC()
model.fit(data, target)
# ValueError: setting an array element with a sequence.

1.jpg

1.jpg

2.png

2.png

4

2 回答 2

2

为此,我真的建议使用Keras专门设计用于以高度可扩展和高效的方式预处理图像的工具。

from keras.preprocessing.image import ImageDataGenerator
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np

1 确定新图片的目标尺寸

h,w = 150,150 # desired height and width
batch_size = 32 
N_images = 100 #total number of images

Keras批量工作,因此batch_size只需确定一次将处理多少张图片(这不会影响您的最终结果,只会影响速度)。

2 创建您的图像生成器

train_datagen = ImageDataGenerator(
    rescale=1./255)

train_generator = train_datagen.flow_from_directory(
    'Pictures_dir',
    target_size=(h, w),
    batch_size=batch_size,
    class_mode = 'binary')

将要进行图像提取的对象是ImageDataGenerator。它具有flow_from_directory我认为可能对您有用的方法。它将读取文件夹的内容,Pictures_dir并期望您的图像按类别位于文件夹中(例如:Pictures_dir/class0 和 Pictures_dir/class1)。生成器在调用时将从这些文件夹创建图像并导入它们的标签(在本例中为“class0”和“class1”)。

这个生成器还有很多其他参数,您可以在Keras文档中查看它们(特别是如果您想进行数据扩充)。

注意:这将根据您的要求拍摄任何图像,无论是 PNG 还是 JPG

如果要获取从类名到标签索引的映射,请执行以下操作:

train_generator.class_indices
# {'class0': 0, 'class1': 1}

你可以检查发生了什么

plt.imshow(train_generator[0][0][0])

3 从生成器中提取所有调整大小的图像

现在您已准备好从以下文件中提取图像ImageGenerator

def extract_images(generator, sample_count):
    images = np.zeros(shape=(sample_count, h, w, 3))
    labels = np.zeros(shape=(sample_count))
    i = 0
    for images_batch, labels_batch in generator: # we are looping over batches
        images[i*batch_size : (i+1)*batch_size] = images_batch
        labels[i*batch_size : (i+1)*batch_size] = labels_batch
        i += 1
        if i*batch_size >= sample_count:
            # we must break after every image has been seen once, because generators yield indifinitely in a loop
            break
    return images, labels

images, labels = extract_images(train_generator, N_images)

print(labels[0])
plt.imshow(images[0])

现在,您在 中拥有所有大小相同的图像,在 中拥有images它们相应的标签labels,然后您可以将其输入到scikit-learn您选择的任何分类器中。

于 2019-06-30T01:39:25.843 回答
1

由于幕后的数学运算,这很困难,(细节超出范围)如果你设法这样做,假设你构建了自己的算法,但你仍然不会得到想要的结果。我曾经遇到过这个问题,面部大小不同。也许这段代码可以为您提供起点。

from PIL import Image
import face_recognition

def face_detected(file_address = None , prefix = 'detect_'):
    if file_address is None:
        raise FileNotFoundError('File address required')
    image = face_recognition.load_image_file(file_address)
    face_location = face_recognition.face_locations(image)

    if face_location:
        face_location = face_location[0]
        UP = int(face_location[0] - (face_location[2] - face_location[0]) / 2)
        DOWN = int(face_location[2] + (face_location[2] - face_location[0]) / 2)
        LEFT = int(face_location[3] - (face_location[3] - face_location[2]) / 2)
        RIGHT = int(face_location[1] + (face_location[3] - face_location[2]) / 2)

        if UP - DOWN is not LEFT - RIGHT:
            height = UP - DOWN
            width = LEFT - RIGHT
            delta = width - height
            LEFT -= int(delta / 2)
            RIGHT += int(delta / 2)

        pil_image = Image.fromarray(image[UP:DOWN, LEFT:RIGHT, :])
        pil_image.thumbnail((50, 50), Image.ANTIALIAS)
        pil_image.save(prefix + file_address)

        return True

    pil_image = Image.fromarray(image)
    pil_image.thumbnail((200, 200), Image.ANTIALIAS)
    pil_image.save(prefix + file_address)
    return False

注意:我很久以前写过这个可能不是一个好习惯

于 2019-06-26T23:16:38.210 回答