我有这个雕像像。
我试图找到雕像上最顶部,最底部,最左侧和最右侧的点。有没有一种方法可以测量每边的边缘以确定雕像上最外面的点?我想获得每一边的(x,y)
坐标。我尝试使用cv2.findContours()
和cv2.drawContours()
来获得雕像的轮廓。
import cv2
img = cv2.imread('statue.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[0]
cv2.drawContours(img, contours, -1, (0, 200, 0), 3)
cv2.imshow('img', img)
cv2.waitKey()
答案 0 :(得分:8)
这是一种潜在的方法:
转换为灰度并模糊图像后,我们阈值以获取二进制图像
现在,我们使用cv2.findContours()
查找轮廓。由于OpenCV使用Numpy数组对图像进行编码,因此轮廓只是(x,y)
坐标的Numpy数组。我们可以对Numpy数组进行切片,并使用argmin()
或argmax()
来确定像这样的外部左,右,上和下坐标
left = tuple(c[c[:, :, 0].argmin()][0])
right = tuple(c[c[:, :, 0].argmax()][0])
top = tuple(c[c[:, :, 1].argmin()][0])
bottom = tuple(c[c[:, :, 1].argmax()][0])
这是结果
左:(162,527)
右:(463,467)
顶部:(250,8)
底部:(381,580)
import cv2
import numpy as np
image = cv2.imread('2.png')
blur = cv2.GaussianBlur(image, (3,3), 0)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY_INV)[1]
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
c = max(cnts, key=cv2.contourArea)
left = tuple(c[c[:, :, 0].argmin()][0])
right = tuple(c[c[:, :, 0].argmax()][0])
top = tuple(c[c[:, :, 1].argmin()][0])
bottom = tuple(c[c[:, :, 1].argmax()][0])
cv2.drawContours(image, [c], -1, (36, 255, 12), 2)
cv2.circle(image, left, 8, (0, 50, 255), -1)
cv2.circle(image, right, 8, (0, 255, 255), -1)
cv2.circle(image, top, 8, (255, 50, 0), -1)
cv2.circle(image, bottom, 8, (255, 255, 0), -1)
print('left: {}'.format(left))
print('right: {}'.format(right))
print('top: {}'.format(top))
print('bottom: {}'.format(bottom))
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
答案 1 :(得分:3)
这可能是对nathancy's answer的改进,它是大多数代码的来源,也是使用np.argmax
的主要思想。因此,请先查看该答案!
由于我们已经有一个来自cv2.threshold
的二值化图像,因此输入图像的(白色)背景被设置为零,因此我们可以使用cv2.boundingRect
的功能来“点集的右上边界矩形或灰度图像的非零像素” 。该方法返回一个元组(x, y, w, h)
,其中(x, y)
的左上点以及边界矩形的宽度w
和高度h
。从那里,可以在left
图像的相应切片上使用right
轻松获得提到的点np.argmax
,thresh
等。
完整代码如下:
import cv2
import numpy as np
image = cv2.imread('images/dMXjY.png')
blur = cv2.GaussianBlur(image, (3,3), 0)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY_INV)[1]
x, y, w, h = cv2.boundingRect(thresh) # Replaced code
#
left = (x, np.argmax(thresh[:, x])) #
right = (x+w-1, np.argmax(thresh[:, x+w-1])) #
top = (np.argmax(thresh[y, :]), y) #
bottom = (np.argmax(thresh[y+h-1, :]), y+h-1) #
cv2.circle(image, left, 8, (0, 50, 255), -1)
cv2.circle(image, right, 8, (0, 255, 255), -1)
cv2.circle(image, top, 8, (255, 50, 0), -1)
cv2.circle(image, bottom, 8, (255, 255, 0), -1)
print('left: {}'.format(left))
print('right: {}'.format(right))
print('top: {}'.format(top))
print('bottom: {}'.format(bottom))
cv2.imshow('thresh', thresh)
cv2.imshow('image', image)
cv2.waitKey()
图像输出看起来像是纳坦西的答案。
尽管如此,结果之一还是有些不同:
左:(162,527)
右:(463,461)(而不是(463,467))
顶部:(250,8)
底部:(381,580)
如果我们仔细查看thresh
图像,我们会发现对于第463
列,461 ... 467
范围内的所有像素的值均为{ {1}}。因此,对于右边缘,没有唯一的极值。
在nathancy的方法中找到的轮廓255
依次保持两个点c
和(463, 467)
,这样(463, 461)
会首先找到np.argmax
。在我的方法中,检查第(463, 467)
列是从463
到0
,这样(height of image)
会首先找到np.argmax
。
从我的角度来看,两个(或什至两者之间的所有其他点)都是合适的结果,因为在处理多个极端点时没有其他约束。
至少在使用(463, 461)
的一些简短测试中,使用cv2.boundingRect
可以节省两行代码,并且执行速度更快。
披露:同样,大多数代码和主要思想都来自nathancy's answer。
答案 2 :(得分:3)
与其检查每个元素(并为每个像素使用if
语句使CPU停顿),不如将所有元素加总到每一列上可能更快。它们应为600 * 255,如果全部为白色,则应为153,000。因此,然后找到153,000减去列总数的非零值。第一个和最后一个将是雕像的顶部和底部。
然后在各行中重复以找到左右极值。
因此,从灰度图像开始,将每一行向下累积总计像素:
import numpy as np
# Total up all the elements in each column
colsums = np.sum(gray, axis=0)
每列的总和现在看起来像这样:
array([153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 152991, 153000, 152976, 152920,
152931, 152885, 151600, 148818, 147448, 146802, 146568, 146367,
146179, 145888, 145685, 145366, 145224, 145066, 144745, 144627,
144511, 144698, 144410, 144329, 144162, 143970, 143742, 143381,
141860, 139357, 135358, 133171, 131138, 129246, 128410, 127866,
127563, 127223, 126475, 125614, 125137, 124848, 122906, 121653,
119278, 115548, 114473, 113800, 113486, 112655, 112505, 112670,
111845, 111124, 110378, 110315, 109996, 109693, 109649, 109411,
110626, 110628, 112247, 112348, 111865, 111571, 110601, 108308,
107213, 106768, 105546, 103971, 103209, 101866, 100215, 98964,
98559, 97008, 94981, 94513, 92490, 91555, 91491, 90072,
88642, 87210, 86960, 86834, 85759, 84496, 83237, 81911,
80249, 78942, 77715, 76918, 75746, 75826, 75443, 75087,
75156, 75432, 75730, 75699, 77028, 77825, 76813, 76718,
75958, 75207, 74216, 73042, 72527, 72043, 71819, 71384,
70693, 69922, 69537, 69685, 69688, 69876, 69552, 68937,
68496, 67942, 67820, 67626, 67627, 68113, 68426, 67894,
67868, 67365, 66191, 65334, 65752, 66438, 66285, 66565,
67616, 69090, 69386, 69928, 70470, 70318, 70228, 71028,
71197, 71827, 71712, 71312, 72013, 72878, 73398, 74038,
75017, 76270, 76087, 75317, 75210, 75497, 75099, 75620,
75059, 75008, 74146, 73531, 73556, 73927, 75395, 77235,
77094, 77229, 77463, 77808, 77538, 77104, 76816, 76500,
76310, 76331, 76889, 76293, 75626, 74966, 74871, 74950,
74931, 74852, 74885, 75077, 75576, 76104, 76208, 75387,
74971, 75878, 76311, 76566, 77014, 77205, 77231, 77456,
77983, 78379, 78793, 78963, 79154, 79710, 80777, 82547,
85164, 88944, 91269, 92438, 93646, 94836, 96071, 97918,
100244, 102011, 103553, 104624, 104961, 105354, 105646, 105866,
106367, 106361, 106461, 106659, 106933, 107055, 106903, 107028,
107080, 107404, 107631, 108022, 108194, 108261, 108519, 109023,
109349, 109873, 110373, 110919, 111796, 112587, 113219, 114143,
115161, 115733, 116531, 117615, 118338, 119414, 120492, 121332,
122387, 123824, 124938, 126113, 127465, 128857, 130411, 131869,
133016, 133585, 134442, 135772, 136440, 136828, 137200, 137418,
137705, 137976, 138167, 138481, 138788, 138937, 139194, 139357,
139375, 139583, 139924, 140201, 140716, 140971, 141285, 141680,
141837, 141975, 142260, 142567, 142774, 143154, 143533, 143853,
144521, 145182, 145832, 147978, 149006, 150026, 151535, 152753,
152922, 152960, 152990, 152991, 153000, 152995, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000,
153000, 153000, 153000, 153000, 153000, 153000, 153000, 153000],
dtype=uint64)
现在找到那些列的总和不超过153,000:
np.nonzero(153000-colsums)
看起来像这样:
(array([156, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195,
196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286,
287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312,
313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325,
326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338,
339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351,
352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377,
378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390,
391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403,
404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416,
417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429,
430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442,
443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455,
456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 469]),)
因此,不完全由白色像素组成的第一行是第156行(第一个条目),不完全由白色像素组成的下一行是469行(最后一个条目)。
现在将另一个轴(轴= 1)上的和求和,并再次执行相同的操作以获取左右极值。
答案 3 :(得分:1)
import cv2
import numpy as np
img = cv2.imread('statue.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY_INV)[1]
sz=thresh.shape
top=divmod(np.flatnonzero(thresh)[0], sz[0])[::-1]
botton=divmod(np.flatnonzero(thresh)[-1], sz[0])[::-1]
thresh=thresh.T
left=divmod(np.flatnonzero(thresh)[0], sz[1])
right=divmod(np.flatnonzero(thresh)[-1], sz[1])
print(left, right, top, botton, sep='\n')
答案 4 :(得分:0)
您不需要昂贵的代码,例如 public class foo
{
public Guid id { get; set; }
}
public class foo2
{
public Guid id { get; set; }
}
public IReadOnlyCollection<T> GetDocumentAsync<T>(Guid id) where T: class
{
var searchResponse = _client.Search<T>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.id) //f.id is not a property of T
.Query(id.ToString())
)
)
);
return searchResponse.Documents;
}
。您只需要从外到内4个面逐行扫描图像,直到找到第一个非白色像素即可。
从左开始,从左上到左下扫描。如果找不到白色像素,请向右移动1像素,然后再次从上到下移动。找到非白色像素后,即为findContours
。
对所有方面都做同样的事情。