使用Python OpenCV查找图像中的极端外部点
我有一尊雕像的图像 我在试着找到雕像的顶部、底部、左侧和右侧。有没有办法测量每一面的边缘来确定雕像最外面的点?我想得到两边的使用Python OpenCV查找图像中的极端外部点,python,image,opencv,image-processing,computer-vision,Python,Image,Opencv,Image Processing,Computer Vision,我有一尊雕像的图像 我在试着找到雕像的顶部、底部、左侧和右侧。有没有办法测量每一面的边缘来确定雕像最外面的点?我想得到两边的(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.
(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()
以下是一种可能的方法:
- 将图像转换为和
- 获取二值图像
- 获取外部坐标
在转换为灰度和模糊图像后,我们对图像进行阈值处理,得到一幅二值图像 现在我们使用
cv2.findContours()
查找轮廓。由于OpenCV使用Numpy数组对图像进行编码,因此轮廓只是(x,y)
坐标的Numpy数组。我们可以对Numpy数组进行切片,然后使用或来确定外部的左、右、上、下坐标,如下所示
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])
这是结果
左:(162527)
右:(463467)
顶部:(250,8)
底部:(381580)
这里有一个可能的改进,大部分代码都来自于此,这也是使用的主要思想。所以,请先看看这个答案
由于我们已经有了来自的二值化图像,因此输入图像的(白色)背景设置为零,因此我们可以使用的功能“计算点集的右上边界矩形或灰度图像的非零像素”。该方法返回一个元组
(x,y,w,h)
,其中(x,y)
为边界矩形的左上点以及宽度w
和高度h
。从那里,可以使用thresh
图像对应切片上的np.argmax
轻松获得所述点left
、right
等
下面是完整的代码:
导入cv2
将numpy作为np导入
image=cv2.imread('images/dMXjY.png')
模糊=cv2.高斯模糊(图像,(3,3),0)
灰色=cv2.CVT颜色(模糊,cv2.COLOR\u BGR2GRAY)
thresh=cv2.阈值(灰色,220255,cv2.thresh\u二进制\u INV)[1]
x、 y,w,h=cv2.boundingRect(thresh)#替换代码
#
左=(x,np.argmax(thresh[:,x])#
右=(x+w-1,np.argmax(thresh[:,x+w-1])#
top=(np.argmax(thresh[y,:]),y)#
底部=(np.argmax(thresh[y+h-1,:]),y+h-1)#
cv2.圆(图,左,8,(0,50,255),-1)
cv2.圆(图,右,8,(0,255,255),-1)
cv2.圆(图像,顶部,8,(255,50,0),-1)
cv2.圆(图像,底部,8,(255,255,0),-1)
打印('左:{}'。格式(左))
打印('右:{}'。格式(右))
打印('top:{}'。格式(top))
打印('bottom:{}'。格式(bottom))
cv2.imshow('thresh',thresh)
cv2.imshow(“图像”,图像)
cv2.waitKey()
图像输出看起来与nathancy的答案类似
然而,其中一个结果有点不同:
左:(162527)
右:(463461)(代替(463467))
顶部:(250,8)
底部:(381580)
如果我们仔细查看thresh
图像,我们将看到463
第列中461范围内的所有像素。。。467
的值为255
。所以,对于右边缘,没有唯一的极值
nathancy方法中的等高线c
将两个点(463467)
和(463461)
按顺序保存,这样np.argmax
将首先找到(463467)
。在我的方法中,从0
到(图像高度)
检查463
-th列,这样np.argmax
将首先找到(463461)
在我看来,这两个点(甚至中间的所有其他点)都是合适的结果,因为在处理多个极值点时没有额外的约束
使用cv2.boundingRect
可以保存两行代码,而且执行速度更快,至少根据使用timeit
的一些简短测试
披露:同样,大部分代码和主要思想都来自。您不需要像
FindContentours这样昂贵的代码。您只需从外到内的4个面逐行扫描图像,直到找到第一个非白色像素
从左侧开始从左上到左下扫描。如果没有找到白色像素,请向右移动1个像素,然后再次从上到下移动。一旦找到非白色像素,这就是您的左侧
对所有方面都做同样的操作。与其检查每个元素(并对每个像素使用if
语句暂停CPU),不如将每个列中的所有元素相加。它们的值应该是600*255,如果它们都是白色,则为153000。那么,找出其中153000减去列总数是非零的。第一个和最后一个是雕像的顶部和底部
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()
然后在各行中重复,以找到左右极值
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')
因此,从灰度图像开始,沿着每一行计算像素总数:
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)
(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]),)
现在找出那些列的总和不等于153000的地方:
np.nonzero(153000-colsums)
看起来是这样的:
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)
(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)上求和,并再次执行相同的操作以获得左右极值。由于也适用于灰度图像,并且您已经有了二值化(阈值)图像,您还可以使用x,y,w,h=cv2.boundingRect(thresh)
,并计算左,右,然后使用np.argmax
使用您的方法。我修改了你的密码
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')