Сферическая проекция OpenCV: деформация и деформирование - PullRequest
1 голос
/ 10 мая 2019

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

Ранее я успешно использовал функцию деформации сферического варпера:

detail::SphericalWarper Projection = detail::SphericalWarper(((360.0/PX2DEG)/PI)/2.0);
Mat SrcProj;
Projection.warp(Src, CameraIntrinsics, Rotation, INTER_LINEAR, 0,SrcProj);

Но когда я использую функцию warpBackward, мне нужно указать размер целевого мата. Кажется, что если он не очень определенного размера, это вызывает ошибку. Я покопался в файлах библиотеки и нашел assert, который отправляет ошибку, и нашел это (фрагмент из warpers_inl.hpp):

void RotationWarperBase<P>::warpBackward(InputArray src, InputArray K, InputArray R, int interp_mode, int border_mode, Size dst_size, OutputArray dst)
{
projector_.setCameraParams(K, R);
Point src_tl, src_br;
detectResultRoi(dst_size, src_tl, src_br);
Size size = src.size();
CV_Assert(src_br.x - src_tl.x + 1 == size.width && src_br.y - src_tl.y + 1 == size.height);

к сожалению detectResultRoi - это защищенная функция, поэтому я немного застрял в том, как найти правильный размер целевого изображения.

Любая помощь будет высоко ценится, спасибо!

==================================== Редактировать ========== ========================== Размер Src может быть рассчитан с помощью общедоступной функции warpRoi.

Mat SrcProj=Mat(480,640,CV_8UC3,Scalar(0,0,0));
Rect WindowSize=Projection.warpRoi(SrcProj.size(),CameraIntrinsics,Rotation);

Выше я определил свой размер вывода, затем использовал warpRoi, чтобы найти размер Src (или размер окна). Теперь у вас есть размер, который вы можете вырезать мат этого размера из изображения Src (или изменить его размер), а затем без проблем использовать функцию warpBackward.

1 Ответ

0 голосов
/ 10 мая 2019

Вы не можете получить доступ к detectResultRoi напрямую, но вы можете наследовать его и использовать по своему усмотрению в своем собственном классе.

class MySphericalWarper : private SphericalWarper
{
public:
    using SphericalWarper::warp;
    void unwarp( ... ) { 
         ...
        detectResultRoi( ... );
         ...
    }
     ...
};

Тогда просто используйте вашу реализацию.

MySphericalWarper warper( ... );
Mat proj, unproj;
warper.warp(src, ... , proj);
// warp backward
warper.unwarp(proj, ... , unproj);

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

Вам необходимо знать, где находятся пиксели проекции в сферическом изображении. Затем вы можете рассчитать размер непроецированного изображения: определите разницу между позициями крайних правых и крайних левых, максимальных и минимальных непроецированных пикселей среди всех граничных пикселей этой (обычно не прямоугольной) области. Эти позиции можно получить с помощью SphericalWarper::projector_.mapBackward(). projector_ член тоже protected, поэтому вам нужно использовать его так же, как описано выше для detectResultRoi.

Этот размер такой же, как и размер изображения, которое вы warp, если вы хотите деформировать в обратном направлении результат (или измененный результат, вы можете изменить значения пикселей, это не изменит отображение положений пикселей) warp.

detail::SphericalWarper projection(((360.0/PX2DEG)/PI)/2.0);
Mat proj, unproj;
projection.warp(src, CameraIntrinsics, Rotation, INTER_LINEAR, 0, proj);
// paint on proj or something ...
projection.warpBackward(proj, CameraIntrinsics, Rotation, INTER_LINEAR, 0, src.size(), unproj);
...