Метод расширения набора данных распознавания объектов

искусственный интеллект компьютерное зрение

вводная информация

При обучении глубокой нейронной сети распознаванию изображений использование большего количества обучающих данных может привести к повышению производительности сети, например, к повышению точности классификации сети и предотвращению переобучения. Манипуляции с данными при искусственном расширении обучающих данных должны наилучшим образом отражать изменения в реальном мире. Если точность классификации значительно улучшается после искусственного расширения набора данных, это означает, что операция расширения, которую мы проделали с данными, является доброкачественной и может «отражать изменения в реальном мире», и она будет использоваться для расширения набора данных. весь набор данных. Наоборот, это означает, что эту операцию нельзя использовать для расширения набора данных.

Например, в статье 2003 года Патриса Симарда и др. [1] они расширили набор данных рукописных цифр MNIST за счет поворота, преобразования и деформации. Обучаясь на этом расширенном наборе данных, они повысили точность распознавания рукописных цифр MNIST до 98,9%. Затем также были проведены эксперименты с набором данных «упругой деформации», специального метода деформации изображения, предназначенного для имитации случайного дрожания мышц рук. Используя расширенные данные с эластичной деформацией, они в конечном итоге достигли точности классификации 99,3%.

конкретный метод

исходное изображение

demo.jpg

Преобразование интенсивности изображения

Изменение яркости

lightness

darkness

Добавьте случайное смещение к изображению в целом или масштабируйте все изображение

  • Повышение яркости

    demo_brightness.jpg
  • Уменьшенная яркость

    demo_darkness.jpg
brightness = 1 + np.random.randint(1, 9) / 10
brightness_img = img.point(lambda p: p * brightness)

Не влияет на положение этикетки

Изменение контраста

contrast

Расширить динамический диапазон уровня серого изображения, сжать пиксели в крайних точках и расширить пиксели в среднем диапазоне.

range_contrast=(-50, 50)
contrast = np.random.randint(*range_contrast)
contrast_img = img.point(lambda p: p * (contrast / 127 + 1) - contrast)

Не влияет на положение этикетки

demo_contrast.jpg

фильтрация изображений

точить

sharpen

Улучшить информацию о краях изображения

identity = np.array([[0, 0, 0],
                     [0, 1, 0],
                     [0, 0, 0]])
sharpen = np.array([[ 0, -1,  0],
                    [-1,  4, -1],
                    [ 0, -1,  0]]) / 4
max_center = 4
sharp = sharpen * np.random.random() * max_center
kernel = identity + sharp
sharpen_img = cv2.filter2D(img, -1, kernel)

Не влияет на положение этикетки

demo_sharpen.jpg

Размытие по Гауссу

blur

Сглаживание изображения

kernel_size = (7, 7)
blur_img = cv2.GaussianBlur(img,kernel_size,0)

Не влияет на положение этикетки

demo_blur.jpg

перспективное преобразование

зеркало флип

flip

Отразить изображение по длинной оси

flip_img = cv2.flip(cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR), 1)

Параметр pos=1 - pos на первой позиции, остальная информация остается без изменений, может автоматически генерироваться скриптом

with open(name + "_flip.txt", "w") as outfile:
  with open(name + ".txt", "r") as infile:
    for line in infile.readlines():
      words = line.split(" ")
      horizontal_coord = float(words[1])
      outfile.write(words[0] + " " + str(format(1-horizontal_coord, ".6f")) + " " + words[2] + " " + words[3] + " " + words[4])
demo_flip.jpg

обрезка изображения

crop

Обрежьте центральное изображение на 80% от исходного размера и переместите его случайным образом.

kernel_size = list(map(lambda x: int(x*0.8), size))
shift_min, shift_max = -50, 50
shift_size = [np.random.randint(shift_min, shift_max), np.random.randint(shift_min, shift_max)]

crop_img = img[
  (size[0]-kernel_size[0])//2+shift_size[0]:(size[0]-kernel_size[0])//2+kernel_size[0]+shift_size[0],
  (size[1]-kernel_size[1])//2+shift_size[1]:(size[1]-kernel_size[1])//2+kernel_size[1]+shift_size[1]
]

Целевой объект может быть обрезан, поэтому используется ручная перемаркировка.

demo_crop.jpg

Растяжение изображения

deform

Растянуть квадратное изображение с исходной шириной

deform_img = img.resize((int(w), int(w)))

Информация о масштабе на исходном изображении изменилась, лучше всего переразметить вручную

demo_deform.jpg

дисторсия объектива

distortion

Применение к изображению изменений перспективы, имитирующих искажение объектива «рыбий глаз».

Это достигается игрой радиальных коэффициентов k1, k2, k3 и тангенциальных коэффициентов p1, p2

d_coef= np.array((0.15, 0.15, 0.1, 0.1, 0.05))
# get the height and the width of the image
h, w = img.shape[:2]
# compute its diagonal
f = (h ** 2 + w ** 2) ** 0.5
# set the image projective to carrtesian dimension
K = np.array([[f, 0, w / 2],
              [0, f, h / 2],
              [0, 0,   1  ]])
d_coef = d_coef * np.random.random(5) # value
d_coef = d_coef * (2 * (np.random.random(5) < 0.5) - 1) # sign
# Generate new camera matrix from parameters
M, _ = cv2.getOptimalNewCameraMatrix(K, d_coef, (w, h), 0)
# Generate look-up tables for remapping the camera image
remap = cv2.initUndistortRectifyMap(K, d_coef, None, M, (w, h), 5)
# Remap the original image to a new image
distortion_img = cv2.remap(img, *remap, cv2.INTER_LINEAR)

Лучше перемаркировать вручную

demo_distortion.jpg

ввести шум

шум соли и перца

noise

Случайное добавление белых/черных пикселей к изображению

for i in range(5000):
  x = np.random.randint(0,rows)
  y = np.random.randint(0,cols)
  noise_img[x,y,:] = 255
  noise_img.flags.writeable = True

Не влияет на положение этикетки

demo_noise.jpg

виньетирование

vignetting

Добавляет круговой диапазон шума для имитации ореола

ratio_min_dist=0.2
range_vignette=np.array((0.2, 0.8))
random_sign=False

h, w = img.shape[:2]
min_dist = np.array([h, w]) / 2 * np.random.random() * ratio_min_dist

# create matrix of distance from the center on the two axis
x, y = np.meshgrid(np.linspace(-w/2, w/2, w), np.linspace(-h/2, h/2, h))
x, y = np.abs(x), np.abs(y)
# create the vignette mask on the two axis
x = (x - min_dist[0]) / (np.max(x) - min_dist[0])
x = np.clip(x, 0, 1)
y = (y - min_dist[1]) / (np.max(y) - min_dist[1])
y = np.clip(y, 0, 1)
# then get a random intensity of the vignette
vignette = (x + y) / 2 * np.random.uniform(*range_vignette)
vignette = np.tile(vignette[..., None], [1, 1, 3])
sign = 2 * (np.random.random() < 0.5) * (random_sign) - 1
vignetting_img = img * (1 + sign * vignette)

Не влияет на положение этикетки

demo_vignetting.jpg

разное

Случайный вырез

cutout

Произвольно вырежьте четыре позиции и заполните их черными/цветными прямоугольниками.

channel_wise = False
max_crop = 4
replacement=0

size = np.array(img.shape[:2])
mini, maxi = min_size_ratio * size, max_size_ratio * size
cutout_img = img
for _ in range(max_crop):
  # random size
  h = np.random.randint(mini[0], maxi[0])
  w = np.random.randint(mini[1], maxi[1])
  # random place
  shift_h = np.random.randint(0, size[0] - h)
  shift_w = np.random.randint(0, size[1] - w)

  if channel_wise:
    c = np.random.randint(0, img.shape[-1])
    cutout_img[shift_h:shift_h+h, shift_w:shift_w+w, c] = replacement
    else:
      cutout_img[shift_h:shift_h+h, shift_w:shift_w+w] = replacement

Не влияет на положение этикетки

demo_cutout.jpg