Карта несоответствия с облаком точек отключена
Я пытаюсь выполнить 3D-реконструкцию лица из двух изображений с помощью Python и OpecCV. Мне удалось выполнить калибровку камеры с помощью intructions здесь ссылку, а затем применяяcv2.stereoCalibrate()
а также cv2.stereoRectify()
. Впоследствииcv2.StereoSGBM
использовался для вычисления карты диспаратности, и, наконец, cv2.reprojectImageTo3D
для создания облака точек. Последний отображался с помощьюopen3d
библиотека. Однако результатStereoSGBM.compute()
очень шумно, и получившееся облако точек выглядит совсем не так, как должно.
Что я пробовал:
- нормализация карты диспаратности: алгоритм выводит двумерный массив со значениями от -16 до 240, поэтому я установил его между 0 и 255 и 0,0 и 1,0 соответственно. Первый вариант пошел лучше
- деление значений на 16 (как я видел в реализации на C++)
- настройка параметров StereoSGBM. Я даже создал графический интерфейс для настройки параметров, но результаты все еще не были удовлетворительными.
- используя StereoBM, однако особой разницы не было
- используя разные тестовые изображения
- использование изображений в оттенках серого
- нормализация их в диапазоне 0,0 -> 1,0
- обрезка неискаженных изображений
- повторная реализация
cv2.reprojectImageTo3D
, с теми же результатами - удаление фона на карте несоответствий вручную
- работа с uint8 и float32. Перепроецирование работало намного лучше с использованием поплавков.
Полученные изображения:
начальная:
после калибровки:
карта несоответствия (параметры справа):
облако точек (выглядит как человек под очень специфическим углом):
Что я могу сделать, чтобы получить полезные результаты? Я даже не знаю, как должны выглядеть изображения. Кажется, моя калибровка отключена? Я чувствую, что изображения действительно плохие (так как перспективное искажение довольно велико), но, к сожалению, мне приходится с ними работать.
Некоторые заглушки кода:
_, self.camera_matrix, self.distortion, _, _ = \
cv2.calibrateCamera(self.object_points, self.image_points, self.image_size, None, None)
error, _, _, _, _, self.rotation, self.translation, _, _ = \
cv2.stereoCalibrate(self.camera_left.object_points,
self.camera_left.image_points,
self.camera_right.image_points,
self.camera_left.camera_matrix,
self.camera_left.distortion,
self.camera_right.camera_matrix,
self.camera_right.distortion,
self.camera_left.image_size,
flags=cv2.CALIB_FIX_INTRINSIC)
self.rotation_left, self.rotation_right, self.perspective_left, self.perspective_right, self.Q, self.roi_left, self.roi_right = \
cv2.stereoRectify(self.camera_left.camera_matrix,
self.camera_left.distortion,
self.camera_right.camera_matrix,
self.camera_right.distortion,
self.camera_left.image_size,
self.rotation,
self.translation,
flags=cv2.CALIB_ZERO_DISPARITY)
self.rotation_left, self.rotation_right, self.perspective_left, self.perspective_right, self.Q, self.roi_left, self.roi_right = \
cv2.stereoRectify(self.camera_left.camera_matrix,
self.camera_left.distortion,
self.camera_right.camera_matrix,
self.camera_right.distortion,
self.camera_left.image_size,
self.rotation,
self.translation,
flags=cv2.CALIB_ZERO_DISPARITY)
self.block_matching = cv2.StereoSGBM().create() # params not mentioned here, but they are set
disparity = self.block_matching.compute(undistorted_left, undistorted_right)
disparity = cv2.convertScaleAbs(disparity, beta=16)
point_cloud = cv2.reprojectImageTo3D(disparity_image, Q)
point_cloud = point_cloud.reshape(-1, point_cloud.shape[-1])
point_cloud = point_cloud[~np.isinf(point_cloud).any(axis=1)]
pcl = open3d.geometry.PointCloud()
pcl.points = open3d.utility.Vector3dVector(point_cloud)
open3d.visualization.draw_geometries([pcl])