Вопрос или проблема
Я пытаюсь увеличить FPS своей программы, но этот класс использует слишком много памяти, что замедляет производительность. Как я могу улучшить этот класс, чтобы моя программа могла делать скриншоты быстрее и работать лучше.
import cv2
import numpy as np
# Работайте над этим, чтобы сократить использование памяти и увеличить производительность
class ObjectDetection:
def __init__(self):
self.avg_y_obstacle = None
self.avg_x_obstacle = None
self.avg_y_jump = None
self.avg_x_jump = None
# Предзагрузка шаблонов для обнаружения препятствий для оптимизации производительности
self.templates = {
'template1': cv2.imread('template1.png', 0),
'template2': cv2.imread('template2.png', 0),
'template3': cv2.imread('template3.png', 0),
'template4': cv2.imread('template4.png', 0),
'template5': cv2.imread('template5.png', 0),
'template6': cv2.imread('template6.png', 0),
'template7': cv2.imread('template7.png', 0),
'template8': cv2.imread('template8.png', 0)
}
# Проверьте, правильно ли загружены все шаблоны
for name, template in self.templates.items():
if template is None:
raise ValueError(f"Ошибка загрузки шаблона: {name}")
def ObstacleDetect(self, imageInput=None, threshold=0.8):
if imageInput is None:
raise ValueError("Необходимо ввести изображение")
# Преобразование входного изображения в градации серого
image_gray = cv2.cvtColor(imageInput, cv2.COLOR_BGR2GRAY)
coordinates = []
# Итерация по каждому предзагруженному шаблону
for name, template in self.templates.items():
h, w = template.shape[:2] # Получить размеры шаблона
# Выполнить сопоставление шаблонов
result = cv2.matchTemplate(image_gray, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
# Собрать координаты для обнаруженных объектов и нарисовать ограничивающие прямоугольники
for pt in zip(*loc[::-1]):
coordinates.append((pt[0], pt[1], pt[0] + w, pt[1] + h))
# cv2.rectangle(imageInput, (pt[0], pt[1]), (pt[0] + w, pt[1] + h), (0, 255, 0), 2)
# cv2.putText(imageInput, name, (pt[0], pt[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
# Рассчитать avg_x_obstacle и avg_y_obstacle, если координаты найдены
if coordinates:
coordinates = np.array(coordinates)
self.avg_y_obstacle = np.mean(coordinates[:, 1]) # Среднее значение y-координаты верхнего левого угла
self.avg_x_obstacle = np.mean(coordinates[:, 0]) # Среднее значение x-координаты верхнего левого угла
else:
print("Препятствий не обнаружено.")
self.avg_y_obstacle = None
self.avg_x_obstacle = None
return imageInput
def findJumpArea(self, image=None, threshold=0.8):
# Загружаем шаблон прыжка один раз
template = cv2.imread('jump_template.png', 0)
if image is None or template is None:
raise ValueError("Ошибка: не удалось загрузить входное изображение или шаблон.")
# Преобразование изображения в градации серого
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
h, w = template.shape[:2]
# Выполнить сопоставление шаблонов
result = cv2.matchTemplate(image_gray, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
coordinates = []
# Собрать координаты обнаруженной зоны прыжка и провести линии
for pt in zip(*loc[::-1]):
coordinates.append((pt[0], pt[1]))
# line_length = 50
# cv2.line(image, (pt[0], pt[1]), (pt[0] + line_length, pt[1]), (0, 255, 0), 2)
# Рассчитать avg_x_jump и avg_y_jump, если координаты найдены
if coordinates:
coordinates = np.array(coordinates)
self.avg_y_jump = np.mean(coordinates[:, 1]) # Среднее значение y-координаты верхнего левого угла
self.avg_x_jump = np.mean(coordinates[:, 0]) # Среднее значение x-координаты верхнего левого угла
else:
print("Зона прыжка не обнаружена.")
self.avg_y_jump = None
self.avg_x_jump = None
return image
# Геттеры для средних координат
def getObstacleAvgY(self):
return self.avg_y_obstacle
def getObstacleAvgX(self):
return self.avg_x_obstacle
def getJumpAvgY(self):
return self.avg_y_jump
def getJumpAvgX(self):
return self.avg_x_jump
Я попробовал предзагрузить шаблоны и закомментировал некоторые визуальные элементы cv, это немного улучшило производительность. Однако это было все, что мне удалось придумать.
Ответ или решение
Чтобы уменьшить использование памяти и повысить производительность вашего класса ObjectDetection
, я предлагаю несколько изменений и оптимизаций. Давайте рассмотрим основные из них:
-
Предварительная загрузка и использование шаблонов: На данный момент шаблоны загружаются в методе и используются в методах
ObstacleDetect
иfindJumpArea
, но шаблоны для обнаружения препятствий и зоны прыжков могут быть загружены один раз в конструкторе. Также вы можете использовать один шаблон для обеих функций, если это возможно по цели распознавания. -
Оптимизация загрузки изображений: Если шаблоны не меняются во время работы программы, оптимально загружать их только один раз при инициализации класса. Ваша текущая реализация уже делает это, но вы можете рассмотреть возможность использования формы кэширования или загрузки только по мере необходимости для избежания избыточного использования памяти.
-
Уменьшение размера изображений: Если разрешение входных изображений больше, чем необходимо для вашего алгоритма обнаружения, можно уменьшить их размер перед обработкой, что сократит использование памяти и увеличит скорость обработки.
-
Использование
mask
: Если вам не нужно обрабатывать весь входной образ, вы можете использовать маску для выделения только интересующих вас областей. Это сократит объем данных, с которыми работает алгоритм. -
Уменьшение количества переменных и использование numpy: Вместо индивидуального хранения средних значений для координат можно использовать numpy массивы, что снизит объем используемой памяти и ускорит расчёты. Измените вашу кодовую структуру, чтобы вместо четырех отдельных переменных использовать два массива с двумя значениями для каждого типа (объекты и прыжки).
-
Оптимизация метода
ObstacleDetect
иfindJumpArea
: Вместо хранения нескольких временных массивов, вы можете использовать более прямой подход для хранения информации о координатах. Также следует избегать дублирования кода. Рассмотрите создание отдельной вспомогательной функции для распознавания объектов на основе шаблонов.
Ниже приведен пример переработанного класса с учетом вышеперечисленных предложений:
import cv2
import numpy as np
class ObjectDetection:
def __init__(self):
self.avg_obstacle_coords = None
self.avg_jump_coords = None
# Предварительная загрузка шаблонов для обнаружения
self.templates = {
'obstacle': [cv2.imread(f'template{i}.png', 0) for i in range(1, 9)],
'jump': cv2.imread('jump_template.png', 0)
}
# Проверка загрузки шаблонов
for category, templates in self.templates.items():
if isinstance(templates, list):
for template in templates:
if template is None:
raise ValueError(f"Ошибка загрузки шаблона: {category}")
else:
if templates is None:
raise ValueError(f"Ошибка загрузки шаблона: {category}")
def detect(self, imageInput, category, threshold=0.8):
if imageInput is None:
raise ValueError("Требуется входное изображение")
# Преобразование входного изображения в оттенки серого
image_gray = cv2.cvtColor(imageInput, cv2.COLOR_BGR2GRAY)
coordinates = []
# Обработка шаблонов на основе категории
for template in self.templates[category]:
h, w = template.shape[:2]
result = cv2.matchTemplate(image_gray, template, cv2.TM_CCOEFF_NORMED)
loc = np.where(result >= threshold)
for pt in zip(*loc[::-1]):
coordinates.append((pt[0], pt[1], pt[0] + w, pt[1] + h))
# Расчет средних координат, если координаты найдены
if coordinates:
coordinates = np.array(coordinates)
if category == 'obstacle':
self.avg_obstacle_coords = np.mean(coordinates, axis=0)
else: # category == 'jump'
self.avg_jump_coords = np.mean(coordinates, axis=0)
else:
print(f"Нет обнаруженных {category}.")
return imageInput
def ObstacleDetect(self, imageInput, threshold=0.8):
return self.detect(imageInput, 'obstacle', threshold)
def findJumpArea(self, imageInput, threshold=0.8):
return self.detect(imageInput, 'jump', threshold)
def getObstacleAvg(self):
return self.avg_obstacle_coords
def getJumpAvg(self):
return self.avg_jump_coords
Объяснение:
- Все шаблоны теперь загружаются только один раз в конструкторе.
- Введена единая функция обработки
detect
, которая получает категорию (объект или прыжок), тем самым уменьшая дублирование кода. - Вместо нескольких средних значений теперь хранятся только два numpy массива, что уменьшает использование памяти.
Внедряя эти изменения, вы сможете значительно сократить потребление памяти и повысить производительность вашего класса.