Rather than inspecting every single element (and stalling the CPU with an if
statement for every pixel) it is probably faster to sum all the elements down every column. They should come to 600*255, or 153,000 if they are all white. So, then find where 153,000 minus the column-total is non-zero. The first and last will be the top and bottom of the statue.
Then repeat across the rows to find left and right extrema.
So, starting with the greyscale image, run down each row totalling up the pixels:
import numpy as np
# Total up all the elements in each column
colsums = np.sum(gray, axis=0)
The sums of each column now look like this:
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)
Now find where those columns do not sum up to 153,000:
np.nonzero(153000-colsums)
That looks like this:
(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]),)
So the top row that doesn't consist entirely of white pixels is row 156 (the first entry) and the bottom row that doesn't entirely consist of white pixels is row 469 (the last entry).
Now sum across the other axis (axis=1) and do the same thing again to get left and right extrema.
boundingRect
also works on grayscale images, and you already have a binarized (threshold) image, you could also usex, y, w, h = cv2.boundingRect(thresh)
, and calculateleft
,right
, etc. from there with your approach usingnp.argmax
. I modified your code accordingly and got the same results. You save two LOC, and I could imagine, that this would be even faster (haven't timed it actually) than calculating the whole contour. Anyway, nice job, have my upvote. :-) – Anisotropic