// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #include "gpu/core1/transform.hpp" #include <core/geoTransform.hpp> #include <core/photoTransform.hpp> #include <core/rect.hpp> #include <core1/imageMerger.hpp> #include "libvideostitch/geometryDef.hpp" #include "libvideostitch/panoDef.hpp" #include <string.h> #define MAP_KERNEL_BLOCK_SIZE_X_EmorPhotoCorrection 32 #define MAP_KERNEL_BLOCK_SIZE_Y_EmorPhotoCorrection 16 #define MAP_KERNEL_BLOCK_SIZE_X_LinearPhotoCorrection 16 #define MAP_KERNEL_BLOCK_SIZE_Y_LinearPhotoCorrection 8 #define MAP_KERNEL_BLOCK_SIZE_X_GammaPhotoCorrection 16 #define MAP_KERNEL_BLOCK_SIZE_Y_GammaPhotoCorrection 8 #define MAP_KERNEL_BLOCK_SIZE_X 16 #define MAP_KERNEL_BLOCK_SIZE_Y 8 #define ZONE_KERNEL_BLOCK_SIZE_X 16 #define ZONE_KERNEL_BLOCK_SIZE_Y 16 namespace VideoStitch { namespace Core { namespace { #define MAPBUFFER_PANO2(MERGER, INPUTPROJECTION, ISWITHIN) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, LinearPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, GammaPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, EmorPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, LinearPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, GammaPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, EmorPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, radialScaled, ISWITHIN, LinearPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, radialScaled, ISWITHIN, GammaPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, noopDistortionTransform, radialScaled, ISWITHIN, EmorPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, radialScaled, noopDistortionTransform, ISWITHIN, LinearPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, radialScaled, noopDistortionTransform, ISWITHIN, GammaPhotoCorrection) \ MAPBUFFER_PANO3(MERGER, INPUTPROJECTION, radialScaled, noopDistortionTransform, ISWITHIN, EmorPhotoCorrection) \ Status mapBuffer_##MERGER##_##INPUTPROJECTION##_##ISWITHIN(int time, GPU::Buffer<uint32_t> devOut, GPU::Surface& panoSurf, const unsigned char* mask, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& inSurf, GPU::Stream gpuStream) const { \ if (im.getUseMeterDistortion() == false) { \ if (im.getGeometries().at(time).hasNonRadialDistortion() == false) { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##radialScaled##_##ISWITHIN##_LinearPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##radialScaled##_##ISWITHIN##_GammaPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##radialScaled##_##ISWITHIN##_EmorPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } else { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN##_LinearPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN##_GammaPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN##_EmorPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } \ } \ else { \ if (im.getGeometries().at(time).hasNonRadialDistortion() == false) { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##radialScaled##_##noopDistortionTransform##_##ISWITHIN##_LinearPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##radialScaled##_##noopDistortionTransform##_##ISWITHIN##_GammaPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##radialScaled##_##noopDistortionTransform##_##ISWITHIN##_EmorPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } else { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN##_LinearPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN##_GammaPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return mapBuffer_##MERGER##_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN##_EmorPhotoCorrection(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } \ } \ } \ \ #define MAPBUFFER_PANO(INPUTPROJECTION, ISWITHIN) \ MAPBUFFER_PANO2(gradientMerge, INPUTPROJECTION, ISWITHIN) \ MAPBUFFER_PANO2(noopMerge, INPUTPROJECTION, ISWITHIN) \ Status mapBuffer_##INPUTPROJECTION##_##ISWITHIN(int time, GPU::Buffer<uint32_t> devOut, GPU::Surface& panoSurf, const unsigned char* mask, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& inSurf, GPU::Stream gpuStream) const { \ if (mergeformat == ImageMerger::Format::Gradient) { \ if (!mask) return { Origin::Stitcher, ErrType::UnsupportedAction, "Mask was not allocated" }; \ return mapBuffer_gradientMerge_##INPUTPROJECTION##_##ISWITHIN(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ } else { \ return mapBuffer_noopMerge_##INPUTPROJECTION##_##ISWITHIN(time, devOut, panoSurf, mask, outputBounds, pano, im, inSurf, gpuStream); \ } \ } #define MAPBUFFERLOOKUP_PANO2(MERGER, ISWITHIN) \ MAPBUFFERLOOKUP_PANO3(MERGER, ISWITHIN, LinearPhotoCorrection) \ MAPBUFFERLOOKUP_PANO3(MERGER, ISWITHIN, GammaPhotoCorrection) \ MAPBUFFERLOOKUP_PANO3(MERGER, ISWITHIN, EmorPhotoCorrection) \ Status mapBufferLookup_##MERGER##_##ISWITHIN(int time, GPU::Buffer<uint32_t> devOut, GPU::Surface& panoSurf, const unsigned char* mask, const GPU::Surface& coordIn, \ const float coordShrinkFactor, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& inSurf, GPU::Stream gpuStream) const { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return mapBufferLookup_##MERGER##_##ISWITHIN##_LinearPhotoCorrection(time, devOut, panoSurf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return mapBufferLookup_##MERGER##_##ISWITHIN##_GammaPhotoCorrection(time, devOut, panoSurf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, inSurf, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return mapBufferLookup_##MERGER##_##ISWITHIN##_EmorPhotoCorrection(time, devOut, panoSurf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, inSurf, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } \ #define MAPBUFFERLOOKUP_PANO \ MAPBUFFERLOOKUP_PANO2(gradientMerge, isWithinCropRect) \ MAPBUFFERLOOKUP_PANO2(gradientMerge, isWithinCropCircle) \ MAPBUFFERLOOKUP_PANO2(noopMerge, isWithinCropRect) \ MAPBUFFERLOOKUP_PANO2(noopMerge, isWithinCropCircle) \ #define MAPBUFFERCOORD_PANO2(INPUTPROJECTION, ISWITHIN) \ MAPBUFFERCOORD_PANO3(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN) \ MAPBUFFERCOORD_PANO3(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status mapBufferCoord_##INPUTPROJECTION##_##ISWITHIN(int time, VideoStitch::GPU::Surface& devOut, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { \ if (im.getUseMeterDistortion() == false) { \ return mapBufferCoord_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN(time, devOut, outputBounds, pano, im, gpuStream); \ } \ else { \ return mapBufferCoord_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN(time, devOut, outputBounds, pano, im, gpuStream); \ } \ } \ #define MAPBUFFERCOORD_PANO \ MAPBUFFERCOORD_PANO2(SphereToRect, isWithinCropRect) \ MAPBUFFERCOORD_PANO2(SphereToErect, isWithinCropRect) \ MAPBUFFERCOORD_PANO2(SphereToExternal, isWithinCropRect) \ MAPBUFFERCOORD_PANO2(SphereToExternal, isWithinCropCircle) \ MAPBUFFERCOORD_PANO2(SphereToFisheye, isWithinCropRect) \ MAPBUFFERCOORD_PANO2(SphereToFisheye, isWithinCropCircle) #define MAPCOORDINPUT_PANO2(INPUTPROJECTION, ISWITHIN) \ MAPCOORDINPUT_PANO3(INPUTPROJECTION, noopDistortionTransform, inverseDistortionScaled, ISWITHIN) \ MAPCOORDINPUT_PANO3(INPUTPROJECTION, inverseDistortionScaled, noopDistortionTransform, ISWITHIN) \ Status mapCoordInput_##INPUTPROJECTION##_##ISWITHIN(int time, const int scaleFactor, GPU::Buffer<float2> inputCoord, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { \ if (im.getUseMeterDistortion() == false) { \ return mapCoordInput_##INPUTPROJECTION##_##noopDistortionTransform##_##inverseDistortionScaled##_##ISWITHIN(time, scaleFactor, inputCoord, pano, im, gpuStream); \ } \ else { \ return mapCoordInput_##INPUTPROJECTION##_##inverseDistortionScaled##_##noopDistortionTransform##_##ISWITHIN(time, scaleFactor, inputCoord, pano, im, gpuStream); \ } \ } #define MAPCOORDINPUT_PANO \ MAPCOORDINPUT_PANO2(RectToSphere, isWithinCropRect) \ MAPCOORDINPUT_PANO2(ErectToSphere, isWithinCropRect) \ MAPCOORDINPUT_PANO2(ExternalToSphere, isWithinCropRect) \ MAPCOORDINPUT_PANO2(ExternalToSphere, isWithinCropCircle) \ MAPCOORDINPUT_PANO2(FisheyeToSphere, isWithinCropRect) \ MAPCOORDINPUT_PANO2(FisheyeToSphere, isWithinCropCircle) #define COMPUTEZONE_PANO2(INPUTPROJECTION, ISWITHIN) \ COMPUTEZONE_PANO3(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN) \ COMPUTEZONE_PANO3(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status computeZone_##INPUTPROJECTION##_##ISWITHIN(GPU::Buffer<uint32_t> devOut, const PanoDefinition& pano, const InputDefinition& im, videoreaderid_t imId, GPU::Buffer<const unsigned char> maskDevBuffer, GPU::Stream stream) const { \ if (im.getUseMeterDistortion() == false) { \ return computeZone_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN(devOut, pano, im, imId, maskDevBuffer, stream); \ } \ else { \ return computeZone_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN(devOut, pano, im, imId, maskDevBuffer, stream); \ } \ } \ #define COMPUTEZONE_PANO \ COMPUTEZONE_PANO2(SphereToRect, isWithinCropRect) \ COMPUTEZONE_PANO2(SphereToErect, isWithinCropRect) \ COMPUTEZONE_PANO2(SphereToExternal, isWithinCropRect) \ COMPUTEZONE_PANO2(SphereToExternal, isWithinCropCircle) \ COMPUTEZONE_PANO2(SphereToFisheye, isWithinCropRect) \ COMPUTEZONE_PANO2(SphereToFisheye, isWithinCropCircle) \ #define CUBEMAPMAP_PANO3(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN) \ CUBEMAPMAP_PANO4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, true) \ CUBEMAPMAP_PANO4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, false) \ Status cubemapMap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN(GPU::Buffer<uint32_t> xPos, GPU::Buffer<uint32_t> xNeg, \ GPU::Buffer<uint32_t> yPos, GPU::Buffer<uint32_t> yNeg, \ GPU::Buffer<uint32_t> zPos, GPU::Buffer<uint32_t> zNeg, \ const PanoDefinition& pano, const InputDefinition& im, videoreaderid_t imId, \ GPU::Buffer<const unsigned char> maskDevBuffer, \ bool equiangular, \ GPU::Stream stream) const { \ if (equiangular) { \ return cubemapMap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##true (xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, stream); \ } else { \ return cubemapMap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##false (xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, stream); \ } \ } #define CUBEMAPMAP_PANO2(INPUTPROJECTION, ISWITHIN) \ CUBEMAPMAP_PANO3(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN) \ CUBEMAPMAP_PANO3(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status cubemapMap_##INPUTPROJECTION##_##ISWITHIN(GPU::Buffer<uint32_t> xPos, GPU::Buffer<uint32_t> xNeg, \ GPU::Buffer<uint32_t> yPos, GPU::Buffer<uint32_t> yNeg, \ GPU::Buffer<uint32_t> zPos, GPU::Buffer<uint32_t> zNeg, \ const PanoDefinition& pano, const InputDefinition& im, videoreaderid_t imId, \ GPU::Buffer<const unsigned char> maskDevBuffer, \ bool equiangular, \ GPU::Stream stream) const { \ if (im.getUseMeterDistortion() == false) { \ return cubemapMap_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); \ } \ else { \ return cubemapMap_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); \ } \ } \ #define CUBEMAPMAP_PANO \ CUBEMAPMAP_PANO2(SphereToRect, isWithinCropRect) \ CUBEMAPMAP_PANO2(SphereToErect, isWithinCropRect) \ CUBEMAPMAP_PANO2(SphereToExternal, isWithinCropRect) \ CUBEMAPMAP_PANO2(SphereToExternal, isWithinCropCircle) \ CUBEMAPMAP_PANO2(SphereToFisheye, isWithinCropRect) \ CUBEMAPMAP_PANO2(SphereToFisheye, isWithinCropCircle) #define WARP_CUBEMAP2(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, PHOTORESPONSE) \ WARP_CUBEMAP3(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, PHOTORESPONSE, true) \ WARP_CUBEMAP3(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, PHOTORESPONSE, false) \ Status warpCubemap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##PHOTORESPONSE(int time, \ GPU::Buffer<uint32_t> xPos, const Rect& xPosBB, \ GPU::Buffer<uint32_t> xNeg, const Rect& xNegBB, \ GPU::Buffer<uint32_t> yPos, const Rect& yPosBB, \ GPU::Buffer<uint32_t> yNeg, const Rect& yNegBB, \ GPU::Buffer<uint32_t> zPos, const Rect& zPosBB, \ GPU::Buffer<uint32_t> zNeg, const Rect& zNegBB, \ const PanoDefinition& pano, const InputDefinition& im, \ GPU::Surface& surface, \ bool equiangular, \ GPU::Stream stream) const { \ if (equiangular) { \ return warpCubemap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##PHOTORESPONSE##_##true (time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, stream); \ } else { \ return warpCubemap_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##PHOTORESPONSE##_##false (time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, stream); \ } \ } #define WARP_CUBEMAP(INPUTPROJECTION, ISWITHIN) \ WARP_CUBEMAP2(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, LinearPhotoCorrection) \ WARP_CUBEMAP2(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, GammaPhotoCorrection) \ WARP_CUBEMAP2(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN, EmorPhotoCorrection) \ WARP_CUBEMAP2(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, LinearPhotoCorrection) \ WARP_CUBEMAP2(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, GammaPhotoCorrection) \ WARP_CUBEMAP2(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN, EmorPhotoCorrection) \ Status warpCubemap_##INPUTPROJECTION##_##ISWITHIN(int time, \ GPU::Buffer<uint32_t> xPos, const Rect& xPosBB, \ GPU::Buffer<uint32_t> xNeg, const Rect& xNegBB, \ GPU::Buffer<uint32_t> yPos, const Rect& yPosBB, \ GPU::Buffer<uint32_t> yNeg, const Rect& yNegBB, \ GPU::Buffer<uint32_t> zPos, const Rect& zPosBB, \ GPU::Buffer<uint32_t> zNeg, const Rect& zNegBB, \ const PanoDefinition& pano, const InputDefinition& im, \ GPU::Surface& surface, \ bool equiangular, \ GPU::Stream gpuStream) const { \ if (im.getUseMeterDistortion() == false) { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return warpCubemap_##INPUTPROJECTION##_noopDistortionTransform_distortionScaled_##ISWITHIN##_LinearPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return warpCubemap_##INPUTPROJECTION##_noopDistortionTransform_distortionScaled_##ISWITHIN##_GammaPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return warpCubemap_##INPUTPROJECTION##_noopDistortionTransform_distortionScaled_##ISWITHIN##_EmorPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } \ else { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return warpCubemap_##INPUTPROJECTION##_distortionScaled_noopDistortionTransform_##ISWITHIN##_LinearPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return warpCubemap_##INPUTPROJECTION##_distortionScaled_noopDistortionTransform_##ISWITHIN##_GammaPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return warpCubemap_##INPUTPROJECTION##_distortionScaled_noopDistortionTransform_##ISWITHIN##_EmorPhotoCorrection(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } \ } \ #define MAPDISTORTION_PANO2(INPUTPROJECTION, ISWITHIN) \ MAPDISTORTION_PANO3(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN) \ MAPDISTORTION_PANO3(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status mapDistortion_##INPUTPROJECTION##_##ISWITHIN(int time, GPU::Buffer<unsigned char> devOut, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { \ if (im.getUseMeterDistortion() == false) { \ return mapDistortion_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN (time, devOut, outputBounds, pano, im, gpuStream); \ } else { \ return mapDistortion_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN (time, devOut, outputBounds, pano, im, gpuStream); \ } \ } \ #define MAPDISTORTION_PANO \ MAPDISTORTION_PANO2(SphereToRect, isWithinCropRect) \ MAPDISTORTION_PANO2(SphereToErect, isWithinCropRect) \ MAPDISTORTION_PANO2(SphereToExternal, isWithinCropCircle) \ MAPDISTORTION_PANO2(SphereToExternal, isWithinCropRect) \ MAPDISTORTION_PANO2(SphereToFisheye, isWithinCropRect) \ MAPDISTORTION_PANO2(SphereToFisheye, isWithinCropCircle) #define UNDISTORT_INPUT4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, OUTPROJECTION) \ UNDISTORT_INPUT5(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, OUTPROJECTION, LinearPhotoCorrection) \ UNDISTORT_INPUT5(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, OUTPROJECTION, GammaPhotoCorrection) \ UNDISTORT_INPUT5(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, OUTPROJECTION, EmorPhotoCorrection) \ Status undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##OUTPROJECTION(int time, \ GPU::Surface& dst, const GPU::Surface& src, \ const PanoDefinition& pano, \ const InputDefinition& in, const InputDefinition& out, \ GPU::Stream& stream) const { \ switch (photoresponse) { \ case InputDefinition::PhotoResponse::LinearResponse: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##OUTPROJECTION##_LinearPhotoCorrection(time, dst, src, pano, in, out, stream); \ case InputDefinition::PhotoResponse::GammaResponse: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##OUTPROJECTION##_GammaPhotoCorrection(time, dst, src, pano, in, out, stream); \ case InputDefinition::PhotoResponse::EmorResponse: \ case InputDefinition::PhotoResponse::InvEmorResponse: \ case InputDefinition::PhotoResponse::CurveResponse: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##OUTPROJECTION##_EmorPhotoCorrection(time, dst, src, pano, in, out, stream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid photo response" }; \ } \ } #define UNDISTORT_INPUT3(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN) \ UNDISTORT_INPUT4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, RectToSphere) \ UNDISTORT_INPUT4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, ErectToSphere) \ UNDISTORT_INPUT4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, ExternalToSphere) \ UNDISTORT_INPUT4(INPUTPROJECTION, DISTORTIONMETERS, DISTORTIONPIXELS, ISWITHIN, FisheyeToSphere) \ Status undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN(int time, \ GPU::Surface& dst, const GPU::Surface& src, \ const PanoDefinition& pano, \ const InputDefinition& in, const InputDefinition& out, \ GPU::Stream& stream) const { \ switch (out.getFormat()) { \ case InputDefinition::Format::Rectilinear: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##RectToSphere(time, dst, src, pano, in, out, stream); \ case InputDefinition::Format::Equirectangular: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##ErectToSphere(time, dst, src, pano, in, out, stream); \ case InputDefinition::Format::CircularFisheye_Opt: \ case InputDefinition::Format::FullFrameFisheye_Opt: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##ExternalToSphere(time, dst, src, pano, in, out, stream); \ case InputDefinition::Format::CircularFisheye: \ case InputDefinition::Format::FullFrameFisheye: \ return undistortInput_##INPUTPROJECTION##_##DISTORTIONMETERS##_##DISTORTIONPIXELS##_##ISWITHIN##_##FisheyeToSphere(time, dst, src, pano, in, out, stream); \ default: \ return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; \ }; \ } #define UNDISTORT_INPUT2(INPUTPROJECTION, ISWITHIN) \ UNDISTORT_INPUT3(INPUTPROJECTION, noopDistortionTransform, distortionScaled, ISWITHIN) \ UNDISTORT_INPUT3(INPUTPROJECTION, distortionScaled, noopDistortionTransform, ISWITHIN) \ Status undistortInput_##INPUTPROJECTION##_##ISWITHIN(int time, \ GPU::Surface& dst, const GPU::Surface& src, \ const PanoDefinition& pano, \ const InputDefinition& in, const InputDefinition& out, \ GPU::Stream& stream) const { \ if (in.getUseMeterDistortion() == false) { \ return undistortInput_##INPUTPROJECTION##_##noopDistortionTransform##_##distortionScaled##_##ISWITHIN(time, dst, src, pano, in, out, stream); \ } else { \ return undistortInput_##INPUTPROJECTION##_##distortionScaled##_##noopDistortionTransform##_##ISWITHIN(time, dst, src, pano, in, out, stream); \ } \ } #define UNDISTORT_INPUT \ UNDISTORT_INPUT2(SphereToRect, isWithinCropRect) \ UNDISTORT_INPUT2(SphereToErect, isWithinCropRect) \ UNDISTORT_INPUT2(SphereToExternal, isWithinCropCircle) \ UNDISTORT_INPUT2(SphereToExternal, isWithinCropRect) \ UNDISTORT_INPUT2(SphereToFisheye, isWithinCropRect) \ UNDISTORT_INPUT2(SphereToFisheye, isWithinCropCircle) /** *Transform final implementation. *The factory is here since we need explicit access to the transform stack for template instantiation */ class TransformImpl : public Transform { public: TransformImpl(DevicePhotoTransform* p, const InputDefinition::Format & inputf, const InputDefinition::PhotoResponse & presponse, const ImageMerger::Format & type) : photo(p), inputformat(inputf), photoresponse(presponse), mergeformat(type) { } virtual ~TransformImpl() { delete photo; } Status mapBuffer(int time, GPU::Buffer<uint32_t> devOut, GPU::Surface& surf, const unsigned char* mask, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& surface, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapBuffer_SphereToRect_isWithinCropRect(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); case InputDefinition::Format::Equirectangular: return mapBuffer_SphereToErect_isWithinCropRect(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapBuffer_SphereToExternal_isWithinCropCircle(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapBuffer_SphereToExternal_isWithinCropRect(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); case InputDefinition::Format::CircularFisheye: return mapBuffer_SphereToFisheye_isWithinCropCircle(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapBuffer_SphereToFisheye_isWithinCropRect(time, devOut, surf, mask, outputBounds, pano, im, surface, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; } } Status warpCubemap(int time, GPU::Buffer<uint32_t> xPos, const Rect& xPosBB, GPU::Buffer<uint32_t> xNeg, const Rect& xNegBB, GPU::Buffer<uint32_t> yPos, const Rect& yPosBB, GPU::Buffer<uint32_t> yNeg, const Rect& yNegBB, GPU::Buffer<uint32_t> zPos, const Rect& zPosBB, GPU::Buffer<uint32_t> zNeg, const Rect& zNegBB, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& surface, bool equiangular, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return warpCubemap_SphereToRect_isWithinCropRect(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); case InputDefinition::Format::Equirectangular: return warpCubemap_SphereToErect_isWithinCropRect(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return warpCubemap_SphereToExternal_isWithinCropCircle(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return warpCubemap_SphereToExternal_isWithinCropRect(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); case InputDefinition::Format::CircularFisheye: return warpCubemap_SphereToFisheye_isWithinCropCircle(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); case InputDefinition::Format::FullFrameFisheye: return warpCubemap_SphereToFisheye_isWithinCropRect(time, xPos, xPosBB, xNeg, xNegBB, yPos, yPosBB, yNeg, yNegBB, zPos, zPosBB, zNeg, zNegBB, pano, im, surface, equiangular, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; } } Status mapBufferLookup(int time, GPU::Buffer<uint32_t> devOut, GPU::Surface& surf, const unsigned char* mask, const GPU::Surface& coordIn, const float coordShrinkFactor, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Surface& surface, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: case InputDefinition::Format::Equirectangular: case InputDefinition::Format::FullFrameFisheye_Opt: case InputDefinition::Format::FullFrameFisheye: if (mergeformat == ImageMerger::Format::Gradient) { if (!mask) return { Origin::Stitcher, ErrType::UnsupportedAction, "Mask was not allocated" }; return mapBufferLookup_gradientMerge_isWithinCropRect(time, devOut, surf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, surface, gpuStream); } else { return mapBufferLookup_noopMerge_isWithinCropRect(time, devOut, surf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, surface, gpuStream); } case InputDefinition::Format::CircularFisheye_Opt: case InputDefinition::Format::CircularFisheye: if (mergeformat == ImageMerger::Format::Gradient) { if (!mask) return { Origin::Stitcher, ErrType::UnsupportedAction, "Mask was not allocated" }; return mapBufferLookup_gradientMerge_isWithinCropCircle(time, devOut, surf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, surface, gpuStream); } else { return mapBufferLookup_noopMerge_isWithinCropCircle(time, devOut, surf, mask, coordIn, coordShrinkFactor, outputBounds, pano, im, surface, gpuStream); } default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } Status mapBufferCoord(int time, GPU::Surface& devOut, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapBufferCoord_SphereToRect_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::Equirectangular: return mapBufferCoord_SphereToErect_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapBufferCoord_SphereToExternal_isWithinCropCircle(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapBufferCoord_SphereToExternal_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye: return mapBufferCoord_SphereToFisheye_isWithinCropCircle(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapBufferCoord_SphereToFisheye_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } Status mapCoordInput(int time, const int scaleFactor, GPU::Buffer<float2> inputCoord, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapCoordInput_RectToSphere_isWithinCropRect(time, scaleFactor, inputCoord, pano, im, gpuStream); case InputDefinition::Format::Equirectangular: return mapCoordInput_ErectToSphere_isWithinCropRect(time, scaleFactor, inputCoord, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapCoordInput_ExternalToSphere_isWithinCropCircle(time, scaleFactor, inputCoord, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapCoordInput_ExternalToSphere_isWithinCropRect(time, scaleFactor, inputCoord, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye: return mapCoordInput_FisheyeToSphere_isWithinCropCircle(time, scaleFactor, inputCoord, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapCoordInput_FisheyeToSphere_isWithinCropRect(time, scaleFactor, inputCoord, pano, im, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } Status computeZone(GPU::Buffer<uint32_t> devOut, const PanoDefinition& pano, const InputDefinition& im, videoreaderid_t imId, GPU::Buffer<const unsigned char> maskDevBuffer, GPU::Stream stream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return computeZone_SphereToRect_isWithinCropRect(devOut, pano, im, imId, maskDevBuffer, stream); case InputDefinition::Format::Equirectangular: return computeZone_SphereToErect_isWithinCropRect(devOut, pano, im, imId, maskDevBuffer, stream); case InputDefinition::Format::CircularFisheye_Opt: return computeZone_SphereToExternal_isWithinCropCircle(devOut, pano, im, imId, maskDevBuffer, stream); case InputDefinition::Format::FullFrameFisheye_Opt: return computeZone_SphereToExternal_isWithinCropRect(devOut, pano, im, imId, maskDevBuffer, stream); case InputDefinition::Format::CircularFisheye: return computeZone_SphereToFisheye_isWithinCropCircle(devOut, pano, im, imId, maskDevBuffer, stream); case InputDefinition::Format::FullFrameFisheye: return computeZone_SphereToFisheye_isWithinCropRect(devOut, pano, im, imId, maskDevBuffer, stream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } Status cubemapMap(GPU::Buffer<uint32_t> xPos, GPU::Buffer<uint32_t> xNeg, GPU::Buffer<uint32_t> yPos, GPU::Buffer<uint32_t> yNeg, GPU::Buffer<uint32_t> zPos, GPU::Buffer<uint32_t> zNeg, const PanoDefinition& pano, const InputDefinition& im, videoreaderid_t imId, GPU::Buffer<const unsigned char> maskDevBuffer, bool equiangular, GPU::Stream stream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return cubemapMap_SphereToRect_isWithinCropRect(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); case InputDefinition::Format::Equirectangular: return cubemapMap_SphereToErect_isWithinCropRect(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); case InputDefinition::Format::CircularFisheye_Opt: return cubemapMap_SphereToExternal_isWithinCropCircle(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); case InputDefinition::Format::FullFrameFisheye_Opt: return cubemapMap_SphereToExternal_isWithinCropRect(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); case InputDefinition::Format::CircularFisheye: return cubemapMap_SphereToFisheye_isWithinCropCircle(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); case InputDefinition::Format::FullFrameFisheye: return cubemapMap_SphereToFisheye_isWithinCropRect(xPos, xNeg, yPos, yNeg, zPos, zNeg, pano, im, imId, maskDevBuffer, equiangular, stream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } Status mapDistortion(int time, GPU::Buffer<unsigned char> devOut, const Rect& outputBounds, const PanoDefinition& pano, const InputDefinition& im, GPU::Stream gpuStream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return mapDistortion_SphereToRect_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::Equirectangular: return mapDistortion_SphereToErect_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye_Opt: return mapDistortion_SphereToExternal_isWithinCropCircle(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye_Opt: return mapDistortion_SphereToExternal_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::CircularFisheye: return mapDistortion_SphereToFisheye_isWithinCropCircle(time, devOut, outputBounds, pano, im, gpuStream); case InputDefinition::Format::FullFrameFisheye: return mapDistortion_SphereToFisheye_isWithinCropRect(time, devOut, outputBounds, pano, im, gpuStream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } virtual Status undistortInput(int time, GPU::Surface& dst, const GPU::Surface& src, const PanoDefinition& pano, const InputDefinition& in, const InputDefinition& out, GPU::Stream& stream) const { switch (inputformat) { case InputDefinition::Format::Rectilinear: return undistortInput_SphereToRect_isWithinCropRect(time, dst, src, pano, in, out, stream); case InputDefinition::Format::Equirectangular: return undistortInput_SphereToErect_isWithinCropRect(time, dst, src, pano, in, out, stream); case InputDefinition::Format::CircularFisheye_Opt: return undistortInput_SphereToExternal_isWithinCropCircle(time, dst, src, pano, in, out, stream); case InputDefinition::Format::FullFrameFisheye_Opt: return undistortInput_SphereToExternal_isWithinCropRect(time, dst, src, pano, in, out, stream); case InputDefinition::Format::CircularFisheye: return undistortInput_SphereToFisheye_isWithinCropCircle(time, dst, src, pano, in, out, stream); case InputDefinition::Format::FullFrameFisheye: return undistortInput_SphereToFisheye_isWithinCropRect(time, dst, src, pano, in, out, stream); default: return { Origin::Stitcher, ErrType::UnsupportedAction, "Invalid input projection" }; }; } private: MAPBUFFER_PANO(SphereToRect, isWithinCropRect) MAPBUFFER_PANO(SphereToErect, isWithinCropRect) MAPBUFFER_PANO(SphereToExternal, isWithinCropRect) MAPBUFFER_PANO(SphereToExternal, isWithinCropCircle) MAPBUFFER_PANO(SphereToFisheye, isWithinCropRect) MAPBUFFER_PANO(SphereToFisheye, isWithinCropCircle) WARP_CUBEMAP(SphereToRect, isWithinCropRect) WARP_CUBEMAP(SphereToErect, isWithinCropRect) WARP_CUBEMAP(SphereToExternal, isWithinCropRect) WARP_CUBEMAP(SphereToExternal, isWithinCropCircle) WARP_CUBEMAP(SphereToFisheye, isWithinCropRect) WARP_CUBEMAP(SphereToFisheye, isWithinCropCircle) MAPBUFFERLOOKUP_PANO MAPBUFFERCOORD_PANO MAPCOORDINPUT_PANO COMPUTEZONE_PANO CUBEMAPMAP_PANO MAPDISTORTION_PANO UNDISTORT_INPUT private: DevicePhotoTransform * const photo; InputDefinition::Format inputformat; InputDefinition::PhotoResponse photoresponse; ImageMerger::Format mergeformat; }; Transform* createTransform(const InputDefinition& im, const ImageMerger::Format type) { DevicePhotoTransform * photo = DevicePhotoTransform::create(im); if (!photo) { return nullptr; } return new TransformImpl(photo, im.getFormat(), im.getPhotoResponse(), type); } } } }