как найти пиксель, переданный графиком, нарисованным с помощью matplotlib - PullRequest
1 голос
/ 26 мая 2020

Я рисую функцию, используя следующий код:

t = np.arange(0., 5., 0.2)
plt.plot(t, (t**2)+10*np.sin(t))
plt.axis('off')

Мне интересно, как сохранить график в виде массива 0/1, где значение пикселя равно 1, если график проходит его, иначе это 0.

Следующий вопрос: если я рисую график с некоторой шириной линии, я хочу, чтобы значение пикселя было равно 1, только если он находится на «центральной» линии графика, в противном случае - 0. как мне это сделать? Спасибо!

1 Ответ

1 голос
/ 26 мая 2020

Преобразование фигуры в массив RGBA можно выполнить разными способами. Самым простым, вероятно, является сохранение файла в формате PNG, а затем повторная загрузка файла с plt.imread или аналогичным. Если это кажется вам окольным, вы можете использовать plot2img, который я использую ниже, который захватывает холст и преобразует его в массив через промежуточное представление в виде строкового буфера.

После этого остается просто установить порог изображения и выделить среднюю ось, что можно легко сделать с помощью функций, предоставляемых scikit-image.

enter image description here

#!/usr/bin/env python
"""
https://stackoverflow.com/q/62014554/2912349
"""

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.backends.backend_agg import FigureCanvasAgg

from skimage.color import rgb2gray
from skimage.filters import threshold_otsu
from skimage.morphology import medial_axis


def plot2img(fig, remove_margins=True):
    # https://stackoverflow.com/a/35362787/2912349
    # https://stackoverflow.com/a/54334430/2912349

    if remove_margins:
        fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)

    canvas = FigureCanvasAgg(fig)
    canvas.draw()
    img_as_string, (width, height) = canvas.print_to_buffer()
    return np.fromstring(img_as_string, dtype='uint8').reshape((height, width, 4))


if __name__ == '__main__':

    t = np.arange(0., 5., 0.2)
    y = (t**2)+10*np.sin(t)

    # plot in a large figure such that the resulting image has a high resolution
    fig, ax = plt.subplots(figsize=(20, 20))
    ax.plot(t, y)
    ax.axis('off')

    # convert figure to an RGBA array
    as_rgba = plot2img(fig)

    # close plot made with non-interactive Agg backend so that we can open the other later
    plt.close('all')

    # threshold the image
    as_grayscale = rgb2gray(as_rgba)
    threshold = threshold_otsu(as_grayscale)
    as_bool = as_grayscale < threshold

    # find midline
    midline = medial_axis(as_bool)

    # plot results
    fig, (ax1, ax2) = plt.subplots(1, 2)
    ax1.imshow(as_bool, cmap='gray_r')
    ax2.imshow(midline, cmap='gray_r')
    plt.show()
...