【问题标题】:How to convert contour to marker for plotting?如何将轮廓转换为标记以进行绘图?
【发布时间】:2020-06-15 04:23:07
【问题描述】:

我有一个image,我已经使用 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()

现在我想用轮廓作为标记来绘制它们,比如:

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()

我不知道从哪里开始将轮廓转换为标记。我知道轮廓被保存为点的集合,并且看着this post,将它们从图像中裁剪出来并不简单。相反,会创建蒙版或从图像中裁剪出矩形。但是,如果形状不符合规则多边形,则此技术不起作用。如果轮廓可以转换为图像,那么它们可以像this example 一样轻松绘制。

【问题讨论】:

    标签: python image opencv image-processing contour


    【解决方案1】:

    使用cv2.drawContoursoffset 参数从轮廓生成单张图像并不复杂。人们可能只想注意“标记图像”的适当透明背景。

    我不得不使用不同形状的图像,因为我无法使用您的原始图像(必要的预处理略有不同):

    包含answer you linked 的输出如下所示:

    这是完整的代码:

    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
    ----------------------------------------
    

    【讨论】:

    • 是的,这很棒!当然,我仍在修改绘图细节,但 OffsetImageAnnotationBbox 的合并很棒。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多