Эффективное попиксельное измерение в градациях серого в numpy и тензорном потоке - PullRequest
0 голосов
/ 04 мая 2018

У меня есть сочетание трехканальных изображений в градациях серого и цветных изображений в каталоге, и я хотел бы в меру подсчитать, насколько RGB-изображение на самом деле является эмпирически серым, и чтобы его можно было очень эффективно вычислить.

Я понимаю, что если R == G == B, у меня пиксел в градациях серого, а если R, G, B на пиксель не равны, у меня цветной пиксель. Я согласен с тем, чтобы сказать, что оттенки серого - это то, какая доля пикселей по сравнению с цветными оттенками Все истинные изображения в градациях серого должны иметь оценку == 1.

Я сделал глупую метрику, которая работает в PIL:

>>> from PIL import Image
>>> im = Image.open(filename)
>>> sum([1 for pixel in im.getdata() if (pixel[0]==pixel[1]==pixel[2])])/len(list(im.getdata()))

Для произвольного цвета im ==:

0.0003056384175265294

Для градаций серого == 1011 *

1.0

Так что это работает как ожидалось.

Как правильно транслировать это правильно, если предположить, что я начинаю с массива или тензорного потока, а не с файла, к которому я могу получить доступ к необработанным пикселям в PIL?

Я начинаю с:

sess = tf.Session()

dat = tf.read_file(filename)
ten = tf.image.decode_jpeg(dat)
x = sess.run(ten)

>>> x[0,0,:]
array([255, 255, 255], dtype=uint8)

выглядит хорошо. Я попробовал следующее, которое, похоже, не дает того, что я искал:

def grayscaler(x):
  """Input is a pixel.  Compare R == G == B"""
  if (x[0] == x[1] == x[2]):
    return 1
  else:
    return 0

>>> np.mean(np.apply_along_axis(grayscaler , axis=2, arr=x))

К сожалению, независимо от изображения, цвета или оттенков серого, я всегда получаю 1, цвет или оттенки серого, поэтому моя функция выше не переводится правильно.

>>> np.mean(np.apply_along_axis(grayscaler, axis=2, arr=x))
1.0

Каков правильный синтаксис и функция для зацикливания всех трех цветовых каналов попиксельным образом для массива-пустышки?

1 Ответ

0 голосов
/ 04 мая 2018

Думайте масштабно, думайте с точки зрения тензоров. Простая идея будет 1. вычислить версию в оттенках серого (для бедного человека) 2. вычесть полутоновую версию из intput 3. L2-расстояние

Как насчет

import tensorflow as tf
import numpy as np

fake_color = np.random.randn(8, 256, 256, 3).astype(np.float32)
fake_grayscale = np.random.randn(8, 256, 256, 3).mean(axis=3, keepdims=True).astype(np.float32)


def measure_grayscale(x):
    gray_version = tf.reduce_mean(x, axis=3, keepdims=True)
    difference = tf.reduce_mean(tf.squared_difference(x, gray_version), axis=[1, 2, 3])
    return difference


def regions_grayscale(x, tresh=0.1):
    gray_version = tf.reduce_mean(x, axis=3, keepdims=True)
    difference = tf.squared_difference(x, gray_version)
    return tf.greater(difference, tresh * tf.ones_like(difference))


with tf.Session() as sess:
    data = tf.placeholder(tf.float32)
    print sess.run(measure_grayscale(data), {data: fake_color})
    print sess.run(measure_grayscale(data), {data: fake_grayscale})

Это дает здесь:

  • [0.6701656 0.6660412 0.6667728 0.6642832 0.667957 0.66799116 0,6700557 0,66249603] для партии цветных изображений
  • [0. 0. 0. 0. 0. 0. 0. 0.] для серии изображений только в градациях серого

Обнаружение областей, которые являются оттенками серого согласно вашей эвристике, может быть выполнено с помощью порогового значения в regions_grayscale. Вы даже можете применить tf.reduce_mean(.., axis=1), чтобы заставить вашу "глупую метрику" работать.

Синтаксис NumPy такой же. Поскольку вы используете тег TensorFlow, код выше использует TensorFlow.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...