Здесь должна быть шутка
image

Сегодня я хочу представить вам третью статью из серии «Нейронные сети для начинающих». Мы научимся обрабатывать изображения и сохранять результаты в отдельные файлы. Вот небольшой список задач, которые будут разобраны ниже:

  1. Преобразование изображения в оттенки серого.
  2. Уменьшение размерности изображения (в пикселях) в 4 раза.
  3. Нахождение и выделение (рамкой) самого тёмного объекта на изображении.

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

Перед началом работы советую вам прочитать предыдущие статьи для более полного понимания материала:


Код


Итак, приступим. Для начала нам потребуется библиотека OpenCV, которую мы разбирали в предыдущей статье в пункте «Поверхностное знакомство с библиотекой OpenCV». Давайте установим её. Для этого введём в терминале команду:

pip install opencv-python

После этого в нашем файле с расширением .py, мы можем импортировать библиотеку cv2 (краткое название библиотеки OpenCV). Давайте пропишем это:

import cv2
import numpy as np

Также мы импортировали библиотеку NumPy, которая предназначена для математических вычислений. Подробнее о ней вы можете прочитать в предыдущей статье, в пункте «Знакомство с библиотекой NumPy».

Теперь давайте отойдём от кода и вспомним немного теории.

Основные операции с изображениями


Установив OpenCV, пощупаем основные функциональные возможности данной библиотеки.

▍ Вывод изображения на экран


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

Для вывода изображения на экран нам необходимо задать две вещи:

  1. Путь к файлу, в котором содержится изображение (подойдёт как относительный, так и абсолютный путь).
  2. Режим чтения файла (только чтение, запись и т. д.).

Функция, при помощи которой мы считываем изображение, называется cv2.imread(). У неё есть три режима работы:

  1. IMREAD_GRAYSCALE. Как видно из названия, он преобразует изображение в чёрно-белое с оттенками серого.
  2. IMREAD_UNCHANGED, который загружает изображение без обрезания альфа-канала.
  3. IMREAD_COLOR (используемый по умолчанию). Он просто загружает цветное изображение, используя RGB-каналы.

Вот пример кода:

import cv2

my_bike = cv2.imread('bike.png')

Замечание: если в результате выполнения данного кода возникла ошибка, есть три возможных причины для этого. Первая — вы неправильно задали путь к файлу. Вторая — такого файла просто не существует, и третья — тип изображения (jpg/jpeg/png) задан неверно.

Теперь давайте выведем на экран только что загруженное изображение. Для этого используется функция cv2.imshow(). Если вы пользовались Matlab, её работа должна быть вам знакома.

cv2.imshow('my_bike', my_bike)

Первый параметр функции imshow() — это строка, которую мы хотим использовать в качестве заголовка к нашему изображению. Второй параметр — переменная, содержащая загруженное нами изображение.

▍ Сохранение изображений


Для сохранения результатов нашей работы с изображениями в библиотеке OpenCV существует функция cv2.imwrite().

Вот пример её использования:

cv2.imwrite('bike.png', my_bike)

Здесь мы задали название файла и переменную, в которой содержится изображение. Оно будет сохранено в текущую рабочую директорию.

▍ Преобразование изображений


Эта тема находит применение в самых разных приложениях, но отдельно следует упомянуть задачу аугментации данных для моделей машинного обучения. Речь идёт о ситуациях, когда в датасете недостаточно данных для полноценного обучения, и мы, дополняя и видоизменяя существующие картинки, увеличиваем первоначальный датасет до нужного размера. Это помогает серьёзно увеличить точность работы обучаемой модели.

Список возможных преобразований весьма велик и включает в себя масштабирование, афинное преобразование изображений, вращение, транспонирование и многое другое. Мы кратко расскажем только про масштабирование и вращение, но в библиотеке OpenСV есть поддержка всех возможных преобразований. Разберём масштабирование.

▍ Масштабирование


Попросту говоря, масштабирование — это не что иное, как изменение размеров изображения, его увеличение либо уменьшение. В библиотеке OpenCV для этого существует функция resize. У этой функции, в свою очередь, есть три метода: INTER_CUBIC, INTER_LINEAR и INTER_AREA. Давайте на примере конкретного кода разберём, как это всё работает. Пожалуйста, внимательно изучите код, комментарии к нему и описание ниже.

import cv2
import numpy as np
import matplotlib.pyplot as plt

image = cv2.imread('my_bike.jpg')

# Увеличиваем масштаб/расширяем в 2 раза по ширине и высоте
result_1 = cv2.resize(image, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)

# Уменьшаем масштаб/сжимаем в 2 раза по ширине и высоте
result_2 = cv2.resize(image, None, fx=2, fy=2, interpolation=cv2.INTER_AREA)

# Выводим на экран получившиеся изображения
plt.imshow(result_1)
plt.imshow(result_2)
plt.show()

Здесь в функции resize параметр fx определяет масштаб изменений по ширине, fy — по высоте, а параметр interpolation отвечает за сам способ изменений (то есть расширение или сжатие).

OpenCV cvtColor


Цвета, присутствующие в изображении, представлены цветовыми пространствами в OpenCV. Существует несколько цветовых пространств, каждое из которых имеет свою важность, например, RGB, CMYK и т. д. Всякий раз, когда возникает необходимость преобразовать изображение из одного цветового пространства в другое в OpenCV, мы используем функцию cvtColor(). Всего в OpenCV доступно более 150 кодов преобразования цветового пространства (cv2.COLOR_BGR2GRAY, cv2.COLOR_BGR2HSV и т. д.). Преобразование цветового пространства с помощью функции cvtColor() очень полезно для решения задач в области компьютерного зрения.

Синтаксис для определения функции cvtColor() в OpenCV следующий:

cvtColor(image, code)

Здесь image — это изображение, цветовое пространство которого должно быть преобразовано, а code — это код преобразования цветового пространства.

▍ Как работает функция cvtColor() в OpenCV


Функция cvtColor() в OpenCV принимает два параметра, а именно изображение и код. То есть изображение, цветовое пространство которого должно быть преобразовано в другое цветовое пространство, а также код преобразования цвета. Функция cvtColor() возвращает изображение с изменённым цветовым пространством.

▍ Обсудим примеры OpenCV cvtColor


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

Для примера будем использовать следующую картинку:

image

Код программы:

import cv2

# Считывание изображения, которое должно быть преобразовано 
# в цветовое пространство HSV
image1 = cv2.imread('test_img_color.png')

# Преобразование изображения в цветовое пространство HSV 
# с помощью функции cvtColor и сохранение полученного изображения
imageresult = cv2.cvtColor(image1, cv2.COLOR_BGR2HSV)

# Вывод результата 
cv2.imshow("Start image", image1)
cv2.imshow("End image", imageresult)
cv2.waitKey(0)

image

В приведённой выше программе мы импортируем модуль cv2. Затем мы читаем изображение, цветовое пространство которого необходимо преобразовать с помощью функции imread(). Далее используем функцию cvtColor(), указав код преобразования цветового пространства. Полученное изображение отображается как вывод на экране. Результат показан на снимке выше.

Выглядит круто! А теперь давайте поменяем цветовое пространство на серое. Для этого используем следующий код:

import cv2

# Считывание изображения, которое должно быть преобразовано
# в серое цветовое пространство
image1 = cv2.imread('test_img_color.png')

# Преобразование изображения в серое цветовое пространство
# с помощью функции cvtColor и сохранение полученного изображения
imageresult = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)

# Вывод результата 
cv2.imshow("Start image", image1)
cv2.imshow("End image", imageresult)
cv2.waitKey(0)

image

Алгоритм детектирования краёв Canny Edge Detector


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

Например, такие функции, как линии и кривые, могут быть извлечены с помощью обнаружения краёв, которые затем обычно используются компьютерным зрением более высокого уровня или алгоритмами обработки изображений. Хороший алгоритм будет выделять расположение основных краёв на изображении, в то же время игнорируя любые ложные края, вызванные шумом.

Но что такое рёбра? Края — это особенности изображения, которые можно использовать для оценки и анализа структуры объектов на нём. Они представляют значительные локальные изменения, которые произошли в интенсивности изображения (то есть значение пикселя). Края обычно появляются на границе между двумя разными областями изображения.

Сейчас мы познакомимся с алгоритмом детектора рёбер Canny и тем, как мы можем реализовать его в Python.

Небольшая историческая справка: алгоритм детектора краёв Canny назван в честь его изобретателя Джона Ф. Кэнни, который изобрёл алгоритм в 1986 году. Детектор краёв Canny обычно принимает изображение в градациях серого в качестве входных данных и создаёт изображение, показывающее местоположение разрывов интенсивности в качестве выходных данных.

Не хочется описывать здесь много математики, но давайте разберёмся, что происходит за кулисами в алгоритме детектора краёв с точки зрения высокого уровня.

Первое, что делает детектор краёв Canny, — использует гауссовую свёртку для сглаживания входного изображения и удаления шума. Затем первый оператор производной применяется к сглаженному изображению, чтобы выделить области изображения с высокими первыми пространственными производными. Затем алгоритм находит как величину, так и направление градиента, вычисляя x-производную и y-производную. Тем более что знание направления градиента фактически позволяет нам найти направление рёбер.

Затем алгоритм выполняет то, что называется «не максимальным подавлением», где он отслеживает вершину гребней, которые поднимаются от краёв, и устанавливает в ноль пиксели, которые находятся не на вершине гребня, в результате чего получается тонкая линия.

Другими словами, мы проверяем, считается ли градиент, вычисленный на предыдущем шаге, максимальным среди соседних точек, лежащих как в положительном, так и в отрицательном направлении. Если градиент был максимальным, он считается частью края, и наоборот.

Процесс отслеживания, описанный выше, контролируется двумя порогами, t1 и t2, так что t1>t2, называемый порогом гистерезиса. Отслеживание начинается в точке на гребне выше t1, а затем продолжается в обоих направлениях из этой точки, пока высота гребня не станет меньше t2.

В результате мы выбираем все граничные точки, которые находятся выше верхнего порога t1, а затем исследуем, существуют ли соседи этих точек, которые рассматриваются ниже верхнего порога t1 и выше нижнего порога t2. В этом случае такие соседи будут частью края.

Таким образом, ширина гауссова ядра, используемого для сглаживания входного изображения, и пороговые значения t1 (верхний) и t2 (нижний), используемые трекером, являются параметрами, которые определяют эффект детектора краёв Canny.

▍ Немного кода для понимания реализации Canny Edge Detector с использованием OpenCV


В OpenCV есть функция canny() для применения алгоритма детектора краёв Canny к изображению. Следующий код показывает, как мы можем использовать OpenCV, чтобы найти края в нашем изображении:

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('test_img_color.png')
edges = cv2.Canny(img,25,255,L2gradient=False)
cv2.imshow('Start image', img)
plt.imshow(edges, cmap='gray')
plt.show()
cv2.waitKey(0)

Обратите внимание, что я передал следующее в качестве аргументов функции Canny():
  • img — имя изображения,
  • lower threshold — 25,
  • upper threshold — 255,
  • L2gradient=False — это означает, что используется L1-норма. Если установлено значение True, будет использоваться L2-норма.

Затем для построения результатов используем библиотеку matplotlib и получаем следующий результат:

image

Более подробно про алгоритм можно почитать здесь (очень советую к прочтению) и здесь.

Возвращение к коду


Надеюсь, вы не забыли, что мы учимся обрабатывать изображения и сохранять результаты в отдельные файлы, поэтому давайте продолжим. После импорта необходимых библиотек нам нужно считать нашу тестовую картинку. У меня их будет две:

image

image

На первой изображены геометрические фигуры разных цветов (нас будет интересовать самый тёмный объект, то есть чёрный). На второй же мы видим тестовую карту с цветовыми квадратами, разбитыми на сектора. На ней нас также будет интересовать самый тёмный объект, то есть чёрный.

Хорошо, на картинки мы полюбовались, а как же их загрузить?

Из пункта «Основные операции с изображениями» мы знаем, что для загрузки изображения нам нужно прописать команду cv2.imread. Давайте загрузим оба изображения и выведем их с помощью кода:

img_1 = cv2.imread('test_map_1.png')
img_2 = cv2.imread('test_map_2.png')

cv2.imshow('First image', img_1)
cv2.imshow('Second image', img_2)
# функция waitKey() позволяет нам не закрывать выведенные картинки сразу, а дожидаться нажатия любой кнопки, перед тем как всё закрыть 
cv2.waitKey(0)

Вот что нам выведет программа:

image

Далее мы выполняем следующий код (внимательно прочитайте комментарии к нему):

import cv2
import numpy as np

img = cv2.imread('test_map_1.png')

# Создаём копию изначального изображения
img_cont = img.copy()

# Переводим изначальное изображение img в серый канал (с этим методом
# мы познакомились выше) и сохраняем в переменной gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Производим изменение размерности в 4 раза (изменение размерности производится
# в пикселях) относительно изначальной картинки img и сохраняем полученное 
# изображение в переменной img_resize
img_resize = cv2.resize(img, (int(img.shape[1] / 4), int(img.shape[0] / 4)))

# Далее идёт большой блок кода, в котором мы создаём 
# алгоритм детектирования краёв Canny Edge Detector (с этим методом
# мы познакомились выше) 
canny_1 = 200
canny_2 = 225
canny = cv2.Canny(img, canny_1, canny_2)
contours, hierarchy = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
min_black = 255
cnt_black = []

for cnt in contours:
    c_area = cv2.contourArea(cnt) + 1e-7
    if cv2.contourArea(cnt) + 1e-7 > 500:
        cv2.drawContours(img_cont, [cnt], -1, 3)
        mask = np.zeros_like(gray)
        cv2.drawContours(mask, [cnt], -1, (255,255,255), -1)
        temp_mask = cv2.bitwise_and(gray, mask)
        temp_col = np.sum(temp_mask).real/(cv2.contourArea(cnt)+1e-7)
        if (temp_col < min_black) or (len(cnt_black) == 0):
            cnt_black = cnt
            min_black = temp_col

if len(cnt_black)!=0:
    cv2.drawContours(img_cont, [cnt_black], -1, (0,0,255), 3)

Нам остаётся совсем немного, а именно вывести результат работы нашей программы на экран и сохранить данные в папку с проектом. Это легко сделать с помощью следующего кода:

# Сохранение результатов работы нашей программы в папку

# Сохранение изображения с детектированными контурами
cv2.imwrite('img_contour_1_1.jpg', img_cont)
# Сохранение изображения в сером цветовом канале
cv2.imwrite('img_gray_channel_1_1.png', gray)
# Сохранение уменьшенного в 4 раза изображения 
cv2.imwrite('img_resize_1_1.png', img_resize)

# Вывод на экран изначального изображения
cv2.imshow('Basic image', img)
# Вывод на экран изображения с детектированными контурами
cv2.imshow('Contour image', img_cont)
# Вывод на экран изображения в сером цветовом канале
cv2.imshow('Gray channel image', gray)
# Вывод на экран уменьшенного в 4 раза изображения 
cv2.imshow('Resize image', img_resize)

# Режим ожидания нажатия кнопки
cv2.waitKey(0)

Это код выполняет преобразование первой картинки с именем «test_map_1». Чтобы преобразовать вторую, достаточно в строке img = cv2.imread('test_map_1.png') поменять название файла с «test_map_1.png», на «test_map_2.png».

Теперь давайте посмотрим результаты работы нашей программы для «test_map_1.png».

Изначальное изображение:

image

Изображение в сером цветовом канале:

image

Уменьшенное в 4 раза изображение:

image

Изображение с детектированными контурами самого тёмного элемента:

image

То же самое давайте посмотрим для «test_map_2.png».

Изначальное изображение:

image

Изображение в сером цветовом канале:

image

Уменьшенное в 4 раза изображение:

image

Изображение с детектированными контурами самого тёмного элемента:

image

Приведу здесь весь код для тех, кому не хочется собирать его по крупицам:
import cv2
import numpy as np

img = cv2.imread('test_map_1.png')

img_cont = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_resize = cv2.resize(img, (int(img.shape[1] / 4), int(img.shape[0] / 4)))
canny_1 = 200
canny_2 = 225
canny = cv2.Canny(img, canny_1, canny_2)
contours, hierarchy = cv2.findContours(canny, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
min_black = 255
cnt_black = []

for cnt in contours:
    c_area = cv2.contourArea(cnt) + 1e-7
    if cv2.contourArea(cnt) + 1e-7 > 500:
        cv2.drawContours(img_cont, [cnt], -1, 3)
        mask = np.zeros_like(gray)
        cv2.drawContours(mask, [cnt], -1, (255,255,255), -1)
        temp_mask = cv2.bitwise_and(gray, mask)
        temp_col = np.sum(temp_mask).real/(cv2.contourArea(cnt)+1e-7)
        if (temp_col < min_black) or (len(cnt_black) == 0):
            cnt_black = cnt
            min_black = temp_col

if len(cnt_black)!=0:
    cv2.drawContours(img_cont, [cnt_black], -1, (0,0,255), 3)
   
cv2.imwrite('img_basic_1_1.jpg', img)
cv2.imwrite('img_contour_1_1.jpg', img_cont)
cv2.imwrite('img_gray_channel_1_1.png', gray)
cv2.imwrite('img_resize_1_1.png', img_resize)

cv2.imshow('Basic image', img)
cv2.imshow('Contour image', img_cont)
cv2.imshow('Gray channel image', gray)
cv2.imshow('Resize image', img_resize)
cv2.waitKey(0)

Всё очень просто!

Все файлы для повторения кода из статьи, включая код и картинки, вы можете найти на моём GitHub.

А теперь вопрос к вам! Давайте поразмышляем, где можно применить данные технологии? Как, преобразовав задачу и усовершенствовав код, все эти знания можно использовать в реальных проектах? Жду ваших комментариев!

RUVDS | Community в telegram и уютный чат

Комментарии (28)


  1. fk0
    26.10.2022 16:09
    +4

    1. Преобразование изображения в оттенки серого.

    2. Уменьшение размерности изображения (в пикселях) в 4 раза.

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

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

    И да, третий алгоритм наверняка реализуется без нейронных сетей.


    1. VolinNilov Автор
      26.10.2022 19:09

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


      1. masai
        26.10.2022 20:32
        +3

        поэтому в этой и предыдущих статьях я стараюсь осветить именно нейросетевой подход к решению

        Но в этой статье же нет нейронных сетей.


        1. VolinNilov Автор
          26.10.2022 20:38
          -1

          Алгоритм Canny Edge Detector можно отнести к группе алгоритмов машинного обучения и машинного зрения в частности


          1. masai
            26.10.2022 20:51
            +7

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

            Но речь не об этом. Я лишь хотел сказать, что нейронных сетей в этой конкретной статье нет.


      1. dimnsk
        27.10.2022 09:20

        а что такое нейросетевой подход?


        1. VolinNilov Автор
          27.10.2022 09:31

          Нейросетевой подход в моём понимании это подход к решению задачи с применением нейронных сетей


    1. masai
      26.10.2022 20:30

      Всё так. В этой статье нейронных сетей нет.


      1. VolinNilov Автор
        26.10.2022 20:36
        -2

        Здравствуйте, позвольте не согласиться с Вашим высказыванием, алгоритм Canny Edge Detector является одним из алгоритмов машинного обучения и машинного зрения в частности, так что я не совсем согласен с Вами. К тому же в названии статьи чётко указано, что здесь речь идёт об аспектах обработки изображения в OpenCV, а так же про сам алгоритм Canny Edge Detector. Данная статья входит в цикл статей про нейронные сети и даже если Вы не усмотрели здесь нейросетевого подтекст, то хочу Вас заверить, что в таком случае данный материал можно квалифицировать как теоретическую основу для изучения и базового погружения в мир нейронных сетей


        1. masai
          26.10.2022 20:57
          +3

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

          Единственное, что я хотел сказать, это то, что в этой конкретной статье нет ни нейронных сетей, ни машинного обучения. Детектор границ Кэнни — это не машинное обучение. В противном случае, что именно в нём обучается или что он обучает?


          1. VolinNilov Автор
            26.10.2022 21:10
            +1

            Да Вы правы, конкретно алгоритм под собой не имеет нейросетей, он применяется при решении некоторых задач для машинного зрения


  1. panteleymonov
    26.10.2022 16:18
    +5

    От простой разницы между компонентами цвета до вейвлет фильтра можно вычислять контуры с разной степенью качества, детализации и отсеивания шумов. Причем тут нейронные сети?

    Давайте теперь ДКТ называть нейронной сетью.


    1. VolinNilov Автор
      26.10.2022 19:11

      Здравствуйте, что конкретно Вы понимаете под ДКТ?

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


      1. masai
        26.10.2022 20:33

        Здравствуйте, что конкретно Вы понимаете под ДКТ?

        Очевидно, имеется в виду DCT, то есть дискретное косинус-преобразование.


        1. VolinNilov Автор
          26.10.2022 20:40

          Конечно же DCT нельзя назвать нейронной сетью, здесь я с Вами полностью согласен, но это математический модуль, который как и алгоритм Canny Edge Detector применяется в нейронных сетях


          1. masai
            26.10.2022 21:02

            алгоритм Canny Edge Detector применяется в нейронных сетях

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

            Кроме как на входе этот детектор особо поставить больше некуда (впрочем, модели бывают разные, может кто-то и приспособил для обработки feature maps, хотя я большого смысла в этом не вижу), так что я б отнёс его скорее к методам преобработки данных.


            1. VolinNilov Автор
              26.10.2022 21:18

              Согласен с Вами, но как Вы уже заметили, этот алгоритм можно использовать не только в качестве предобработки, хотя согласен, что он основное его применение как раз таки в этом. В статье я приложил ссылки на научные статьи по этой теме, дублирую их здесь (по ссылкам pdf документы для скачивания, один из них автоматом качается, так что не пугайтесь; прикладываю статьи для общего понимания основных направлений применения этого алгоритма):

              1. https://osf.io/yrmk5/download

              2. https://www.sciencedirect.com/science/article/pii/S2212017312004136?ref=pdf_download&fr=RR-2&rr=760529f4dc529d69

              Спасибо за дискуссию)


              1. masai
                27.10.2022 23:23

                Увы, эти статьи не про применение детектора. В первой описывается реализация на ПЛИС, а во второй модификация детектора.

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


                1. VolinNilov Автор
                  27.10.2022 23:51

                  Да, Вы правы, спасибо за замечание


          1. panteleymonov
            27.10.2022 21:10

            Конечно же DCT нельзя назвать нейронной сетью

            Условно можно, и я привел ее пример именно из-за параллелей. Поскольку нейронная сеть после обучения становится своеобразным фильтром подобным в том числе DCT. Но дискретное косинусное преобразование получено иным путем и не имеет излишек или нехватки узлов (и много чего еще "ненужного"), также как и методы описываемые в вашей статье. Нейронная сеть это все-таки что-то более обобщенное и гибкое.

            Я думаю ваша вводная часть должна раскрыть то, что данная статья посвящена вспомогательной математике.


            1. VolinNilov Автор
              27.10.2022 23:27

              Спасибо за замечание, учту в дальнейших работах)


  1. iShrimp
    26.10.2022 20:07
    +3

    Если уж зашла речь про преобразование цветовых пространств, то нужно обязательно упомянуть про гамма-коррекцию: поскольку дефолтное пространство sRGB нелинейно, перед любыми манипуляциями с цветом проводится процедура gamma expansion, а по окончании преобразований - gamma compression.


    1. VolinNilov Автор
      26.10.2022 20:17

      Здравствуйте, спасибо за дополнение! Всего в одной статье охватить не возможно, поэтому я очень ценю такие посты, где можно найти дополнения!

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


  1. catBasilio
    26.10.2022 20:23
    +4

    И где тут нейронные сети? Все что вы описали, OpenCV делает без них.


    1. VolinNilov Автор
      26.10.2022 20:41

      В данной статье речь идёт об некоторых аспектах обработки изображения, а также описание и применение алгоритма Canny Edge Detector, в данном случае это аспекты нейронных сетей и машинного зрения


  1. Kotofay
    26.10.2022 21:07

    Алгоритм довольно подробно рассматривали в https://habr.com/ru/post/114589/


    1. VolinNilov Автор
      26.10.2022 21:23

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


  1. p0cky
    28.10.2022 07:47

    В библиотеке OpenCV для этого существует функция resize. У этой функции, в свою очередь, есть три метода: INTER_CUBIC, INTER_LINEAR и INTER_AREA.

    Dushnila mode enabled
    Если мне не изменяет память, методы есть у класса, но никак не у функций.

    Dushnila mode disabled