我有一个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中那样轻松地绘制轮廓。
答案 0 :(得分:1)
使用cv2.drawContours
的offset
参数从轮廓生成单个图像并不复杂。可能只需要注意“标记图像”的适当透明背景即可。
我必须使用其他形状的图像,因为无法使用您的原始图像(必要的预处理略有不同):
包含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
----------------------------------------