Класс UImageGray: получение информации об объекте изображения
Получить информацию об объекте изображения позволяют следующие методы::
get_width() и get_height() — возвращают ширину и высоту соответственно. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(300, 200, 128)
w = img.get_width()
h = img.get_height()
print(w, h) # 300 200
get_size() — возвращает объект USize с размерами изображения. Пример:
s = img.get_size()
print(s) # USize(width=300, height=200)
w = s.get_width()
h = s.get_height()
print(w, h) # 300 200
w, h = img.get_size()
print(w, h) # 300 200
get_rect() — возвращает объект URect с координатами и размерами изображения. Пример:
r = img.get_rect()
print(r) # URect(x=0, y=0, width=300, height=200)
x = r.get_x()
y = r.get_y()
w = r.get_width()
h = r.get_height()
print(x, y, w, h) # 0 0 300 200
x, y, w, h = img.get_rect()
print(x, y, w, h) # 0 0 300 200
get_num_channels() — возвращает число каналов. Пример:
print(img.get_num_channels()) # 1
get_img_mode() — возвращает режим изображения в виде строки. Пример:
print(img.get_img_mode()) # L
get_mat_type() — возвращает тип матрицы (значение UMat.Type_8U). Пример:
print(img.get_mat_type()) # 1
get_arr_len() — возвращает количество элементов списка arr, в котором хранится изображение. При этом вычисление размера списка не производится. Размер списка вычисляется только при создании объекта изображения и при вызове метода update_arr_len(). Если объект не является валидным, то значение, возвращаемое методом, будет неправильным. Пример:
print(img.get_arr_len()) # 60000
print(len(img.arr)) # 60000
update_arr_len() — обновляет информацию о размере списка с изображением. Ничего не возвращает;
is_valid() — возвращает значение True, если объект изображения является валидным, и False — в противном случае. Проверяется соответствие размеров изображения размеру списка. Содержимое списка не проверяется. Пример:
img = UImageGray(300, 200, 128)
print(img.is_valid()) # True
img2 = UImageGray(3, 2, create_arr=False)
print(img2.arr) # []
print(img2.get_arr_len()) # 0
img2.arr = [255] * 6 # Добавляем существующий список
print(img2.is_valid()) # False
img2.update_arr_len() # Обновление данных
print(img2.is_valid()) # True
print(img2.get_arr_len()) # 6
is_transparent() — всегда возвращает значение False, т. к. объект изображения не содержит прозрачные пиксели. Пример:
img = UImageGray(300, 200, 0)
print(img.is_transparent()) # False
Получение и изменение пикселей изображения
Получить или изменить значений пикселей изображения позволяют следующие методы:
fill(<Цвет>) — заливает все изображение заданным оттенком серого цвета. В качестве параметра указывается число от 0 до 255. В результате выполнения операции создается новый список, который заменит старый список. Метод возвращает значение True, если операция выполнена успешно, и False — в противном случае. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
print(img.fill(128)) # True
print(img.arr) # [128, 128, 128, 128, 128, 128]
get_pixel(x, y) — возвращает число с оттенком серого цвета для пикселя, расположенного по координатам x и y. Валидность объекта не проверяется. Если координаты находятся вне пределов изображения, то метод вернет значение None. Пример:
print(img.get_pixel(0, 0)) # 128
print(img.get_pixel(10, -1)) # None
set_pixel(x, y, color) — изменяет цвет пикселя, расположенного по координатам x и y. Валидность объекта и диапазоны значений для компонентов цвета не проверяются. Если операция выполнена успешно, то метод вернет значение True. Если координаты находятся вне пределов изображения, то метод вернет значение False. Пример:
print(img.set_pixel(0, 0, 255)) # True
print(img.get_pixel(0, 0)) # 255
print(img.set_pixel(10, -1, 255)) # False
# Диапазоны значений не проверяются!
print(img.set_pixel(0, 0, 256)) # True
print(img.get_pixel(0, 0)) # 256
В основе объекта изображения лежит одномерный список, доступный через атрибут arr. Размер списка вычисляется следующим образом:
Строки двумерной матрицы записываются в список слева направо и сверху вниз. Давайте зальем все изображение черным цветом с помощью метода set_pixel():
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
for y in range(img.get_height()):
for x in range(img.get_width()):
img.set_pixel(x, y, 0)
print(img.arr) # [0, 0, 0, 0, 0, 0]
Этот код с синтаксической точки зрения абсолютно верный. Однако он содержит огромную проблему. Код абсолютно неэффективный! Чтобы повысить эффективность, нужно обращаться к пикселям напрямую через атрибут arr. При этом обращаться к списку следует не через объект изображения, а через ссылку, предварительно сохраненную в переменной. Вычисление положения элемента внутри списка arr, при известных координатах x и y, производится по следующей формуле:
Переделаем наш предыдущий пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img_width = img.get_width()
img_height = img.get_height()
img_arr = img.arr
for y in range(img_height):
for x in range(img_width):
i = x + y * img_width
img_arr[i] = 0
print(img.arr) # [0, 0, 0, 0, 0, 0]
Учитывая, что положение пикселя по осям X и Y в этой задаче нам не нужно, будем работать с одномерным списком:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img_arr_len = img.get_arr_len()
img_arr = img.arr
for i in range(img_arr_len):
img_arr[i] = 0
print(img.arr) # [0, 0, 0, 0, 0, 0]
В нашей задаче одно значение должно заполнить весь список. Для этого перебирать все значения списка не нужно, достаточно создать список заново средствами языка Python:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img.arr = [0] * img.get_arr_len()
print(img.arr) # [0, 0, 0, 0, 0, 0]
print(img.is_valid()) # True
Метод fill() выполняет аналогичное действие, поэтому код можно записать так:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img.fill(0)
print(img.arr) # [0, 0, 0, 0, 0, 0]
print(img.is_valid()) # True
Нормализация диапазона значений
Значения внутри списка arr должны находиться в диапазоне от 0 до 255. При выполнении различных операций можно выйти за границы этого диапазона. Учитывая, что список в Python может хранить весь диапазон целых чисел, увеличение максимального значения на единицу приведет лишь к числу 256. Если подобную операцию выполнить при использовании массива NumPy с типом uint8, то мы получим число 0, т. е. белый цвет превратится в черный. В Python такой проблемы нет.
Если внутри списка существует хотя бы одно значение вне диапазона от 0 до 255, то сохранить такое изображение или преобразовать его в другой объект не получится. Проверить валидность объекта и целостность диапазона значений позволяет метод is_normal(). Метод возвращает значение True, если объект валидный и список можно преобразовать в массив байтов, и False — в противном случае. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2, 128)
print(img.is_normal()) # True
img.arr[0] = 256
img.arr[1] = -1
print(img.arr[:3]) # [256, -1, 128]
print(img.is_normal()) # False
Вернуть значения внутрь диапазона позволяет метод normalize(). Если значение меньше 0, то оно будет заменено значением 0, если значение больше 255, то оно будет заменено значением 255. Метод возвращает значение True, если объект валидный и список можно преобразовать в массив байтов, и False — в противном случае. Пример:
print(img.normalize()) # True
print(img.arr[:3]) # [255, 0, 128]
print(img.is_normal()) # True
Работа с черно-белым изображением
Объект UImageGray может хранить черно-белое изображение, т. е. изображение в котором присутствуют только два цвета: 0 (черный) и 255 (белый). Преобразовать изображение в оттенках серого в черно-белое изображение позволяет метод bw(). Формат метода:
В качестве параметра указывается число от 0 до 255. Все пиксели со значением меньшим или равным этому числу станут черными, а все остальные пиксели станут белыми. Метод возвращает значение True, если операция выполнена успешно, и False — в противном случае. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img.arr = [0, 64, 128, 200, 254, 255]
print(img.bw(254)) # True
print(img.arr) # [0, 0, 0, 0, 0, 255]
img.arr = [0, 64, 128, 200, 254, 255]
print(img.bw(128)) # True
print(img.arr) # [0, 0, 0, 255, 255, 255]
Обратите внимание, метод изменяет значения в текущем объекте. Если нужно этого избежать, то следует применить метод к копии объекта.
Проверить, является ли изображение черно-белым позволяет метод is_bw(). Метод возвращает значение True, если в изображении присутствуют только два цвета: 0 (черный) и 255 (белый), и False — в противном случае. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
print(img.arr) # [255, 255, 255, 255, 255, 255]
print(img.is_bw()) # True
img.arr = [0, 64, 128, 200, 254, 255]
print(img.is_bw()) # False
img.bw(254)
print(img.arr) # [0, 0, 0, 0, 0, 255]
print(img.is_bw()) # True
Инверсия цвета
Инвертировать цвет всех пикселей позволяет метод invert(). Метод возвращает значение True, если операция выполнена успешно, и False — в противном случае. Пример преобразования белого цвета в черный:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
print(img.arr) # [255, 255, 255, 255, 255, 255]
print(img.invert()) # True
print(img.arr) # [0, 0, 0, 0, 0, 0]
Обратите внимание, метод изменяет значения в текущем объекте. Если нужно этого избежать, то следует применить метод к копии объекта.
Создание копии изображения
Создать копию изображения позволяет метод copy(). Если операция выполнена успешно, то метод вернет копию объекта, а в противном случае — значение None. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
print(img.arr) # [255, 255, 255, 255, 255, 255]
img2 = img.copy()
print(img2) # UImageGray(width=3, height=2)
print(img2 is img) # False
img2.arr[0] = 0
print(img2.arr) # [0, 255, 255, 255, 255, 255]
print(img.arr) # [255, 255, 255, 255, 255, 255]
Если объект изображения не является валидным, то метод вернет значение None:
img3 = UImageGray(3, 2, create_arr=False)
img4 = img3.copy()
print(img4) # None
Если просто присвоить объект другой переменной, то будет скопирована лишь ссылка на объект, а не сам объект:
img2 = img
print(img2) # UImageGray(width=3, height=2)
print(img2 is img) # True
img2.arr[0] = 0
print(img2.arr) # [0, 255, 255, 255, 255, 255]
print(img.arr) # [0, 255, 255, 255, 255, 255]
Как видно из результата, изменение списка через один объект, привело к изменению списка в другом объекте. Иными словами, оба объекта ссылаются на один и тот же список.
Сравнение изображений
Сравнить два объекта изображений можно с помощью операторов == и !=.Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2, 128)
img2 = UImageGray(3, 2, 128)
img3 = UImageGray(3, 2, 255)
print(img == img2) # True
print(img == img3) # False
print(img != img2) # False
print(img != img3) # True
Для проверки, ссылаются ли две переменные на один и тот же объект, нужно использовать оператор is:
img4 = img
print(img is img4) # True
print(img is img2) # False
Вычисление гистограммы
Вычислить гистограмму изображения позволяет метод histogram(). Метод возвращает объект UMat или значение None в случае ошибки. Список матрицы будет содержать 257 значений. Индексы первых 256 элементов соответствуют коду цвета в оттенках серого. Значения элементов соответствуют числу пикселей с таким цветом внутри изображения. Последний элемент списка содержит общее число пикселей в изображении. Пример:
from unicross_image.uimagegray import UImageGray
img = UImageGray(3, 2)
img.arr = [0, 0, 128, 255, 255, 255]
m = img.histogram()
print(m.width) # 257 (ширина)
print(m.height) # 1 (высота)
print(m.num_channels) # 1 (число каналов)
print(len(m.arr)) # 257
print(m.mat_type) # 6 (тип данных UMat.Type_32S)
print(m.arr[0]) # 2 (число черных пикселей)
print(m.arr[255]) # 3 (число белых пикселей)
print(m.arr[128]) # 1 (число пикселей с цветом 128)
print(m.arr[64]) # 0 (число пикселей с цветом 64)
print(m.arr[256]) # 6 (число всех пикселей)
Класс входит в состав графической библиотеки UImage для Python 3. Описание библиотеки UImage