Setting a circle to a binary image

I use threshold age algorithms to get some binary mask. For example, I get binary images as follows:

Binary image obtained as a result of Otsu thresholding

What I'm trying to figure out is how I can put a circle in this binary mask. A constraint is a circle that should cover as many white areas as possible, and the entire circumference of the circle should lie entirely on the white parts.

I was ruining my head by how I can do this efficiently, but did not come up with any solution that works.

One approach I thought there might be something to eat:

  • Find the optimal center of the image / circle (I'm not sure how to do this. Perhaps some kind of raster search is similar to the approach).
  • Calculate a circle to increase the radius and find out when it starts to leave the white area or outside the image.
  • Then the centroid and radius will describe the circle.
+6
source share
5 answers

Here is a solution that tries to minimize the optimal range. It soon becomes apparent that the bubble is not a circle :) Note the use of "regionprops" to easily identify areas, center, etc. Regions.

Circle fit to bubble

from skimage import io, color, measure, draw, img_as_bool import numpy as np from scipy import optimize import matplotlib.pyplot as plt image = img_as_bool(color.rgb2gray(io.imread('bubble.jpg'))) regions = measure.regionprops(image) bubble = regions[0] y0, x0 = bubble.centroid r = bubble.major_axis_length / 2. def cost(params): x0, y0, r = params coords = draw.circle(y0, x0, r, shape=image.shape) template = np.zeros_like(image) template[coords] = 1 return -np.sum(template == image) x0, y0, r = optimize.fmin(cost, (x0, y0, r)) import matplotlib.pyplot as plt f, ax = plt.subplots() circle = plt.Circle((x0, y0), r) ax.imshow(image, cmap='gray', interpolation='nearest') ax.add_artist(circle) plt.show() 
+5
source

This should give very good and reliable results:

 import numpy as np from skimage import measure, feature, io, color, draw img = color.rgb2gray(io.imread("circle.jpg")) img = feature.canny(img).astype(np.uint8) img[img > 0] = 255 coords = np.column_stack(np.nonzero(img)) model, inliers = measure.ransac(coords, measure.CircleModel, min_samples=3, residual_threshold=1, max_trials=500) print model.params rr, cc = draw.circle(model.params[0], model.params[1], model.params[2], shape=img.shape) img[rr, cc] = 128 
+5
source

Actually this is a problem that is mainly resolved when processing images. It looks like you want a Hough Transform , particularly circular or elliptical. I believe that the roundabout as a whole is less intense.

Here are some sample code for scikit-image that shows exactly what you are trying to do. And here is the link to the documentation .

+1
source

Updated Answer

In fact, if you use Connected Components Analysis, aka Blob Analysis, you can do it with ImageMagick much more succinctly and exactly like this:

 convert 3J3qz.jpg \ -define connected-components:verbose=true \ -define connected-components:area-threshold=100 \ -connected-components 8 null: 

Output:

 Objects (id: bounding-box centroid area mean-color): 0: 720x576+0+0 370.6,322.1 213779 srgb(0,0,0) 13: 488x513+104+0 347.7,250.7 200941 srgb(255,255,255) <-- answer 

which shows that your largest blob (speech bubble) has a center of gravity at 347,250 coordinates from the upper left corner, and also gives a bounding box that measures 488x513 pixels, and its upper left corner is 104.0, from which you can get the radius .

I can mark them with ImageMagick as follows:

 convert 3J3qz.jpg \ -fill red -draw "rectangle 342,245 352,255" -stroke red -fill none -draw "rectangle 104,0 592,513" out.png 

enter image description here

Original answer

As you are curious ... you can do what I suggested with ImageMagick in two lines:

 convert 3J3qz.jpg -resize 1x! -colorspace gray txt: # ImageMagick pixel enumeration: 1,576,255,gray 0,0: (66,66,66) #424242 gray(66) 0,1: (70,70,70) #464646 gray(70) 0,2: (72,72,72) #484848 gray(72) 0,3: (76,76,76) #4C4C4C gray(76) ... 0,152: (176,176,176) #B0B0B0 gray(176) 0,153: (176,176,176) #B0B0B0 gray(176) 0,154: (177,177,177) #B1B1B1 gray(177) 0,155: (177,177,177) #B1B1B1 gray(177) 0,156: (177,177,177) #B1B1B1 gray(177) 0,157: (177,177,177) #B1B1B1 gray(177) 0,158: (178,178,178) #B2B2B2 gray(178) 0,159: (178,178,178) #B2B2B2 gray(178) 0,160: (179,179,179) #B3B3B3 gray(179) 0,161: (179,179,179) #B3B3B3 gray(179) 0,162: (179,179,179) #B3B3B3 gray(179) 0,163: (179,179,179) #B3B3B3 gray(179) 0,164: (179,179,179) #B3B3B3 gray(179) 0,165: (179,179,179) #B3B3B3 gray(179) 0,166: (179,179,179) #B3B3B3 gray(179) 0,167: (179,179,179) #B3B3B3 gray(179) 0,168: (180,180,180) #B4B4B4 gray(180) 0,169: (180,180,180) #B4B4B4 gray(180) 0,170: (180,180,180) #B4B4B4 gray(180) 0,171: (180,180,180) #B4B4B4 gray(180) 0,172: (180,180,180) #B4B4B4 gray(180) 0,173: (180,180,180) #B4B4B4 gray(180) 0,174: (180,180,180) #B4B4B4 gray(180) 0,175: (180,180,180) #B4B4B4 gray(180) 0,176: (181,181,181) #B5B5B5 gray(181) 0,177: (181,181,181) #B5B5B5 gray(181) 0,178: (182,182,182) #B6B6B6 gray(182) 0,179: (182,182,182) #B6B6B6 gray(182) 0,180: (182,182,182) #B6B6B6 gray(182) 0,181: (182,182,182) #B6B6B6 gray(182) 0,182: (182,182,182) #B6B6B6 gray(182) 0,183: (182,182,182) #B6B6B6 gray(182) 0,184: (183,183,183) #B7B7B7 gray(183) 0,185: (183,183,183) #B7B7B7 gray(183) 0,186: (183,183,183) #B7B7B7 gray(183) 0,187: (183,183,183) #B7B7B7 gray(183) 0,188: (183,183,183) #B7B7B7 gray(183) 0,189: (183,183,183) #B7B7B7 gray(183) 0,190: (183,183,183) #B7B7B7 gray(183) 0,191: (183,183,183) #B7B7B7 gray(183) 0,192: (184,184,184) #B8B8B8 gray(184) 0,193: (184,184,184) #B8B8B8 gray(184) 0,194: (184,184,184) #B8B8B8 gray(184) 0,195: (184,184,184) #B8B8B8 gray(184) 0,196: (184,184,184) #B8B8B8 gray(184) 0,197: (184,184,184) #B8B8B8 gray(184) 0,198: (184,184,184) #B8B8B8 gray(184) 0,199: (184,184,184) #B8B8B8 gray(184) 0,200: (185,185,185) #B9B9B9 gray(185) 0,201: (185,185,185) #B9B9B9 gray(185) 0,202: (185,185,185) #B9B9B9 gray(185) 0,203: (185,185,185) #B9B9B9 gray(185) 0,204: (185,185,185) #B9B9B9 gray(185) 0,205: (185,185,185) #B9B9B9 gray(185) 0,206: (185,185,185) #B9B9B9 gray(185) 0,207: (185,185,185) #B9B9B9 gray(185) 0,208: (186,186,186) #BABABA gray(186) 0,209: (186,186,186) #BABABA gray(186) 0,210: (186,186,186) #BABABA gray(186) 0,211: (186,186,186) #BABABA gray(186) 0,212: (185,185,185) #B9B9B9 gray(185) 0,213: (186,186,186) #BABABA gray(186) 0,214: (186,186,186) #BABABA gray(186) 0,215: (186,186,186) #BABABA gray(186) 0,216: (186,186,186) #BABABA gray(186) 0,217: (186,186,186) #BABABA gray(186) 0,218: (186,186,186) #BABABA gray(186) 0,219: (186,186,186) #BABABA gray(186) 0,220: (186,186,186) #BABABA gray(186) 0,221: (186,186,186) #BABABA gray(186) 0,222: (186,186,186) #BABABA gray(186) 0,223: (186,186,186) #BABABA gray(186) 0,224: (186,186,186) #BABABA gray(186) 0,225: (186,186,186) #BABABA gray(186) 0,226: (186,186,186) #BABABA gray(186) 0,227: (186,186,186) #BABABA gray(186) 0,228: (187,187,187) #BBBBBB gray(187) 0,229: (187,187,187) #BBBBBB gray(187) 0,230: (187,187,187) #BBBBBB gray(187) 0,231: (187,187,187) #BBBBBB gray(187) 0,232: (187,187,187) #BBBBBB gray(187) 0,233: (187,187,187) #BBBBBB gray(187) 0,234: (187,187,187) #BBBBBB gray(187) <---- max=234 0,235: (187,187,187) #BBBBBB gray(187) 0,236: (187,187,187) #BBBBBB gray(187) 0,237: (187,187,187) #BBBBBB gray(187) 0,238: (187,187,187) #BBBBBB gray(187) 0,239: (187,187,187) #BBBBBB gray(187) 0,240: (187,187,187) #BBBBBB gray(187) 0,241: (187,187,187) #BBBBBB gray(187) 0,242: (187,187,187) #BBBBBB gray(187) 0,243: (187,187,187) #BBBBBB gray(187) 0,244: (187,187,187) #BBBBBB gray(187) 0,245: (187,187,187) #BBBBBB gray(187) 0,246: (187,187,187) #BBBBBB gray(187) 0,247: (187,187,187) #BBBBBB gray(187) 0,248: (187,187,187) #BBBBBB gray(187) 0,249: (187,187,187) #BBBBBB gray(187) 0,250: (187,187,187) #BBBBBB gray(187) ... 0,573: (0,0,0) #000000 gray(0) 0,574: (0,0,0) #000000 gray(0) 0,575: (0,0,0) #000000 gray(0) 

And the other side

 convert 3J3qz.jpg -resize x1! -colorspace gray txt: # ImageMagick pixel enumeration: 720,1,255,gray 0,0: (0,0,0) #000000 gray(0) 1,0: (0,0,0) #000000 gray(0) 2,0: (0,0,0) #000000 gray(0) 3,0: (0,0,0) #000000 gray(0) 4,0: (0,0,0) #000000 gray(0) ... 241,0: (219,219,219) #DBDBDB gray(219) 242,0: (220,220,220) #DCDCDC gray(220) 243,0: (220,220,220) #DCDCDC gray(220) 244,0: (221,221,221) #DDDDDD gray(221) 245,0: (222,222,222) #DEDEDE gray(222) 246,0: (223,223,223) #DFDFDF gray(223) 247,0: (223,223,223) #DFDFDF gray(223) 248,0: (224,224,224) #E0E0E0 gray(224) 249,0: (224,224,224) #E0E0E0 gray(224) 250,0: (225,225,225) #E1E1E1 gray(225) 251,0: (227,227,227) #E3E3E3 gray(227) 252,0: (229,229,229) #E5E5E5 gray(229) 253,0: (230,230,230) #E6E6E6 gray(230) 254,0: (231,231,231) #E7E7E7 gray(231) 255,0: (232,232,232) #E8E8E8 gray(232) <--- max=255 256,0: (231,231,231) #E7E7E7 gray(231) 257,0: (231,231,231) #E7E7E7 gray(231) 258,0: (231,231,231) #E7E7E7 gray(231) 259,0: (231,231,231) #E7E7E7 gray(231) 260,0: (230,230,230) #E6E6E6 gray(230) 261,0: (230,230,230) #E6E6E6 gray(230) 262,0: (230,230,230) #E6E6E6 gray(230) 263,0: (230,230,230) #E6E6E6 gray(230) 264,0: (230,230,230) #E6E6E6 gray(230) 265,0: (230,230,230) #E6E6E6 gray(230) 266,0: (230,230,230) #E6E6E6 gray(230) 267,0: (230,230,230) #E6E6E6 gray(230) 268,0: (229,229,229) #E5E5E5 gray(229) 269,0: (230,230,230) #E6E6E6 gray(230) 270,0: (229,229,229) #E5E5E5 gray(229) 271,0: (229,229,229) #E5E5E5 gray(229) 272,0: (229,229,229) #E5E5E5 gray(229) 273,0: (229,229,229) #E5E5E5 gray(229) 274,0: (229,229,229) #E5E5E5 gray(229) 275,0: (229,229,229) #E5E5E5 gray(229) 276,0: (229,229,229) #E5E5E5 gray(229) 277,0: (229,229,229) #E5E5E5 gray(229) 278,0: (229,229,229) #E5E5E5 gray(229) 279,0: (229,229,229) #E5E5E5 gray(229) 280,0: (229,229,229) #E5E5E5 gray(229) 281,0: (229,229,229) #E5E5E5 gray(229) 282,0: (229,229,229) #E5E5E5 gray(229) 283,0: (229,229,229) #E5E5E5 gray(229) 284,0: (229,229,229) #E5E5E5 gray(229) 285,0: (229,229,229) #E5E5E5 gray(229) 286,0: (229,229,229) #E5E5E5 gray(229) 287,0: (230,230,230) #E6E6E6 gray(230) 288,0: (230,230,230) #E6E6E6 gray(230) 289,0: (230,230,230) #E6E6E6 gray(230) 290,0: (230,230,230) #E6E6E6 gray(230) 291,0: (230,230,230) #E6E6E6 gray(230) 292,0: (230,230,230) #E6E6E6 gray(230) 293,0: (230,230,230) #E6E6E6 gray(230) 294,0: (230,230,230) #E6E6E6 gray(230) 295,0: (231,231,231) #E7E7E7 gray(231) 296,0: (231,231,231) #E7E7E7 gray(231) 297,0: (231,231,231) #E7E7E7 gray(231) 298,0: (231,231,231) #E7E7E7 gray(231) 299,0: (231,231,231) #E7E7E7 gray(231) 300,0: (231,231,231) #E7E7E7 gray(231) 301,0: (231,231,231) #E7E7E7 gray(231) 302,0: (231,231,231) #E7E7E7 gray(231) 303,0: (231,231,231) #E7E7E7 gray(231) 304,0: (232,232,232) #E8E8E8 gray(232) 305,0: (231,231,231) #E7E7E7 gray(231) 306,0: (231,231,231) #E7E7E7 gray(231) 307,0: (231,231,231) #E7E7E7 gray(231) 308,0: (231,231,231) #E7E7E7 gray(231) 309,0: (232,232,232) #E8E8E8 gray(232) 310,0: (232,232,232) #E8E8E8 gray(232) 311,0: (232,232,232) #E8E8E8 gray(232) 312,0: (233,233,233) #E9E9E9 gray(233) 313,0: (232,232,232) #E8E8E8 gray(232) 314,0: (232,232,232) #E8E8E8 gray(232) 315,0: (232,232,232) #E8E8E8 gray(232) 316,0: (232,232,232) #E8E8E8 gray(232) 317,0: (232,232,232) #E8E8E8 gray(232) 318,0: (232,232,232) #E8E8E8 gray(232) 319,0: (232,232,232) #E8E8E8 gray(232) 320,0: (232,232,232) #E8E8E8 gray(232) 321,0: (233,233,233) #E9E9E9 gray(233) 322,0: (233,233,233) #E9E9E9 gray(233) 323,0: (233,233,233) #E9E9E9 gray(233) 324,0: (233,233,233) #E9E9E9 gray(233) 325,0: (233,233,233) #E9E9E9 gray(233) 326,0: (233,233,233) #E9E9E9 gray(233) 327,0: (233,233,233) #E9E9E9 gray(233) 328,0: (233,233,233) #E9E9E9 gray(233) 329,0: (233,233,233) #E9E9E9 gray(233) 330,0: (233,233,233) #E9E9E9 gray(233) 331,0: (233,233,233) #E9E9E9 gray(233) 332,0: (233,233,233) #E9E9E9 gray(233) 333,0: (233,233,233) #E9E9E9 gray(233) 334,0: (233,233,233) #E9E9E9 gray(233) 335,0: (233,233,233) #E9E9E9 gray(233) 336,0: (233,233,233) #E9E9E9 gray(233) 337,0: (233,233,233) #E9E9E9 gray(233) 338,0: (233,233,233) #E9E9E9 gray(233) 339,0: (233,233,233) #E9E9E9 gray(233) 340,0: (233,233,233) #E9E9E9 gray(233) 341,0: (233,233,233) #E9E9E9 gray(233) 342,0: (233,233,233) #E9E9E9 gray(233) 343,0: (233,233,233) #E9E9E9 gray(233) 344,0: (233,233,233) #E9E9E9 gray(233) 345,0: (233,233,233) #E9E9E9 gray(233) 346,0: (233,233,233) #E9E9E9 gray(233) 347,0: (233,233,233) #E9E9E9 gray(233) 348,0: (233,233,233) #E9E9E9 gray(233) 349,0: (233,233,233) #E9E9E9 gray(233) 350,0: (233,233,233) #E9E9E9 gray(233) 351,0: (233,233,233) #E9E9E9 gray(233) 352,0: (233,233,233) #E9E9E9 gray(233) 353,0: (233,233,233) #E9E9E9 gray(233) 354,0: (233,233,233) #E9E9E9 gray(233) ... 717,0: (0,0,0) #000000 gray(0) 718,0: (0,0,0) #000000 gray(0) 719,0: (0,0,0) #000000 gray(0) 
+1
source

For someone looking for Mark's offer code in python, this is pretty simple.

 collapsed = np.sum(binary_array, axis=0) # These indices will be already sorted indices = np.where(collapsed == collapsed.max())[0] c = indices[int(round((len(indices) - 1) / 2))] # Same for rows collapsed = np.sum(binary_array, axis=1) # These indices will be already sorted indices = np.where(collapsed == collapsed.max())[0] r = indices[int(round((len(indices) - 1) / 2))] # circle center is (r, c) 

This code takes over when your shape is not spherical, and collapse along the axes can have several maxima. In this case, it takes an average (one that can give you the largest radius when you fit into a circle).

0
source

Source: https://habr.com/ru/post/981880/


All Articles