AutoQuad / distortion.py
Can Günen
changed the variables names and fixed some functions
64dc6be
import cv2
import numpy as np
import ezdxf
import gradio as gr
from pathlib import Path
coordis = []
def save_matrix(mtx, dist, path):
"""Save camera matrix and distortion coefficients to file."""
cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_WRITE)
cv_file.write('K', mtx)
cv_file.write('D', dist)
cv_file.release()
def load_matrix(path):
"""Load camera matrix and distortion coefficients from file."""
cv_file = cv2.FileStorage(path, cv2.FILE_STORAGE_READ)
camera_matrix = cv_file.getNode('K').mat()
dist_matrix = cv_file.getNode('D').mat()
cv_file.release()
return [camera_matrix, dist_matrix]
def correct_image(image, yaml):
image = cv2.imread(image)
mtx, dist = load_matrix(yaml.name)
dst = cv2.undistort(image, mtx, dist, None, None)
return dst
def color_tab(file_path, yaml):
coordinates = []
img = cv2.imread(file_path)
mtx, dist = load_matrix(yaml.name)
img = cv2.undistort(img, mtx, dist, None, None)
height, width, _ = img.shape
# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Apply a threshold to convert the grayscale image into a binary image
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY)
# Find the contours in the binary image
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Select the contour with the largest area (the object we want to extract the corners from)
contour = max(contours, key=cv2.contourArea)
# Approximate the contour with a polygon
epsilon = 0.01 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
# Draw the polygon on the original image
cv2.polylines(img, [approx], True, (0, 255, 0), thickness=2)
doc = ezdxf.new("R2010", setup=True)
msp = doc.modelspace()
# Print the coordinates of the corners
for corner in approx:
x, y = corner[0]
coordinates.append([x,y])
#This method of adding line is brute force and needs to be changed, find a way to generalize for polygons
msp.add_line((coordinates[0][0], -coordinates[0][1]), (coordinates[1][0], -coordinates[1][1]))
msp.add_line((coordinates[1][0], -coordinates[1][1]), (coordinates[2][0], -coordinates[2][1]))
msp.add_line((coordinates[2][0], -coordinates[2][1]), (coordinates[3][0], -coordinates[3][1]))
msp.add_line((coordinates[3][0], -coordinates[3][1]), (coordinates[0][0], -coordinates[0][1]))
msp.add_line((0,0), (0, -height))
msp.add_line((0, -height), (width, -height))
msp.add_line((width, -height), (width, 0))
msp.add_line((width, 0), (0,0))
doc.saveas("output.dxf")
return "output.dxf", img
def corner_tab(img, evt: gr.SelectData):
height, width, _ = img.shape
row, col = evt.index
coordis.append([row, col])
if len(coordis) == 4 :
coordinates = np.array(coordis)
dwg = ezdxf.new("R2010")
msp = dwg.modelspace()
dwg.layers.new(name="greeny green lines", dxfattribs={"color": 3})
msp.add_line((coordinates[0][0], -coordinates[0][1]), (coordinates[1][0], -coordinates[1][1]))
msp.add_line((coordinates[1][0], -coordinates[1][1]), (coordinates[2][0], -coordinates[2][1]))
msp.add_line((coordinates[2][0], -coordinates[2][1]), (coordinates[3][0], -coordinates[3][1]))
msp.add_line((coordinates[3][0], -coordinates[3][1]), (coordinates[0][0], -coordinates[0][1]))
msp.add_line((0,0), (0, -height))
msp.add_line((0, -height), (width, -height))
msp.add_line((width, -height), (width, 0))
msp.add_line((width, 0), (0,0))
dwg.saveas("output.dxf")
coordis.clear()
return "output.dxf"
def generate_matrix(filename, board_vert, board_horz):
"""Main function to calibrate camera and undistort image."""
filename_stem = Path(filename).stem
# Define the checkerboard pattern size and criteria for corner detection
CHECKERBOARD = (int(board_vert)-1, int(board_horz)-1)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# Initialize object points and image points arrays
object_points = [] # 3D points in real world space
image_points = [] # 2D points in image plane
# Create the object points for the chessboard corners
objectp3d = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
objectp3d[0, :, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
# Load the image and convert to grayscale
image = cv2.imread(filename)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Find chessboard corners
ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH
+ cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
# If corners found, add object points and image points to arrays
if ret:
object_points.append(objectp3d)
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
image_points.append(corners2)
image = cv2.drawChessboardCorners(image, CHECKERBOARD, corners2, ret)
# Calibrate camera using object points and image points
h, w = gray.shape[:2]
try:
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(object_points, image_points, gray.shape[::-1], None, None)
# Save camera matrix and distortion coefficients to file
save_matrix(mtx, dist, f"{filename_stem}.yml")
return f"{filename_stem}.yml"
except:
print("Please check the Chessboard Dimensions")
def slider(img, h1, s1, v1, h2, s2, v2):
# Load the image
img = cv2.imread(img)
while(1):
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# Create the NumPy arrays
lower_red = np.array([h1, s1, v1])
upper_red = np.array([h2, s2, v2])
# Convert every element to integer using int() function
lower_red = np.array([int(x) for x in lower_red])
upper_red = np.array([int(x) for x in upper_red])
mask = cv2.inRange(img, lower_red, upper_red)
res = cv2.bitwise_and(img,img, mask= mask)
return res