Crop image with corrected distortion in OpenCV (Python)

3.3k views Asked by At

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.

1

There are 1 answers

2
ebeneditos On BEST ANSWER

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!