
Теоретическая основа:
HSV (Hue, Saturation, Value) — цветовое пространство, более интуитивное для восприятия человеком:
Определяет основной цвет (0-179 в OpenCV, вместо 0-360 в реальности)
Степень чистоты цвета (0-255): 0 = серый, 255 = полностью насыщенный
Яркость цвета (0-255): 0 = черный, 255 = максимально яркий
Преимущества HSV перед BGR:
Используемые методы:
| Метод | Описание |
|---|---|
cv2.namedWindow(window_name) |
Создание именованного окна |
cv2.resizeWindow(window_name, width, height) |
Изменение размера окна |
cv2.createTrackbar(name, window, value, count, onChange) |
Создание трекбара |
cv2.getTrackbarPos(name, window) |
Получение значения трекбара |
Практический пример:
import cv2
import numpy as np
# Создание окна для трекбаров
cv2.namedWindow("TrackBars")
cv2.resizeWindow("TrackBars", 640, 240)
# Пустая функция для обратного вызова
def empty(a):
pass
# Создание трекбаров для настройки HSV диапазона
cv2.createTrackbar("Hue Min", "TrackBars", 0, 179, empty)
cv2.createTrackbar("Hue Max", "TrackBars", 19, 179, empty)
cv2.createTrackbar("Sat Min", "TrackBars", 110, 255, empty)
cv2.createTrackbar("Sat Max", "TrackBars", 240, 255, empty)
cv2.createTrackbar("Val Min", "TrackBars", 153, 255, empty)
cv2.createTrackbar("Val Max", "TrackBars", 255, 255, empty)
# Инициализация веб-камеры
cap = cv2.VideoCapture(0)
while True:
# Захват кадра с веб-камеры
success, img = cap.read()
if not success:
break
# Конвертация в HSV
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Получение значений трекбаров
h_min = cv2.getTrackbarPos("Hue Min", "TrackBars")
h_max = cv2.getTrackbarPos("Hue Max", "TrackBars")
s_min = cv2.getTrackbarPos("Sat Min", "TrackBars")
s_max = cv2.getTrackbarPos("Sat Max", "TrackBars")
v_min = cv2.getTrackbarPos("Val Min", "TrackBars")
v_max = cv2.getTrackbarPos("Val Max", "TrackBars")
# Вывод текущих параметров
print(f"Hue: {h_min}-{h_max}, Sat: {s_min}-{s_max}, Val: {v_min}-{v_max}")
# Отображение изображения
cv2.imshow("Original", img)
cv2.imshow("HSV", imgHSV)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Используемые методы:
| Метод | Описание |
|---|---|
cv2.inRange(src, lowerb, upperb) |
Создание маски в заданном диапазоне |
cv2.bitwise_and(src1, src2, mask) |
Побитовое И для наложения маски |
Практический пример:
import cv2
import numpy as np
# Чтение изображения
img = cv2.imread('resources/lambo.png')
# Конвертация в HSV
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Определение диапазона для оранжевого цвета
lower_orange = np.array([5, 50, 50]) # [H_min, S_min, V_min]
upper_orange = np.array([15, 255, 255]) # [H_max, S_max, V_max]
# Создание маски
mask = cv2.inRange(imgHSV, lower_orange, upper_orange)
# Применение маски к исходному изображению
result = cv2.bitwise_and(img, img, mask=mask)
# Отображение результатов
cv2.imshow("Original", img)
cv2.imshow("Mask", mask)
cv2.imshow("Result", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Типичные диапазоны HSV для разных цветов:
| Цвет | Hue Min-Max | Sat Min-Max | Val Min-Max |
|---|---|---|---|
| Красный | 0-10 и 160-179 | 100-255 | 100-255 |
| Оранжевый | 10-25 | 100-255 | 100-255 |
| Желтый | 25-35 | 100-255 | 100-255 |
| Зеленый | 40-80 | 100-255 | 100-255 |
| Синий | 90-130 | 100-255 | 100-255 |
| Фиолетовый | 130-160 | 100-255 | 100-255 |
Практический пример:
import cv2
import numpy as np
# Список цветов для детектирования: [h_min, s_min, v_min, h_max, s_max, v_max, color_name]
myColors = [
[5, 107, 0, 19, 255, 255, "Orange"],
[133, 56, 0, 159, 156, 255, "Purple"],
[57, 76, 0, 100, 255, 255, "Green"],
[105, 50, 50, 130, 255, 255, "Blue"]
]
# Список цветов для отображения (BGR)
myColorValues = [
[51, 153, 255], # Оранжевый
[255, 0, 255], # Фиолетовый
[0, 255, 0], # Зеленый
[255, 0, 0] # Синий
]
def findColor(img, myColors, myColorValues):
"""
Поиск цветов на изображении и определение их позиций
Args:
img: Исходное изображение
myColors: Список цветовых диапазонов
myColorValues: Список цветов для отображения
Returns:
list: Список найденных точек [[x, y, colorId], ...]
"""
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
count = 0
newPoints = []
for color in myColors:
lower = np.array(color[0:3])
upper = np.array(color[3:6])
mask = cv2.inRange(imgHSV, lower, upper)
# Поиск контуров для определения позиции цвета
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 500: # Фильтрация по площади для удаления шума
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img, (x, y), (x + w, y + h), myColorValues[count], 2)
newPoints.append([x + w // 2, y, count]) # Центр верхней границы + индекс цвета
count += 1
return newPoints
# Использование функции
cap = cv2.VideoCapture(0)
myPoints = [] # [[x, y, colorId], ...]
while True:
success, img = cap.read()
if not success:
break
newPoints = findColor(img, myColors, myColorValues)
# Сохранение точек для рисования
if newPoints:
for point in newPoints:
myPoints.append(point)
# Рисование всех точек
for point in myPoints:
cv2.circle(img, (point[0], point[1]), 10, myColorValues[point[2]], cv2.FILLED)
cv2.imshow("Result", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
myColors и myColorValuesarea > 500 удаляет мелкий шум и ложные срабатыванияx + w // 2, y используется как точка рисованияТеоретическая основа:
Методы поиска контуров:
| Метод | Описание |
|---|---|
cv2.RETR_EXTERNAL |
Только внешние контуры |
cv2.RETR_LIST |
Все контуры без иерархии |
cv2.RETR_TREE |
Все контуры с полной иерархией |
cv2.RETR_CCOMP |
Все контуры с двумя уровнями иерархии |
Методы аппроксимации контуров:
| Метод | Описание |
|---|---|
cv2.CHAIN_APPROX_NONE |
Все точки контура |
cv2.CHAIN_APPROX_SIMPLE |
Сжатие вертикальных, горизонтальных и диагональных сегментов |
Используемые методы:
| Метод | Описание |
|---|---|
cv2.findContours(image, mode, method) |
Поиск контуров на бинарном изображении |
cv2.contourArea(contour) |
Вычисление площади контура |
cv2.arcLength(contour, closed) |
Вычисление длины контура (периметра) |
cv2.approxPolyDP(contour, epsilon, closed) |
Аппроксимация контура многоугольником |
cv2.boundingRect(contour) |
Получение ограничивающего прямоугольника |
cv2.drawContours(image, contours, idx, color, thickness) |
Отрисовка контуров |
Практический пример:
import cv2
import numpy as np
def getContours(img, imgContour):
"""
Поиск и анализ контуров для классификации геометрических фигур
Args:
img: Бинарное изображение (результат Canny)
imgContour: Изображение для визуализации результатов
"""
# Поиск контуров
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
# Вычисление площади контура
area = cv2.contourArea(cnt)
print(f"Area: {area}")
if area > 500: # Фильтрация по площади
# Отрисовка контура
cv2.drawContours(imgContour, cnt, -1, (255, 0, 0), 3)
# Вычисление длины контура (периметра)
peri = cv2.arcLength(cnt, True)
print(f"Perimeter: {peri}")
# Аппроксимация контура
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
print(f"Corner points: {len(approx)}")
# Получение ограничивающего прямоугольника
x, y, w, h = cv2.boundingRect(approx)
cv2.rectangle(imgContour, (x, y), (x + w, y + h), (0, 255, 0), 2)
# Определение типа фигуры
objType = "Unknown"
if len(approx) == 3:
objType = "Triangle"
elif len(approx) == 4:
# Проверка на квадрат: отношение сторон близко к 1
aspRatio = w / float(h)
if 0.95 < aspRatio < 1.05:
objType = "Square"
else:
objType = "Rectangle"
elif len(approx) > 4:
objType = "Circle"
# Отображение типа фигуры
cv2.putText(imgContour, objType,
(x + (w // 2) - 30, y + (h // 2)),
cv2.FONT_HERSHEY_COMPLEX, 0.7, (0, 0, 0), 2)
# Основной код
img = cv2.imread('resources/shapes.png')
imgContour = img.copy()
# Предварительная обработка
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imgBlur = cv2.GaussianBlur(imgGray, (7, 7), 1)
imgCanny = cv2.Canny(imgBlur, 50, 50)
# Поиск контуров
getContours(imgCanny, imgContour)
# Отображение результатов
cv2.imshow("Original", img)
cv2.imshow("Canny", imgCanny)
cv2.imshow("Contours", imgContour)
cv2.waitKey(0)
cv2.destroyAllWindows()
Canny или threshold)area > 500 удаляет мелкие контуры-шумepsilon = 0.02 * peri — стандартное значение для аппроксимации (2% от периметра)aspRatiocv2.drawContours с contourIdx = -1 рисует все контуры в списке1. Центр массы контура:
M = cv2.moments(cnt)
if M["m00"] != 0: # Проверка деления на ноль
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
2. Выпуклая оболочка:
hull = cv2.convexHull(cnt)
cv2.drawContours(img, [hull], -1, (0, 255, 0), 2)
3. Дефекты выпуклости (для распознавания пальцев):
hull = cv2.convexHull(cnt, returnPoints=False)
defects = cv2.convexityDefects(cnt, hull)
4. Минимальная площадь и минимальный круг:
# Минимальный ограничивающий прямоугольник (с поворотом)
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
# Минимальный ограничивающий круг
(x, y), radius = cv2.minEnclosingCircle(cnt)
5. Эллипс минимальной площади:
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img, ellipse, (0, 255, 0), 2)
cv2.moments предоставляют информацию о форме и распределении массыТеоретическая основа:
Исторический контекст: Алгоритм Виолы-Джонса (2001) был первым, обеспечивающим детектирование лиц в реальном времени.
Основные компоненты:
Быстрое вычисление суммы пикселей в прямоугольнике
Последовательность простых классификаторов для быстрого отсеивания
Простые прямоугольные признаки для описания локальных особенностей
Выбор лучших признаков и создание сильного классификатора
Преимущества и ограничения:
| Преимущества | Ограничения |
|---|---|
| Высокая скорость работы | Плохо работает с повернутыми лицами |
| Хорошая точность для фронтальных лиц | Требует предварительно обученных каскадов |
| Низкие требования к вычислительным ресурсам | Может давать ложные срабатывания |
Используемые методы:
| Метод | Описание |
|---|---|
cv2.CascadeClassifier(filename) |
Загрузка предобученного каскада |
detectMultiScale(image, scaleFactor, minNeighbors, minSize, maxSize) |
Детектирование объектов |
Параметры detectMultiScale:
image — изображение в градациях серогоscaleFactor — параметр масштабирования (1.05-1.3)minNeighbors — минимальное количество соседей для подтверждения обнаружения (3-6)minSize, maxSize — минимальный и максимальный размер объектаПрактический пример:
import cv2
# Загрузка предобученного каскада для детектирования лиц
faceCascade = cv2.CascadeClassifier("resources/haarcascade_frontalface_default.xml")
# Загрузка изображения
img = cv2.imread('resources/lena.png')
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Детектирование лиц
faces = faceCascade.detectMultiScale(
imgGray,
scaleFactor=1.1, # Уменьшение масштаба на 10% на каждом шаге
minNeighbors=4, # Минимум 4 совпадения для подтверждения
minSize=(30, 30) # Минимальный размер лица
)
# Отрисовка прямоугольников вокруг обнаруженных лиц
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, "Face", (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (255, 0, 0), 2)
# Детектирование глаз на том же изображении
eyeCascade = cv2.CascadeClassifier("resources/haarcascade_eye.xml")
for (x, y, w, h) in faces:
roiGray = imgGray[y:y + h, x:x + w]
roiColor = img[y:y + h, x:x + w]
eyes = eyeCascade.detectMultiScale(roiGray, scaleFactor=1.1, minNeighbors=5)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roiColor, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
# Отображение результата
cv2.imshow("Face Detection", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Доступные предобученные каскады:
| Файл | Назначение |
|---|---|
haarcascade_frontalface_default.xml |
Фронтальные лица |
haarcascade_eye.xml |
Глаза |
haarcascade_smile.xml |
Улыбки |
haarcascade_fullbody.xml |
Полный рост человека |
scaleFactor=1.1 означает уменьшение масштаба на 10% на каждом шаге (меньше = точнее, но медленнее)minNeighbors=4 требует минимум 4 совпадающих прямоугольникаROI (Region of Interest) — область лицаПрактический пример:
import cv2
# Загрузка каскадов
faceCascade = cv2.CascadeClassifier("resources/haarcascade_frontalface_default.xml")
eyeCascade = cv2.CascadeClassifier("resources/haarcascade_eye.xml")
# Инициализация веб-камеры
cap = cv2.VideoCapture(0)
cap.set(3, 640) # Ширина
cap.set(4, 480) # Высота
cap.set(10, 150) # Яркость
while True:
success, img = cap.read()
if not success:
break
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Детектирование лиц
faces = faceCascade.detectMultiScale(imgGray, 1.1, 4)
# Обработка каждого обнаруженного лица
for (x, y, w, h) in faces:
# Отрисовка прямоугольника вокруг лица
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.putText(img, f"Face {w}x{h}", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
# ROI для детектирования глаз
roiGray = imgGray[y:y + h, x:x + w]
roiColor = img[y:y + h, x:x + w]
# Детектирование глаз
eyes = eyeCascade.detectMultiScale(roiGray, 1.1, 5)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roiColor, (ex, ey), (ex + ew, ey + eh), (0, 255, 0), 2)
# Отображение количества обнаруженных лиц
cv2.putText(img, f"Faces detected: {len(faces)}", (20, 450),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.imshow("Face Detection", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
scaleFactor=1.1 и minNeighbors=4 — хороший баланс для веб-камерыw x h помогает в настройке параметровТребования к системе:
Архитектура проекта:
Захват видео с веб-камеры
Детектирование цветов и позиций маркеров
Управление точками и отрисовка на холсте
Отображение результатов и управление
Ключевые компоненты:
import cv2
import numpy as np
# Конфигурация цветов: [Hmin, Smin, Vmin, Hmax, Smax, Vmax, Name]
myColors = [
[5, 107, 0, 19, 255, 255, "Orange"],
[133, 56, 0, 159, 156, 255, "Purple"],
[57, 76, 0, 100, 255, 255, "Green"],
[105, 50, 50, 130, 255, 255, "Blue"]
]
# Цвета для рисования (BGR)
myColorValues = [
[51, 153, 255], # Оранжевый
[255, 0, 255], # Фиолетовый
[0, 255, 0], # Зеленый
[255, 0, 0] # Синий
]
# Холст для рисования
myPoints = [] # [[x, y, colorId], ...]
def findColor(img, myColors, myColorValues):
"""
Поиск цветов и определение позиций маркеров
"""
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
newPoints = []
for i, color in enumerate(myColors):
lower = np.array(color[0:3])
upper = np.array(color[3:6])
mask = cv2.inRange(imgHSV, lower, upper)
# Улучшение маски с помощью морфологических операций
kernel = np.ones((5, 5), np.uint8)
mask = cv2.erode(mask, kernel, iterations=1)
mask = cv2.dilate(mask, kernel, iterations=2)
# Поиск контуров
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Нахождение самого большого контура
max_area = 0
max_cnt = None
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 1000 and area > max_area:
max_area = area
max_cnt = cnt
if max_cnt is not None:
x, y, w, h = cv2.boundingRect(max_cnt)
cx, cy = x + w // 2, y # Центр верхней границы
# Визуальная обратная связь
cv2.circle(img, (cx, cy), 15, myColorValues[i], cv2.FILLED)
newPoints.append([cx, cy, i])
return newPoints
def drawOnCanvas(myPoints, myColorValues, img):
"""
Отрисовка точек на изображении
"""
for point in myPoints:
cv2.circle(img, (point[0], point[1]), 10, myColorValues[point[2]], cv2.FILLED)
# Основной цикл
cap = cv2.VideoCapture(0)
cap.set(3, 1280) # Увеличенное разрешение
cap.set(4, 720)
cap.set(10, 150)
while True:
success, img = cap.read()
if not success:
break
img = cv2.flip(img, 1) # Зеркальное отображение
imgResult = img.copy()
# Поиск цветов
newPoints = findColor(imgResult, myColors, myColorValues)
# Добавление новых точек
if newPoints:
for point in newPoints:
myPoints.append(point)
# Отрисовка всех точек
if myPoints:
drawOnCanvas(myPoints, myColorValues, imgResult)
# Отображение интерфейса
cv2.putText(imgResult, "Virtual Paint", (10, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)
cv2.putText(imgResult, "Press 'c' to clear, 'q' to quit", (10, 100),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (200, 200, 200), 2)
cv2.imshow("Virtual Paint", imgResult)
# Управление
key = cv2.waitKey(1)
if key == ord('c'):
myPoints = []
elif key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
cv2.flip(img, 1) делает интерфейс интуитивнымarea > 1000 отсекает мелкие объектыОптимизации:
Улучшенная версия с плавным рисованием:
# Глобальные переменные для новых функций
brushThickness = 15
xp, yp = 0, 0 # Предыдущие координаты
imgCanvas = np.zeros((720, 1280, 3), np.uint8) # Чистый холст
# Внутри основного цикла:
if newPoints:
for point in newPoints:
x, y = point[0:2]
if xp == 0 and yp == 0: # Первый кадр
xp, yp = x, y
# Плавное рисование с использованием линии между точками
cv2.line(imgCanvas, (xp, yp), (x, y), myColorValues[point[2]], brushThickness)
xp, yp = x, y # Обновление предыдущих координат
else:
xp, yp = 0, 0 # Сброс при отсутствии маркера
# Наложение холста на изображение камеры
imgGray = cv2.cvtColor(imgCanvas, cv2.COLOR_BGR2GRAY)
_, imgInv = cv2.threshold(imgGray, 50, 255, cv2.THRESH_BINARY_INV)
imgInv = cv2.cvtColor(imgInv, cv2.COLOR_GRAY2BGR)
imgResult = cv2.bitwise_and(img, imgInv)
imgResult = cv2.bitwise_or(imgResult, imgCanvas)
Требования к системе:
Теоретическая основа:
Математическое преобразование, корректирующее искажение перспективы
Проективное преобразование между двумя плоскостями
Поиск характерных точек документа
Улучшение контрастности для лучшего детектирования
Последовательность операций:
| Операция | Назначение |
|---|---|
| Конвертация в градации серого | Уменьшение размерности данных |
| Размытие по Гауссу | Уменьшение шума и сглаживание |
| Детектирование границ (Canny) | Выделение контуров документа |
| Дилатация | Утолщение границ для соединения разорванных линий |
| Эрозия | Утончение границ для удаления мелких деталей |
Практический пример:
import cv2
import numpy as np
# Параметры изображения
widthImg = 640
heightImg = 480
def preProcessing(img):
"""
Предварительная обработка изображения для детектирования документа
Args:
img (numpy.ndarray): Исходное изображение
Returns:
numpy.ndarray: Обработанное бинарное изображение
"""
# Изменение размера для стандартизации обработки
img = cv2.resize(img, (widthImg, heightImg))
# Конвертация в градации серого
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Гауссово размытие
imgBlur = cv2.GaussianBlur(imgGray, (5, 5), 1)
# Детектирование границ Canny
imgCanny = cv2.Canny(imgBlur, 200, 200)
# Морфологические операции для улучшения контуров
kernel = np.ones((5, 5), np.uint8)
imgDilate = cv2.dilate(imgCanny, kernel, iterations=2)
imgEroded = cv2.erode(imgDilate, kernel, iterations=1)
return imgEroded
Практический пример:
def getContours(img, imgOriginal):
"""
Поиск контура документа и определение угловых точек
Args:
img: Бинарное изображение после предобработки
imgOriginal: Исходное изображение для визуализации
Returns:
numpy.ndarray: Угловые точки документа
numpy.ndarray: Изображение с контурами
"""
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
biggest = np.array([])
maxArea = 0
imgWithContours = imgOriginal.copy()
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 5000: # Минимальная площадь
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
# Проверка на четырехугольник
if area > maxArea and len(approx) == 4:
biggest = approx
maxArea = area
cv2.drawContours(imgWithContours, cnt, -1, (0, 255, 0), 2)
# Сортировка угловых точек
if biggest.size != 0:
biggest = biggest.reshape((4, 2))
add = biggest.sum(1)
diff = np.diff(biggest, axis=1)
pts = np.zeros((4, 1, 2), dtype=np.int32)
pts[0] = biggest[np.argmin(add)] # Верхний левый
pts[3] = biggest[np.argmax(add)] # Нижний правый
pts[1] = biggest[np.argmin(diff)] # Верхний правый
pts[2] = biggest[np.argmax(diff)] # Нижний левый
cv2.drawContours(imgWithContours, pts, -1, (0, 0, 255), 20)
return pts, imgWithContours
return biggest, imgWithContours
area > 5000 отсекает мелкие объекты2% от периметра определяет углыlen(approx) == 4 гарантирует детектирование документаИспользуемые методы:
| Метод | Описание |
|---|---|
cv2.getPerspectiveTransform() |
Вычисление матрицы перспективного преобразования |
cv2.warpPerspective() |
Применение перспективного преобразования |
cv2.adaptiveThreshold() |
Бинаризация для лучшей читаемости |
Полный код функций:
def getWarp(img, biggest):
"""
Применение перспективного преобразования к изображению документа
"""
if biggest.size == 0:
return img
# Определение целевых точек
pts1 = np.float32(biggest)
pts2 = np.float32([[0, 0], [widthImg, 0], [0, heightImg], [widthImg, heightImg]])
# Вычисление матрицы преобразования
matrix = cv2.getPerspectiveTransform(pts1, pts2)
# Применение преобразования
imgOutput = cv2.warpPerspective(img, matrix, (widthImg, heightImg))
# Обрезка краев для удаления артефактов
imgOutput = imgOutput[20:imgOutput.shape[0] - 20, 20:imgOutput.shape[1] - 20]
imgOutput = cv2.resize(imgOutput, (widthImg, heightImg))
return imgOutput
def enhanceDocument(img):
"""
Улучшение качества документа для лучшей читаемости
"""
imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Адаптивная пороговая обработка
imgEnhanced = cv2.adaptiveThreshold(imgGray, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
imgEnhanced = cv2.cvtColor(imgEnhanced, cv2.COLOR_GRAY2BGR)
return imgEnhanced
# Основной цикл программы
cap = cv2.VideoCapture(0)
cap.set(3, widthImg)
cap.set(4, heightImg)
while True:
success, img = cap.read()
if not success:
break
img = cv2.resize(img, (widthImg, heightImg))
imgOriginal = img.copy()
imgProcessed = preProcessing(img)
# Детектирование контуров документа
biggest, imgWithContours = getContours(imgProcessed, imgOriginal)
if biggest.size != 0:
# Перспективное преобразование
imgWarped = getWarp(imgOriginal, biggest)
# Улучшение качества документа
imgEnhanced = enhanceDocument(imgWarped)
cv2.imshow("Document", imgEnhanced)
cv2.imshow("Original", imgOriginal)
cv2.imshow("Processed", imgProcessed)
# Управление: 's' для сохранения, 'q' для выхода
key = cv2.waitKey(1)
if key == ord('s') and biggest.size != 0:
cv2.imwrite("scanned_document.jpg", imgEnhanced)
print("Document saved!")
elif key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
| ✓ | Задача |
|---|---|
| Понимаю различия между BGR и HSV цветовыми пространствами | |
| Знаю диапазоны значений для H (0-179), S (0-255) и V (0-255) в OpenCV | |
| Умею создавать трекбары для интерактивной настройки параметров | |
Могу конвертировать изображение в HSV: cv2.cvtColor(img, cv2.COLOR_BGR2HSV) |
|
Умею создавать маски с помощью cv2.inRange() |
|
Знаю, как применять маски с cv2.bitwise_and() |
|
| Понимаю типичные диапазоны HSV для основных цветов | |
| Реализовал систему детектирования нескольких цветов одновременно |
| ✓ | Задача |
|---|---|
| Понимаю, что такое контур и иерархия контуров | |
| Знаю различия между режимами поиска контуров (RETR_EXTERNAL, RETR_TREE и т.д.) | |
Умею находить контуры с помощью cv2.findContours() |
|
Могу вычислять площадь контура: cv2.contourArea() |
|
Умею вычислять периметр контура: cv2.arcLength() |
|
Знаю, как аппроксимировать контур многоугольником: cv2.approxPolyDP() |
|
Могу получать ограничивающий прямоугольник: cv2.boundingRect() |
|
| Реализовал классификацию геометрических фигур по количеству углов | |
| Знаю дополнительные методы анализа контуров (моменты, выпуклая оболочка) |
| ✓ | Задача |
|---|---|
| Понимаю принцип работы алгоритма Виолы-Джонса | |
| Знаю основные компоненты: интегральное изображение, признаки Хаара, AdaBoost | |
Умею загружать предобученные каскады: cv2.CascadeClassifier() |
|
Могу детектировать лица с помощью detectMultiScale() |
|
Понимаю параметры scaleFactor и minNeighbors |
|
| Умею использовать ROI для детектирования глаз внутри области лица | |
| Реализовал детектирование лиц в реальном времени с веб-камеры | |
| Знаю доступные предобученные каскады (лица, глаза, улыбки и т.д.) |
| ✓ | Задача |
|---|---|
| Понимаю архитектуру системы виртуальной рисовальной доски | |
| Реализовал детектирование цветных маркеров в реальном времени | |
| Умею применять морфологические операции для улучшения маски | |
| Реализовал фильтрацию по площади для отсеивания шума | |
| Создал систему рисования с сохранением точек | |
| Реализовал плавное рисование линиями вместо отдельных точек | |
| Добавил функции очистки холста и управления с клавиатуры | |
| Создал интуитивный интерфейс с визуальной обратной связью |
| ✓ | Задача |
|---|---|
| Понимаю теоретическую основу перспективного преобразования | |
| Реализовал предварительную обработку изображения для детектирования документа | |
| Умею находить контур документа и определять угловые точки | |
| Знаю, как сортировать угловые точки в правильном порядке | |
Могу применять перспективное преобразование: cv2.getPerspectiveTransform() и cv2.warpPerspective() |
|
| Реализовал обрезку краев для удаления артефактов | |
| Умею применять адаптивную пороговую обработку для улучшения читаемости | |
| Создал полнофункциональную систему сканирования документов |
| ✓ | Задача |
|---|---|
| Все проекты работают стабильно без сбоев | |
| Производительность оптимизирована для работы в реальном времени | |
| Код хорошо документирован с комментариями | |
| Все внешние зависимости (OpenCV, NumPy) установлены | |
| Тестирование проведено на различных изображениях и условиях | |
| Визуальная обратная связь понятна пользователю | |
| Все ресурсы (изображения, каскады) доступны в папке resources |
