Kinect: избавляемся от искажений при помощи потолка

Идеально плоский потолок

Давеча я писал про то, как выглядят данные, которые приходят с сенсора. Такое поведение сенсора просто возмутительно и долго это продолжаться не может.

Ок. А что нам потребуется? Нам потребуется потолок. Я внимательно его осмотрел и убедился, что в реальности он плоский. А вот на восстановленом изображении - нифига.

Для начала нам нужно сохранить дамп глубин “идеального” потолка. Можно и стену если у вас есть достаточно плоской поверхности. :)

В файл будет сохранена двумерная матрица из чисел разделенных пробелами. Строки по строкам и т.д. Позже поймем зачем именно так.

Кусочек файла

888 889 890 890 890 890 890 891 890 891 891 892 892 892 892 892 892 892 892 892 891 893 892 892 892 892 892 ... 2047 2047 2047 2047 2047 2047 ...

Теперь посмотрим на картинку этой самой плоскости. Для этого запускаем maxima.

(%i1) load(numericalio);  
(%i2) m: read_matrix("<путь к файлу с глубинами>");  
($i3) f(x, y) := float('m [round(x), round(y)]);  
-- тут мы зададим функцию извлечения нужного значения из матрицы.  
-- Так как матрица наши данные дискретны  
-- и существуют только в определенных точках  
(%i4) plot3d (f(x, y), [x, 1, 640], [y, 1, 480]);

О! Круто. Мы что-то видим.

Потолок. Необработанная карта глубин

Что-то не то :)

Стоит заметить, что в режиме сырых данных FREENECT_DEPTH_11BIT самые правые 8 столбцов не используются и всегда возвращают значение FREENECT_DEPTH_RAW_MAX_VALUE. Об этом не стоит забывать при последующих действиях.

Поэтому нам нужно посмотреть плоскость без правых столбцов (8 штук).

(%i4) plot3d (f(x, y), [x, 1, 632], [y, 1, 480]);

И тут уже то, что нам надо.

Потолок: карта глубин после доработки

Это плоскость. Но не очень плоская. И таки да. Надо сделать ее обратно плоской. :)

Мы знаем, что все точки данной поверхности равноудалены от плоскости, где расположен сенсор.

Поэтому можно ввести коэффициент нормировки для каждой из точек (x, y). Который будет равен отношению реального расстояния к полученному.

Зная этот коэффициент можно узнать, реальное расстояние до точки. Просто умножив полученное от кинекта значение на коэффициент нормировки в данной точке (x, y).

Коэффициенты считаем один раз по калибровочному изображению. А затем загружаем в свое приложение и пользуемся.

Минусы решения

  • Я предположил, что коэффициент нормировки зависит только от координат (x, y), но не зависит от глубины. Так это или нет - проверю. (пока датчик говорит, что я прав)
  • Плоскость по которой выполняется калибровка должна находится на расстоянии 2,5-3,5 метров от сенсора. Именно при таком положении коэффициенты нормировки будет точными.
  • Так как сенсор довольно чувствителен, то его положение должно быть параллельно плоскости калибровки (мне помогал обычный строительный уровень)
  • Так же перед калибровкой полученное изображение плоскости нужно сгладить для того, чтобы избавиться от шумов (это умеет делать матлабоский smoothn)

UPD

Код на гитхабе

Категории: JFF kinect