Класс UMat: матрица с произвольными значениями
Стандартные классы изображений UImage, UImageRGB и UImageGray позволяют работать только с целочисленными значениями. Для значений другого типа предназначен класс UMat, который описывает матрицу с произвольными значениями. Инструкция импорта:
from unicross_image.umat import UMat
Например, можно преобразовать объект изображения в матрицу с вещественными значениями, выполнить какие-либо операции, а затем обратно преобразовать матрицу в объект изображения:
from unicross_image.ucolor import UColor
from unicross_image.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]
Формат конструктора класса UMat:
UMat(width, height, num_channels=1, value=0.0, mat_type=Type_64F)
Параметры width и height задают ширину и высоту матрицы соответственно. С помощью необязательного параметра num_channels можно указать количество каналов, а с помощью параметра value — значение по умолчанию, которое заполнит всю матрицу. Параметр mat_type задает тип данных элементов матрицы:
UMat.Type_8U — 8 бит (0...255);
UMat.Type_8S — 8 бит (-128...127);
UMat.Type_8B — 8 бит (True или False);
UMat.Type_16U — 16 бит (0...65535);
UMat.Type_16S — 16 бит (-32768...32767);
UMat.Type_32S — 32 бита (-2 147 483 648 ... 2 147 483 647);
UMat.Type_32F — 32 бита float (из C++);
UMat.Type_64F — 64 бита double (соответствует типу float в Python):
UMat.Type_USER — пользовательский тип.
Выведем значения констант:
print(UMat.Type_8U) # 1
print(UMat.Type_8S) # 2
print(UMat.Type_8B) # 3
print(UMat.Type_16U) # 4
print(UMat.Type_16S) # 5
print(UMat.Type_32S) # 6
print(UMat.Type_32F) # 7
print(UMat.Type_64F) # 8
print(UMat.Type_USER) # 9
Если ширина или высота меньше 1 или больше 8000, то будет сгенерировано исключение. Исключение также генерируется, если число каналов меньше одного или тип не соответствует указанным выше типам.
Пример создания матрицы с одним каналом шириной 5 элементов и высотой 1 элемент со значениями от 0.0 до 1.0:
m = UMat(5, 1)
print(m.width) # 5 (ширина)
print(m.height) # 1 (высота)
print(m.num_channels) # 1 (число каналов)
print(m.arr) # [0.0, 0.0, 0.0, 0.0, 0.0] (список)
print(len(m.arr)) # 5
print(m.arr_len) # 5 (длина списка)
print(m.mat_type) # 8 (тип данных)
Все атрибуты класса UMat являются общедоступными и их можно изменить извне класса. Для проверки валидности объекта предназначен метод is_valid(), который возвращает True, если все атрибуты содержат корректные значения:
m = UMat(3, 2, num_channels=3, value=0)
print(m.is_valid()) # True
m.width = -1
print(m.is_valid()) # False
Матрица может хранить как вещественные числа, так и любые другие данные, например, целые числа, описывающие компоненты цвета RGB:
m = UMat(3, 2, num_channels=3, value=0, mat_type=UMat.Type_8U)
print(m.width) # 3
print(m.height) # 2
print(m.num_channels) # 3
print(m.arr)
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
print(len(m.arr)) # 18
print(m.arr_len) # 18
print(m.mat_type) # 1
В предыдущем примере мы указали три канала, хотя можем использовать один канал и хранить в элементах списка кортежи из трех элементов:
m = UMat(2, 2, value=(255, 0, 0), mat_type=UMat.Type_USER)
print(m.width) # 2
print(m.height) # 2
print(m.num_channels) # 1
print(m.arr)
# [(255, 0, 0), (255, 0, 0), (255, 0, 0), (255, 0, 0)]
print(len(m.arr)) # 4
print(m.arr_len) # 4
print(m.mat_type) # 9
В основе матрицы лежит одномерный список, доступный через атрибут arr. Размер списка вычисляется следующим образом (размер доступен через атрибут arr_len):
len = width * height * num_channels
Перебрать все элементы матрицы с одним каналом можно так:
m = UMat(3, 2, num_channels=1, value=0, mat_type=UMat.Type_8U)
print(m.width) # 3
print(m.height) # 2
print(m.num_channels) # 1
print(m.arr) # [0, 0, 0, 0, 0, 0]
print(m.arr_len) # 6
print(m.mat_type) # 1
if m.is_valid():
n = 1
m_arr = m.arr
for i in range(m.arr_len):
m_arr[i] = n
n += 1
print(m.arr) # [1, 2, 3, 4, 5, 6]
Если каналов несколько, то перебрать элементы можно так:
m = UMat(2, 2, num_channels=3, value=0, mat_type=UMat.Type_8U)
print(m.width) # 2
print(m.height) # 2
print(m.num_channels) # 3
print(m.arr)
# [0, 0, 0, 0, 0, 0,
# 0, 0, 0, 0, 0, 0]
print(m.arr_len) # 12
print(m.mat_type) # 1
if m.is_valid():
n = 1
m_arr = m.arr
for i in range(0, m.arr_len, m.num_channels):
for j in range(m.num_channels):
m_arr[i + j] = n + j * 10
n += 1
print(m.arr)
# [1, 11, 21, 2, 12, 22,
# 3, 13, 23, 4, 14, 24]
Чаще всего мы знаем значения, которые нужно записать в конкретный элемент. Например, записать компоненты цвета во все элементы матрицы с тремя каналами можно так:
m = UMat(2, 2, num_channels=3, value=0, mat_type=UMat.Type_8U)
if m.is_valid() and m.num_channels == 3:
r, g, b = 255, 128, 0
m_arr = m.arr
for i in range(0, m.arr_len, m.num_channels):
m_arr[i] = r
m_arr[i + 1] = g
m_arr[i + 2] = b
print(m.arr)
# [255, 128, 0, 255, 128, 0,
# 255, 128, 0, 255, 128, 0]
Если каналов несколько, то вычисление положения элемента внутри списка arr, при известных координатах x и y, производится по следующей формуле:
i = x * num_channels + y * width * num_channels
Например, записать компоненты цвета во все элементы матрицы с тремя каналами можно так:
m = UMat(2, 2, num_channels=3, value=0, mat_type=UMat.Type_8U)
if m.is_valid() and m.num_channels == 3:
r, g, b = 255, 128, 0
m_line = m.width * m.num_channels
m_arr = m.arr
m_num_channels = m.num_channels
for y in range(m.height):
for x in range(m.width):
i = x * m_num_channels + y * m_line
m_arr[i] = r
m_arr[i + 1] = g
m_arr[i + 2] = b
print(m.arr)
# [255, 128, 0, 255, 128, 0,
# 255, 128, 0, 255, 128, 0]
Класс входит в состав графической библиотеки UImage для Python 3. Описание библиотеки UImage