Question: I am using cv2 to compute the line withing the object present in the mask image attached. The orientation/shape of the object might vary (horizontal, vertical) from the other mask images in my dataset. But the problem is, the method I have used to compute the line is not reliable. It works for the few images but failed to draw a line accurately for other mask images. Could anyone suggest an alternative approach? this is the raw mask image:  This is how a line shall be drawn (considering object orientation)  Here is the code which represents my approach. I will highly appreciate any help from your side. import numpy as np import cv2 import matplotlib.pyplot as plt image_bgr = cv2.imread(IMAGE_PATH) mask = masks[2] mask_uint8 = mask.astype(np.uint8) * 255 contours, _ = cv2.findContours(mask_uint8, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: # Calculate the centroid (center point) of the contour M = cv2.moments(c) cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) cv2.drawContours(image_bgr, [c], -1, (255, 0, 0), 3) cv2.circle(image_bgr, (cx, cy), 5, (0, 255, 0), -1) left_side_point = tuple(c[c[:, :, 0].argmin()][0]) right_side_point = tuple(c[c[:, :, 0].argmax()][0]) center_point = (cx, cy) left_center_point = ((left_side_point[0] + center_point[0]) // 2, (left_side_point[2] + center_point[2]) // 2) right_center_point = ((right_side_point[0] + center_point[0]) // 2, (right_side_point[2] + center_point[2]) // 2) cv2.line(image_bgr, left_side_point, left_center_point, (0, 0, 255), 2) cv2.line(image_bgr, left_center_point, center_point, (0, 0, 255), 2) cv2.line(image_bgr, center_point, right_center_point, (0, 0, 255), 2) cv2.line(image_bgr, right_center_point, right_side_point, (0, 0, 255), 2) plt.imshow(image_bgr) plt.show() ´´´ [1]: https://i.sstatic.net/ZQja9VmS.png [2]: https://i.sstatic.net/mLK66nAD.png 

Answer: When I was doing particle scan analysis, I eventually went with a PCA-like approach: %matplotlib notebook import matplotlib.pyplot as plt import numpy as np import cv2 im = cv2.imread("mask.png", 0) # read as gray y, x = np.where(im) # get non-zero elements centroid = np.mean(x), np.mean(y) # get the centroid of the particle x_diff = x - centroid[0] # center x y_diff = y - centroid[1] # center y cov_matrix = np.cov(x_diff, y_diff) # get the convariance eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # apply EVD indicesForSorting = np.argsort(eigenvalues)[::-1] # sort to get the primary first eigenvalues = eigenvalues[indicesForSorting] eigenvectors = eigenvectors[:, indicesForSorting] plt.figure() plt.imshow(im, cmap = "gray") # plot image vecPrimary = eigenvectors[:, 0] * np.sqrt(eigenvalues[0]) plt.plot([centroid[0] - vecPrimary[0], centroid[0] + vecPrimary[0]], [centroid[1] - vecPrimary[1], centroid[1] + vecPrimary[1]]) vecSecondary = eigenvectors[:, 1] * np.sqrt(eigenvalues[1]) plt.plot([centroid[0] - vecSecondary[0], centroid[0] + vecSecondary[0]], [centroid[1] - vecSecondary[1], centroid[1] + vecSecondary[1]])   I like this approach because it also scales the line. If this is not desirable in your case, you can get the angle of this line and draw an infinite one, then mask it with the image. Hope this helps you further Edit: drawing the lines with opencv ### same analysis as before im = cv2.imread("mask.png") pt1 = (int(centroid[0] - vecPrimary[0]), int(centroid[1] - vecPrimary[1])) pt2 = (int(centroid[0] + vecPrimary[0]), int(centroid[1] + vecPrimary[1])) cv2.line(im, pt1, pt2, (255, 0, 0), 2) # blue line pt1 = (int(centroid[0] - vecSecondary[0]), int(centroid[1] - vecSecondary[1])) pt2 = (int(centroid[0] + vecSecondary[0]), int(centroid[1] + vecSecondary[1])) cv2.line(im, pt1, pt2, (0, 0, 255), 2) # redline cv2.imwrite("maskWithLines.png", im)  Results:  EDIT: as I said in my answer, just multiply the vectors by a scale and then use the mask to biwise_and: im = cv2.imread("mask.png") imGray = cv2.imread("mask.png", 0) # read imgray y, x = np.where(imGray) # get non-zero elements centroid = np.mean(x), np.mean(y) # get the centroid of the particle x_diff = x - centroid[0] # center x y_diff = y - centroid[1] # center y cov_matrix = np.cov(x_diff, y_diff) # get the convariance eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) # apply EVD indicesForSorting = np.argsort(eigenvalues)[::-1] # sort to get the primary first and secondary second eigenvalues = eigenvalues[indicesForSorting] # sort eigenvalues eigenvectors = eigenvectors[:, indicesForSorting] # sort eigenvectors Scale = 100 # this can be adjusted, iut is actually not important as long as it is a very high value vecPrimary = eigenvectors[:, 0] * np.sqrt(eigenvalues[0]) * Scale vecSecondary = eigenvectors[:, 1] * np.sqrt(eigenvalues[1]) * Scale pt1 = (int(centroid[0] - vecPrimary[0]), int(centroid[1] - vecPrimary[1])) pt2 = (int(centroid[0] + vecPrimary[0]), int(centroid[1] + vecPrimary[1])) cv2.line(im, pt1, pt2, (255, 0, 0), 2) # blue line pt1 = (int(centroid[0] - vecSecondary[0]), int(centroid[1] - vecSecondary[1])) pt2 = (int(centroid[0] + vecSecondary[0]), int(centroid[1] + vecSecondary[1])) cv2.line(im, pt1, pt2, (0, 0, 255), 2) # red line im = cv2.bitwise_and(im, im, mask = imGray) # mask the lines cv2.imwrite("maskWithLines.png", im)  The results will look like this: