Комментарии 50
плашку туториал надо было прилепить.
+1
"Опошлю" и эту статью «магией» «консольного „фотошопа“» :)
Оттенки серого
Получается выразительней. Наверное, потому что используется что-нибудь посложнее среднего значения
Сепия
Негатив
Яркость. Положительный параметр делает ярче, отрицательный — темнее
Бинаризацию вообще можно многими путями:
Вот результаты:
Еще можно расчехлить -fx и использовать для всех этих эффектов свои формулы-программы. :)
Оттенки серого
convert input.jpg -colorspace gray gray.jpg
Получается выразительней. Наверное, потому что используется что-нибудь посложнее среднего значения
Скрытый текст
Сепия
convert input.jpg -sepia-tone 80% sepia.jpg
Негатив
convert input.jpg -negate negated.jpg
Яркость. Положительный параметр делает ярче, отрицательный — темнее
convert input.jpg -brightness-contrast -20% dark.jpg
convert input.jpg -brightness-contrast 20% bright.jpg
Бинаризацию вообще можно многими путями:
convert input.jpg -monochrome -normalize binarize3.jpg
convert input.jpg -remap pattern:gray50 binarize2.jpg
convert input.jpg -colorspace gray +dither -colors 2 binarize1.jpg
Вот результаты:
Скрытый текст
Еще можно расчехлить -fx и использовать для всех этих эффектов свои формулы-программы. :)
+25
Это конечно хорошо, но не спортивно, самому же интереснее. Конечно, так удобнее и быстрее, но для обучения, можно и попрактиковаться.
+3
Кстати насчёт оттенков серого: автор мог бы всё же поинтересоваться, и узнать, что обычно берется не среднее, а что-то вроде
(R*30 + G*59 + B*11)/100
(R*30 + G*59 + B*11)/100
+2
ImageMagick это здорово, но на деле PIL быстрее
0
Оттенки серого считаются вовсе не так.
+14
А остальные эффекты где можно найти? Может какой ресурс есть.
+2
Формула, использованная автором, очень грубая и лобовая — и тем не менее, имеет место и такой вариант тоже.
Вообще не существует какой-то одной единственно-верной формулы пересчета в grayscale, аналогично для сепии и пр.
Там если углубляться — черт ногу сломит.
Вообще не существует какой-то одной единственно-верной формулы пересчета в grayscale, аналогично для сепии и пр.
Там если углубляться — черт ногу сломит.
+1
Спасибо, как раз неспешно в обеденное время прохожу python challenge, там надо как раз по всякому ковырять картинки на предмет зашифрованного содержимого.
0
> Это очень просто, достаточно лишь каждое значение пиксела вычесть из 255.
> draw.point((i, j), (255 — a, 255 — b, 255 — c))
Здесь что-то не сходится. Особенно если там по вычету 255, то вычитать 255 не имеет смысла.
> draw.point((i, j), (255 — a, 255 — b, 255 — c))
Здесь что-то не сходится. Особенно если там по вычету 255, то вычитать 255 не имеет смысла.
0
А насколько это все медленно/быстро работает?
0
Для картинки из примеров приблизительно 3 сек на моём нетбуке.
0
OpenCV в среднем такие операции на картинке такого размера выполняет за 1 мс, без учета IO конечно.
+1
Пойду почитаю о нем.
0
Сами посудите, если у вас процессор 2ГГц, получается что на обработку 1 пикселя уходит 30 000 тактов. Как-то многовато
0
Но у меня и нетбук слабенький очень.
0
Это просто задача не для Python. Безопасность, проверки границ и др. очень сильно тормозит работу.
0
Я полностью согласен. Питоновская скорость работы тут не годится для реального применения, но тем не менее получается красивый и лаконичный код, писать это на питоне нужно, я думаю, только для практики.
0
PIL написан на сях, поэтому PIL достаточно быстр. Быстрее чем ImageMagick, например.
+1
Это разве длиннее?
#include <QCoreApplication>
#include <QImage>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QImage img("test.jpg");
for (int i = 0; i < img.width(); i++) {
for (int j = 0; j < img.height(); j++) {
QRgb rgb = img.pixel(j, i);
int s = (qRed(rgb) + qGreen(rgb) + qBlue(rgb)) / 3;
img.setPixel(j, i, qRgb(s, s, s));
}
}
img.save("outtest.jpg", "JPEG");
return 0;
}
time ./imagecvt
real 0m0.033s
user 0m0.023s
sys 0m0.010s
+1
Дело не только а размере кода (хотя код на Питоне из-за особенностей языка всеравно будет короче), а в том, что не нужен процесс компиляции.
Т.е. делаете вы тулсет для работы с изображениями, вдруг требования немного изменились — открыли в notepad скрипт, подправили, сохранили — можно работать дальше.
Т.е. делаете вы тулсет для работы с изображениями, вдруг требования немного изменились — открыли в notepad скрипт, подправили, сохранили — можно работать дальше.
+1
Если бы я писал тулсет, я всё равно писал бы на C++. Компиляция не так страшна. Но даже если бы и понадобилось на Python, то написать часть оптимизированную на Си (вроде Python это позволяет, и выше мне подсказывают, что PIL так и сделан), а вызовы дёргать из Python. И тогда реализовать метод с матрицей 5х5 для цветового преобразования изображения.
0
Так вот для этого и используют Python+PIL :)
И не нужно писать ничего низкоуровневого — все написано до нас.
И не нужно писать ничего низкоуровневого — все написано до нас.
0
А в PIL есть что-то вроде:
Для инверсии?
Или
Для grayscale?
image2 = image.colorTransform([[-1, 0, 0, 0, 1],
[0, -1, 0, 0, 1],
[0, 0, -1, 0, 1],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]]);
Для инверсии?
Или
[[0.299, 0.587, 0.114, 0, 0],
[0.299, 0.587, 0.114, 0, 0],
[0.299, 0.587, 0.114, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]]
Для grayscale?
0
Ну, PIL быстрее, чем ImageMagick, например
+1
Код примера
from PIL import Image, ImageDraw, ImageMath
def bw1(s):
d = s.copy()
pix = d.load()
draw = ImageDraw.Draw(d)
for i in range(s.size[0]):
for j in range(s.size[1]):
a = pix[i, j][0]
b = pix[i, j][1]
c = pix[i, j][2]
S = (a + b + c) // 3
draw.point((i, j), (S, S, S))
return d
def bw2(s):
r, g, b = s.split()
return ImageMath.eval("convert((r + g + b) / 3, 'L')", r=r, g=g, b=b)
def bw3(s):
return s.convert('L')
s = Image.open('s.jpg')
bw1(s).save('bw1.jpg')
bw2(s).save('bw2.jpg')
bw3(s).save('bw3.jpg')
from timeit import timeit
print 'Per pixel:', timeit(lambda: bw1(s), number=10)
print 'ImageMath:', timeit(lambda: bw2(s), number=10)
print 'Image.convert:', timeit(lambda: bw3(s), number=10)
$ ./test.py
Per pixel: 7.06867003441
ImageMath: 0.0504641532898
Image.convert: 0.00568413734436
Разница более чем в 100 и 1000 раз. Второй вариант идентичен вашему (ну вдруг вам именно это нужно было), третий — правильный. Все остальные преобразования делаются аналогично.
+5
c = max(c, 0)
c = min(c, 255)
А лучше вынесли бы в отдельную функцию:
def limit(value, low=0, high=255):
return min(max(value, low), high)
+1
Другие алгоритмы:
Мой вариант сепии, где картинка получается более насыщенной. У сепии RGB = (112, 66, 20), компоненты с разницей в 46, поэтому я просто складываю и вычитаю на 46.
Чёрно-белое со случайным порогом (factor). Выглядит лучше, при просмотре издалека.
Есть ещё интересное создание чёрно-белых изображений с матрицами возмущений, но там уже не так очевидно, лучше почитайте где-нибудь.
Мой вариант сепии, где картинка получается более насыщенной. У сепии RGB = (112, 66, 20), компоненты с разницей в 46, поэтому я просто складываю и вычитаю на 46.
mean = (R + G + B) / 3
R = mean + 46 // если больше 255, то = 255
G = mean
B = mean - 46 // если меньше 0, то = 0
Чёрно-белое со случайным порогом (factor). Выглядит лучше, при просмотре издалека.
mean = (R + G + B) / 3
factor = rand()%255 + 1 // Случайное число от 1 до 256
Если mean < factor то
result = 0
Иначе
result = 255
R = result
G = result
B = result
Есть ещё интересное создание чёрно-белых изображений с матрицами возмущений, но там уже не так очевидно, лучше почитайте где-нибудь.
+1
Зачем использовать draw, если можно писать напрямую в пиксели аналогично тому, как вы их читаете? Это будет быстрее. В качестве туториала статья никуда не годится. Такое ощущение, что вы освоили цикл пробежки по пикселям и все. PIL позволяет делать куда больше. Позволяет пережимать в различные форматы, увеличивать/уменьшать с различным качеством, вырезать/вставлять куски изображений. Все, что вы сделали можно сделать фильтрами PIL и работать это будет гораздо быстрее.
+4
Не понимаю, почему человеку влепили за это минус, он прав!
getpixel и putpixel работает несколько быстрее, да и PIL из коробки это умеет делать, причем ресурсоемкие операции написаны на Си.
getpixel и putpixel работает несколько быстрее, да и PIL из коробки это умеет делать, причем ресурсоемкие операции написаны на Си.
+1
Как эффективнее всего переставлять пиксели местами? Хочу написать программу, создающую изображение как результат комплексной функции, взятой от исходного изображения, где горизонтальные координаты пикселей - действительная ось, а вертикальные - мнимая.
0
if (mode == 2):
goto 100
+3
a = pix[i, j][0]
b = pix[i, j][1]
c = pix[i, j][2]
->
a, b, c = pix[i, j]
+3
Все хорошо. Вот только это далеко не Pythonic way. Да и вообще с python мало связано. То же можно было на чем угодно продемонстрировать.
+1
Простите меня за непрофильный вопрос, который, чесслово, мучает со времен школы: правильно ли говорить «играться» и существует ли такое слово? «Биться об стену» и «бить баклуши» понимаю, а вот с «играть с самим собой»… какие-то неприличные синонимы в голову лезут. Ау, Mithgol!
0
Сделал на базе вашего интересный эффект:
Добавляем в начало кода строки
Image2 нужен, в качестве «палитры» оригинальных пикселей, без искажения.
Сам код (добавляем перед сохранением изображения):
Вот, например, стандартная картинка из Windows7, пропущенная через прогу с параметрами mul = 10, freq = 40:
Добавляем в начало кода строки
image2 = Image.open("test.jpg")
pix = image2.load() #Выгружаем значения пикселей.
Image2 нужен, в качестве «палитры» оригинальных пикселей, без искажения.
Сам код (добавляем перед сохранением изображения):
if (mode == 6):
mul = int(input('Multiple: '))
abc = float(input('Frequency: '))
freq = abc / 1000
for i in range(width):
for j in range(1,height-1):
v = round((mul*math.sin(i*freq)))
m = v + j -mul
if (m > (height-1)):
m = height-1
if (m < 1):
m = 1
a = pix[i,m][0]
b = pix[i,m][1]
c = pix[i,m][2]
draw.point((i,j),(a,b,c))
Вот, например, стандартная картинка из Windows7, пропущенная через прогу с параметрами mul = 10, freq = 40:
0
Коэффицент восприимчивости RGB — не, не слышали
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Играемся с изображениями в Python