Python - Find center of object in an image

16,651

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.

result CoM

Remarks:

  • If you do not have numpy, you can still do it. It is just a bit more tedious as you have to do the summations by loops / comprehensions.
  • This method can easily be extended if you want to assign a 'mass' based on color. You just have to change 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.
  • If you want to avoid the double loop, you can us np.asarray(im), but then be careful with the indices

No 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
Share:
16,651

Related videos on Youtube

Nir
Author by

Nir

Automation software engineer and team leader at Waves Audio. Python is the main language that I code in. I'm also a sound engineer and a saxophone player.

Updated on June 04, 2022

Comments

  • Nir
    Nir almost 2 years

    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: Moon

    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)
    
  • PaulDong
    PaulDong about 7 years
    really good solution with clean code. Can I suggest to add a link to the intuition behind "You find the marginal distributions, then you calculate the expected values as if it was a discrete probability distribution."? I think it makes sense, but may not be as approachable to ppl who are not familiar with probability theory (which I think is beautiful).