Как преобразовать контур в маркер для построения? - PullRequest
3 голосов
/ 02 марта 2020

У меня есть изображение , для которого я извлек контуры с помощью OpenCV и рассчитал их площади.

image = cv2.imread("shapes_and_colors.jpg")

"""Find contours"""
gray = cv2.cvtColor(shapes.copy(), cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(src=blur, thresh=60, maxval=255, type=cv2.THRESH_BINARY)[1]
new_image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

"""Plot image and contours"""
fig, ax = plt.subplots(ncols=2)
ax[0].imshow(image)
ax[0].axis('off')

canvas = np.zeros_like(image)
for i, c in enumerate(contours):
    M = cv2.moments(c)
    if M["m00"] != 0:
        cX = int((M["m10"] / M["m00"]))
        cY = int((M["m01"] / M["m00"]))
    else:
        cX,cY = 0,0
    cv2.drawContours(canvas, [c], -1, (255, 0, 255), 2)
    ax[1].text(x=cX, y=cY, s=u"{}".format(cv2.contourArea(c)), color="cyan", size=8)


ax[1].imshow(canvas)
ax[1].axis('off')

plt.tight_layout()

enter image description here

Теперь я хотел бы построить их, используя контур в качестве маркера, что-то вроде:

fig, ax = plt.subplots()

"""Convert contour to marker"""
def contour2marker(contour):
     ...

    return marker


for i,c in enumerate(sorted(contours, key=cv2.contourArea)):
    ax.scatter(x=i, y=cv2.contourArea(c), marker=contour2marker(c))

plt.tight_layout()

enter image description here

Я не знаю с чего начать с преобразования контуров в маркеры. Я знаю, что контуры сохраняются как набор точек, и, глядя на этот пост , нелегко вырезать их из изображения. Скорее маски создаются или прямоугольники обрезаются на изображениях. Однако, если фигуры не соответствуют обычным полигонам, эта техника не работает. Если бы контуры можно было преобразовать в изображения, их можно было бы легко построить, как в в этом примере .

1 Ответ

1 голос
/ 03 марта 2020

Нетрудно создать отдельные изображения из контуров с помощью параметра offset, равного cv2.drawContours. Можно было бы просто обратить внимание на правильный прозрачный фон «маркерных изображений».

Мне пришлось использовать изображение другой формы, так как ваше исходное изображение было мне недоступно (необходимая предварительная обработка немного отличается) :

Shapes

Результат, включающий ответ , который вы связали , выглядит следующим образом:

Output

Вот полный код:

import cv2
from matplotlib import pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import numpy as np


# Modified from https://stackoverflow.com/a/22570069/11089932
def imscatter(x, y, marker, ax=None, zoom=1.0):
    if ax is None:
        ax = plt.gca()
    im = OffsetImage(marker, zoom=zoom)
    x, y = np.atleast_1d(x, y)
    artists = []
    for x0, y0 in zip(x, y):
        ab = AnnotationBbox(im, (x0, y0), xycoords='data', frameon=False)
        artists.append(ax.add_artist(ab))
    ax.update_datalim(np.column_stack([x, y]))
    ax.autoscale()
    return artists


# Read image
image = cv2.imread("shapes.png")

# Convert to grayscale, (inverse) binary threshold
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY_INV)[1]

# Find contours with respect to the OpenCV version
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

# Sort contours with respect to the area
cnts = sorted(cnts, key=cv2.contourArea)

# Plot contours as markers
plt.figure(1, figsize=(10, 10))
for i, cnt in enumerate(cnts):
    x, y, w, h = cv2.boundingRect(cnt)
    img = np.zeros((h + 11, w + 11, 4), np.uint8)
    img = cv2.drawContours(img, [cnt], -1, (255, 255, 255, 255), cv2.FILLED, offset=(-x+5, -y+5))
    img = cv2.drawContours(img, [cnt], -1, (0, 128, 0, 255), 3, offset=(-x+5, -y+5))
    imscatter(i, cv2.contourArea(cnt), img, zoom=0.5)
plt.tight_layout()
plt.show()

Надеюсь, это поможет!

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
Matplotlib:  3.2.0rc3
NumPy:       1.18.1
OpenCV:      4.2.0
----------------------------------------
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...