Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/*
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Binary file added docs/examples/res.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
187 changes: 160 additions & 27 deletions filter.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,161 @@
from PIL import Image
from argparse import ArgumentParser, Namespace
from typing import Tuple

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 ValidationError(Exception):
pass


def _save_image(image_array: np.ndarray, output_image_path: str) -> None:
"""
Сохранить изображение по указанному пути
"""
res = Image.fromarray(image_array)
res.save(output_image_path)


def _load_image(input_image_path: str) -> np.ndarray:
"""
Загрузить изображение по указанному пути
"""
img = Image.open(input_image_path)
return np.array(img, dtype=np.uint8)


def _get_and_validate_size(
pixel_matrix: np.ndarray, segment_size: int
) -> Tuple[int, int]:
"""
Получение и валидация размеров матрицы пикселей
"""
rows_count = len(pixel_matrix)

if not rows_count:
raise ValidationError("Изображение пустое")

columns_count = len(pixel_matrix[0])

if rows_count % segment_size != 0 or columns_count % segment_size != 0:
raise ValidationError(
f"Невозможно разделить изображение размером: ({rows_count}, "
"{columns_count}) на сегменты размером: {segment_size}"
)

return rows_count, columns_count


def _calculate_mean_by_sector(
pixel_matrix: np.ndarray, begin_corrdinates: Tuple[int, int], segment_size: int
) -> int:
min_row_number, min_column_number = begin_corrdinates
return int(
pixel_matrix[
min_row_number : min_row_number + segment_size,
min_column_number : min_column_number + segment_size,
].mean()
)


def _calculate_grayscale_gradation(
mean_mosaic_segment_value: int, grayscale_gradation: int
) -> int:
if mean_mosaic_segment_value < grayscale_gradation:
return 0

return (mean_mosaic_segment_value // grayscale_gradation) * grayscale_gradation


def _insert_grayscale_segment(
pixel_matrix: np.ndarray,
begin_corrdinates: Tuple[int, int],
segment_size: int,
grayscale_gradation_value: int,
) -> None:
min_row_number, min_column_number = begin_corrdinates
pixel_matrix[
min_row_number : min_row_number + segment_size,
min_column_number : min_column_number + segment_size,
][...].fill(grayscale_gradation_value)


def _create_pixel_art(
input_image_path: str,
output_image_path: str,
segment_size: int = 10,
grayscale_gradation: int = 50,
) -> None:
pixel_matrix = _load_image(input_image_path)

rows_count, columns_count = _get_and_validate_size(pixel_matrix, segment_size)

min_row_number = 0

while min_row_number < rows_count:
min_column_number = 0

while min_column_number < columns_count:
mean_mosaic_segment_value = _calculate_mean_by_sector(
pixel_matrix, (min_row_number, min_column_number), segment_size
)
grayscale_gradation_value = _calculate_grayscale_gradation(
mean_mosaic_segment_value, grayscale_gradation
)

_insert_grayscale_segment(
pixel_matrix,
(min_row_number, min_column_number),
segment_size,
grayscale_gradation_value,
)

min_column_number = min_column_number + segment_size
min_row_number = min_row_number + segment_size

_save_image(pixel_matrix, output_image_path)


def _parser() -> Namespace:
parser = ArgumentParser(description="Преобразование изображения в пиксель арт")
parser.add_argument(
"-i",
"--input-image",
type=str,
default="./docs/examples/img2.jpg",
help="Путь до ихображения которое вы хотите преобразовать",
)
parser.add_argument(
"-o",
"--output-image",
type=str,
default="./docs/examples/res.jpg",
help="Путь, куда вы хотите сохранить изображение",
)
parser.add_argument(
"-s",
"--segment-size",
type=int,
default=10,
help="Размер сегмента мозаики",
)
parser.add_argument(
"-g",
"--grayscale-gradation",
type=int,
default=50,
help="Градация серого цвета",
)
return parser.parse_args()


def main():
args = _parser()
_create_pixel_art(
args.input_image, args.output_image, args.segment_size, args.grayscale_gradation
)


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions requirements.dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# formatters
isort==5.10.1
black==21.10b0

# linters
pylint==2.11.1
mypy==0.910
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
numpy==1.21.4
Pillow==8.4.0