Jema
Jema

Reputation: 75

How to find orientation of an object in image?

I have bunch of images of gear and they all are in different orientation and I need them all in same orientation. I mean there is one reference image and rest of the images should be rotated so they look like same as reference image. I followed these steps, first segment the gear and then tried to find an angle using moments but its not working correctly. I've attached the 3 images considering the first image as reference image and here's the code so far

def adjust_gamma(image, gamma=1.0):
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255
            for i in np.arange(0, 256)]).astype("uint8")
    
    return cv2.LUT(image, table)

def unsharp_mask(image, kernel_size=(13, 13), sigma=1.0, amount=2.5, threshold=10):
    """Return a sharpened version of the image, using an unsharp mask."""
    blurred = cv2.GaussianBlur(image, kernel_size, sigma)
    sharpened = float(amount + 1) * image - float(amount) * blurred
    sharpened = np.maximum(sharpened, np.zeros(sharpened.shape))
    sharpened = np.minimum(sharpened, 255 * np.ones(sharpened.shape))
    sharpened = sharpened.round().astype(np.uint8)
    if threshold > 0:
        low_contrast_mask = np.absolute(image - blurred) < threshold
        np.copyto(sharpened, image, where=low_contrast_mask)
        
    return sharpened

def find_orientation(cont):
    m = cv2.moments(cont, True)
    cen_x = m['m10'] / m['m00']
    cen_y = m['m01'] / m['m00']

    m_11 = 2*m['m11'] - m['m00'] * (cen_x*cen_x+cen_y*cen_y)
    m_02 = m['m02'] - m['m00'] * cen_y*cen_y
    m_20 = m['m20'] - m['m00'] * cen_x*cen_x

    theta = 0 if m_20==m_02 else atan2(m_11, m_20-m_02)/2.0
    theta = theta * 180 / pi

    return (cen_x, cen_y, theta)

def rotate_image(img, angles):
    height, width = img.shape[:2]
    
    rotation_matrix = cv2.getRotationMatrix2D((width/2, height/2), angles, 1)
    rotated_image = cv2.warpAffine(img, rotation_matrix, (width,height))

    return rotated_image


img = cv2.imread('gear1.jpg')

resized_img = imutils.resize(img, width=540)
height, width = resized_img.shape[:2]

gamma_adjusted = adjust_gamma(resized_img, 2.5)
sharp = unsharp_mask(gamma_adjusted)
gray = cv2.cvtColor(sharp, cv2.COLOR_BGR2GRAY)
gauss_blur = cv2.GaussianBlur(gray, (13,13), 2.5)
ret, thresh = cv2.threshold(gauss_blur, 250, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_DILATE, kernel, iterations=2)

kernel = np.ones((3,3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

contours = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)[0]

cen_x, cen_y, theta = find_orientation(contours[0])

reference_angle = -24.14141919602858
rot_angle = 0.0
if theta < reference_angle:
    rot_angle = -(theta - reference_angle)
else:
    rot_angle = (reference_angle - theta)

rot_img = rotate_image(resized_img, rot_angle)

reference imagegear1gear2

Can anyone tell me where did i go wrong? Any help would be appreciated.

Upvotes: 1

Views: 756

Answers (1)

user1196549
user1196549

Reputation:

Binarization of the gear and the holes seems easy. You should be able to discriminate the holes from noise and extra small features.

First find the geometric center, and sort the holes by angle around the center. Also compute the areas of the holes. Then you can try to match the holes to the model in a cyclic way. There are 20 holes, and you just need to test 20 positions. You can rate a matching by some combination of the differences in the angles and the areas. The best match tells you the orientation.

This should be very reliable.

You can obtain a very accurate value of the angle by computing the average error per hole and correcting to cancel that value (this is equivalent to least-squares fitting).

Upvotes: 2

Related Questions