Наблюдение за табло. Часть 3. Поиск красного и обрезка
Итак, в прошлых частях мы получили картинку и перенесли ее на компьютер. Теперь надо работать с ней, извлекать цифры. Но перед распознаванием картинку желательно упростить, даже нейросети лучше скармливать изображения попроще, это человек может вычленить главное за доли секунды, компьютер тоже может, но у нас не сервера яндекса, так что лучше все же предварительно обработаем.
Содержание цикла
- Часть 1. Вступление: идея и план работы
- Часть 2. Удаленное управление камерой
- Часть 3. Поиск красного и обрезка
Есть еще одно табло слева ниже. Иногда его нет, но иногда есть. И оно нас совсем не интересует.
Вот скрипт с подробными комментариями
from PIL import Image
import math
def find_color_and_crop(input_path, output_path, target_hex="#C26577", tolerance=30):
"""
Ищет цвет начиная от правого верхнего угла к центру и делает кроп.
"""
# 1. Загрузка изображения
try:
img = Image.open(input_path).convert("RGB")
except FileNotFoundError:
print(f"Ошибка: Файл {input_path} не найден.")
return
except Exception as e:
print(f"Ошибка при открытии файла: {e}")
return
width, height = img.size
pixels = img.load()
# Преобразование целевого цвета из HEX в RGB
target_hex = target_hex.lstrip('#')
target_r = int(target_hex[0:2], 16)
target_g = int(target_hex[2:4], 16)
target_b = int(target_hex[4:6], 16)
target_color = (target_r, target_g, target_b)
print(f"Размер изображения: {width}x{height}")
print(f"Поиск цвета {target_color} с допуском {tolerance}...")
# Координаты центра
center_x, center_y = width / 2, height / 2
# Координаты старта (правый верхний угол)
start_x, start_y = width - 1, 0
found_point = None
best_diff = float('inf')
best_point = None
# Более эффективный поиск: идем по спирали или по диагонали от угла к центру
# Но для простоты - проверим все пиксели, но с приоритетом направления
# Создаем список координат, отсортированных по расстоянию от старта
# и по направлению к центру
coords_with_priority = []
for y in range(height):
for x in range(width):
# Вычисляем приоритет: меньше расстояние до линии угол-центр = выше приоритет
# Вектор от старта до точки
dx = x - start_x
dy = y - start_y
# Вектор от старта до центра
cdx = center_x - start_x
cdy = center_y - start_y
# Расстояние от точки до линии угол-центр
if cdx != 0 or cdy != 0:
# Перпендикулярное расстояние до линии
line_len = math.sqrt(cdx**2 + cdy**2)
if line_len > 0:
# Расстояние от точки до линии через векторное произведение
dist_to_line = abs(dx*cdy - dy*cdx) / line_len
else:
dist_to_line = 0
else:
dist_to_line = 0
# Расстояние от старта
dist_from_start = math.sqrt(dx**2 + dy**2)
# Приоритет: меньше расстояние до линии и меньше расстояние от старта
priority = dist_from_start + dist_to_line * 5 # Вес для расстояния до линии
coords_with_priority.append((x, y, priority, dist_from_start))
# Сортируем по приоритету
coords_with_priority.sort(key=lambda k: k[2])
# Поиск цвета
for x, y, priority, dist in coords_with_priority:
r, g, b = pixels[x, y]
# Вычисление разницы цветов (Манхэттенское расстояние)
diff = abs(r - target_r) + abs(g - target_g) + abs(b - target_b)
if diff <= tolerance:
found_point = (x, y)
print(f"Цвет найден в координатах: X={x}, Y={y}. Разница цвета: {diff}")
print(f"Расстояние от старта: {dist:.1f} пикселей")
break
elif diff < best_diff:
best_diff = diff
best_point = (x, y)
if not found_point:
if best_point:
x, y = best_point
r, g, b = pixels[x, y]
print(f"Точный цвет не найден. Ближайший цвет: RGB{target_color} -> найден RGB({r},{g},{b}) с разницей {best_diff}")
print(f"Координаты ближайшего цвета: X={x}, Y={y}")
found_point = best_point
else:
print("Цвет не найден в указанной области с заданным допуском.")
return
x, y = found_point
# 3. Расчет координат для обрезки
left = x - 200
top = y - 50
right = x + 50
bottom = y + 100
# Корректировка границ
left = max(0, left)
top = max(0, top)
right = min(width, right)
bottom = min(height, bottom)
if left >= right or top >= bottom:
print("Ошибка: Область обрезки получилась некорректной.")
return
print(f"Область обрезки: Left={left}, Top={top}, Right={right}, Bottom={bottom}")
# 4. Создание нового изображения
cropped_img = img.crop((left, top, right, bottom))
cropped_img.save(output_path)
print(f"Изображение успешно сохранено в {output_path}")
if __name__ == "__main__":
input_file = "input.jpg"
output_file = "result_crop.jpg"
# Увеличим допуск для JPEG изображений
find_color_and_crop(input_file, output_file, tolerance=30)
И в итоге получается вот такая обрезанная картинка, распознавать цифры с которой уже гораздо проще

Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.
Программы на заказ
Отзывы
Контакты