HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>В этой статье мы рассмотрим, как в кратчайшие сроки написать Python-скрипт, который пригодится для подсчёта числа книг на изображении. Для работы будем использовать библиотеку алгоритмов компьютерного зрения OpenCV.</p>
1 <p>В этой статье мы рассмотрим, как в кратчайшие сроки написать Python-скрипт, который пригодится для подсчёта числа книг на изображении. Для работы будем использовать библиотеку алгоритмов компьютерного зрения OpenCV.</p>
2 <h2>Какова задача?</h2>
2 <h2>Какова задача?</h2>
3 <p>Посмотрите на фото ниже:</p>
3 <p>Посмотрите на фото ниже:</p>
4 <p>На изображении мы видим 4 книги и различные отвлекающие предметы: конфету, магниты, кофе, чашку. Наша задача - найти эти 4 книги с помощью машинного зрения и не определить как книгу ни один другой предмет.</p>
4 <p>На изображении мы видим 4 книги и различные отвлекающие предметы: конфету, магниты, кофе, чашку. Наша задача - найти эти 4 книги с помощью машинного зрения и не определить как книгу ни один другой предмет.</p>
5 <p>Чтобы выполнить эту задачу, мы, кроме вышеупомянутой библиотеки OpenCV, будем использовать также и NumPy, поэтому эти библиотеки понадобится установить.</p>
5 <p>Чтобы выполнить эту задачу, мы, кроме вышеупомянутой библиотеки OpenCV, будем использовать также и NumPy, поэтому эти библиотеки понадобится установить.</p>
6 <h2>Приступаем к поиску</h2>
6 <h2>Приступаем к поиску</h2>
7 <p>Открываем редактор кода, создаём новый файл с именем find_books.py и начинаем:</p>
7 <p>Открываем редактор кода, создаём новый файл с именем find_books.py и начинаем:</p>
8 # -*- coding: utf-8 -*- # импортируем нужные пакеты import numpy as np import cv2 # загружаем изображение, меняем цвет на оттенки серого и уменьшаем резкость image = cv2.imread("example.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (3, 3), 0) cv2.imwrite("gray.jpg", gray)<p>Прежде всего, надо выполнить импорт библиотеки OpenCV. Обратите внимание, что загрузка изображения с диска обрабатывается с помощью функции cv2.imread. Тут мы просто загружаем его с диска, после чего преобразуем цветовую гамму в оттенки серого.</p>
8 # -*- coding: utf-8 -*- # импортируем нужные пакеты import numpy as np import cv2 # загружаем изображение, меняем цвет на оттенки серого и уменьшаем резкость image = cv2.imread("example.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (3, 3), 0) cv2.imwrite("gray.jpg", gray)<p>Прежде всего, надо выполнить импорт библиотеки OpenCV. Обратите внимание, что загрузка изображения с диска обрабатывается с помощью функции cv2.imread. Тут мы просто загружаем его с диска, после чего преобразуем цветовую гамму в оттенки серого.</p>
9 <p>Кроме этого, мы немного размываем изображение, дабы уменьшить ВЧ-шумы и увеличить точность приложения. После исполнения кода изображение будет выглядеть следующим образом:</p>
9 <p>Кроме этого, мы немного размываем изображение, дабы уменьшить ВЧ-шумы и увеличить точность приложения. После исполнения кода изображение будет выглядеть следующим образом:</p>
10 <p>То есть мы выполнили загрузку изображения с диска, преобразовали фото в оттенки серого, а потом немного размыли изображение.</p>
10 <p>То есть мы выполнили загрузку изображения с диска, преобразовали фото в оттенки серого, а потом немного размыли изображение.</p>
11 <p>Что же, давайте определим контуры объектов на изображении:</p>
11 <p>Что же, давайте определим контуры объектов на изображении:</p>
12 # распознаём контуры edged = cv2.Canny(gray, 10, 250) cv2.imwrite("edged.jpg", edged)<p>Теперь изображение выглядит так:</p>
12 # распознаём контуры edged = cv2.Canny(gray, 10, 250) cv2.imwrite("edged.jpg", edged)<p>Теперь изображение выглядит так:</p>
13 <p>Итак, мы определили на изображении контуры объектов. Но, как видно, часть контуров не закрыта, а между контурами есть промежутки. Дабы убрать промежутки, существующие между белыми пикселями, задействуем операцию "закрытия":</p>
13 <p>Итак, мы определили на изображении контуры объектов. Но, как видно, часть контуров не закрыта, а между контурами есть промежутки. Дабы убрать промежутки, существующие между белыми пикселями, задействуем операцию "закрытия":</p>
14 # создаём и применяем закрытие kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7)) closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel) cv2.imwrite("closed.jpg", closed)<p>Вуаля, теперь пробелы в контурах закрыты:</p>
14 # создаём и применяем закрытие kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7)) closed = cv2.morphologyEx(edged, cv2.MORPH_CLOSE, kernel) cv2.imwrite("closed.jpg", closed)<p>Вуаля, теперь пробелы в контурах закрыты:</p>
15 <p>Следующий этап - фактическое обнаружение контуров объектов. Теперь задействуем функцию cv2.findContours:</p>
15 <p>Следующий этап - фактическое обнаружение контуров объектов. Теперь задействуем функцию cv2.findContours:</p>
16 # находим контуры в изображении и подсчитываем число книг cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1] total = 0<p>Теперь несколько слов о геометрии книги. Как известно - это прямоугольник, который, соответственно, имеет 4 вершины. Следовательно, если при рассмотрении контура мы обнаружим наличие 4-х вершин, мы сможем предположить, что перед нами именно книга. Чтобы это проверить, надо выполнить цикл по каждому контуру:</p>
16 # находим контуры в изображении и подсчитываем число книг cnts = cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1] total = 0<p>Теперь несколько слов о геометрии книги. Как известно - это прямоугольник, который, соответственно, имеет 4 вершины. Следовательно, если при рассмотрении контура мы обнаружим наличие 4-х вершин, мы сможем предположить, что перед нами именно книга. Чтобы это проверить, надо выполнить цикл по каждому контуру:</p>
17 # выполняем цикл по контурам for c in cnts: # сглаживаем контур peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # если у контура есть четыре вершины, это, скорее всего, книга if len(approx) == 4: cv2.drawContours(image, [approx], -1, (0, 255, 0), 4) total += 1<p>При этом для каждого из контуров производится вычисление периметра (с помощью cv2.arcLength), а потом происходит аппроксимация (сглаживание) контура с помощью cv2.approxPolyDP.</p>
17 # выполняем цикл по контурам for c in cnts: # сглаживаем контур peri = cv2.arcLength(c, True) approx = cv2.approxPolyDP(c, 0.02 * peri, True) # если у контура есть четыре вершины, это, скорее всего, книга if len(approx) == 4: cv2.drawContours(image, [approx], -1, (0, 255, 0), 4) total += 1<p>При этом для каждого из контуров производится вычисление периметра (с помощью cv2.arcLength), а потом происходит аппроксимация (сглаживание) контура с помощью cv2.approxPolyDP.</p>
18 <p>Зачем выполняем аппроксимацию? Дело в том, что контур может и не быть идеальным прямоугольником, так как зашумление и тени на изображении всё же оказывают влияние. Когда мы аппроксимируем контур, мы эту проблему решаем.</p>
18 <p>Зачем выполняем аппроксимацию? Дело в том, что контур может и не быть идеальным прямоугольником, так как зашумление и тени на изображении всё же оказывают влияние. Когда мы аппроксимируем контур, мы эту проблему решаем.</p>
19 <p>В конце концов, мы осуществляем проверку, что у аппроксимируемого контура действительно есть 4 вершины. Если это так, мы рисуем вокруг книги контур с одновременным увеличением счётчика общего числа книг.</p>
19 <p>В конце концов, мы осуществляем проверку, что у аппроксимируемого контура действительно есть 4 вершины. Если это так, мы рисуем вокруг книги контур с одновременным увеличением счётчика общего числа книг.</p>
20 <p>Давайте завершим этот пример и покажем полученное изображение и число книг, которые удалось найти:</p>
20 <p>Давайте завершим этот пример и покажем полученное изображение и число книг, которые удалось найти:</p>
21 # покажем результирующее изображение print("Я нашёл {0} книг на этой картинке".format(total) cv2.imwrite("output.jpg", image))<p>На этом этапе наше фото будет выглядеть так:</p>
21 # покажем результирующее изображение print("Я нашёл {0} книг на этой картинке".format(total) cv2.imwrite("output.jpg", image))<p>На этом этапе наше фото будет выглядеть так:</p>
22 <p>Что касается терминала, то он нам покажет, что мы успешно нашли 4 книги и проигнорировали посторонние предметы:</p>
22 <p>Что касается терминала, то он нам покажет, что мы успешно нашли 4 книги и проигнорировали посторонние предметы:</p>
23 <h2>Делаем выводы</h2>
23 <h2>Делаем выводы</h2>
24 <p>Итак, мы показали, как можно найти книги на фотографиях с помощью простых методов обработки изображений, а также компьютерного зрения, Python и OpenCV.</p>
24 <p>Итак, мы показали, как можно найти книги на фотографиях с помощью простых методов обработки изображений, а также компьютерного зрения, Python и OpenCV.</p>
25 <p>Кратко перескажем суть подхода: 1. Загружаем изображение с диска, преобразуем его в оттенки серого. 2. Немного размываем изображение. 3. Применяем детектор контуров Canny с целью обнаружения объектов на изображении. 4. Закрываем промежутки в контурах. 5. Находим контуры объектов на изображении. 6. Применяем контурную аппроксимацию для определения, был ли контур прямоугольником и, соответственно, книгой.</p>
25 <p>Кратко перескажем суть подхода: 1. Загружаем изображение с диска, преобразуем его в оттенки серого. 2. Немного размываем изображение. 3. Применяем детектор контуров Canny с целью обнаружения объектов на изображении. 4. Закрываем промежутки в контурах. 5. Находим контуры объектов на изображении. 6. Применяем контурную аппроксимацию для определения, был ли контур прямоугольником и, соответственно, книгой.</p>
26 <p><em>По материалам статьи "<a>A guide to finding books in images using Python and OpenCV</a>".</em></p>
26 <p><em>По материалам статьи "<a>A guide to finding books in images using Python and OpenCV</a>".</em></p>
27  
27