// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "parallax/spaceTransform.hpp" #include "core/geoTransform.hpp" #include "core/rect.hpp" #include "libvideostitch/geometryDef.hpp" #include "libvideostitch/panoDef.hpp" #include <string.h> #define MAP_KERNEL_BLOCK_SIZE_X 16 #define MAP_KERNEL_BLOCK_SIZE_Y 8 namespace VideoStitch { namespace Core { namespace { #define MAPCOORDOUTPUTTOINPUT_DEF2(SPHERETOINPUT, ISWITHIN) \ MAPCOORDOUTPUTTOINPUT_DEF3(SPHERETOINPUT, noopDistortionTransform, distortionScaled, ISWITHIN) \ MAPCOORDOUTPUTTOINPUT_DEF3(SPHERETOINPUT, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status mapCoordOutputToInput_##SPHERETOINPUT##_##ISWITHIN(const int time, const int offsetX, const int offsetY, const int croppedWidth, const int croppedHeight, GPU::Buffer<float2> outputBuffer, GPU::Buffer<uint32_t> maskBuffer, const PanoDefinition& pano, const videoreaderid_t id, GPU::Stream gpuStream) const { \ if (pano.getInput(id).getUseMeterDistortion() == false) { \ return mapCoordOutputToInput_##SPHERETOINPUT##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN (time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); \ } else { \ return mapCoordOutputToInput_##SPHERETOINPUT##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN (time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); \ } \ } \ #define MAPCOORDOUTPUTTOINPUT_DEF \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToRect, isWithinCropRect) \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToErect, isWithinCropRect) \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToExternal, isWithinCropRect) \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToExternal, isWithinCropCircle) \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToFisheye, isWithinCropRect) \ MAPCOORDOUTPUTTOINPUT_DEF2(SphereToFisheye, isWithinCropCircle) #define MAPCOORDINPUTTOOUTPUT_DEF2(INPUTTOSPHERE, ISWITHIN) \ MAPCOORDINPUTTOOUTPUT_DEF3(INPUTTOSPHERE, noopDistortionTransform, inverseDistortionScaled, ISWITHIN) \ MAPCOORDINPUTTOOUTPUT_DEF3(INPUTTOSPHERE, inverseDistortionScaled, noopDistortionTransform, ISWITHIN) \ Status mapCoordInputToOutput_##INPUTTOSPHERE##_##ISWITHIN(const int time, GPU::Buffer<float2> outputBuffer, const int inputWidth, const int inputHeight, const GPU::Buffer<const float2> inputBuffer, const GPU::Buffer<const uint32_t> inputMask, const PanoDefinition& pano, const videoreaderid_t id, GPU::Stream gpuStream) const { \ if (pano.getInput(id).getUseMeterDistortion() == false) { \ return mapCoordInputToOutput_##INPUTTOSPHERE##_##noopDistortionTransform##_##inverseDistortionScaled##_##ISWITHIN (time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); \ } else { \ return mapCoordInputToOutput_##INPUTTOSPHERE##_##inverseDistortionScaled##_##noopDistortionTransform##_##ISWITHIN (time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); \ } \ } \ #define MAPCOORDINPUTTOOUTPUT_DEF \ MAPCOORDINPUTTOOUTPUT_DEF2(RectToSphere, isWithinCropRect) \ MAPCOORDINPUTTOOUTPUT_DEF2(ErectToSphere, isWithinCropRect) \ MAPCOORDINPUTTOOUTPUT_DEF2(ExternalToSphere, isWithinCropRect) \ MAPCOORDINPUTTOOUTPUT_DEF2(ExternalToSphere, isWithinCropCircle) \ MAPCOORDINPUTTOOUTPUT_DEF2(FisheyeToSphere, isWithinCropRect) \ MAPCOORDINPUTTOOUTPUT_DEF2(FisheyeToSphere, isWithinCropCircle) \ /** *SpaceTransform final implementation. *The factory is here since we need explicit access to the transform stack for template instantiation */ class SpaceTransformImpl : public SpaceTransform { public: SpaceTransformImpl(const InputDefinition::Format & inputf, const Vector3<double> oldOriCoord, const Vector3<double> newOriCoord) : inputformat(inputf), SpaceTransform(oldOriCoord, newOriCoord) { } Status mapCoordInputToOutput(const int time, GPU::Buffer<float2> outputBuffer, const int inputWidth, const int inputHeight, const GPU::Buffer<const float2> inputBuffer, const GPU::Buffer<const uint32_t> inputMask, const PanoDefinition& pano, const videoreaderid_t id, GPU::Stream gpuStream) const override { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapCoordInputToOutput_RectToSphere_isWithinCropRect(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); case InputDefinition::Format::Equirectangular: return mapCoordInputToOutput_ErectToSphere_isWithinCropRect(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapCoordInputToOutput_ExternalToSphere_isWithinCropCircle(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapCoordInputToOutput_ExternalToSphere_isWithinCropRect(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); case InputDefinition::Format::CircularFisheye: return mapCoordInputToOutput_FisheyeToSphere_isWithinCropCircle(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapCoordInputToOutput_FisheyeToSphere_isWithinCropRect(time, outputBuffer, inputWidth, inputHeight, inputBuffer, inputMask, pano, id, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; } } Status mapCoordOutputToInput(const int time, const int offsetX, const int offsetY, const int croppedWidth, const int croppedHeight, GPU::Buffer<float2> outputBuffer, GPU::Buffer<uint32_t> maskBuffer, const PanoDefinition& pano, const videoreaderid_t id, GPU::Stream gpuStream) const override { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapCoordOutputToInput_SphereToRect_isWithinCropRect(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); case InputDefinition::Format::Equirectangular: return mapCoordOutputToInput_SphereToErect_isWithinCropRect(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapCoordOutputToInput_SphereToExternal_isWithinCropCircle(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapCoordOutputToInput_SphereToExternal_isWithinCropRect(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); case InputDefinition::Format::CircularFisheye: return mapCoordOutputToInput_SphereToFisheye_isWithinCropCircle(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapCoordOutputToInput_SphereToFisheye_isWithinCropRect(time, offsetX, offsetY, croppedWidth, croppedHeight, outputBuffer, maskBuffer, pano, id, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } private: MAPCOORDINPUTTOOUTPUT_DEF MAPCOORDOUTPUTTOINPUT_DEF private: InputDefinition::Format inputformat; }; SpaceTransform* createSpaceTransform(const InputDefinition& im, const Vector3<double> oldOriCoord, const Vector3<double> newOriCoord) { return new SpaceTransformImpl(im.getFormat(), oldOriCoord, newOriCoord); } } } }