使用CNN是否可以对同一对象但具有不同区域的图像补丁进行分类?

时间:2018-10-25 00:51:22

标签: python opencv keras deep-learning computer-vision

我有两张打印对象的图片,第一张具有2.5x2.5 cm ^ 2的打印区域,第二张是相同的对象,但是打印区域是5.0x5.0 cm ^ 2。在将对象与背景分离并均衡了两张图片的直方图之后,我尝试在深度学习方法(CNN)中使用小的补丁(64x64)来了解它们的模式并对其进行分类。我正在尝试使用2.5x2.5cm ^ 2打印对象中的64x64补丁来训练深度学习分类器,并使用5.0x5.0cm ^ 2对象中的补丁来测试它们。这两个对象的数字图像具有与对象提取器定义的分辨率大致相同的分辨率。这是用于训练和测试CNN二进制分类器的64x64补丁的示例。


2.5x2.5cm ^ 2对象的64x64补丁

5x5cm ^ 2对象的64x64补丁

我要预测的类如下:

Negative Class

否定类(首次打印)

Positive Class

正类(已复制并转载)

我发现的东西:

  1. 如果使用相同大小(面积)的物体训练CNN,则对2.5x2.5cm ^ 2对象的补丁进行分类很容易
  2. 如果CNN使用2.5x2.5cm ^ 2对象的64x64补丁进行训练,并使用5x5cm ^ 2对象的64x64补丁进行测试,则预测仅针对一类(准确度为50%)。
  3. 在这种情况下,某些多尺度和多分辨率描述符可以很好地工作,例如使用“视觉单词袋”
  4. 在这种情况下,其他基准CNN也会失败,例如Mobilenet,Densenet和Resnet
  5. 我试图在数据扩充过程中包含缩放(如一个答案所建议)。它也不起作用:-(

这是我到目前为止尝试过的keras模型

model = Sequential()

# GROUP1
model.add(Conv2D(filters=32, kernel_size=3, strides=1, padding='same',
                 input_shape=input_shape))
model.add(LeakyReLU(alpha=0.2))


# GROUP2
model.add(Conv2D(filters=32, kernel_size=3, strides=2, padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))

# GROUP3
model.add(Conv2D(filters=64, kernel_size=3, strides=1, padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))

# GROUP4
model.add(Conv2D(filters=64, kernel_size=3, strides=2, padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))

# GROUP5
model.add(Conv2D(filters=96, kernel_size=3, strides=1, padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))

# GROUP6
model.add(Conv2D(filters=96, kernel_size=3, strides=2, padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(axis=-1, momentum=0.9, epsilon=0.001))

model.add(Flatten())
model.add(Dense(1024))
model.add(LeakyReLU(alpha=0.2))

model.add(Dense(2, activation='softmax'))

return model

这是我正在使用的数据扩充

datagen = ImageDataGenerator(
            width_shift_range=0.2,
            height_shift_range=0.2,
            horizontal_flip=True,
        vertical_flip=True,
        zoom_range=0.2,
            fill_mode='nearest')


    datagen.fit(x_train)
    datagen.fit(x_validation)

    # Fit the model on the batches generated by datagen.flow().
    model.fit_generator(datagen.flow(x_train, y_train, batch_size=batch_size),
                        steps_per_epoch=x_train.shape[0] // batch_size,
                        validation_data=datagen.flow(x_validation, y_validation, batch_size=batch_size),
                        epochs=nb_epoch, verbose=1, max_q_size=100,
                        validation_steps=x_validation.shape[0]//batch_size,
                        callbacks=[lr_reducer, early_stopper, csv_logger, model_checkpoint])

那么,在这种非常困难的CNN情况下,是否有解决方案来提高准确性?我的意思是,CNN可以从数据中学习功能,并且您可以看到,同一类的培训和测试数据是不同的。那么,是否有可能执行可以最小化或模拟训练数据中的测试数据的任何数据增强或CNN操作(如上所示,我的CNN没有丢失和池化)?

1 个答案:

答案 0 :(得分:1)

如果您的目标是预测多个缩放级别,则需要使用多个缩放级别训练CNN ... 我认为当前的增强生成的样本不是您想要的。例如,这是当zoom = 1.2时可能生成的图像之一:

augmented_image

最简单的解决方案是在训练5x5cm ^ 2色块时使用这样的生成器:

ImageDataGenerator(horizontal_flip=True,
                   vertical_flip=True,
                   zoom_range=[0.5, 1])

在这种情况下,当zoom = 0.5时,您将获得如下图像:

enter image description here

或多或少相当于2.5x2.5cm ^ 2的图像。

如果您必须使用2.5x2.5补丁进行培训,请尝试:

ImageDataGenerator(horizontal_flip=True,
                   vertical_flip=True,
                   zoom_range=[1, 2],
                   fill_mode='constant',
                   cval=0)

生成类似这样的图像:

enter image description here

有了足够的样本和纪元,CNN应该能够得知填充零可以忽略。