Фон
Оптимизирую проект.
Профилируя код, я обнаружил, что 50% времени тратится на функцию, в которой набор кругов (разные радиусы, цвета и местоположения) рисуются в выбранном секторе фиксированного размера (белый холст), если их центральная часть находится в пределах сектора. В зависимости от использования функция сохраняет фигуру как png и возвращает путь или возвращает изображение как массив numpy.
build-in method matplotlib._png.write_png
из savefig
является самым дорогим, но есть также некоторые накладные расходы на создание фигур, et c.
Обычно код используется с многопроцессорным / параллельным программированием .
Пример вывода
Код
import matplotlib.pyplot as plt
import cv2
import os
def get_top_view(sector, circles, file_path, save_image_flag):
# get the sector bounds.
x_low, y_low, x_high, y_high = get_sector_bounds(sector)
# init figure
fig, ax = plt.subplots()
ax.set_xlim(y_low, y_high)
ax.set_ylim(x_low, x_high)
ax.set_yticklabels([])
ax.set_xticklabels([])
ax.set_yticks([])
ax.set_xticks([])
ax.set_aspect('equal')
ax.axis('off')
# c is a circle object with all relevant data (center coordinates,
# radius, RGB color tuple)
for c in circles:
if x_low <= c.x_coord <= x_high and y_low <= c.y_coord <= y_high:
shape = plt.Circle((c.x_coord, c.y_coord), c.radius, color=c.color)
shape_plot = ax.add_artist(shape)
shapes.append(shape_plot)
plt.gca().invert_yaxis()
if save_image_flag:
plt.savefig(file_path + '_cc.png', bbox_inches='tight', pad_inches=0.02)
plt.close()
return file_path
else:
ax.margins(0)
fig.tight_layout()
fig.canvas.draw()
image_from_plot = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
image_from_plot = image_from_plot.reshape(
fig.canvas.get_width_height()[::-1] + (3,))
image_from_plot = image_from_plot[:, 13:-14]
resized = cv2.resize(image_from_plot, (499, 391))
cropped = resized[78:-78]
plt.close()
return cropped
Вопросы
Есть проблема в том, что версия массива и изображение png немного отличаются. Я думаю, это связано с DPI изображения. Я хочу это исправить и думаю о разных вариантах, которые могут ускорить эту функцию.
- Ускорьте процесс и сохраните matplotlib, аналогично этому примеру из Github .
Избавьтесь от matplotlib и нарисуйте его с помощью Pillow, например например:
from PIL import Image, ImageDraw
def get_top_view(sector, circles, file_path, save_image_flag):
# get the sector bounds.
x_low, y_low, x_high, y_high = get_sector_bounds(sector)
im = Image.new('RGB', (499, 235), (255, 255, 255))
draw = ImageDraw.Draw(im)
# there needs to be some rescaling that the corrdinates match which
# I don't account for at the moment.
for c in circles:
if x_low <= c.x_coord <= x_high and y_low <= c.y_coord <= y_high:
draw.ellipse((c.x_coord - c.radius, c.y_coord - c.radius,
c.x_coord + c.radius, c.y_coord + c.radius),
fill=c.color)
if save_image_flag:
im.save(file_path + '.png')
return file_path
else:
image_as_array = convert_to_array() # have to think about how I'll do that
return image_as_array
Другой подход, который быстрее (и в чем-то удобнее) ...
Я был бы рад за любые отзывы по двум вопросам.