UImageC: библиотека для работы с изображениями в Python, C и C++
Графическая библиотека UImageC (только для Windows x64) содержит код не только на языке Python, но и код на языке C, который можно вызвать из программ на Python, C или C++. Код на языке C компилируется в динамические библиотеки (dll) под Windows x64. Подключить библиотеку в программе на Python позволяет модуль ctypes, входящий в состав стандартной библиотеки.
Основная часть библиотеки UImageC реализована для Python 3.8+. Она является надстройкой над библиотеками Pillow и ImageMagick. При этом она имеет свой собственный формат файла и дополнительные возможности. Если библиотека Pillow отсутствует, то выполняется попытка выполнить операцию с помощью библиотеки ImageMagick.
В отличии от библиотеки UImage в библиотеке UImageC для хранения пикселей изображения используются массивы ctypes, а не списки Python, что позволяет получить доступ к пикселям из программы на языке C без необходимости выполнения преобразований. При этом базовая часть функционала библиотеки UImageC реализована на языке C без использования сторонних библиотек.
Библиотека UImage предназначена для "блондинок", тогда как библиотека UImageC — для опытных программистов, для которых такие слова как malloc() и указатель не лишены смысла, а действия по РУЧНОМУ освобождению динамической памяти доведены до автоматизма. "Блондинки" также могут использовать библиотеку UImageC, но... главное под "капот" не заглядывать.
Библиотека работает только в Windows x64. Библиотеки Python, Pillow, ImageMagick, NumPy и Matplotlib в комплект не входят и лицензия библиотеки UImageC на них не распространяется.
Обзор возможностей библиотеки
Библиотека UImageC содержит следующие основные классы:
UMat — описывает матрицу с произвольными значениями;
UImage — класс цветного изображения с 4-я каналами RGBA (int от 0 до 255);
UImageRGB — класс цветного изображения с 3-я каналами RGB (int от 0 до 255);
UImageGray — класс изображения в оттенках серого с одним каналом (int от 0 до 255);
UMask — класс, предназначенный для хранения маски или черно-белого изображения с одним каналом (тип bool).
Для каждого класса изображения существует свой класс обработки (в конец названия класса изображения добавляется фрагмент Change) и свой класс рисования (в конец названия класса изображения добавляется фрагмент DrawPIL). Например, выполнить преобразование изображения класса UImageRGB можно с помощью методов из класса UImageRGBChange, а нарисовать что-либо можно с помощью методов класса UImageRGBDrawPIL. Фрагмент PIL в конце названия класса рисования говорит о том, что рисование выполняется с помощью библиотеки Pillow.
Пример загрузки изображения из файла, выполнения поворота изображения на 90 градусов и сохранения изображения в файл:
from unicross_img.uimagergb import UImageRGB
from unicross_img.uimagergbchange import UImageRGBChange
img = UImageRGB.load("foto.jpg")
if img:
img = UImageRGBChange.rotate_90(img)
if img:
if img.save("foto2.jpg"):
print("Изображение успешно сохранено")
else:
print("Не удалось сохранить изображение")
else:
print("Не удалось повернуть изображение")
else:
print("Не удалось загрузить изображение")
Пример создания нового изображения красного цвета с размерами 300x200px и сохранения его в файл в формате PNG:
from unicross_img.ucolor import UColor
from unicross_img.uimagergb import UImageRGB
img = UImageRGB(300, 200, UColor("красный"))
print(img.get_width()) # 300
print(img.get_height()) # 200
print(img.get_num_channels()) # 3
print(img.get_arr_len()) # 180000
img.save("foto2.png")
Характерной особенностью библиотеки является хранение значений матрицы в одномерном массиве ctypes и возможность непосредственного доступа к этому массиву:
from unicross_img.ucolor import UColor
from unicross_img.uimagergb import UImageRGB
img = UImageRGB(3, 2, UColor("красный"))
print(img.arr[:])
# [255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
# 255, 0, 0]
# Проверка валидности
if img.is_valid():
# Перебор
for item in img.arr:
print(item)
# Изменение
r, g, b = 0, 128, 255
for i in range(0, img.get_arr_len(), img.get_num_channels()):
img.arr[i] = r
img.arr[i + 1] = g
img.arr[i + 2] = b
print(img.arr[:])
# [0, 128, 255, 0, 128, 255, 0, 128, 255, 0, 128, 255, 0, 128, 255,
# 0, 128, 255]
Можно использовать уже существующий список или массив для создания объекта:
from unicross_img.uhelper import UCArray
from unicross_img.uimagergb import UImageRGB
arr = [255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
255, 0, 0]
img = UImageRGB(3, 2, create_arr=False)
img.arr = UCArray.create_ctypes_array_int_from_list(arr)
print(img.is_valid()) # True
print(img.arr[:])
# [255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0,
# 255, 0, 0]
В любой момент времени можно преобразовать объект одного класса в объект другого класса:
from unicross_img.ucolor import UColor
from unicross_img.uimage import UImage
from unicross_img.uimagergb import UImageRGB
img = UImageRGB(300, 200, UColor("красный"))
print(img.get_num_channels()) # 3
# Преобразование в оттенки серого
img_gray = img.get_uimagegray()
print(img_gray.get_num_channels()) # 1
# Добавление альфа-канала
img_rgba = UImage.from_uimagergb(img, opacity=128)
print(img_rgba.get_num_channels()) # 4
Стандартные классы позволяют работать только с целочисленными значениями. Для значений другого типа предназначен класс UMat. Например, можно преобразовать объект изображения в матрицу с вещественными значениями, выполнить какие-либо операции, а затем обратно преобразовать матрицу в объект изображения:
from unicross_img.ucolor import UColor
from unicross_img.uimagergb import UImageRGB
img = UImageRGB(2, 2, UColor(255, 0, 0))
print(img.arr[:])
# [255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0]
m = img.get_umat_64f()
print(m.arr)
# [1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0]
img = UImageRGB.from_umat_64f(m)
print(img.arr[:])
# [255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0]
Использование Pillow в программе на Python
Графическая библиотека UImageC тесно связана с библиотекой Pillow. Загрузка изображений из файлов стандартных форматов, сохранение в файл, а также выполнение различных преобразований в основном выполняется средствами библиотеки Pillow. Эти операции можно выполнить и с помощью библиотеки ImageMagick, но вот рисование и вывод текста возможны только при условии доступности библиотеки Pillow. В любой момент времени имеется возможность преобразования объектов из разных библиотек:
from PIL import Image
from unicross_img.uimagergb import UImageRGB
img = Image.open("foto.jpg")
print(img.size) # (500, 333)
img2 = UImageRGB.from_pil_image(img)
print(img2.get_size()) # USize(width=500, height=333)
img3 = img2.get_pil_image()
print(img3.size) # (500, 333)
Использование ImageMagick в программе на Python
Если библиотека Pillow недоступна, то автоматически вызывается метод, выполняющий аналогичную операцию с помощью библиотеки ImageMagick. Если библиотека ImageMagick также недоступна, то метод вернет значение None. Можно сразу вызвать метод, выполняющий операцию с помощью библиотеки ImageMagick. В названиях таких методов последним будет фрагмент "_im". Выполним все операции только с помощью библиотеки ImageMagick:
from unicross_img.uimagergb import UImageRGB
from unicross_img.uimagergbchange import UImageRGBChange
img = UImageRGB.load_im("foto.jpg")
if img:
img = UImageRGBChange.rotate_90_im(img)
if img:
if img.save_im("foto2.jpg"):
print("Изображение успешно сохранено")
else:
print("Не удалось сохранить изображение")
else:
print("Не удалось повернуть изображение")
else:
print("Не удалось загрузить изображение")
Форматы файлов UImage и PPM
На самом деле стандартные классы библиотеки UImageC могут работать и без библиотек Pillow и ImageMagick. Просто станет нельзя загрузить изображение из стандартных графических форматов и сохранить изображение в этих форматах. Но остается возможность использовать форматы без сжатия, например, формат PPM, а также собственный формат библиотеки .uimage:
from unicross_img.uimagergb import UImageRGB
# Загрузка PPM
img = UImageRGB.load_ppm_p6("foto.ppm")
if img:
print(img.get_size()) # USize(width=500, height=333)
# Сохранение PPM
img.save_ppm_p6("foto2.ppm")
# Сохранение .uimage
img.save_uimage_rgb("foto.uimage")
else:
print("Не удалось загрузить изображение")
# Загрузка .uimage
img = UImageRGB.load_uimage("foto.uimage")
if img:
print(img.get_size()) # USize(width=500, height=333)
else:
print("Не удалось загрузить изображение")
Формат файла определяется по расширению файла, поэтому можно просто использовать методы load() и save() без явного указания типа файла:
from unicross_img.uimagergb import UImageRGB
# Загрузка PPM
img = UImageRGB.load("foto.ppm")
if img:
print(img.get_size()) # USize(width=500, height=333)
# Сохранение PPM
img.save("foto2.ppm")
# Сохранение .uimage
img.save("foto.uimage")
else:
print("Не удалось загрузить изображение")
# Загрузка .uimage
img = UImageRGB.load("foto.uimage")
if img:
print(img.get_size()) # USize(width=500, height=333)
else:
print("Не удалось загрузить изображение")
Взаимодействие с Tkinter и объектом PhotoImage
Графическая библиотека UImageC тесно связана также с библиотекой Tkinter. Для этого предназначен класс UHelperTk. Отобразим изображение в компоненте Canvas:
from unicross_img.uimagergb import UImageRGB
from unicross_img.uhelper_tk import UHelperTk
from tkinter import *
root = Tk()
root.title("Взаимодействие с Tkinter и объектом PhotoImage")
root.geometry("700x450")
canvas = Canvas(bg="white", width=600, height=400)
canvas.pack(anchor=CENTER, expand=1)
img = UImageRGB.load("foto.jpg")
# Преобразование в PhotoImage
img2 = UHelperTk.uimage_to_photoimage(img)
canvas.create_image(10, 10, anchor=NW, image=img2)
root.mainloop()
Кстати, если библиотеки Pillow и ImageMagick недоступны, то можно загрузить изображение из стандартных графических форматов с помощью объекта PhotoImage из библиотеки Tkinter. В классе UHelperTk для этой цели предусмотрены специальные методы.
Взаимодействие с библиотекой NumPy
С помощью класса UHelperNP можно преобразовать объект изображения в массив NumPy, а также выполнить обратное преобразование:
from unicross_img.ucolor import UColor
from unicross_img.uimagergb import UImageRGB
from unicross_img.uhelper_np import UHelperNP
img = UImageRGB(3, 2, UColor(255, 0, 0))
# Преобразование UImageRGB в массив NumPy
arr = UHelperNP.uimage_to_ndimage(img)
print(arr.shape) # (2, 3, 3)
print(arr.dtype) # uint8
print(arr)
# [[[255 0 0]
# [255 0 0]
# [255 0 0]]
#
# [[255 0 0]
# [255 0 0]
# [255 0 0]]]
# Преобразование массива NumPy в UImageRGB
img2 = UHelperNP.ndimage_to_uimage(arr)
print(img2) # UImageRGB(width=3, height=2)
Класс UHelperNP содержит также методы для выполнения различных преобразований для изображений в оттенках серого, например, можно повернуть изображение на угол кратный 90 градусам, зеркально отразить по горизонтали или вертикали, обрезать, вставить одно изображение в другое, добавить рамку или паддинг и др.
Взаимодействие с библиотекой Matplotlib
Класс UHelperPlt позволяет отображать изображения и гистограммы с помощью библиотеки Matplotlib. Отобразим изображение в диалоговом окне:
from unicross_img.uhelper_plt import UHelperPlt, UImageRGB
img = UImageRGB.load("foto.jpg")
UHelperPlt.imshow(img)
Вычислим гистограммы и отобразим графики сразу для всех каналов:
from unicross_img.uhelper_plt import UHelperPlt, UImageRGB
img = UImageRGB.load("foto.jpg")
UHelperPlt.uimagergb_show_hist(img)
Модули библиотеки UImageC
Библиотека UImageC поставляется в виде пакета unicross_img. Если программа расположена рядом с каталогом библиотеки, то подключение модуля из пакета и импорт класса выполняются примерно так:
from unicross_img.uimagergb import UImageRGB
Если программа расположена в другом месте, то предварительно нужно прописать путь к библиотеке в пути поиска модулей:
import sys
sys.path.append(r"D:\UImageC")
from unicross_img.uimagergb import UImageRGB
Библиотека UImageC должна быть расположена в каталоге, запись в который не требует прав администратора. Иначе работа с библиотекой ImageMagick станет невозможной, т. к. взаимодействие выполняется через файловую систему. Еще раз. Нельзя размещать библиотеку в системных папках и в папках с русским буквами в пути!
Внутри пакета unicross_img расположены следующие модули:
ucolor.py — вспомогательный модуль для работы с цветом. Содержит следующие идентификаторы:
- класс
UColor для хранения цвета RGBA (значения от 0 до 255);
- объекты
URGBA и URGB;
- словарь
COLOR_NAMES со списком всех поддерживаемых названий цветов;
uhelper.py — вспомогательный модуль, содержащий следующие идентификаторы:
- класс
UPoint описывает координаты точки (тип int) в двумерном пространстве;
- класс
UPointF описывает координаты точки (тип float) в двумерном пространстве;
- класс
USize описывает размеры прямоугольной области (тип int);
- класс
USizeF описывает размеры прямоугольной области (тип float);
- класс
URect описывает координаты и размеры (тип int) прямоугольной области;
- класс
UCArray содержит методы для работы с массивами ctypes;
uhelper_pil.py — содержит класс UHelperPIL, предназначенный для выполнения загрузки и сохранения файла .uimage для библиотеки Pillow;
uhelper_tk.py — содержит класс UHelperTk, предназначенный для выполнения преобразований между UImage и Tk PhotoImage;
uhelper_np.py — содержит класс UHelperNP, предназначенный для выполнения преобразований с помощью библиотеки NumPy;
uhelper_plt.py — содержит класс UHelperPlt, предназначенный для отображения изображений и гистограмм с помощью библиотеки Matplotlib;
uimage.py — содержит класс UImage, предназначенный для хранения цветного изображения с 4-я каналами RGBA (int от 0 до 255);
uimagechange.py — содержит класс UImageChange, предназначенный для выполнения преобразований UImage (средствами Pillow или ImageMagick и без). Почти все методы принимают объект UImage и возвращают копию преобразованного объекта UImage или None;
uimagergb.py — содержит класс UImageRGB, предназначенный для хранения цветного изображения с 3-я каналами RGB (int от 0 до 255);
uimagergbchange.py — содержит класс UImageRGBChange, предназначенный для выполнения преобразований UImageRGB (средствами Pillow или ImageMagick и без). Почти все методы принимают объект UImageRGB и возвращают копию преобразованного объекта UImageRGB или None;
uimagegray.py — содержит следующие идентификаторы:
- класс
UImageGray, предназначенный для хранения изображения в оттенках серого с одним каналом (int от 0 до 255);
- класс
UMask, предназначенный для хранения маски или черно-белого изображения с одним каналом (тип bool);
uimagegraychange.py — содержит класс UImageGrayChange, предназначенный для выполнения преобразований UImageGray (средствами Pillow или ImageMagick и без). Почти все методы принимают объект UImageGray и возвращают копию преобразованного объекта UImageGray или None;
uimagedraw.py — модуль для рисования. Содержит следующие идентификаторы:
- класс
UFont, описывающий характеристики шрифта;
- класс
UImageDrawPIL, предназначенный для рисования на UImage средствами Pillow;
- класс
UImageRGBDrawPIL, предназначенный для рисования на UImageRGB средствами Pillow;
- класс
UImageGrayDrawPIL, предназначенный для рисования на UImageGray средствами Pillow;
umat.py — содержит класс двумерной матрицы UMat.
Как скачать
Пока никак. Библиотека сейчас находится в разработке.
Поддержать проект