Рубрики
Без рубрики

Базовая Обработка Изображений В Python – Часть 1

Основной обзор обработки изображений в Python

Автор оригинала: Mohammed Innat.

Часть 2 Опубликована на Codementor 🥳 🥳 🥳/| И Он Горит! 😎 😎

Лейтмотив

Следуйте за мной на Twitter и Quora для программирования и других технических вещей 😉 😉

Введение: Немного О Пикселе

Компьютер хранит изображения в виде мозаики из крошечных квадратов. Это похоже на древнюю форму искусства плиточной мозаики или плавящиеся наборы бусин, с которыми дети играют сегодня. Теперь, если эти квадратные плитки слишком велики, тогда трудно сделать гладкие края и кривые. Чем больше и меньше плиток мы используем, тем более гладким или, как мы говорим, менее пикселизированным будет изображение. Это иногда называют разрешением изображений.

Векторная графика-это несколько иной метод хранения изображений, который направлен на то, чтобы избежать проблем, связанных с пикселями. Но даже векторные изображения, в конце концов, отображаются как мозаика пикселей. Слово пиксель означает элемент изображения. Простой способ описать каждый пиксель-это использовать комбинацию из трех цветов, а именно Красного, Зеленого и синего. Это то, что мы называем RGB-изображением.

В RGB-изображении каждый пиксель представлен тремя 8-битными числами, связанными со значениями Красного, Зеленого и Синего соответственно. В конце концов, используя увеличительное стекло, если мы увеличим изображение, мы увидим, что оно состоит из крошечных точек малого света или, точнее, пикселей, и что еще интереснее, мы увидим, что эти крошечные точки малого света на самом деле являются множеством крошечных точек малого света разных цветов, которые являются не чем иным, как красными, зелеными, синими каналами.

Пиксель вместе издалека создает изображение, а спереди это просто маленькие огоньки, которые то включаются, то выключаются. Их сочетание создает образы и в основном то, что мы видим на экране каждый божий день.

Каждая фотография в цифровом виде состоит из пикселей. Они являются самой маленькой единицей информации, которая составляет картину. Обычно круглые или квадратные, они обычно расположены в 2-мерной сетке.

Каждая фотография в цифровом виде состоит из пикселей. Они являются самой маленькой единицей информации, которая составляет картину. Обычно круглые или квадратные, они обычно расположены в 2-мерной сетке.

Теперь, если все три значения имеют полную интенсивность, это означает, что они равны 255, то он отображается как белый, а если все три цвета приглушены или имеют значение 0, то цвет отображается как черный. Сочетание этих трех цветов, в свою очередь, даст нам определенный оттенок цвета пикселя. Поскольку каждое число является 8-битным, значения варьируются от 0 до 255.

Теперь, если все три значения имеют полную интенсивность, это означает, что они равны 255, то он отображается как белый, а если все три цвета приглушены или имеют значение 0, то цвет отображается как черный. Сочетание этих трех цветов, в свою очередь, даст нам определенный оттенок цвета пикселя. Поскольку каждое число является 8-битным, значения варьируются от 0 до 255.

Сочетание этих трех цветов будет обладать, как правило, наивысшим значением среди них. Поскольку каждое значение может иметь 256 различных значений интенсивности или яркости, оно составляет 16,8 миллиона общих оттенков.

Посмотреть на более удобный env: Jupyter nbviewer

Импорт Изображения

Теперь давайте загрузим изображение и рассмотрим его различные свойства в целом.

if __name__ == '__main__':
    import imageio
    import matplotlib.pyplot as plt
    %matplotlib inline

    pic = imageio.imread('F:/demo_2.jpg')
    plt.figure(figsize = (15,15))

    plt.imshow(pic)
Теперь давайте загрузим изображение и рассмотрим его различные свойства в целом.

Соблюдайте основные свойства изображения

print('Type of the image : ' , type(pic))
print()
print('Shape of the image : {}'.format(pic.shape))
print('Image Hight {}'.format(pic.shape[0]))
print('Image Width {}'.format(pic.shape[1]))
print('Dimension of Image {}'.format(pic.ndim))
Type of the image :  

Shape of the image : (562, 960, 3)
Image Hight 562
Image Width 960
Dimension of Image 3

Форма ndarray показывает, что это трехслойная матрица. Первые два числа здесь-длина и ширина, а третье число (т. е. 3) – для трех слоев: красного, Зеленого, Синего. Итак, если мы вычислим размер RGB-изображения, то общий размер будет засчитан как высота х ширина х 3

print('Image size {}'.format(pic.size))
print('Maximum RGB value in this image {}'.format(pic.max()))
print('Minimum RGB value in this image {}'.format(pic.min()))

Image size 1618560
Maximum RGB value in this image 255
Minimum RGB value in this image 0

Эти значения важно проверить, так как восьмибитная интенсивность цвета находится, не может быть вне диапазона от 0 до 255.

Теперь, используя переменную picture assigned, мы также можем получить доступ к любому конкретному значению пикселя изображения и далее получить доступ к каждому каналу RGB отдельно.

'''
Let's pick a specific pixel located at 100 th Rows and 50 th Column. 
And view the RGB value gradually. 
'''
pic[ 100, 50 ]
Image([109, 143,  46], dtype=uint8)

В этом случае: R ; ; и мы можем понять, что в этом конкретном пикселе много ЗЕЛЕНОГО. И теперь мы могли бы также выбрать один из этих номеров специально, дав индексное значение этих трех каналов. Теперь мы знаем для этого

  • 0 значение индекса для красного канала
  • 1 значение индекса для зеленого канала
  • 2 значение индекса для синего канала

Но хорошо знать, что в OpenCV Images принимает не RGB, а BGR. imageio.imread загружает изображение как RGB (или RGBA), но OpenCV предполагает, что изображение будет BGR или BGRA (BGR-это цветовой формат OpenCV по умолчанию).

# A specific pixel located at Row : 100 ; Column : 50 
# Each channel's value of it, gradually R , G , B
print('Value of only R channel {}'.format(pic[ 100, 50, 0]))
print('Value of only G channel {}'.format(pic[ 100, 50, 1]))
print('Value of only B channel {}'.format(pic[ 100, 50, 2]))
Value of only R channel 109
Value of only G channel 143
Value of only B channel 46

Хорошо, теперь давайте быстро рассмотрим каждый канал во всем изображении.

plt.title('R channel')
plt.ylabel('Height {}'.format(pic.shape[0]))
plt.xlabel('Width {}'.format(pic.shape[1]))

plt.imshow(pic[ : , : , 0])
plt.show()
Хорошо, теперь давайте быстро рассмотрим каждый канал во всем изображении.
plt.title('G channel')
plt.ylabel('Height {}'.format(pic.shape[0]))
plt.xlabel('Width {}'.format(pic.shape[1]))

plt.imshow(pic[ : , : , 1])
plt.show()

Хорошо, теперь давайте быстро рассмотрим каждый канал во всем изображении.
plt.title('B channel')
plt.ylabel('Height {}'.format(pic.shape[0]))
plt.xlabel('Width {}'.format(pic.shape[1]))

plt.imshow(pic[ : , : , 2])
plt.show()
Хорошо, теперь давайте быстро рассмотрим каждый канал во всем изображении.

Теперь здесь мы также можем изменить количество значений RGB. В качестве примера давайте установим Красный, Зеленый, Синий слой для следующих значений строк на полную интенсивность.

  • Канал R: Ряд – от 100 до 110
  • Канал g: Ряд – от 200 до 210
  • Канал b: Ряд – 300 – 310

Мы загрузим изображение один раз, чтобы визуализировать каждое изменение одновременно.

pic = imageio.imread('F:/demo_2.jpg')

pic[50:150 , : , 0] = 255 # full intensity to those pixel's R channel
plt.figure( figsize = (10,10))
plt.imshow(pic)
plt.show()

Мы загрузим изображение один раз, чтобы визуализировать каждое изменение одновременно.
pic[200:300 , : , 1] = 255 # full intensity to those pixel's G channel
plt.figure( figsize = (10,10))
plt.imshow(pic)
plt.show()
Мы загрузим изображение один раз, чтобы визуализировать каждое изменение одновременно.
pic[350:450 , : , 2] = 255 # full intensity to those pixel's B channel
plt.figure( figsize = (10,10))
plt.imshow(pic)
plt.show()
Мы загрузим изображение один раз, чтобы визуализировать каждое изменение одновременно.

Чтобы сделать это более понятным, давайте также изменим раздел столбца, и на этот раз мы одновременно изменим канал RGB.

# set value 200 of all channels to those pixels which turns them to white
pic[ 50:450 , 400:600 , [0,1,2] ] = 200 
plt.figure( figsize = (10,10))
plt.imshow(pic)
plt.show()
Чтобы сделать это более понятным, давайте также изменим раздел столбца, и на этот раз мы одновременно изменим канал RGB.

Посмотреть на более удобный env: Jupyter nbviewer

Разделение Слоев

Теперь мы знаем, что каждый пиксель изображения представлен тремя целыми числами. Разбиение изображения на отдельные цветовые компоненты-это всего лишь вопрос извлечения правильного среза массива изображений.

import numpy as np
pic = imageio.imread('F:/demo_2.jpg')

fig, ax = plt.subplots(nrows = 1, ncols=3, figsize=(15,5))

for c, ax in zip(range(3), ax):
    
    # create zero matrix
    split_img = np.zeros(pic.shape, dtype="uint8") # 'dtype' by default: 'numpy.float64'
    
    # assing each channel 
    split_img[ :, :, c] = pic[ :, :, c]
    
    # display each channel
    ax.imshow(split_img)

Теперь мы знаем, что каждый пиксель изображения представлен тремя целыми числами. Разбиение изображения на отдельные цветовые компоненты-это всего лишь вопрос извлечения правильного среза массива изображений.

Полутоновый

Черно-белые изображения хранятся в 2-мерных массивах. Существует два типа черно-белых изображений:

  • Оттенки серого : Диапазоны оттенков серого: 0 ~ 255
  • Двоичный : Пиксель либо черный, либо белый: 0 или 255

Так вот, оттенки серого-это такой процесс, с помощью которого изображение преобразуется из полноцветного в оттенки серого. В инструментах обработки изображений, например: в OpenCV многие функции используют изображения в оттенках серого перед обработкой, и это делается потому, что это упрощает изображение, действуя почти как шумоподавление и увеличивая время обработки, поскольку в изображениях меньше информации.

Есть несколько способов сделать это в python, чтобы преобразовать изображение в оттенки серого . Но простой способ использования matplotlib состоит в том, чтобы взять средневзвешенное значение RGB исходного изображения, используя эту формулу.

Y' = 0.299 R + 0.587 G + 0.114 B
pic = imageio.imread('F:/demo_2.jpg')

gray = lambda rgb : np.dot(rgb[... , :3] , [0.299 , 0.587, 0.114]) 
gray = gray(pic)  

plt.figure( figsize = (10,10))
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
plt.show()
Есть несколько способов сделать это в python, чтобы || преобразовать изображение в оттенки серого || . Но простой способ использования matplotlib состоит в том, чтобы взять средневзвешенное значение RGB исходного изображения, используя || эту || формулу.

Однако программа GIMP преобразования цвета в оттенки серого изображения имеет три алгоритма для выполнения этой задачи.

Легкость Уровень серого будет рассчитываться следующим образом

Легкость × (max(R,G,B) + min(R,G,B))

Светимость Уровень серого будет рассчитываться как

Светимость.21 × R + 0.72 × G + 0.07 × B

Средний уровень серого будет рассчитываться следующим образом

Средняя яркость = (R + G + B) ÷ 3

Давайте попробуем один из их алгоритмов, как насчет светимости.

pic = imageio.imread('F:/demo_2.jpg')

gray = lambda rgb : np.dot(rgb[... , :3] , [0.21 , 0.72, 0.07]) 
gray = gray(pic)  

plt.figure( figsize = (10,10))
plt.imshow(gray, cmap = plt.get_cmap(name = 'gray'))
plt.show()

'''
Let's take a quick overview some the changed properties now the color image.
Like we observe some properties of color image, same statements are applying 
now for gray scaled image.
'''

print('Type of the image : ' , type(gray))
print()

print('Shape of the image : {}'.format(gray.shape))
print('Image Hight {}'.format(gray.shape[0]))
print('Image Width {}'.format(gray.shape[1]))
print('Dimension of Image {}'.format(gray.ndim))
print()

print('Image size {}'.format(gray.size))
print('Maximum RGB value in this image {}'.format(gray.max()))
print('Minimum RGB value in this image {}'.format(gray.min()))
print('Random indexes [X,Y] : {}'.format(gray[100, 50]))

Давайте попробуем один из их алгоритмов, как насчет светимости.
Type of the image : 

Shape of the image : (562,960)
Image Height 562
Image Widht 960
Dimension of Image 2

Image size 539520
Maximum RGB value in this image 254.9999999997
Minimum RGB value in this image 0.0
Random indexes [X,Y] : 129.07

Используйте логический Оператор Для Обработки Значений Пикселей

Мы можем создать bullion ndarray того же размера с помощью логического оператора. Однако это не создаст никакого нового массива, а просто вернет True в его переменную хоста. Например: давайте рассмотрим, что мы хотим отфильтровать какой-то пиксель низкого значения или высокое значение или (любое условие) в RGB-изображении, и да, было бы здорово преобразовать RGB в серую шкалу, но пока мы не будем идти на это, а не иметь дело с цветным изображением.

Давайте сначала загрузим изображение и покажем его на экране.

pic = imageio.imread('F:/demo_1.jpg')
plt.figure(figsize = (10,10))
plt.imshow(pic)
plt.show()

Давайте сначала загрузим изображение и покажем его на экране.

Хорошо, давайте рассмотрим этот образ дампа. Теперь, в любом случае, мы хотим отфильтровать все значения пикселей, которые ниже, чем, допустим, 20. Для этого мы будем использовать логический оператор для выполнения этой задачи, который мы вернем как значение True для всего индекса.

low_pixel = pic < 20

# to ensure of it let's check if all values in low_pixel are True or not
if low_pixel.any() == True:
    print(low_pixel.shape)


(1079, 1293, 3)

Теперь, как мы уже сказали , переменная хоста, ну, это имя традиционно не используется, но я ссылаюсь на него, потому что он ведет себя. Он просто имеет истинную ценность и ничего больше. Итак, если мы увидим форму обоих low_pixel и pic , мы обнаружим, что оба имеют одинаковую форму.

print(pic.shape)
print(low_pixel.shape)

> Output

(1079, 1293, 3)
(1079, 1293, 3)

Мы сгенерировали этот фильтр низких значений, используя глобальный оператор сравнения для всех значений меньше 200. Однако мы можем использовать этот массив low_pixel в качестве индекса, чтобы установить эти низкие значения на некоторые конкретные значения, которые могут быть выше или ниже предыдущего значения пикселя.

# randomly choose a value 
import random

# load the orginal image
pic = imageio.imread('F:/demo_1.jpg')

# set value randomly range from 25 to 225 - these value also randomly choosen
pic[low_pixel] = random.randint(25,225)

# display the image
plt.figure( figsize = (10,10))
plt.imshow(pic)
plt.show()
Мы сгенерировали этот фильтр низких значений, используя глобальный оператор сравнения для всех значений меньше 200. Однако мы можем использовать этот массив low_pixel в качестве индекса, чтобы установить эти низкие значения на некоторые конкретные значения, которые могут быть выше или ниже предыдущего значения пикселя.

Маскировка

Маскировка изображений-это метод обработки изображений, который используется для удаления фона, с которого фотографии имеют нечеткие края, прозрачные или волосковые участки.

Теперь мы создадим маску в форме круглого диска. Сначала мы измерим расстояние от центра изображения до значений каждого пограничного пикселя. И мы возьмем удобное значение радиуса, а затем с помощью логического оператора создадим круговой диск. Это довольно просто, давайте посмотрим код.

if __name__ == '__main__':
    
    # load the image
    pic = imageio.imread('F:/demo_1.jpg')
    
    # seperate the row and column values
    total_row , total_col , layers = pic.shape
    
    '''
    Create vector.
    
    Ogrid is a compact method of creating a multidimensional-
    ndarray operations in single lines.
    for ex:
    
    >>> ogrid[0:5,0:5]
    output: [array([[0],
                    [1],
                    [2],
                    [3],
                    [4]]), 
            array([[0, 1, 2, 3, 4]])]
            
    '''
    x , y = np.ogrid[:total_row , :total_col]

    # get the center values of the image
    cen_x , cen_y = total_row/2 , total_col/2
    
    
    '''
    Measure distance value from center to each border pixel.
    To make it easy, we can think it's like, we draw a line from center-
    to each edge pixel value --> s**2 = (Y-y)**2 + (X-x)**2 
    '''
    distance_from_the_center = np.sqrt((x-cen_x)**2 + (y-cen_y)**2)

    # Select convenient radius value
    radius = (total_row/2)

    # Using logical operator '>' 
    '''
    logical operator to do this task which will return as a value 
    of True for all the index according to the given condition
    '''
    circular_pic = distance_from_the_center > radius

    '''
    let assign value zero for all pixel value that outside the cirular disc.
    All the pixel value outside the circular disc, will be black now.
    '''
    pic[circular_pic] = 0
    plt.figure(figsize = (10,10))
    plt.imshow(pic) 
    plt.show()
Теперь мы создадим маску в форме круглого диска. Сначала мы измерим расстояние от центра изображения до значений каждого пограничного пикселя. И мы возьмем удобное значение радиуса, а затем с помощью логического оператора создадим круговой диск. Это довольно просто, давайте посмотрим код.

Посмотреть на более удобный env: Jupyter nbviewer

Обработка Спутниковых Изображений

Один из курсов MOOC по edX мы познакомили с некоторыми спутниковыми снимками и системой их обработки. Это, конечно, очень информативно.Однако давайте сделаем на нем несколько аналитических заданий.

# load the image
pic = imageio.imread('F:\satimg.jpg')
plt.figure(figsize = (10,10))
plt.imshow(pic)
plt.show()

Один из курсов MOOC по edX мы познакомили с некоторыми спутниковыми снимками и системой их обработки. Это, конечно, очень информативно.Однако давайте сделаем на нем несколько аналитических заданий.

Давайте посмотрим на некоторые основные сведения о нем.

print(f'Shape of the image {pic.shape}')
print(f'hieght {pic.shape[0]} pixels')
print(f'width {pic.shape[1]} pixels')

> Output
Shape of the image (3725, 4797, 3)
hieght 3725 pixels
width 4797 pixels

В этом образе есть что-то интересное. Как и многие другие визуализации, цвета в каждом слое rgb что-то значат. Например, интенсивность красного цвета будет указывать на высоту точки географических данных в пикселе. Интенсивность синего цвета будет указывать на меру аспекта, а зеленый-на наклон. Эти цвета помогут быстрее и эффективнее передавать эту информацию, а не показывать цифры.

  • Красный пиксель указывает: Высота
  • Синий пиксель указывает: Аспект
  • Зеленый пиксель указывает: Наклон

Там, просто глядя на это красочное изображение, тренированный глаз уже может сказать, какая высота, какой наклон, какой аспект. Так что идея заключается в том, чтобы придать этим цветам больше смысла, чтобы указать на что-то более научное.

Обнаружение высокого пикселя каждого канала

# Only Red Pixel value , higher than 180
pic = imageio.imread('F:\satimg.jpg')
red_mask = pic[:, :, 0] < 180

pic[red_mask] = 0
plt.figure(figsize=(15,15))
plt.imshow(pic)


# Only Green Pixel value , higher than 180
pic = imageio.imread('F:\satimg.jpg')
green_mask = pic[:, :, 1] < 180


pic[green_mask] = 0
plt.figure(figsize=(15,15))
plt.imshow(pic)


# Only Blue Pixel value , higher than 180
pic = imageio.imread('F:\satimg.jpg')
blue_mask = pic[:, :, 2] < 180

pic[blue_mask] = 0
plt.figure(figsize=(15,15))
plt.imshow(pic)

# Composite mask using logical_and
pic = imageio.imread('F:\satimg.jpg')
final_mask = np.logical_and(red_mask, green_mask, blue_mask)
pic[final_mask] = 40
plt.figure(figsize=(15,15))
plt.imshow(pic)

Обнаружение высокого пикселя каждого канала

Продолжать…

Скачать Найти Полный Исходный код

Найдите эти статьи также на

Рекомендации

.

Свяжитесь со Мной: