Crop image with corrected distortion in OpenCV (Python)

Question

I've been looking for a response in other posts and trying several ways to get it but I couldn't find anything solving my problem. I'm trying to correct optical distortion in an image and I get it, but now I want to crop my image in order to delete the curved black borders in the result image. So, in summary, this is my problem:

problem

I want to crop like this:

enter image description here

I've tried to crop with the following code:

h,  w = corrected_img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(cameraMTX,distortionCoeffs,(w,h),1,(w,h))
x,y,w,h = roi
desired_result = corrected_img[y:y+h, x:x+w]

But unfortunately roi always takes the value (0,0,0,0).

Could anyone help me?

Thanks in advance.


Show source
| python   | opencv   | computer-vision   | crop   | distortion   2016-12-14 19:12 1 Answers

Answers ( 1 )

  1. 2016-12-14 21:12

    As the void part has its maximum/minimum in the middle of the image, you could look for the middle lines and see when there is a change of color. The image below may clarify this:

    enter image description here

    You just need to find the x1, y1, x2 and y2 shown in the image. This can be done as follows:

    import cv2
    # Reads the image in grayscale
    img = cv2.imread('Undistorted.jpg', 0)
    h, w = img.shape
    x1, x2, y1, y2 = (0,0,0,0)
    
    # Color threshold of the void part
    void_th = 10
    
    # List of colors in the vertical an horizontal lines that cross the image in the middle
    vertical = [img[i, int(w/2)] for i in range(h)]
    horizontal = [img[int(h/2), i] for i in range(w)]
    
    # Reverses both lists
    vertical_rev = vertical[::-1]
    horizontal_rev = horizontal[::-1]
    
    # Looks when the change of color is done
    for i in range(2,h):
        if vertical[i] > void_th and y1 == 0:
            y1 = i
        if vertical_rev[i] > void_th and y2 == 0:
            y2 = i
        if y1 != 0 and y2 != 0:
            break
    for i in range(2,w):
        if horizontal[i] > void_th and x1 == 0:
            x1 = i
        if horizontal_rev[i] > void_th and x2 == 0:
            x2 = i
        if x1 != 0 and x2 != 0:
            break
    
    desired_result = img[y1:h-y2, x1:w-x2]
    cv2.imshow('Crop', desired_result)
    

    What I did is a list of the pixel colors in the middle lines, and then loop them until the color is above a threshold (0 is Black and 255 is White). When the first pixel that changes of color is detected, the position is stored and the loop breaks. The output is the cropped image:

    enter image description here

    Note: I started looping from position 2 because of the border line, with the original image this is not needed.

    Hope this helped!

◀ Go back