I have an image file that's has a white background with a non-white object. I want to find the center of the object using python (Pillow).
I have found a similar question in c++ but no acceptable answer - How can I find center of object?
Similar question, but with broken links in answer - What is the fastest way to find the center of an irregularly shaped polygon? (broken links in answer)
I also read this page but it doesn't give me a useful recipe - https://en.wikipedia.org/wiki/Smallest-circle_problem
Here's an example image:
Edit: The current solution I'm using is this:
def find_center(image_file):
img = Image.open(image_file)
img_mtx = img.load()
top = bottom = 0
first_row = True
# First we find the top and bottom border of the object
for row in range(img.size[0]):
for col in range(img.size[1]):
if img_mtx[row, col][0:3] != (255, 255, 255):
bottom = row
if first_row:
top = row
first_row = False
middle_row = (top + bottom) / 2 # Calculate the middle row of the object
left = right = 0
first_col = True
# Scan through the middle row and find the left and right border
for col in range(img.size[1]):
if img_mtx[middle_row, col][0:3] != (255, 255, 255):
left = col
if first_col:
right = col
first_col = False
middle_col = (left + right) / 2 # Calculate the middle col of the object
return (middle_row, middle_col)
To find out the center of an object, you can use the Moments. Threshold the image and get the contours of the object with findContours. Compute the Moments withcv.Moments(arr, binary=0) → moments. As arryou can pass the contours.
Find Circles and Ellipses in an Image using OpenCV | Python. To identify circles, ellipses or in general any shape in which the pixels are connected we use the SimpleBlobDetector() function of OpenCV. In non-technical terms, a blob is understood as a thick liquid drop.
Placing a white circle at the center (cX, cY) -coordinates of the shape. Writing the text center near the white circle. To execute our script, just open up a terminal and execute the following command: Figure 3: Looping over each of the shapes individually and then computing the center (x, y)-coordinates for each shape.
To find the centroid of the image, we generally convert it to binary format and then find its center. is the x coordinate and is the y coordinate of the centroid and denotes the Moment.
If you define center as Center of Mass, then it is not difficult, although the CoM can be outside of your shape. You can interpret your image as a 2D distribution, and you can find its expected value (CoM) using integration (summation).
If you have numpy it is quite simple. First create a numpy array containing 1 where your image is non-white, then to make it a probability distribution divide it by the total number of ones.
from PIL import Image
import numpy as np
im = Image.open('image.bmp')
immat = im.load()
(X, Y) = im.size
m = np.zeros((X, Y))
for x in range(X):
for y in range(Y):
m[x, y] = immat[(x, y)] != (255, 255, 255)
m = m / np.sum(np.sum(m))
From this point on it turns into basic probability theory. You find the marginal distributions, then you calculate the expected values as if it was a discrete probability distribution.
# marginal distributions
dx = np.sum(m, 1)
dy = np.sum(m, 0)
# expected values
cx = np.sum(dx * np.arange(X))
cy = np.sum(dy * np.arange(Y))
(cx, cy)
is the CoM you are looking for.
Remarks:
m[x, y] = immat[(x, y)] != (255, 255, 255)
to m[x, y] = f(immat[(x, y)])
where f
is an arbitary (non-negative valued) function.np.asarray(im)
, but then be careful with the indicesNo loops:
m = np.sum(np.asarray(im), -1) < 255*3
m = m / np.sum(np.sum(m))
dx = np.sum(m, 0) # there is a 0 here instead of the 1
dy = np.sum(m, 1) # as np.asarray switches the axes, because
# in matrices the vertical axis is the main
# one, while in images the horizontal one is
# the first
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With