В этой статье мы научимся реализовывать маркировку и анализ подключенных компонентов с помощью OpenCV в Python.
- Маркировка подключенных компонентов
- Установка зависимостей
- Шаг 1: Загрузка изображения и предварительная обработка
- Шаг 2: Пороговое значение
- Шаг 3: Применение метода анализа компонентов
- Шаг 4: Отфильтруйте полезные компоненты
- Шаг 5: Визуализируйте конечный результат
- Маркировка и анализ подключенных компонентов OpenCV
Маркировка подключенных компонентов
Маркировка компонентов в основном представляет собой извлечение области из исходного изображения, за исключением того, что мы пытаемся найти только компоненты, которые «связаны», что определяется применением теории графов.
OpenCV предоставляет нам следующие 4 функции для этой задачи:
- connectedComponents
- connectedComponentsWithStats
- connectedComponentsWithAlgorithm
- connectedComponentsWithStatsWithAlgorithm
Нижние два более эффективны и быстрее, но работают, только если у вас есть параллельная предварительная обработка с включенным OpenCV, в противном случае разумнее придерживаться первых двух. И первый, и второй методы одинаковы, за исключением того, что во втором методе, как следует из названия, мы получаем статистику для каждого из компонентов, и мы будем использовать второй метод, потому что в большинстве случаев вам понадобится эта статистика..
В этой программе мы собираемся использовать изображение баннера для извлечения текстовых компонентов.
Установка зависимостей
Начнем с установки необходимых пакетов:
$ pip install opencv-contrib-python
Шаг 1: Загрузка изображения и предварительная обработка
Давайте сначала загрузим наше изображение и преобразуем его в изображение в градациях серого, это сделает алгоритм намного более эффективным и точным. После этого мы также применим размытие по Гауссу 7 × 7, это поможет удалить нежелательные края и поможет сделать более четкую сегментацию, которую мы сделаем на следующем шаге.
Python3
# Applying threshold
threshold
=
cv2.threshold(blurred,
0
,
255
,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[
1
]
Шаг 2: Пороговое значение
Пороговое определение — это очень простой метод сегментации изображения, который помогает нам отделить интересующие нас объекты фона и переднего плана. После применения размытия воспользуемся функцией cv2.threshold для сегментации изображения.
Python3
# Applying threshold
threshold
=
cv2.threshold(blurred,
0
,
255
,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[
1
]
Шаг 3: Применение метода анализа компонентов
Сначала мы применяем cv2.connectedComponentsWithStats, а затем распаковываем значения, которые он возвращает, в разные переменные, которые мы будем использовать в следующих шагах, а также создадим новый массив для хранения всех найденных компонентов.
Python3
# Apply the Component analysis function
analysis
=
cv2.connectedComponentsWithStats(threshold,
4
,
cv2.CV_32S)
(totalLabels, label_ids, values, centroid)
=
analysis
# Initialize a new image to
# store all the output components
output
=
np.zeros(gray_img.shape, dtype
=
"uint8"
)
Теперь, когда у нас есть компоненты и анализ, давайте пройдемся по каждому компоненту и отфильтруем полезные компоненты.
Шаг 4: Отфильтруйте полезные компоненты
Давайте пройдемся по каждому из компонентов и воспользуемся статистикой, полученной на последнем шаге, чтобы отфильтровать полезные компоненты. Например, здесь я использовал значение «Площадь», чтобы отфильтровать только символы на изображении. И после фильтрации компонентов мы будем использовать переменную label_ids, чтобы создать маску для компонента, который мы просматриваем, и использовать операцию bitwise_or на маске для создания нашего окончательного вывода. Звучит сложно, но вы поймете это лучше после самостоятельной реализации кода.
Python3
# Loop through each component
for
i
in
range
(
1
, totalLabels):
area
=
values[i, cv2.CC_STAT_AREA]
if
(area >
140
)
and
(area <
400
):
# Labels stores all the IDs of the components on the each pixel
# It has the same dimension as the threshold
# So we'll check the component
# then convert it to 255 value to mark it white
componentMask
=
(label_ids
=
=
i).astype(
"uint8"
)
*
255
# Creating the Final output mask
output
=
cv2.bitwise_or(output, componentMask)
Как выбрать значение площади (или любое другое условие, например ширину или высоту) для фильтрации?
Добавьте оператор печати, чтобы распечатать значение статистики, которую вы хотите использовать в качестве условия, а затем для полезных компонентов запишите диапазон значений и используйте их для создания условия фильтра.
Шаг 5: Визуализируйте конечный результат
Теперь наш последний шаг — просто отобразить наше исходное изображение и окончательную маску, которую мы получили.
Python3
cv2.imshow(
"Image"
, img)
cv2.imshow(
"Filtered Components"
, output)
cv2.waitKey(
0
)
Ниже приведена реализация:
Python3
import
cv2
import
numpy as np
# Loading the image
img
=
cv2.imread(
'Images/img5.png'
)
# preprocess the image
gray_img
=
cv2.cvtColor(img , cv2.COLOR_BGR2GRAY)
# Applying 7x7 Gaussian Blur
blurred
=
cv2.GaussianBlur(gray_img, (
7
,
7
),
0
)
# Applying threshold
threshold
=
cv2.threshold(blurred,
0
,
255
,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[
1
]
# Apply the Component analysis function
analysis
=
cv2.connectedComponentsWithStats(threshold,
4
,
cv2.CV_32S)
(totalLabels, label_ids, values, centroid)
=
analysis
# Initialize a new image to store
# all the output components
output
=
np.zeros(gray_img.shape, dtype
=
"uint8"
)
# Loop through each component
for
i
in
range
(
1
, totalLabels):
# Area of the component
area
=
values[i, cv2.CC_STAT_AREA]
if
(area >
140
)
and
(area <
400
):
componentMask
=
(label_ids
=
=
i).astype(
"uint8"
)
*
255
output
=
cv2.bitwise_or(output, componentMask)
cv2.imshow(
"Image"
, img)
cv2.imshow(
"Filtered Components"
, output)
cv2.waitKey(
0
)
Выход:
это выходная маска и исходное изображение
Примечание. Запустите программу на нескольких больших и маленьких изображениях, чтобы увидеть, что на выходе много «шума». Поэтому мы применили «фильтр» в последнем прогоне, и окончательный результат, который мы получили, содержал только нужные нам текстовые символы.
Маркировка и анализ подключенных компонентов OpenCV
Вот еще одна реализация, в которой я продемонстрировал весь процесс для каждого компонента, чтобы вам было легче его визуализировать:
Python3
import
cv2
import
numpy as np
# Loading the image
img
=
cv2.imread(
'Images/img5.png'
)
# preprocess the image
gray_img
=
cv2.cvtColor(img ,
cv2.COLOR_BGR2GRAY)
# Applying 7x7 Gaussian Blur
blurred
=
cv2.GaussianBlur(gray_img, (
7
,
7
),
0
)
# Applying threshold
threshold
=
cv2.threshold(blurred,
0
,
255
,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[
1
]
# Apply the Component analysis function
analysis
=
cv2.connectedComponentsWithStats(threshold,
4
,
cv2.CV_32S)
(totalLabels, label_ids, values, centroid)
=
analysis
# Initialize a new image to
# store all the output components
output
=
np.zeros(gray_img.shape, dtype
=
"uint8"
)
# Loop through each component
for
i
in
range
(
1
, totalLabels):
# Area of the component
area
=
values[i, cv2.CC_STAT_AREA]
if
(area >
140
)
and
(area <
400
):
# Create a new image for bounding boxes
new_img
=
img.copy()
# Now extract the coordinate points
x1
=
values[i, cv2.CC_STAT_LEFT]
y1
=
values[i, cv2.CC_STAT_TOP]
w
=
values[i, cv2.CC_STAT_WIDTH]
h
=
values[i, cv2.CC_STAT_HEIGHT]
# Coordinate of the bounding box
pt1
=
(x1, y1)
pt2
=
(x1
+
w, y1
+
h)
(X, Y)
=
centroid[i]
# Bounding boxes for each component
cv2.rectangle(new_img,pt1,pt2,
(
0
,
255
,
0
),
3
)
cv2.circle(new_img, (
int
(X),
int
(Y)),
4
, (
0
,
0
,
255
),
-
1
)
# Create a new array to show individual component
component
=
np.zeros(gray_img.shape, dtype
=
"uint8"
)
componentMask
=
(label_ids
=
=
i).astype(
"uint8"
)
*
255
# Apply the mask using the bitwise operator
component
=
cv2.bitwise_or(component,componentMask)
output
=
cv2.bitwise_or(output, componentMask)
# Show the final images
cv2.imshow(
"Image"
, new_img)
cv2.imshow(
"Individual Component"
, component)
cv2.imshow(
"Filtered Components"
, output)
cv2.waitKey(
0
)
Выход: