2013-05-01 2 views
1

Я пытаюсь проанализировать изображение. Я в основном делаю, что в 2 этапа:Python конвертировать изображение в ч/б с определенными правилами

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

Моя программа работает очень хорошо в большинстве случаев, но не для всех. Это в основном потому, что я никогда не понимал, как преобразовать изображение в черно-белое. Я в основном копировал код, который я нашел, и заставил его работать с пробной версией и ошибкой (вот почему я закончил с серой шкалой, а не с ч/б, поскольку я не нашел, как сделать каждый не белый пиксель в оттенках серого черным)

Я использую PIL для своих операций с изображениями, и мои основные функции для работы с изображениями выглядят следующим образом (convert() используется один раз, и avgcol() используется для каждой части преобразованного изображения, я хочу проанализировать)

def convert(): 
    global im 
    matrix = (1.412453, 0.357580, 0.180423, 0, 
      0.212671, 0.715160, 0.072169, 0, 
      0.019334, 0.119193, 0.950227, 0) 
    im = im.convert("L", matrix) 

def avgcol(im): 
    p_colors=im.getcolors() 
    cnt_pix=(im.size[0])*(im.size[1]) 
    avgpix=0 
    for i in range(len(p_colors)): 
     avgpix=avgpix+p_colors[i][0]*p_colors[i][1] 
    return round(avgpix/cnt_pix , 1) 

Я действительно не знаю, что делает матрица (не нашел сайт, который объясняет одиночные значения). Моя конкретная проблема прямо сейчас заключается в том, что я бы хотел конвертировать пиксели со слишком большим количеством зеленых в белые пиксели, но я уверен, что если это будет решено, что-то еще выскочит, так что некоторые основные объяснения, что-то вроде этого сделано, было бы здорово. Но я благодарен за любой указатель в правильном направлении. И, пожалуйста, не нужно решение для циклизации каждого пикселя. Фотографии довольно большие, и программа должна быть быстрой.

+0

Вы не знаете, как найти [документации] (http://www.pythonware.com/library/pil/handbook/image.htm)? – abarnert

ответ

2

Если вы посмотрите на the documentation, вы увидите несколько вещей.

Во-первых, convert имеет версию с одним аргументом, которая принимает только mode.

Если вы просто хотите RGB-на-преобразование: оттенки серого

grey = im.convert("L") 

Единственная причина, чтобы обеспечить матрицу, если вы не хотите использовать преобразование по умолчанию.

И вы также можете конвертировать непосредственно в двухуровневый черный & белым:

bw = im.convert("1") 

Как документы говорят:

При преобразовании в двухуровневый изображение (режим «1»), исходное изображение сначала преобразуется в черно-белый. После этого значения, превышающие 127, затем устанавливаются в белый цвет, и изображение уменьшается. Чтобы использовать другие пороговые значения, используйте метод точки.

Итак, если вы хотите стандартный порог и сглаживание, просто convert.Если вы хотите различный порог, он выглядит следующим образом:

grey = im.convert("L") 
table = [int(i>200) for i in range(256)] 
bw = grey.point(table, '1') 

В своем ответе, вы говорите:

... как сделать каждый небелый пиксель в оттенках серого до черного

Если вы действительно имеете в виду «ничего, кроме абсолютного чистого белого», как «небелые», вы не можете использовать для этого point. Даже если вы convert до L16 и point с таблицей 65536 пунктов, которая не может отличить 99,998% и 100% от белого, и вполне возможно, что некоторые из ваших исходных пикселей, которые были не белыми, не совпадают. Поэтому для этого вы, вероятно, хотите просто перебрать исходные пиксели напрямую (с функцией load) и создать новое изображение вручную.


Что касается матрицы, то это довольно просто, если вы понимаете основы математической матрицы. (Если вы этого не сделаете, я не могу объяснить это здесь, но the Wikipedia article может быть хорошим стартовым местом.)

Рассматривайте каждый пиксель источника как вектор (например, в изображении RGBA, вектор <red, green, blue, alpha>. Умножьте это вектор по матрице, и вы получите новый вектор. Рассматривайте это как пиксель в целевом цветовом пространстве.

Например, если у вас есть пиксели D65 RGBA, и вы умножаете каждый на матрицу 4x3, указанную в документах, результаты - это пиксели CIE XYZ.

Это означает, что нет необходимости использовать матрицу 4x3 для преобразования в L. То, что вы хотите, это матрица 4x1. И тогда, только если вы не хотите, чтобы по умолчанию. docs говорят:

Когда из цветного изображения в черно-белый, библиотека использует МСЭ-R 601-2 Luma преобразования:

L = R * 299/1000 + G * 587/1000 + B * 114/1000 

... который только (.299, .587, .114, 0).


Так что, если вы хотите:

конвертировать пиксели слишком много зеленого в белых пикселей

Это несколько неоднозначна. Но хотя бы один способ сделать что-то подобное - просто переоценить зеленый цвет. Например, если вы используете (.1495, .8448 , .0057, 0), зеленый цвет будет подсчитан намного больше, чем обычно (и красный и синий намного меньше) для определения яркости.


Между тем, в конце вашего вопроса:

И не угождать никакого решения с для-цикла каждого пикселя. Фотографии довольно большие, и программа должна быть быстрой.

Под одеялом, конечно, PIL команда как bw = grey.point([int(i>200) for i in range(256)], '1') фактически для-зацикливание каждый пиксель в grey. Он просто делает цикл на C, а не на Python. И вы можете сделать то же самое с Cython, или сделать это неявно с помощью numpy, или просто использовать PyPy вместо существующего интерпретатора Python (который может JIT для вашего Python для цикла до почти C-скорости).

Зачем вам это нужно? Ну, посмотрите на код порогов каждый путь:

# PIL 
table = [int(i>200) for i in range(256)] 
bw = grey.point(table, '1') 

# Python (run in PyPy) or Cython 
bw = [pixel > 200 for pixel in grey] 

# numpy 
bw = grey > 200 
+0

спасибо, это дало мне несколько идей. Я все еще не понимаю все то, что вы сказали, но это дало мне несколько советов, чтобы попробовать все. Я посмотрел еще немного на значения RGB, и я просто понял, что зеленый цвет не имеет большого значения. Синий - это цвет, когда лишний цвет должен быть черным. После некоторых попыток решение, которое работает лучше всего, - это def convert(): глобальный im matrix = (1, 1, -1, 100) table = [int (i> 250) для i в диапазоне (256) ] im = im.convert («L», matrix) .point (table, '1') все еще, я не понимаю, что означает альфа, википедия говорит, что это прозрачность, но здесь нет смысла –

+0

@ user2179887: На картинке, которая не имеет прозрачности, 'alpha' всегда 100% (то есть' 1.0', если вы используете float, '255' для 8-битных ints,' 65535' для 16-разрядных ints), и вам не нужно беспокоиться об этом. Если у изображения _does_ есть прозрачность, тогда 'alpha' составляет 0% для полностью прозрачных пикселей, 100% для полностью непрозрачных и промежуточных для частично видимых пикселей. – abarnert

+0

после некоторого тестирования я понял, что могу использовать альфа-значение, чтобы сделать оттенки серого более темными или светлыми. это означает, что im.convert ("L", (1, 1, -1, -50)) .point ([int (i> 100) для i в диапазоне (256)], '1') является таким же, как im.convert ("L", (1, 1, -1, 0)) .point ([int (i> 150) для i в диапазоне (256)], '1'). Я думал, что im.point ([int (i> 127) для i в диапазоне (256)], '1') совпадает с im.convert ('1'), но это не кажется истинным. Я мог бы использовать это, чтобы удалить всю операцию точки, но эти две операции, похоже, работают совершенно по-разному. Какие-либо предложения? –

Смежные вопросы