Лаб. работа “Компьютерное зрение”
Введение в компьютерное зрение
Компьютерное зрение — это область искусственного интеллекта, которая занимается автоматическим извлечением, анализом и пониманием информации из изображений и видео. Компьютерное зрение объединяет методы обработки изображений, машинного обучения и глубокого обучения для решения задач распознавания, классификации и анализа визуальных данных.
Основные задачи компьютерного зрения:
- Классификация изображений — определение категории объекта на изображении
- Обнаружение объектов — нахождение и классификация объектов на изображении
- Сегментация — разделение изображения на осмысленные регионы
- Распознавание лиц — идентификация и верификация личности
- Оптическое распознавание текста (OCR) — извлечение текста из изображений
- Трехмерное зрение — восстановление 3D-структуры из 2D-изображений
- Отслеживание объектов — отслеживание движения объектов в видео
Теоретические основы компьютерного зрения
Основные понятия
1. Представление изображений
- Изображение как матрица пикселей
- Цветовые пространства (RGB, HSV, Grayscale)
- Глубина цвета (8-bit, 16-bit, 24-bit)
2. Предобработка изображений
- Изменение размера (resizing)
- Нормализация (normalization)
- Фильтрация (filtering)
- Геометрические преобразования
3. Особенности (Features)
- Цветовые гистограммы
- Текстурные признаки
- Геометрические признаки
- Градиенты и границы
4. Современные подходы
- Сверточные нейронные сети (CNN)
- Предобученные модели (Transfer Learning)
- Обнаружение объектов (YOLO, R-CNN)
- Сегментация (U-Net, Mask R-CNN)
Базовая обработка изображений
import cv2
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_sample_images
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import classification_report, accuracy_score
import pandas as pd
import os
# Настройка matplotlib для inline отображения
%matplotlib inline
# Загрузка примера изображения
dataset = load_sample_images()
image = dataset.images[0] # Первое изображение из набора
print(f"=== Информация об изображении ===")
print(f"Размер изображения: {image.shape}")
print(f"Тип данных: {image.dtype}")
print(f"Минимальное значение: {image.min()}")
print(f"Максимальное значение: {image.max()}")
# Отображение исходного изображения
plt.figure(figsize=(10, 8))
plt.subplot(2, 3, 1)
plt.imshow(image)
plt.title('Оригинальное изображение')
plt.axis('off')
# Преобразование в оттенки серого
gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.subplot(2, 3, 2)
plt.imshow(gray_image, cmap='gray')
plt.title('Изображение в оттенках серого')
plt.axis('off')
# Изменение размера
resized_image = cv2.resize(image, (200, 200))
plt.subplot(2, 3, 3)
plt.imshow(resized_image)
plt.title('Измененное изображение (200x200)')
plt.axis('off')
# Гауссово размытие
blurred_image = cv2.GaussianBlur(image, (15, 15), 0)
plt.subplot(2, 3, 4)
plt.imshow(blurred_image)
plt.title('Размытое изображение')
plt.axis('off')
# Обнаружение границ (Canny)
edges = cv2.Canny(gray_image, 100, 200)
plt.subplot(2, 3, 5)
plt.imshow(edges, cmap='gray')
plt.title('Границы (Canny edge detection)')
plt.axis('off')
# Цветовая гистограмма
colors = ('r', 'g', 'b')
plt.subplot(2, 3, 6)
for i, color in enumerate(colors):
hist = cv2.calcHist([image], [i], None, [256], [0, 256])
plt.plot(hist, color=color)
plt.title('Цветовая гистограмма')
plt.xlabel('Интенсивность')
plt.ylabel('Частота')
plt.tight_layout()
plt.show()Классификация изображений
Создание простого датасета
# Создание синтетического датасета для классификации
def create_synthetic_dataset():
"""Создание простого датасета с геометрическими фигурами"""
images = []
labels = []
# Круги
for _ in range(100):
img = np.zeros((64, 64, 3), dtype=np.uint8)
center = (np.random.randint(20, 44), np.random.randint(20, 44))
radius = np.random.randint(8, 16)
color = tuple(np.random.randint(100, 255, 3).tolist())
cv2.circle(img, center, radius, color, -1)
images.append(img)
labels.append(0) # Класс 0 - круг
# Квадраты
for _ in range(100):
img = np.zeros((64, 64, 3), dtype=np.uint8)
x1 = np.random.randint(10, 30)
y1 = np.random.randint(10, 30)
size = np.random.randint(15, 25)
color = tuple(np.random.randint(100, 255, 3).tolist())
cv2.rectangle(img, (x1, y1), (x1 + size, y1 + size), color, -1)
images.append(img)
labels.append(1) # Класс 1 - квадрат
# Треугольники
for _ in range(100):
img = np.zeros((64, 64, 3), dtype=np.uint8)
x1 = np.random.randint(15, 35)
y1 = np.random.randint(40, 55)
size = np.random.randint(15, 25)
color = tuple(np.random.randint(100, 255, 3).tolist())
pts = np.array([[x1, y1], [x1 + size, y1], [x1 + size//2, y1 - size]], np.int32)
cv2.fillPoly(img, [pts], color)
images.append(img)
labels.append(2) # Класс 2 - треугольник
return np.array(images), np.array(labels)
# Создание датасета
X, y = create_synthetic_dataset()
print(f"=== Созданный датасет ===")
print(f"Количество изображений: {len(X)}")
print(f"Количество классов: {len(np.unique(y))}")
print(f"Размер изображений: {X[0].shape}")
# Визуализация примеров из каждого класса
fig, axes = plt.subplots(3, 5, figsize=(15, 9))
class_names = ['Circle', 'Square', 'Triangle']
for class_id in range(3):
class_indices = np.where(y == class_id)[0][:5]
for i, idx in enumerate(class_indices):
axes[class_id, i].imshow(X[idx])
axes[class_id, i].set_title(f'{class_names[class_id]} {i+1}')
axes[class_id, i].axis('off')
plt.suptitle('Примеры изображений из датасета')
plt.tight_layout()
plt.show()Извлечение признаков
def extract_features(images):
"""Извлечение признаков из изображений"""
features = []
for img in images:
# Преобразование в оттенки серого
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# Извлечение признаков
feature_vector = []
# 1. Статистические признаки
feature_vector.extend([
gray.mean(), # Средняя яркость
gray.std(), # Стандартное отклонение
gray.min(), # Минимальная яркость
gray.max() # Максимальная яркость
])
# 2. Геометрические признаки (моменты Ху)
moments = cv2.moments(gray)
hu_moments = cv2.HuMoments(moments).flatten()
feature_vector.extend(hu_moments)
# 3. Текстурные признаки (гистограмма направленных градиентов)
hog = cv2.HOGDescriptor((64, 64), (16, 16), (8, 8), (8, 8), 9)
hog_features = hog.compute(gray).flatten()[:20] # Берем первые 20 признаков
feature_vector.extend(hog_features)
# 4. Цветовые признаки
for channel in range(3):
hist = cv2.calcHist([img], [channel], None, [8], [0, 256])
feature_vector.extend(hist.flatten())
features.append(feature_vector)
return np.array(features)
# Извлечение признаков
print("=== Извлечение признаков ===")
X_features = extract_features(X)
print(f"Размерность признаков: {X_features.shape}")
print(f"Количество признаков на изображение: {X_features.shape[1]}")
# Нормализация признаков
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_features_scaled = scaler.fit_transform(X_features)Классификация
# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X_features_scaled, y,
test_size=0.3, random_state=42,
stratify=y)
# Обучение моделей
models = {
'SVM': SVC(kernel='rbf', random_state=42),
'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
'Logistic Regression': LogisticRegression(max_iter=1000, random_state=42)
}
# Обучение и оценка моделей
results = {}
for name, model in models.items():
# Обучение
model.fit(X_train, y_train)
# Предсказание
y_pred = model.predict(X_test)
# Оценка
accuracy = accuracy_score(y_test, y_pred)
results[name] = {
'model': model,
'predictions': y_pred,
'accuracy': accuracy,
'report': classification_report(y_test, y_pred,
target_names=class_names,
output_dict=True)
}
print(f"\n=== {name} ===")
print(f"Accuracy: {accuracy:.3f}")
print("Classification Report:")
print(classification_report(y_test, y_pred, target_names=class_names))Визуализация результатов
# Сравнение точности моделей
model_names = list(results.keys())
accuracies = [results[name]['accuracy'] for name in model_names]
plt.figure(figsize=(10, 6))
bars = plt.bar(model_names, accuracies, color=['skyblue', 'lightgreen', 'salmon'])
plt.title('Сравнение точности моделей классификации изображений')
plt.xlabel('Модель')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
# Добавление значений на столбцы
for bar, acc in zip(bars, accuracies):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.01,
f'{acc:.3f}', ha='center', va='bottom')
plt.grid(True, alpha=0.3)
plt.show()
# Матрицы ошибок
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
for idx, (name, result) in enumerate(results.items()):
cm = confusion_matrix(y_test, result['predictions'])
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names,
yticklabels=class_names,
ax=axes[idx])
axes[idx].set_title(f'Confusion Matrix - {name}')
axes[idx].set_xlabel('Предсказанный класс')
axes[idx].set_ylabel('Истинный класс')
plt.tight_layout()
plt.show()Распознавание лиц
# Загрузка каскадов Хаара для распознавания лиц
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
# Создание синтетических данных для распознавания лиц
def create_face_dataset():
"""Создание простого датасета для распознавания лиц"""
# В реальности здесь должны быть настоящие изображения лиц
# Для демонстрации создадим синтетические данные
faces = []
labels = []
# Создание "лиц" (в реальности используйте настоящие фотографии)
for person_id in range(3): # 3 разных "человека"
for _ in range(50): # 50 изображений на человека
# Создание изображения с "лицом" (упрощенная версия)
img = np.random.randint(0, 255, (100, 100, 3), dtype=np.uint8)
# Добавление "лицевых" признаков (в реальности - настоящие лица)
cv2.rectangle(img, (25, 25), (75, 75), (200, 200, 200), -1)
cv2.circle(img, (40, 45), 5, (0, 0, 0), -1)
cv2.circle(img, (60, 45), 5, (0, 0, 0), -1)
cv2.rectangle(img, (45, 60), (55, 70), (0, 0, 0), -1)
# Добавление шума и вариаций
noise = np.random.randint(-50, 50, (100, 100, 3))
img = cv2.add(img, noise.astype(np.uint8))
img = np.clip(img, 0, 255).astype(np.uint8)
faces.append(cv2.cvtColor(img, cv2.COLOR_RGB2GRAY))
labels.append(person_id)
return faces, labels
# Создание датасета
faces, face_labels = create_face_dataset()
print(f"=== Датасет для распознавания лиц ===")
print(f"Количество изображений: {len(faces)}")
print(f"Количество людей: {len(np.unique(face_labels))}")
# Визуализация примеров
fig, axes = plt.subplots(3, 5, figsize=(15, 9))
for person_id in range(3):
person_indices = np.where(np.array(face_labels) == person_id)[0][:5]
for i, idx in enumerate(person_indices):
axes[person_id, i].imshow(faces[idx], cmap='gray')
axes[person_id, i].set_title(f'Person {person_id + 1} - Image {i + 1}')
axes[person_id, i].axis('off')
plt.suptitle('Примеры изображений лиц')
plt.tight_layout()
plt.show()Обучение распознавателя лиц
# Использование метода Eigenfaces (PCA)
def train_face_recognizer(faces, labels):
"""Обучение распознавателя лиц"""
# Создание распознавателя
recognizer = cv2.face.LBPHFaceRecognizer_create()
# Обучение (в реальности нужно больше данных и предобработка)
recognizer.train(faces, np.array(labels))
return recognizer
# Обучение распознавателя
face_recognizer = train_face_recognizer(faces, face_labels)
# Тестирование распознавателя
def test_face_recognition(recognizer, test_faces, test_labels):
"""Тестирование распознавателя лиц"""
correct = 0
total = len(test_faces)
for i, (face, true_label) in enumerate(zip(test_faces, test_labels)):
# Предсказание
label, confidence = recognizer.predict(face)
if label == true_label:
correct += 1
print(f"Image {i+1}: True label: {true_label}, Predicted: {label}, Confidence: {confidence:.2f}")
accuracy = correct / total
print(f"\nAccuracy: {accuracy:.3f}")
return accuracy
# Создание тестового набора
test_faces = faces[-30:] # Последние 30 изображений
test_labels = face_labels[-30:]
train_faces = faces[:-30]
train_labels = face_labels[:-30]
# Реобучение на обучающем наборе
face_recognizer.train(train_faces, np.array(train_labels))
# Тестирование
print("=== Результаты распознавания лиц ===")
test_face_recognition(face_recognizer, test_faces, test_labels)Обнаружение объектов
# Создание простого детектора объектов на основе цвета
def create_object_detector():
"""Создание детектора объектов по цвету"""
def detect_objects_by_color(image, lower_bound, upper_bound):
"""Обнаружение объектов по диапазону цвета"""
# Преобразование в HSV
hsv = cv2.cvtColor(image, cv2.COLOR_RGB2HSV)
# Создание маски
mask = cv2.inRange(hsv, lower_bound, upper_bound)
# Удаление шума
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
# Поиск контуров
contours, _ = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Фильтрация контуров по площади
detected_objects = []
for contour in contours:
area = cv2.contourArea(contour)
if area > 500: # Минимальная площадь объекта
x, y, w, h = cv2.boundingRect(contour)
detected_objects.append((x, y, w, h))
return detected_objects, mask
return detect_objects_by_color
# Создание детектора
object_detector = create_object_detector()
# Тестовое изображение с объектами
test_image = np.zeros((300, 400, 3), dtype=np.uint8)
# Добавление объектов разных цветов
# Красные объекты
cv2.circle(test_image, (100, 100), 30, (255, 0, 0), -1)
cv2.rectangle(test_image, (200, 50), (280, 130), (200, 0, 0), -1)
# Синие объекты
cv2.circle(test_image, (150, 200), 25, (0, 0, 255), -1)
cv2.rectangle(test_image, (300, 180), (360, 240), (0, 0, 200), -1)
# Зеленые объекты
cv2.circle(test_image, (320, 120), 35, (0, 255, 0), -1)
# Обнаружение красных объектов
lower_red1 = np.array([0, 50, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 50, 50])
upper_red2 = np.array([180, 255, 255])
# Объединение диапазонов для красного цвета
hsv_image = cv2.cvtColor(test_image, cv2.COLOR_RGB2HSV)
mask1 = cv2.inRange(hsv_image, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv_image, lower_red2, upper_red2)
red_mask = cv2.bitwise_or(mask1, mask2)
red_objects, red_mask_clean = object_detector(test_image, lower_red1, upper_red2)
# Визуализация результатов
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# Оригинальное изображение
axes[0, 0].imshow(test_image)
axes[0, 0].set_title('Оригинальное изображение')
axes[0, 0].axis('off')
# Маска для красных объектов
axes[0, 1].imshow(red_mask_clean, cmap='gray')
axes[0, 1].set_title('Маска красных объектов')
axes[0, 1].axis('off')
# Результат обнаружения
result_image = test_image.copy()
for (x, y, w, h) in red_objects:
cv2.rectangle(result_image, (x, y), (x + w, y + h), (0, 255, 255), 2)
cv2.putText(result_image, 'Red Object', (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)
axes[1, 0].imshow(result_image)
axes[1, 0].set_title('Обнаруженные красные объекты')
axes[1, 0].axis('off')
# Гистограмма цветов
for i, color in enumerate(['Red', 'Green', 'Blue']):
hist = cv2.calcHist([test_image], [i], None, [256], [0, 256])
axes[1, 1].plot(hist, color=color.lower())
axes[1, 1].set_title('Гистограмма цветов')
axes[1, 1].set_xlabel('Интенсивность')
axes[1, 1].set_ylabel('Частота')
plt.tight_layout()
plt.show()
print(f"=== Результаты обнаружения объектов ===")
print(f"Найдено красных объектов: {len(red_objects)}")
for i, (x, y, w, h) in enumerate(red_objects):
print(f"Объект {i+1}: x={x}, y={y}, width={w}, height={h}")Самостоятельные задания
Задание 1: Система распознавания рукописных цифр
Цель: Создать систему распознавания рукописных цифр на основе датасета MNIST.
Задачи:
- Загрузите датасет MNIST (используйте
tensorflow.keras.datasets.mnist) - Визуализируйте примеры изображений из каждого класса (цифры 0-9)
- Реализуйте предобработку изображений (нормализация, изменение размера)
- Обучите модель классификации (SVM, Random Forest или простую нейронную сеть)
- Оцените качество модели и постройте матрицу ошибок
- Проанализируйте наиболее частые ошибки классификации
Дополнительные задачи:
- Сравните производительность различных алгоритмов
- Исследуйте влияние размера изображения на точность
- Реализуйте простую веб-интерфейс для ручного ввода цифр
Формат отчета:
- Описание предобработки данных
- Сравнение различных моделей и их точности
- Анализ ошибок классификации
- Визуализация результатов
- Рекомендации по улучшению системы
Задание 2: Детектор движения в видео
Цель: Создать систему обнаружения движения в видеопотоке.
Задачи:
- Реализуйте алгоритм вычитания фона (Background Subtraction)
- Используйте методы накопления (accumulate) и усреднения (average) для создания фона
- Реализуйте пороговую обработку для выделения движущихся объектов
- Примените морфологические операции для улучшения результатов
- Реализуйте отслеживание движущихся объектов
- Постройте график траектории движения объектов
Дополнительные задачи:
- Реализуйте различные методы вычитания фона (MOG2, KNN)
- Добавьте фильтрацию по размеру объектов
- Реализуйте подсчет количества движущихся объектов
- Создайте систему алертов при обнаружении движения
Формат отчета:
- Описание используемых алгоритмов
- Сравнение различных методов вычитания фона
- Визуализация результатов на примерах видео
- Анализ производительности системы
- Проблемы и ограничения метода
Задание 3: Система распознавания жестов
Цель: Создать систему распознавания простых жестов руки.
Задачи:
- Создайте датасет изображений рук в разных позициях (например: кулак, ладонь, указательный жест)
- Реализуйте сегментацию руки на изображении (используйте цвет кожи)
- Извлеките признаки формы руки (контуры, моменты, ориентация)
- Обучите классификатор для распознавания жестов
- Реализуйте реальное распознавание с веб-камеры
- Постройте интерфейс для взаимодействия с системой
Дополнительные задачи:
- Реализуйте отслеживание движения руки
- Добавьте распознавание динамических жестов
- Создайте систему управления компьютером жестами
- Реализуйте калибровку цвета кожи для разных условий освещения
Формат отчета:
- Описание процесса сегментации и извлечения признаков
- Сравнение различных методов классификации
- Демонстрация работы системы на видео
- Анализ точности распознавания
- Идеи для улучшения системы
Задание 4: Система контроля качества продуктов
Цель: Создать систему автоматического контроля качества продуктов на конвейере.
Задачи:
- Создайте датасет изображений продуктов (например: яблоки - хорошее/плохое качество)
- Реализуйте сегментацию продуктов на изображении
- Извлеките признаки качества (цвет, текстура, форма, размер)
- Обучите классификатор для определения качества
- Реализуйте систему подсчета и классификации нескольких продуктов
- Создайте отчет о качестве партии продуктов
Дополнительные задачи:
- Реализуйте классификацию по нескольким критериям (зрелость, повреждения, размер)
- Добавьте систему весов для различных критериев качества
- Создайте визуализацию статистики качества
- Реализуйте систему алертов при низком качестве
Формат отчета:
- Описание критериев качества и методов их оценки
- Сравнение различных признаков и их информативности
- Результаты классификации и мат