#include "warp_images.h"

// ---------- Constructor ---------- //
WarpImages::WarpImages(int no_of_videos,
	std::string warp_type,
	cv::Ptr<cv::WarperCreator> &warper_creator,
	float warped_image_scale,
	double seam_work_aspect) :
	no_of_videos(no_of_videos),
	swa((float)seam_work_aspect) {

	if (warp_type == "plane") warper_creator = new cv::PlaneWarper();
	else if (warp_type == "cylindrical") warper_creator = new cv::CylindricalWarper();
	else if (warp_type == "spherical") warper_creator = new cv::SphericalWarper();
	else if (warp_type == "fisheye") warper_creator = new cv::FisheyeWarper();
	else if (warp_type == "stereographic") warper_creator = new cv::StereographicWarper();
	else if (warp_type == "compressedPlaneA2B1") warper_creator = new cv::CompressedRectilinearWarper(2, 1);
	else if (warp_type == "compressedPlaneA1.5B1") warper_creator = new cv::CompressedRectilinearWarper(1.5, 1);
	else if (warp_type == "compressedPlanePortraitA2B1") warper_creator = new cv::CompressedRectilinearPortraitWarper(2, 1);
	else if (warp_type == "compressedPlanePortraitA1.5B1") warper_creator = new cv::CompressedRectilinearPortraitWarper(1.5, 1);
	else if (warp_type == "paniniA2B1") warper_creator = new cv::PaniniWarper(2, 1);
	else if (warp_type == "paniniA1.5B1") warper_creator = new cv::PaniniWarper(1.5, 1);
	else if (warp_type == "paniniPortraitA2B1") warper_creator = new cv::PaniniPortraitWarper(2, 1);
	else if (warp_type == "paniniPortraitA1.5B1") warper_creator = new cv::PaniniPortraitWarper(1.5, 1);
	else if (warp_type == "mercator") warper_creator = new cv::MercatorWarper();
	else if (warp_type == "transverseMercator") warper_creator = new cv::TransverseMercatorWarper();

	warper = warper_creator->create(static_cast<float>(warped_image_scale * seam_work_aspect));
}

int WarpImages::warp_images(std::vector<cv::Point> &corners,
	std::vector<cv::Mat> &masks_warped,
	std::vector<cv::Mat> &images_warped,
	std::vector<cv::Size> &sizes,
	std::vector<cv::Mat> &images,
	std::vector<cv::detail::CameraParams> &cameraParameters,
	std::vector<cv::Mat> &images_warped_temp) {

	// Prepare image masks
	for (int i = 0; i < no_of_videos; ++i) {
		cv::Mat scalar;
		scalar.create(images[i].size(), CV_8U);
		scalar.setTo(cv::Scalar::all(255));

		masks.push_back(scalar);
	}

	// Warp images and their masks
	for (int i = 0; i < no_of_videos; ++i) {
		cv::Mat_<float> K;
		cameraParameters[i].K().convertTo(K, CV_32F);
		K(0, 0) *= swa;
		K(0, 2) *= swa;
		K(1, 1) *= swa;
		K(1, 2) *= swa;

		corners[i] = warper->warp(images[i], K, cameraParameters[i].R, cv::INTER_LINEAR, cv::BORDER_REFLECT, images_warped[i]);
		sizes[i] = images_warped[i].size();

		warper->warp(masks[i], K, cameraParameters[i].R, cv::INTER_NEAREST, cv::BORDER_CONSTANT, masks_warped[i]);
	}

	for (int i = 0; i < no_of_videos; ++i) {
		images_warped[i].convertTo(images_warped_temp[i], CV_32F);
	}

	return 0;
}
