diff --git a/Black-White.jpg b/Black-White.jpg new file mode 100644 index 0000000..f13e224 Binary files /dev/null and b/Black-White.jpg differ diff --git a/README.md b/README.md index f3543e8..325c28c 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,33 @@ -# Рефакторинг +PIXEL ART +=========== -В последнее время очень популярен [пиксельарт](https://en.wikipedia.org/wiki/Pixel_art), а также разнообразные наборы для ручного крафта. - -Один из проектов, [mozabrick](https://mozabrick.ru/products/model-l/), например, предлагает что-то типа мозайки из квадратиков 5 градаций серого, из которой можно собрать любую фотографию. - -![Преобразование](https://github.com/bibilov/refactoring/blob/main/img-test.png) С помощью приложения вы накладываете фильтр, получаете черно-белый пиксель-арт, который можно набрать уже мозаикой. -Иногда делают такие панно прямо на зданиях. - -![Здание](https://github.com/bibilov/refactoring/blob/main/632.jpg) - - -Вот я прогнал через фильтр свое фото: - -![Фото с фильтром](https://github.com/bibilov/refactoring/blob/main/m0oLR8Tx0zRG8s3SZQlQLnF8bhcnGu6AwzRA5aqi.png_4_1.png) - -Вот так примерно выглядит процесс сборки панно: - -![Сборка](https://github.com/bibilov/refactoring/blob/main/compile.png) - -Естественно, появилось желание написать вручную такой фильтр. Он может понадобится для пиксель-арта, создания игр с анимацией а-ля ранний Mortal Kombat, японских кроссвордов или для вязки свитеров ближе к НГ. Для чтения-записи изображений используется библиотека `pillow`, для всех остальных манипуляций — `numpy`. - - -```python -from PIL import Image -import numpy as np -img = Image.open("img2.jpg") -arr = np.array(img) -a = len(arr) -a1 = len(arr[1]) -i = 0 -while i < a - 11: - j = 0 - while j < a1 - 11: - s = 0 - for n in range(i, i + 10): - for n1 in range(j, j + 10): - n1 = arr[n][n1][0] - n2 = arr[n][n1][1] - n3 = arr[n][n1][2] - M = n1 + n2 + n3 - s += M - s = int(s // 100) - for n in range(i, i + 10): - for n1 in range(j, j + 10): - arr[n][n1][0] = int(s // 50) * 50 - arr[n][n1][1] = int(s // 50) * 50 - arr[n][n1][2] = int(s // 50) * 50 - j = j + 10 - i = i + 10 -res = Image.fromarray(arr) -res.save('res.jpg') -``` - -Картинка прелставляет сосбой трехмерный массив, где два измерения — таблица с пикселями, а пиксель — что-то то типа массива `[12, 240, 123]`, содержащего компоненты RGB. - -Я ввел размер элемента мозайки 10x10 пикселей. Среди 100 пикселей из большой ячейки я просто выясняю среднюю яркость и закрашиваю их все в один цвет средней яркости, приведенный к ступеньке с шагом 50. - -В результате из такой картинки: - -![Исходная каритинка](https://github.com/bibilov/refactoring/blob/main/img2.jpg) - -Получается такая: - -![Результат](https://github.com/bibilov/refactoring/blob/main/res.jpg) +Исходная картинка: +============ +![Исходная каритинка](original.jpg) -Это не тот результат, на который я рассчитывал, и вам предстоит много поработать с моим кодом. +Запуск filter.py: +---------- +![Запуск filter.py](filter.py.png) -Представьте этапы как отдельные коммиты. +Запуск old_filter.py: +-------------- +![Запуск old_filter.py](old_filter.py.png) -## Что делать? +Запуск filter_with_filename.py: +-------------- +![Запуск filter_with_filename.py](filter_with_filename.py.png) -### 1 этап -К коду настолько много вопросов, что я даже не знаю с чего начать... +Результат: +================ +![Результат](Black-White.jpg) -* В коде содержатся как минимум четыре ошибки, которые заставляют фильтр работать не так, как нужно. - * Одна из них очень нетипична для программиста на Питоне и связана с переполнением беззнакового целого `numpy.uint8`. - * В одном месте я запутался с именами переменных. - * Неверно считаю компоненты серого цвета (забываю поделить на 3). - * Неверно работаю с граничными условиями, в результате чего справа и внизу остались необработанные полосы по 10 пикселей. +Тестирование и отладчик: +=============== +![ТЕСТИРОВАНИЕ И ОТЛАДЧИК](тестирование1.png) +![ТЕСТИРОВАНИЕ И ОТЛАДЧИК](тестирование2.png) +![ТЕСТИРОВАНИЕ И ОТЛАДЧИК](отладчик.png) -### 2 этап -* PEP8. -* Именование переменных. -* Возможность управлять размерами мозайки (сейчас — только 10x10). -* Возможность управлять градациями серого (сейчас — с шагом 50). Лучше сделать просто в виде задания количества шагов. Например: 4 градации, 6 градаций. -* Выделение функций. -### 3 этап -* По возможности убрать ручные циклы, заменив их матричными преобразованиями. -### 4 этап -* Возможно, переписать в консольную утилиту, которой на вход подаются имена исходного изображения и результата. Сейчас чтобы заставить код работать с другой картинкой, его надо исправлять. +Мы получаем огромную разницу во времени из-за ожидания пользовательского воода в файле filter.py. В файле filter_with_filename.py изначало прописано имя картинки и прочие необходимые нам параметры. За счет этого небольшого изменения время выполнение программы существенно сократилось. Полученное время намного меньше времени выполнения old_filter.py. Из этого можем сделать вывод, что отрефакторенный код намного быстрее первоначального. diff --git a/filter.py b/filter.py index f7fa90e..92780a0 100644 --- a/filter.py +++ b/filter.py @@ -1,28 +1,38 @@ -from PIL import Image import numpy as np -img = Image.open("img2.jpg") -arr = np.array(img) -a = len(arr) -a1 = len(arr[1]) -i = 0 -while i < a - 11: - j = 0 - while j < a1 - 11: - s = 0 - for n in range(i, i + 10): - for n1 in range(j, j + 10): - n1 = arr[n][n1][0] - n2 = arr[n][n1][1] - n3 = arr[n][n1][2] - M = n1 + n2 + n3 - s += M - s = int(s // 100) - for n in range(i, i + 10): - for n1 in range(j, j + 10): - arr[n][n1][0] = int(s // 50) * 50 - arr[n][n1][1] = int(s // 50) * 50 - arr[n][n1][2] = int(s // 50) * 50 - j = j + 10 - i = i + 10 -res = Image.fromarray(arr) -res.save('res.jpg') +from PIL import Image + +class MonochromePhoto: + def __init__(self, pixArray, pixSize=10, gradation=5): + self.image = np.array(pixArray) + self.size = pixSize + self.grad = 255 // gradation + self.width = len(self.image) + self.height = len(self.image[0]) + + def get_grey_image(self): + for x in range(0, self.width, self.size): + for y in range(0, self.height, self.size): + self.image[x:x + self.size, y:y + self.size] = self.get_medium_color(x, y) + return Image.fromarray(self.image) + def get_medium_color(self, x, y): + return int(self.image[x:x + self.size, y:y + self.size].sum() / 3 // self.size ** 2 // self.grad * self.grad) + +flag = 'no' +while flag == 'no': + print('Введите название фото') + initialImg = Image.open('{}'.format(input())) + print('Выберите величину ячейки\n' + + 'Размер должен быть инициализирован целым положительным числом') + picSize = int(input()) + print('Выберите количество оттенков\n' + + 'Количество должно быть инициализировано целым положительным числом') + grad = int(input()) + arr = MonochromePhoto(initialImg, pixSize=picSize, gradation=grad).get_grey_image() + print('Введите название новой картинки') + name = input() + print('Введите формат нового фото(jpg, png и т.д.)') + formt = input() + arr.save('{}.{}'.format(name, formt)) + print('Если хотите завершить сессию, наберите \'yes\', если нет-нажмите enter') + if input() == 'yes': + flag = 'yes' diff --git a/filter.py.png b/filter.py.png new file mode 100644 index 0000000..0baca8d Binary files /dev/null and b/filter.py.png differ diff --git a/filter_with_filename.py.png b/filter_with_filename.py.png new file mode 100644 index 0000000..20f5ab2 Binary files /dev/null and b/filter_with_filename.py.png differ diff --git a/old_filter.py.png b/old_filter.py.png new file mode 100644 index 0000000..a32b610 Binary files /dev/null and b/old_filter.py.png differ diff --git a/original.jpg b/original.jpg new file mode 100644 index 0000000..991a1c6 Binary files /dev/null and b/original.jpg differ diff --git "a/\320\276\321\202\320\273\320\260\320\264\321\207\320\270\320\272.png" "b/\320\276\321\202\320\273\320\260\320\264\321\207\320\270\320\272.png" new file mode 100644 index 0000000..b225555 Binary files /dev/null and "b/\320\276\321\202\320\273\320\260\320\264\321\207\320\270\320\272.png" differ diff --git "a/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2651.png" "b/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2651.png" new file mode 100644 index 0000000..ac170a9 Binary files /dev/null and "b/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2651.png" differ diff --git "a/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2652.png" "b/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2652.png" new file mode 100644 index 0000000..2881638 Binary files /dev/null and "b/\321\202\320\265\321\201\321\202\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\2652.png" differ