Is there a strait forward way to force a mask to be aligned vertically / horizontally?

I’ve got this geometric shape that I simply want to rotate to be aligned vertically.

I can’t find information online on how to do this, how would you proceed ?

see

change the line

as

thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)[1]

result
Rotated

Given an image processing problem like that, I think of two approaches to try. I’m rusty on OpenCV, so I’ll describe what I’d do in more general terms.

  1. Blur the image with a small radius, about 2 to 4 pixels. Then compute gradient vectors everywhere in the image. With broad black or white areas, they’re zero. Ignore any gradients smaller than some threshold. The bigger ones - make a histogram of directions. Magnitudes don’t matter (aside from the thresholding). There will be strong peaks in that histogram. Those correspond to angles of sides of the shapes in the mask. From the exact locations of the peaks, create a rotation matrix.

  2. Fourier transform the image. Power spectrum, just the magnitudes (squared) of the amplitudes. There may be features, blobs, dark lines, or something that can be identified and measured. Rotation of the image equals rotation of the Fourier power spectrum.

Thanks everyone for the answers, I’ve found an iterative approach that kind of works for this exemple:

def align_vertically(src, mask):
    # img must be grayscale 2D numpy array
    img = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
    
    degree = []
    to_max = []
    step = 1
    init_black_col = img.shape[1] - np.count_nonzero(img.sum(axis = 0))
    
    # rotating positive or negative ?
    rot_pos_black_col = img.shape[1] - np.count_nonzero(imutils.rotate(img, 1).sum(axis = 0))
    
    if rot_pos_black_col > init_black_col:
        
        # positive rotation
        for deg in range(0,91,step):
            black_col = img.shape[1] - np.count_nonzero(imutils.rotate(img, deg).sum(axis = 0))
            degree.append(deg)
            to_max.append(black_col)
            
    else:
        
        # negative rotation
        for deg in range(0,-91,-step):
            black_col = img.shape[1] - np.count_nonzero(imutils.rotate(img, deg).sum(axis = 0))
            degree.append(deg)
            to_max.append(black_col)
    
    max_value = max(to_max)
    max_index = to_max.index(max_value)
    rot_degree = degree[max_index]
    
    mask = imutils.rotate(mask, rot_degree)
    src = imutils.rotate(src, rot_degree)
    
    return src, mask

Where src is the source file and mask the black and white binary mask.