Разделение изображений на равные части с использованием OpenCV Python
Библиотека Python OpenCV позволяет нам использовать различные инструменты обработки изображений, такие как классификация изображений, обнаружение лиц/объектов, отслеживание и многое другое.
В этой статье мы будем использовать методы нарезки списка Python или нарезки массива numpy, чтобы разделить изображение на равные части, поскольку OpenCV-python использует массив Numpy для хранения данных изображения/значений пикселей.
Сценарии ввода-вывода
Предполагая, что у нас есть входное изображение, а на выходе мы увидим поровну разделенные части данного изображения.

Подход
Мы выполним следующие шаги, чтобы разделить изображения на равные части.
- Загрузите изображение.
- Извлеките размеры изображения и сохраните их в переменной.
- Разделите массив изображений, используя технику нарезки Python.
- Наконец, сохраните отдельные части.
Пример
В этом примере мы разделим входное изображение «cat.jpg» по горизонтали на 2 части.
import cv2 image= cv2.imread('Images/cat.jpg') height, width, channels = image.shape half_height = height//2 top_section = image[:half_height, :] bottom_section = image[half_height:, :] cv2.imshow('Top', top_section) cv2.imshow('Bottom', bottom_section) cv2.waitKey(0)
Входное изображение

Вывод изображений

Пример
В этом примере мы разделим входное изображение «logo.png» на 4 равные части.
import cv2 import numpy as np def divide_img_blocks(img, n_blocks=(2,2)): horizontal = np.array_split(img, n_blocks[0]) splitted_img = [np.array_split(block, n_blocks[1], axis=1) for block in horizontal] return np.asarray(splitted_img, dtype=np.ndarray).reshape(n_blocks) result = divide_img_blocks(cv2.imread('Images/logo.png')) for i in range(result.shape[0]): for j in range(result.shape[1]): cv2.imwrite(f"Output Images/my_block__.jpg", result[i,j])
Входное изображение

Вывод изображений

Пример
При таком подходе мы разделим входное изображение «Lenna.png» на 9 равных частей.
import cv2,time img = cv2.imread('Images/Lenna.png') img2 = img height, width, channels = img.shape # Number of pieces Horizontally W_SIZE = 3 # Number of pieces Vertically to each Horizontal H_SIZE = 3 for ih in range(H_SIZE ): for iw in range(W_SIZE ): x = width/W_SIZE * iw y = height/H_SIZE * ih h = (height / H_SIZE) w = (width / W_SIZE ) print(x,y,h,w) img = img[int(y):int(y+h), int(x):int(x+w)] NAME = str(time.time()) cv2.imwrite("Output Images/" + str(ih)+str(iw) + ".png",img) img = img2
Выход
0.0 0.0 124.0 223.0 223.0 0.0 124.0 223.0 446.0 0.0 124.0 223.0 0.0 124.0 124.0 223.0 223.0 124.0 124.0 223.0 446.0 124.0 124.0 223.0 0.0 248.0 124.0 223.0 223.0 248.0 124.0 223.0 446.0 248.0 124.0 223.0
Входное изображение

Вывод изображений

В приведенном выше примере изображение сначала разделится на 3 горизонтальные части, а затем для каждой из этих 3 частей будет обрезано еще 3 изображения, в результате чего останется всего 9 частей. Измените значения W_SIZE и H_SIZE , чтобы указать, сколько равных частей нам нужно, чтобы разделить изображение.
Во всех приведенных выше примерах мы успешно разделили входные изображения на равные части.
Все права защищены. © Linux-Console.net • 2019-2024
Как разделить изображение на несколько частей в Python
Почему k является параметром этой функции? Не должно ли всегда быть 0 при вызове функции? И что такое area ? Почему вы crop изображение дважды?
Giacomo Alzetta 19 окт. 2018, в 15:56
Редактировать: я считаю, что этот ответ пропустил намерение разрезать изображение на прямоугольники в столбцах и строках. Этот ответ разрезается только на строки. Похоже, другие ответы вырезаны в столбцах и строках.
Проще, чем все это использовать колесо, изобретенное кем-то другим 🙂 Может быть, это более сложное в настройке, но это совсем несложно.
Эти инструкции предназначены для Windows 7; они могут нуждаться в адаптации для других ОС.
Получите и установите pip отсюда.
Загрузите установочный архив и распакуйте его в корневой каталог установки Python. Откройте консоль и введите (если я правильно помню):
python get-pip.py install
Затем получите и установите модуль image_slicer через pip, введя следующую команду в консоли:
python -m pip install image_slicer
Скопируйте изображение, которое вы хотите нарезать, в корневой каталог Python, откройте оболочку Python (не «командную строку») и введите следующие команды:
import image_slicer image_slicer.slice('huge_test_image.png', 14)
Прелесть этого модуля в том, что он
- Устанавливается в Python
- Может вызвать разделение изображения с двумя строками кода
- Принимает любое четное число в качестве параметра среза изображения (например, 14 в этом примере)
- Принимает этот параметр и автоматически разбивает данное изображение на множество фрагментов, автоматически сохраняет результирующие пронумерованные листы в одном каталоге и, наконец,
- Имеет функцию для сшивания мозаичных изображений обратно (что я еще не проверял); Файлы, очевидно, должны быть названы в соответствии с соглашением, которое вы увидите в разделенных файлах после тестирования функции image_slicer.slice.
Alex Hall 26 нояб. 2014, в 07:37
Поделиться
это выглядит хорошо, но его документация оставляет желать лучшего. Это также дает хороший контроль над плитками после их создания, но не так просто увидеть, как изображение будет разрезано. Я ожидал своего рода кортеж, чтобы установить количество строк и столбцов
Rodrigo Laguna 08 июнь 2017, в 14:01
Будет ли это работать для изображений, которые не помещаются в ОЗУ?
mercury0114 04 янв. 2019, в 15:44
Согласно комментариям к другим ответам, нет, это, вероятно, не вариант в системах с ограниченным объемом памяти.
Alex Hall 24 янв. 2019, в 16:38
Показать ещё 1 комментарий
- crop будет более многоразовым если вы отделите код обрезки с сохранение изображений код. Это также сделало бы звонок подпись проще.
- im.crop возвращает Image._ImageCrop экземпляр. такие экземпляры не имеют метода сохранения. Вместо этого вы должны вставить Image._ImageCrop экземпляр на новый Image.Image
- Ваши диапазоны не имеют права размеры шага. (Почему height-2 и не height ? например. Зачем останавливаться на imgheight-(height/2) ?).
Итак, вы можете попробовать что-то вроде этого:
import Image import os def crop(infile,height,width): im = Image.open(infile) imgwidth, imgheight = im.size for i in range(imgheight//height): for j in range(imgwidth//width): box = (j*width, i*height, (j+1)*width, (i+1)*height) yield im.crop(box) if __name__=='__main__': infile=. height=. width=. start_num=. for k,piece in enumerate(crop(infile,height,width),start_num): img=Image.new('RGB', (height,width), 255) img.paste(piece) path=os.path.join('/tmp',"IMG-%s.png" % k) img.save(path)
unutbu 10 май 2011, в 20:36
Поделиться
спасибо за ваше решение, но оно не работает со мной, картинка не была обрезана хорошо, я вижу красный цвет, я думаю, что проблема может быть здесь: img.paste(piece)
ElTero 10 май 2011, в 21:07
Это особенно хорошее решение, если у вас есть ограничения памяти. Большие изображения могут давать сбой на компьютерах с низким объемом памяти при использовании image_slicer.
Dean Liu 12 янв. 2017, в 13:54
Разделение изображения на фрагменты MxN пикселей (при условии, что im — numpy.ndarray):
tiles = [im[x:x+M,y:y+N] for x in range(0,im.shape[0],M) for y in range(0,im.shape[1],N)]
В случае, если вы хотите разбить изображение на четыре части:
M = im.shape[0]//2 N = im.shape[1]//2
плитка [0] удерживает верхний левый фрагмент
Nir 30 нояб. 2017, в 21:14
Поделиться
Для моего случая самое простое решение, а также не дорогой расчет
NeStack 14 нояб. 2018, в 12:44
Мне легче skimage.util.view_as_windows или `skimage.util.view_as_blocks, что также позволяет вам настроить шаг
Uwais Iqbal 04 март 2018, в 14:33
Поделиться
Это мои инструменты script, это очень образец для разделения изображения css-sprit на значки:
Usage: split_icons.py img dst_path width height Example: python split_icons.py icon-48.png gtliu 48 48
Сохранить код в файле split_icons.py:
#!/usr/bin/env python # -*- coding:utf-8 -*- import os import sys import glob from PIL import Image def Usage(): print '%s img dst_path width height' % (sys.argv[0]) sys.exit(1) if len(sys.argv) != 5: Usage() src_img = sys.argv[1] dst_path = sys.argv[2] if not os.path.exists(sys.argv[2]) or not os.path.isfile(sys.argv[1]): print 'Not exists', sys.argv[2], sys.argv[1] sys.exit(1) w, h = int(sys.argv[3]), int(sys.argv[4]) im = Image.open(src_img) im_w, im_h = im.size print 'Image width:%d height:%d will split into (%d %d) ' % (im_w, im_h, w, h) w_num, h_num = int(im_w/w), int(im_h/h) for wi in range(0, w_num): for hi in range(0, h_num): box = (wi*w, hi*h, (wi+1)*w, (hi+1)*h) piece = im.crop(box) tmp_img = Image.new('L', (w, h), 255) tmp_img.paste(piece) img_path = os.path.join(dst_path, "%d_%d.png" % (wi, hi)) tmp_img.save(img_path)
winlin 11 янв. 2018, в 14:30
Поделиться
Ещё вопросы
- 1 Могу ли я перехватить вставку в ячейку DataGrid?
- 1 Как исправить этот код, чтобы он работал правильно
- 0 php обновляет динамические строки sql через форму
- 1 Как я могу установить плагин на Mac?
- 0 Как воспроизвести звук на данной ноте / октаве MIDI?
- 1 текст Jlabel становится обрезанным при печати
- 1 Как получить данные из базы данных в реальном времени в Firebase?
- 1 Время Tweepy Status.created_at не соответствует фактическому времени временной шкалы.
- 0 Codeigniter — перенаправить и скачать файл
- 1 Как изменить объект, назначенный JTree?
- 0 Doctrine2 + Symfony2: приведение значений перед привязкой к DQL-запросу
- 1 RadioButton выравнивает текст по левой стороне и кнопку вправо
- 0 Обсуждение проблем strtotime, например, «этот день х», когда день не = х, дает СЛЕДУЮЩИЙ х. ESOTERIC просьба игнорировать
- 0 Sublime Text 2: завершение HTML-тега не работает, и я не могу его отключить
- 1 Контейнер прокрутки в C # winform
- 1 Счетчик времени Vue.js
- 1 HTTPS-соединения — как управляются пары ключей
- 0 Перечисление данных медленно в codeigniter
- 1 Панель инструментов с возможностью выбора типа диаграммы Google
- 1 Как исправить несколько методов одного и того же объекта
- 0 Ошибка JPA при странном сообщении
- 0 Почему статическая переменная класса не может быть размещена в стеке?
- 0 Ошибка проверки формы при использовании тега ion-scroll
- 0 AngularJS + ASP.NET MVC: маршрутизация URL без соответствующего физического представления
- 1 response-native-firebase NullPointerException при выпуске сборки для Android
- 0 Как я могу связать число с определенной строкой и использовать эту строку для фильтрации итерации в AngularJS?
- 0 Мое изображение не загружается на мою таблицу базы данных
- 1 Как найти ключевое слово над несколькими файлами с помощью VsVim
- 0 Jquery переключение анимации слева направо
- 0 Слишком много символов в символьном литерале при преобразовании тега HTML в ссылку на сущность
- 1 как получить значение из виджета входа в tkinter в python3.6
- 0 Сравнение двух массивов объектов с использованием AngularJS
- 1 Загрузка запрещена с помощью X-Frame-Options: websitename / Register не разрешает кадрирование между источниками в MVC5
- 0 создать действие javascript из результата оператора php if / else
- 0 Как ускорить запрос PDO
- 0 Удаление замораживающей панели после сбоя проверки на клиенте с использованием jQuery
- 0 Как разместить невидимый вход в каждой ячейке таблицы
- 0 как переписать URL в Yii?
- 1 Не удалось загрузить ресурс при загрузке изображения
- 1 удаление элемента цикла foreach из перечисленной коллекции
- 0 MySQL поиск дубликатов имен файлов с разными расширениями
- 0 Заменить ноль в 2D массиве пробелом
- 0 Программа SFML 2.1 работает нормально в режиме отладки, но вылетает в режиме выпуска
- 1 Неправильный вывод в моей задаче, не могу ее решить
- 0 Запретить смайлики и символы нулевой ширины при вводе текста
- 0 Вместо электронной почты идентификатор пользователя идет в базу данных
- 0 HTML KickStart — восстановить стиль по умолчанию для полей ввода
- 1 XML-узел заменяется другим
- 0 Инициализация базы данных Ghost при новой установке
- 0 Авто Требуется в PHP
Как разделить изображение на несколько частей в Python
В качестве альтернативного решения, мы создадим плитки, сгенерировав сетку координат с помощью itertools.product . Мы будем игнорировать частичные плитки на краях, только перебирая картезийский продукт между двумя интервалами, т.е. range(0, h-h%d, d) X range(0, w-w%d, d) . Для filename : имя файла изображения, d : размер плитки, dir_in : путь к каталогу, содержащему изображение, и dir_out : каталог, где будут выведены плитки:
from PIL import Image from itertools import product
def tile(filename, dir_in, dir_out, d): name, ext = os.path.splitext(filename) img = Image.open(os.path.join(dir_in, filename)) w, h = img.size grid = product(range(0, h-h%d, d), range(0, w-w%d, d)) for i, j in grid: box = (j, i, j+d, i+d) out = os.path.join(dir_out, f'__') img.crop(box).save(out)

Поделиться 13 января 2021 в 09:11
Редактирование: Я считаю, что этот ответ пропустил намерение разрезать изображение на прямоугольники в столбцах и строках. Этот ответ разрезает только на строки. Похоже, что другие ответы разрезаны на столбцы и строки. Более просто использовать колесо, изобретенное кем-то другим 🙂 Может быть, это больше занято настройкой, но тогда это простой способ использовать. Эти инструкции предназначены для Windows 7; они могут быть адаптированы для других ОС. Скачайте и установите pip здесь. Скачайте архив установки и извлеките его в корневой каталог установки Python. Откройте консоль и введите (если я правильно помню):
python get-pip.py install
Затем получите и установите модуль image_slicer через pip, введя следующую команду в консоли:
python -m pip install image_slicer
Скопируйте изображение, которое вы хотите срезать, в корневой каталог Python, откройте оболочку Python (а не «командную строку»), и введите эти команды:
import image_slicer image_slicer.slice('huge_test_image.png', 14)
- Установлен в Python
- Может вызывать разделение изображения с помощью двух строк кода
- Принимает любое четное число в качестве параметра среза изображения (например, 14 в этом примере)
- Принимает этот параметр и автоматически разделяет данное изображение на столько срезов, и автоматически сохраняет полученные нумерованные плитки в том же каталоге, и, наконец,
- Имеет функцию для стерирования плиток изображения (которую я еще не тестировал); файлы, видимо, должны быть названы после соглашения, которое вы увидите в файлах среза после тестирования функции image_slicer.slice.
Поделиться 26 ноября 2014 в 05:53
from PIL import Image def crop(path, input, height, width, k, page, area): im = Image.open(input) imgwidth, imgheight = im.size for i in range(0,imgheight,height): for j in range(0,imgwidth,width): box = (j, i, j+width, i+height) a = im.crop(box) try: o = a.crop(area) o.save(os.path.join(path,"PNG","%s" % page,"IMG-%s.png" % k)) except: pass k +=1
Поделиться 13 августа 2011 в 14:37
- crop будет более многоразовой функцией, если вы отделите код обрезки от кода сохранения изображения. Это также упростит сигнатуру вызова.
- im.crop возвращает экземпляр Image._ImageCrop . Такие экземпляры не имеют метода сохранения. Вместо этого вы должны вставить экземпляр Image._ImageCrop в новый Image.Image
- Ваши диапазоны не имеют правильных шаговых размеров. (Почему height-2 , а не height ?, например. Почему останавливаемся на imgheight-(height/2) ?).
Таким образом, вы можете попробовать что-то вроде этого:
import Image import os def crop(infile,height,width): im = Image.open(infile) imgwidth, imgheight = im.size for i in range(imgheight//height): for j in range(imgwidth//width): box = (j*width, i*height, (j+1)*width, (i+1)*height) yield im.crop(box) if __name__=='__main__': infile=. height=. width=. start_num=. for k,piece in enumerate(crop(infile,height,width),start_num): img=Image.new('RGB', (height,width), 255) img.paste(piece) path=os.path.join('/tmp',"IMG-%s.png" % k) img.save(path)
Поделиться 10 мая 2011 в 19:07
Вот краткое, чистое решение на Python, которое работает как в Python 3, так и 2:
from PIL import Image infile = '20190206-135938.1273.Easy8thRunnersHopefully.jpg' chopsize = 300 img = Image.open(infile) width, height = img.size # Save Chops of original image for x0 in range(0, width, chopsize): for y0 in range(0, height, chopsize): box = (x0, y0, x0+chopsize if x0+chopsize < width else width - 1, y0+chopsize if y0+chopsize < height else height - 1) print('%s %s' % (infile, box)) img.crop(box).save('zchop.%s.x%03d.y%03d.jpg' % (infile.replace('.jpg',''), x0, y0))
Поделиться 20 февраля 2019 в 20:23
Вот поздний ответ, который работает с Python 3
from PIL import Image import os def imgcrop(input, xPieces, yPieces): filename, file_extension = os.path.splitext(input) im = Image.open(input) imgwidth, imgheight = im.size height = imgheight // yPieces width = imgwidth // xPieces for i in range(0, yPieces): for j in range(0, xPieces): box = (j * width, i * height, (j + 1) * width, (i + 1) * height) a = im.crop(box) try: a.save("images/" + filename + "-" + str(i) + "-" + str(j) + file_extension) except: pass
imgcrop("images/testing.jpg", 5, 5)
Тогда изображения будут обрезаны на куски в соответствии с указанными кусками X и Y, в моем случае 5 x 5 = 25 кусков
Поделиться 26 мая 2020 в 02:33
Вот еще одно решение, просто используя встроенный np.array_split в NumPy:
def divide_img_blocks(img, n_blocks=(5, 5)): horizontal = np.array_split(img, n_blocks[0]) splitted_img = [np.array_split(block, n_blocks[1], axis=1) for block in horizontal] return np.asarray(splitted_img, dtype=np.ndarray).reshape(n_blocks)
Он возвращает массив NumPy с размерностью, переданной как n_block. Каждый элемент массива является блоком, поэтому для доступа к каждому блоку и сохранения его в виде изображения вы должны написать что-то вроде следующего:
result = divide_img_blocks(my_image) for i in range(result.shape[0]): for j in range(result.shape[1]): cv2.imwrite(f"my_block__.jpg", result[i,j])
Этот ответ очень быстрый, быстрее, чем ответ @Nir, который среди опубликованных был самым чистым. Кроме того, он почти на три порядка быстрее, чем предложенный пакет (например, image_slicer ).
Time taken by divide_img_blocks: 0.0009832382202148438 Time taken by Nir answer: 0.002960681915283203 Time taken by image_slicer.slice: 0.4419238567352295
Надеюсь, он все еще может быть полезен.
Поделиться 21 апреля 2021 в 13:49
Я нахожу проще использовать skimage.util.view_as_windows или `skimage.util.view_as_blocks, что также позволяет настроить шаг
Поделиться 04 марта 2018 в 14:16
Не уверен, является ли это наиболее эффективным ответом, но он работает для меня:
import os import glob from PIL import Image Image.MAX_IMAGE_PIXELS = None # to avoid image size warning imgdir = "/path/to/image/folder" # if you want file of a specific extension (.png): filelist = [f for f in glob.glob(imgdir + "**/*.png", recursive=True)] savedir = "/path/to/image/folder/output" start_pos = start_x, start_y = (0, 0) cropped_image_size = w, h = (500, 500) for file in filelist: img = Image.open(file) width, height = img.size frame_num = 1 for col_i in range(0, width, w): for row_i in range(0, height, h): crop = img.crop((col_i, row_i, col_i + w, row_i + h)) name = os.path.basename(file) name = os.path.splitext(name)[0] save_to= os.path.join(savedir, name+"_.png") crop.save(save_to.format(frame_num)) frame_num += 1
Это в основном основано на ответе DataScienceGuy здесь
Поделиться 03 ноября 2019 в 11:59
Для тех, кто ищет простой подход к этому, вот простая рабочая функция для разделения изображения на разделы NxN.
def slice_image(filename, N): i = Image.open(filename) width = i.width height = i.height for x in range(N): for y in range(N): index = (x * pieces) + 1 + y img = i.crop((x * width/N, y * height/N, x * width/N+ width/N, y * height/N+ height/N)) img.save(f"_sliced_.jpeg")
Поделиться 09 ноября 2021 в 18:21
import os import sys from PIL import Image savedir = r"E:\new_mission _data\test" filename = r"E:\new_mission _data\test\testing1.png" img = Image.open(filename) width, height = img.size start_pos = start_x, start_y = (0, 0) cropped_image_size = w, h = (1024,1024) frame_num = 1 for col_i in range(0, width, w): for row_i in range(0, height, h): crop = img.crop((col_i, row_i, col_i + w, row_i + h)) save_to= os.path.join(savedir, "testing_.png") crop.save(save_to.format(frame_num)) frame_num += 1
Поделиться 17 июля 2020 в 07:48
Спасибо @Ивану за то, что научил меня чему-то об инструментах и сетках. Пришел сюда, чтобы разделить томографические данные 3D изображений (tif-файлы) на более мелкие регионы для оценки. Я адаптировал скрипт к файлам 3D-TIF (используя библиотеку tiffile) и добавил подход "центрированный". Таким образом, плитки не начинаются в левом верхнем углу, а центрируются и обрезают слишком маленькие плитки на границах в каждом направлении. Возможно, это также поможет другим людям.
from itertools import product import tifffile as tif import numpy as np path = 'PATH' filename= 'FILENAME.tif' img = tif.imread(path+filename) depth, height, width = img.shape tilesize = 100 grid = product(range(int((depth%tilesize)/2), int(depth-(depth%tilesize)/2), tilesize), range(int((width%tilesize)/2), int(width-((width%tilesize)/2)), tilesize), range(int((height%tilesize)/2), int(height-(height%tilesize)/2), tilesize)) for z,y,x in grid: crop = img[z:z+tilesize, y:y+tilesize, x:x+tilesize] tif.imwrite(path+filename+f'z_y_x.tif', crop, dtype = np.uint8)
Поделиться 17 ноября 2022 в 15:03
Вы можете использовать трюки с помощью numpy stride для достижения этого, но будьте осторожны, так как эта функция должна использоваться с огромной осторожностью (документ)
import numpy as np from numpy.lib.stride_tricks import as_strided def img_pieces(img, piece_size): height, width, chanels = img.shape n_bytes = img.strides[-1] return np.reshape( as_strided( img, ( height // piece_size, width // piece_size, piece_size, piece_size, chanels ), ( n_bytes * chanels * width * piece_size, n_bytes * chanels * piece_size, n_bytes * chanels * width, n_bytes * chanels, n_bytes ) ), ( -1, piece_size, piece_size, chanels ) )
Поделиться 29 ноября 2022 в 13:29
Вот моя попытка на изображении серого размера только с помощью numpy, основанного на решении здесь , с некоторыми незначительными изменениями (добавлением каналов), это может подойти для ваших нужд:
import numpy as np # Seperate grayscale images to w * h tiles, add padding with zeros if image not scaled def to_tiles(arr: np.ndarray, tilesize: tuple[int, int]) -> np.ndarray: def f(x: tuple[int, int]) -> tuple[int, int]: tmp = list(x) if tmp[1] > 0: tmp[0] = tmp[0] + 1 return tuple(tmp) # # Stride Implementation # bytelength = np.int8(np.divide(arr.nbytes, arr.size)) assert arr.ndim == 2, "array must be 2d (grayscale) image" a_h, a_w = arr.shape h, w = tilesize assert a_h > h, "tile height is larger than arr height" assert a_w > w, "tile width is larger than arr width" row, row_r = f(np.divmod(a_h, h)) col, col_r = f(np.divmod(a_w, w)) arr = np.pad( arr, [ ( np.int8(np.ceil(np.divide(h-row_r, 2))) if row_r != 0 else 0, np.int8(np.floor(np.divide(h-row_r, 2))) if row_r != 0 else 0, ), ( np.int8(np.ceil(np.divide(w-col_r, 2))) if col_r != 0 else 0, np.int8(np.floor(np.divide(w-col_r, 2))) if col_r != 0 else 0, ), ], "constant", constant_values=(0), ) # # Stride Implementation # arr = np.lib.stride_tricks.as_strided( # arr, shape=(row, col, h, w), strides=(h*a_w*bytelength, w*bytelength, a_w*bytelength, bytelength) # ) arr = arr.reshape(row, h, col, w).swapaxes(1, 2) arr = arr.reshape(-1, h, w) return arr
Поделиться 30 декабря 2022 в 16:23
Это мои инструменты скрипта, это очень пример для разделения изображения css-sprit на иконки:
Usage: split_icons.py img dst_path width height Example: python split_icons.py icon-48.png gtliu 48 48
Сохраните код в split_icons.py:
#!/usr/bin/env python # -*- coding:utf-8 -*- import os import sys import glob from PIL import Image def Usage(): print '%s img dst_path width height' % (sys.argv[0]) sys.exit(1) if len(sys.argv) != 5: Usage() src_img = sys.argv[1] dst_path = sys.argv[2] if not os.path.exists(sys.argv[2]) or not os.path.isfile(sys.argv[1]): print 'Not exists', sys.argv[2], sys.argv[1] sys.exit(1) w, h = int(sys.argv[3]), int(sys.argv[4]) im = Image.open(src_img) im_w, im_h = im.size print 'Image width:%d height:%d will split into (%d %d) ' % (im_w, im_h, w, h) w_num, h_num = int(im_w/w), int(im_h/h) for wi in range(0, w_num): for hi in range(0, h_num): box = (wi*w, hi*h, (wi+1)*w, (hi+1)*h) piece = im.crop(box) tmp_img = Image.new('L', (w, h), 255) tmp_img.paste(piece) img_path = os.path.join(dst_path, "%d_%d.png" % (wi, hi)) tmp_img.save(img_path)
Поделиться 11 января 2018 в 13:10
Не уверен, все еще ли это актуально, но моя попытка следующая: (Я предполагаю, что изображение является массивом numpy. Я не использую Pil или что-то еще, так как не хотел иметь никаких зависимостей, кроме numpy.)
def cut_image_grid(image:np.ndarray, grid_size:int=4): height, width = image.shape[0], image.shape[1] piece_height, piece_width = height//grid_size, width//grid_size pieces = [] for i in range(grid_size): for j in range(grid_size): y = i * piece_height x = j * piece_width h = (i+1) * piece_height if i < grid_size else None w = (j+1) * piece_width if j < grid_size else None piece = image[y:h, x:w] pieces.append(piece) return np.array(pieces)
На входе функция получает изображение numpy и целое число (которое также можно превратить в кортежи, но я хотел, чтобы ячейки сетки всегда были равномерно разделены с одинаковым количеством строк и столбцов). Сначала код вычисляет ширину и высоту ячеек на основе заданного grid_size . После этого код перебирает все строки и столбцы и генерирует координаты x, y, а также x0 и y0 (y+height, x+width) для определения ячеек. Каждая ячейка сохраняется как список в pieces , который затем преобразуется в массив numpy и возвращается.
Поделиться 10 февраля 2023 в 09:18
Я попробовал решения выше, но иногда вам просто нужно сделать это самостоятельно. Может быть, в некоторых случаях это отключается пикселем, но в целом работает нормально.
import matplotlib.pyplot as plt import numpy as np def image_to_tiles(im, number_of_tiles = 4, plot=False): """ Function that splits SINGLE channel images into tiles :param im: image: single channel image (NxN matrix) :param number_of_tiles: squared number :param plot: :return tiles: """ n_slices = np.sqrt(number_of_tiles) assert int(n_slices + 0.5) ** 2 == number_of_tiles, "Number of tiles is not a perfect square" n_slices = n_slices.astype(np.int) [w, h] = cropped_npy.shape r = np.linspace(0, w, n_slices+1) r_tuples = [(np.int(r[i]), np.int(r[i+1])) for i in range(0, len(r)-1)] q = np.linspace(0, h, n_slices+1) q_tuples = [(np.int(q[i]), np.int(q[i+1])) for i in range(0, len(q)-1)] tiles = [] for row in range(n_slices): for column in range(n_slices): [x1, y1, x2, y2] = *r_tuples[row], *q_tuples[column] tiles.append(im[x1:y1, x2:y2]) if plot: fig, axes = plt.subplots(n_slices, n_slices, figsize=(10,10)) c = 0 for row in range(n_slices): for column in range(n_slices): axes[row,column].imshow(tiles[c]) axes[row,column].axis('off') c+=1 return tiles
Надеюсь, это поможет.
Поделиться 18 февраля 2020 в 22:04
Разбиение изображения на квадраты определенного размера
Я адаптировал решение, чтобы оно принимало определенный размер плитки вместо количества плиток, потому что мне нужно было разрезать изображение в сетку из квадратов 32px.
Параметры - это image_path и размер плитки в пикселях.
Я попытался сделать код максимально читаемым.
# Imports from PIL import Image import os import random # Function def image_to_tiles(im, tile_size = 32): """ Function that splits an image into tiles :param im: image: image path :param tile_size: width in pixels of a tile :return tiles: """ image = Image.open(im) w = image.width h = image.height row_count = np.int64((h-h%tile_size)/tile_size) col_count = np.int64((w-w%tile_size)/tile_size) n_slices = np.int64(row_count*col_count) # Image info print(f'Image: ') print(f'Dimensions: w: h:') print(f'Tile count: ') r = np.linspace(0, w, row_count+1) r_tuples = [(np.int64(r[i]), np.int64(r[i])+tile_size) for i in range(0, len(r)-1)] q = np.linspace(0, h, col_count+1) q_tuples = [(np.int64(q[i]), np.int64(q[i])+tile_size) for i in range(0, len(q)-1)] #print(f'r_tuples:\n\nq_tuples:\n') tiles = [] for row in range(row_count): for column in range(col_count): [y1, y2, x1, x2] = *r_tuples[row], *q_tuples[column] x2 = x1+tile_size y2 = y1+tile_size tile_image = image.crop((x1,y1,x2,y2)) tile_coords = tiles.append() return tiles # Testing: img_path ='/home/user/path/to/image.jpg' tiles = image_to_tiles(img_path) for i in range(20): tile = random.choice(tiles) tile['image'].show()
Поделиться 29 августа 2022 в 15:33
def split(img,nbxsplit,nbysplit): xdemi=int(img.shape[0]/nbxsplit) ydemi=int(img.shape[1]/nbxsplit) arr=[] for i in range(0,img.shape[0]-xdemi+1,xdemi): for j in range(0,img.shape[1]-ydemi+1,ydemi): arr.append(img[i:i+xdemi][j:j+ydemi]) a=np.reshape(a,(img.shape[0]-xdemi,img.shape[1]-xdemi)) return a
Поделиться 09 ноября 2022 в 21:32
Я бы предложил использовать многопроцессинг вместо обычного цикла for следующим образом:
from PIL import Image import os def crop(infile,height,width): im = Image.open(infile) imgwidth, imgheight = im.size for i in range(imgheight//height): for j in range(imgwidth//width): box = (j*width, i*height, (j+1)*width, (i+1)*height) yield im.crop(box) def til_image(infile): infile=. height=. width=. start_num=. for k,piece in enumerate(crop(infile,height,width),start_num): img=Image.new('RGB', (height,width), 255) img.paste(piece) path=os.path.join('/tmp',"IMG-%s.png" % k) img.save(path) from multiprocessing import Pool, cpu_count try: pool = Pool(cpu_count()) pool.imap_unordered(tile_image, os.listdir(root), chunksize=4) finally: pool.close()
Поделиться 02 марта 2021 в 00:01
самый простой способ:
import image_slicer image_slicer.slice('/Address of image for exp/A1.png',16)
эта команда разделяет изображение на 16 срезов и сохраняет их в каталоге, где находится входное изображение. сначала следует установить image_slicer:
pip install image_slicer
Поделиться 19 июля 2021 в 12:06
import cv2 def crop_image(image_path, output_path): im = cv2.imread(os.listdir()[2]) imgheight=im.shape[0] imgwidth=im.shape[1] y1 = 0 M = 2000 N = 2000 for y in range(0,imgheight,M): for x in range(0, imgwidth, N): y1 = y + M x1 = x + N tiles = im[y:y+M,x:x+N] if tiles.shape[0] < 100 or tiles.shape[1].png".format(image_path),tiles) crop_image(os.listdir()[2], './cutted/')
OpenCV — быстрый старт: базовые операции с изображениями
Судя по количеству закладок на первой части, работа моя — не зряшная.
В прошлый раз разбирали скучное открывание-закрывание картинки, в этот раз засунем в неё руки поглубже:
- Доступ к пикселям и работа с ними.
- Масштабирование картинки.
- Обрезка.
- Отражение.
import cv2 import numpy as np import matplotlib.pyplot as plt from PIL import Image
Первой картинкой пойдут уже знакомые шашечки:
Доступ к отдельным пикселям
Изображение в OpenCV — матрица numpy, а значит, для доступа к пикселю будем использовать нотацию матриц: [ r , c ]. Первое значение — строка, второе — колонка. Не забывайте о том, что индексация начинается с нуля!
Для доступа к самому первому пикселю обратимся к элементу матрицы (изображения, то бишь) с индексами 0 и 0:
# Читаем картинку как чб cb_img = cv2.imread("checkerboard_18x18.png",0) # Выводим массив, представляющий картинку print(cb_img) # Выводим значение самого первого пикселя (верх-лево) print(cb_img[0,0]) # Выводим значение первого пикселя слева от чёрной зоны print(cb_img[0,6])
С доступом разобрались, поиграем со значениями.
Изменение пикселей
Просто переназначаем пиксель:
cb_img[0,0] = 255
Что-то похожее мы сделали в прошлый раз с каналами.
Продублируем картинку, и накидаем в неё серых пикселей:
cb_img_copy = cb_img.copy() # копируем загруженное изображение cb_img_copy[2,2] = 200 # пиксель в ячейке [2,2] будет равен 200 cb_img_copy[2,3] = 200 # и так далее cb_img_copy[3,2] = 200 cb_img_copy[3,3] = 200 # То же самое другими словами: # cb_img_copy[2:3,2:3] = 200 plt.imshow(cb_img_copy, cmap='gray') plt.show() print(cb_img_copy)

Обрезка картинок
Можно воспринимать кроп как задачу "из пачки пикселей берём только эти несколько".
Загрузим новозеландскую лодку и потренируемся на ней:

img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg",cv2.IMREAD_COLOR) # или так: # img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg",1) # img_NZ_bgr = cv2.imread("New_Zealand_Boat.jpg") img_NZ_rgb = img_NZ_bgr[. -1] # или так: # img_NZ_rgb = cv2.cvtColor(img_NZ_bgr, cv2.COLOR_BGR2RGB) # или разбить на каналы и пересобрать в правильном порядке :) plt.imshow(img_NZ_rgb) plt.show()
# кропнутый регион = область загруженной картинки # c 200 по 400 строку (или Y, если хотите) # и 300 по 600 колонку (или X, если хотите) cropped_region = img_NZ_rgb[200:400, 300:600] plt.imshow(cropped_region) plt.show()

Масштабирование изображений
Функция resize() отресайзит картинку в больший или меньший размер. А регулируется это всё аргументами src , dsize (обязательные), fx , fy (факультативные).
cv2.resize() — синтаксис и аргументы
dst = resize( src, dsize[, dst[, fx[, fy[, interpolation]]]] )
dst — изображение на выходе. Размер картинки будет равен dsize (если он ненулевой), или посчитан через src.size() , fx , fy .
Тип данных будет тем же, что и в оригинальной картинке.
src — понятно, сама картинка, требующая вмешательства. Обязательный аргумент.
dsize — необходимый размер, обязательный аргумент.
fx — коэффициент масштаба горизонтальный.
fy — коэффициент масштаба вертикальный.
Чуть подробнее о том, что тут происходит
В общем: в dsize кладётся кортеж с натуральными числами, две штуки: (500, 500). Это размер, в который картинка отмасштабируется.
Можно воспользоваться вместо этого коэффициентами масштаба, тогда вместо dsize надо впечатать None .
Коэффициенты масштаба — fx и fy — берут оригинальную картинку, и растягивают/стягивают её пропорционально.
dsize — имеет приоритет: конструкция resize(src, dsize=(100, 100),fx=20, fy=20) выдаст картинку 100×100 пикселей.
Первый вариант масштабирования: коэффициенты масштаба
Увеличим кропнутую лодку в два раза:
resized_cropped_region_2x = cv2.resize(cropped_region,None,fx=2, fy=2) plt.imshow(resized_cropped_region_2x) plt.show()
Второй вариант масштабирования: сразу укажем нужные размеры
desired_width = 100 # желаемая ширина desired_height = 200 # желаемая высота dim = (desired_width, desired_height) # размер в итоге # Масштабируем картинку resized_cropped_region = cv2.resize(cropped_region, dsize = dim, interpolation = cv2.INTER_AREA) # Или так: # resized_cropped_region = cv2.resize(cropped_region, # dsize = (100, 200), # interpolation = cv2.INTER_AREA) plt.imshow(resized_cropped_region) plt.show()
Масштабирование с сохранением пропорций
За основу возьмём вторую методу, но отталкиваться будем от желаемой ширины.
Немного несложной математики:
# Используем 'dsize' desired_width = 100 # желаемая ширина # соотношение сторон: ширина, делённая на ширину оригинала aspect_ratio = desired_width / cropped_region.shape[1] # желаемая высота: высота, умноженная на соотношение сторон desired_height = int(cropped_region.shape[0] * aspect_ratio) dim = (desired_width, desired_height) # итоговые размеры # Масштабируем картинку resized_cropped_region = cv2.resize(cropped_region, dsize=dim, interpolation=cv2.INTER_AREA) plt.imshow(resized_cropped_region) plt.show()
Сохранимся-с!
# Приводим картинку к RGB resized_cropped_region_2x = resized_cropped_region_2x[. -1] # Сохраняем картинку cv2.imwrite("resized_cropped_region_2x.png", resized_cropped_region_2x) # Посмотрим на сокранённую картинку (тут-то нам и пригодится подгруженный PIL) im = Image.open('resized_cropped_region_2x.png') im.show()
Отражение картинки
Происходит с помощью функции flip() .
dst = cv.flip( src, flipCode )
src — понятно, сама картинка, требующая вмешательства. Обязательный аргумент.
flipCode — флаг, объясняющий функции, как конкретно мы хотим картинку отразить.
img_NZ_rgb_flipped_horz = cv2.flip(img_NZ_rgb, 1) img_NZ_rgb_flipped_vert = cv2.flip(img_NZ_rgb, 0) img_NZ_rgb_flipped_both = cv2.flip(img_NZ_rgb, -1) plt.figure(figsize=[18,5]) plt.subplot(141);plt.imshow(img_NZ_rgb_flipped_horz);plt.title("Horizontal Flip"); plt.subplot(142);plt.imshow(img_NZ_rgb_flipped_vert);plt.title("Vertical Flip") plt.subplot(143);plt.imshow(img_NZ_rgb_flipped_both);plt.title("Both Flipped") plt.subplot(144);plt.imshow(img_NZ_rgb);plt.title("Original")

Вот и всё! Второй маленький шажок к человеку-фотошопу пройден! До встречи в следующих сериях.