231 lines
8.3 KiB
Python
231 lines
8.3 KiB
Python
import cv2
|
|
import numpy as np
|
|
from tqdm import tqdm
|
|
import os
|
|
|
|
class FileStorage(object):
|
|
def __init__(self, filename, isWrite=False):
|
|
version = cv2.__version__
|
|
self.version = int(version.split('.')[0])
|
|
if isWrite:
|
|
self.fs = cv2.FileStorage(filename, cv2.FILE_STORAGE_WRITE)
|
|
else:
|
|
self.fs = cv2.FileStorage(filename, cv2.FILE_STORAGE_READ)
|
|
|
|
def __del__(self):
|
|
cv2.FileStorage.release(self.fs)
|
|
|
|
def write(self, key, value, dt='mat'):
|
|
if dt == 'mat':
|
|
cv2.FileStorage.write(self.fs, key, value)
|
|
elif dt == 'list':
|
|
if self.version == 4: # 4.4
|
|
# self.fs.write(key, '[')
|
|
# for elem in value:
|
|
# self.fs.write('none', elem)
|
|
# self.fs.write('none', ']')
|
|
# import ipdb; ipdb.set_trace()
|
|
self.fs.startWriteStruct(key, cv2.FileNode_SEQ)
|
|
for elem in value:
|
|
self.fs.write('', elem)
|
|
self.fs.endWriteStruct()
|
|
else: # 3.4
|
|
self.fs.write(key, '[')
|
|
for elem in value:
|
|
self.fs.write('none', elem)
|
|
self.fs.write('none', ']')
|
|
|
|
def read(self, key, dt='mat'):
|
|
if dt == 'mat':
|
|
output = self.fs.getNode(key).mat()
|
|
elif dt == 'list':
|
|
results = []
|
|
n = self.fs.getNode(key)
|
|
for i in range(n.size()):
|
|
val = n.at(i).string()
|
|
if val == '':
|
|
val = str(int(n.at(i).real()))
|
|
if val != 'none':
|
|
results.append(val)
|
|
output = results
|
|
else:
|
|
raise NotImplementedError
|
|
return output
|
|
|
|
def close(self):
|
|
self.__del__(self)
|
|
|
|
def _FindChessboardCorners(img, patternSize = (9, 6)):
|
|
if len(img.shape) == 3:
|
|
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
|
|
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
|
|
|
|
retval, corners = cv2.findChessboardCorners(img, patternSize,
|
|
flags=cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_NORMALIZE_IMAGE)
|
|
if not retval:
|
|
return False, False
|
|
corners = cv2.cornerSubPix(img, corners, (11, 11), (-1, -1), criteria)
|
|
return True, corners
|
|
|
|
def FindChessboardCorners(image_names, patternSize=(9, 6), gridSize=0.1, debug=False):
|
|
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
|
|
object_points = np.zeros((patternSize[1]*patternSize[0], 3), np.float32)
|
|
object_points[:,:2] = np.mgrid[0:patternSize[0], 0:patternSize[1]].T.reshape(-1,2)
|
|
object_points = object_points * gridSize
|
|
# Arrays to store object points and image points from all the images.
|
|
objpoints = [] # 3d point in real world space
|
|
imgpoints = [] # 2d points in image plane.
|
|
images = []
|
|
for fname in tqdm(image_names):
|
|
img = cv2.imread(fname)
|
|
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
|
|
# Find the chess board corners
|
|
ret, corners = _FindChessboardCorners(gray, patternSize)
|
|
|
|
# If found, add object points, image points (after refining them)
|
|
if ret:
|
|
objpoints.append(object_points)
|
|
imgpoints.append(corners)
|
|
# Draw and display the corners
|
|
images.append(img)
|
|
if debug:
|
|
img = cv2.drawChessboardCorners(img, patternSize, corners, ret)
|
|
cv2.imshow('img',img)
|
|
cv2.waitKey(10)
|
|
else:
|
|
os.remove(fname)
|
|
return imgpoints, objpoints, images
|
|
|
|
def safe_mkdir(path):
|
|
if not os.path.exists(path):
|
|
os.makedirs(path)
|
|
|
|
def read_camera(intri_name, extri_name, cam_names=[0,1,2,3]):
|
|
assert os.path.exists(intri_name), intri_name
|
|
assert os.path.exists(extri_name), extri_name
|
|
|
|
intri = FileStorage(intri_name)
|
|
extri = FileStorage(extri_name)
|
|
cams, P = {}, {}
|
|
for cam in cam_names:
|
|
# 内参只读子码流的
|
|
cams[cam] = {}
|
|
cams[cam]['K'] = intri.read('K_{}'.format( cam))
|
|
cams[cam]['invK'] = np.linalg.inv(cams[cam]['K'])
|
|
Rvec = extri.read('R_{}'.format(cam))
|
|
Tvec = extri.read('T_{}'.format(cam))
|
|
R = cv2.Rodrigues(Rvec)[0]
|
|
RT = np.hstack((R, Tvec))
|
|
|
|
cams[cam]['RT'] = RT
|
|
cams[cam]['R'] = R
|
|
cams[cam]['T'] = Tvec
|
|
P[cam] = cams[cam]['K'] @ cams[cam]['RT']
|
|
cams[cam]['P'] = P[cam]
|
|
|
|
cams[cam]['dist'] = intri.read('dist_{}'.format(cam))
|
|
cams['basenames'] = cam_names
|
|
return cams
|
|
|
|
def write_camera(camera, path):
|
|
from os.path import join
|
|
intri_name = join(path, 'intri.yml')
|
|
extri_name = join(path, 'extri.yml')
|
|
intri = FileStorage(intri_name, True)
|
|
extri = FileStorage(extri_name, True)
|
|
results = {}
|
|
camnames = [key_.split('.')[0] for key_ in camera.keys()]
|
|
intri.write('names', camnames, 'list')
|
|
extri.write('names', camnames, 'list')
|
|
for key_, val in camera.items():
|
|
if key_ == 'basenames':
|
|
continue
|
|
key = key_.split('.')[0]
|
|
intri.write('K_{}'.format(key), val['K'])
|
|
intri.write('dist_{}'.format(key), val['dist'])
|
|
if 'Rvec' not in val.keys():
|
|
val['Rvec'] = cv2.Rodrigues(val['R'])[0]
|
|
extri.write('R_{}'.format(key), val['Rvec'])
|
|
extri.write('Rot_{}'.format(key), val['R'])
|
|
extri.write('T_{}'.format(key), val['T'])
|
|
|
|
def undistort(camera, frame=None, keypoints=None, output=None, bbox=None):
|
|
# bbox: 1, 7
|
|
mtx = camera['K']
|
|
dist = camera['dist']
|
|
if frame is not None:
|
|
frame = cv2.undistort(frame, mtx, dist, None)
|
|
if output is not None:
|
|
output = cv2.undistort(output, mtx, dist, None)
|
|
if keypoints is not None:
|
|
for nP in range(keypoints.shape[0]):
|
|
kpts = keypoints[nP][:, None, :2]
|
|
kpts = np.ascontiguousarray(kpts)
|
|
kpts = cv2.undistortPoints(kpts, mtx, dist, P=mtx)
|
|
keypoints[nP, :, :2] = kpts[:, 0]
|
|
if bbox is not None:
|
|
kpts = np.zeros((2, 1, 2))
|
|
kpts[0, 0, 0] = bbox[0]
|
|
kpts[0, 0, 1] = bbox[1]
|
|
kpts[1, 0, 0] = bbox[2]
|
|
kpts[1, 0, 1] = bbox[3]
|
|
kpts = cv2.undistortPoints(kpts, mtx, dist, P=mtx)
|
|
bbox[0] = kpts[0, 0, 0]
|
|
bbox[1] = kpts[0, 0, 1]
|
|
bbox[2] = kpts[1, 0, 0]
|
|
bbox[3] = kpts[1, 0, 1]
|
|
return bbox
|
|
return frame, keypoints, output
|
|
|
|
def get_bbox(points_set, H, W, thres=0.1, scale=1.2):
|
|
bboxes = np.zeros((points_set.shape[0], 6))
|
|
for iv in range(points_set.shape[0]):
|
|
pose = points_set[iv, :, :]
|
|
use_idx = pose[:,2] > thres
|
|
if np.sum(use_idx) < 1:
|
|
continue
|
|
ll, rr = np.min(pose[use_idx, 0]), np.max(pose[use_idx, 0])
|
|
bb, tt = np.min(pose[use_idx, 1]), np.max(pose[use_idx, 1])
|
|
center = (int((ll + rr) / 2), int((bb + tt) / 2))
|
|
length = [int(scale*(rr-ll)/2), int(scale*(tt-bb)/2)]
|
|
l = max(0, center[0] - length[0])
|
|
r = min(W, center[0] + length[0]) # img.shape[1]
|
|
b = max(0, center[1] - length[1])
|
|
t = min(H, center[1] + length[1]) # img.shape[0]
|
|
conf = pose[:, 2].mean()
|
|
cls_conf = pose[use_idx, 2].mean()
|
|
bboxes[iv, 0] = l
|
|
bboxes[iv, 1] = r
|
|
bboxes[iv, 2] = b
|
|
bboxes[iv, 3] = t
|
|
bboxes[iv, 4] = conf
|
|
bboxes[iv, 5] = cls_conf
|
|
return bboxes
|
|
|
|
def filterKeypoints(keypoints, thres = 0.1, min_width=40, \
|
|
min_height=40, min_area= 50000, min_count=6):
|
|
add_list = []
|
|
# TODO:并行化
|
|
for ik in range(keypoints.shape[0]):
|
|
pose = keypoints[ik]
|
|
vis_count = np.sum(pose[:15, 2] > thres) #TODO:
|
|
if vis_count < min_count:
|
|
continue
|
|
ll, rr = np.min(pose[pose[:,2]>thres,0]), np.max(pose[pose[:,2]>thres,0])
|
|
bb, tt = np.min(pose[pose[:,2]>thres,1]), np.max(pose[pose[:,2]>thres,1])
|
|
center = (int((ll+rr)/2), int((bb+tt)/2))
|
|
length = [int(1.2*(rr-ll)/2), int(1.2*(tt-bb)/2)]
|
|
l = center[0] - length[0]
|
|
r = center[0] + length[0]
|
|
b = center[1] - length[1]
|
|
t = center[1] + length[1]
|
|
if (r - l) < min_width:
|
|
continue
|
|
if (t - b) < min_height:
|
|
continue
|
|
if (r - l)*(t - b) < min_area:
|
|
continue
|
|
add_list.append(ik)
|
|
keypoints = keypoints[add_list, :, :]
|
|
return keypoints, add_list
|