skimage.measure.regionprops
will do what you want. Here's an example:
import imageio as iio
from skimage import filters
from skimage.color import rgb2gray # only needed for incorrectly saved images
from skimage.measure import regionprops
image = rgb2gray(iio.imread('eyeball.png'))
threshold_value = filters.threshold_otsu(image)
labeled_foreground = (image > threshold_value).astype(int)
properties = regionprops(labeled_foreground, image)
center_of_mass = properties[0].centroid
weighted_center_of_mass = properties[0].weighted_centroid
print(center_of_mass)
On my machine and with your example image, I get (228.48663375508113, 200.85290046969845)
.
We can make a pretty picture:
import matplotlib.pyplot as plt
from skimage.color import label2rgb
colorized = label2rgb(labeled_foreground, image, colors=['black', 'red'], alpha=0.1)
fig, ax = plt.subplots()
ax.imshow(colorized)
# Note the inverted coordinates because plt uses (x, y) while NumPy uses (row, column)
ax.scatter(center_of_mass[1], center_of_mass[0], s=160, c='C0', marker='+')
plt.show()
That gives me this output:

You'll note that there's some bits of foreground that you probably don't want in there, like at the bottom right of the picture. That's a whole nother answer, but you can look at scipy.ndimage.label
, skimage.morphology.remove_small_objects
, and more generally at skimage.segmentation
.