Я пытаюсь выполнить 3D реконструкцию лица из двух изображений, используя Python и OpecCV. Мне удалось выполнить калибровку камеры, используя инструкции link , а затем применив cv2.stereoCalibrate()
и cv2.stereoRectify()
. После этого cv2.StereoSGBM
использовался для вычисления карты диспаратности и, наконец, cv2.reprojectImageTo3D
для генерации облака точек. Последний отображался с использованием библиотеки open3d
. Однако результат StereoSGBM.compute()
очень шумный, и получающееся облако точек выглядит совсем не так, как должно.
То, что я пробовал:
- нормализация карты диспаратности: алгоритм выводит двумерный массив со значениями от -16 до 240, поэтому я настроил его в диапазоне от 0 до 255, и 0,0 и 1,0 соответственно. Первый вариант стал лучше
- , разделив значения на 16 (как я видел в реализации C ++)
- , настроив параметры StereoSGBM. Я даже построил GUI для настройки параметров, однако результаты были все еще неудовлетворительными
- с использованием 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])