Skip to content
Snippets Groups Projects
camera.cpp 22.1 KiB
Newer Older
Nicolas Pope's avatar
Nicolas Pope committed
#include "camera.hpp"
#include "pose_window.hpp"
#include "screen.hpp"
#include <nanogui/glutil.h>

#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>

#include <ftl/operators/antialiasing.hpp>

#include <ftl/codecs/faces.hpp>

#include "overlay.hpp"
#include "statsimage.hpp"
#define LOGURU_REPLACE_GLOG 1
#include <loguru.hpp>

Sebastian Hahta's avatar
Sebastian Hahta committed
#ifdef HAVE_OPENVR
#include "vr.hpp"
#endif

Nicolas Pope's avatar
Nicolas Pope committed
using ftl::rgbd::isValidDepth;
using ftl::gui::GLTexture;
using ftl::gui::PoseWindow;
using ftl::codecs::Channel;
using ftl::codecs::Channels;
using cv::cuda::GpuMat;
static int vcamcount = 0;
Nicolas Pope's avatar
Nicolas Pope committed
static Eigen::Affine3d create_rotation_matrix(float ax, float ay, float az) {
Sebastian Hahta's avatar
Sebastian Hahta committed
	Eigen::Affine3d rx =
		Eigen::Affine3d(Eigen::AngleAxisd(ax, Eigen::Vector3d(1, 0, 0)));
	Eigen::Affine3d ry =
		Eigen::Affine3d(Eigen::AngleAxisd(ay, Eigen::Vector3d(0, 1, 0)));
	Eigen::Affine3d rz =
		Eigen::Affine3d(Eigen::AngleAxisd(az, Eigen::Vector3d(0, 0, 1)));
	return rz * rx * ry;
ftl::gui::Camera::Camera(ftl::gui::Screen *screen, int fsmask, int fid, ftl::codecs::Channel c) : screen_(screen), fsmask_(fsmask), fid_(fid), channel_(c),channels_(0u) {
Nicolas Pope's avatar
Nicolas Pope committed
	eye_ = Eigen::Vector3d(0.0f, 0.0f, 0.0f);
	neye_ = Eigen::Vector4d(0.0f, 0.0f, 0.0f, 0.0f);
	rotmat_.setIdentity();
	//up_ = Eigen::Vector3f(0,1.0f,0);
	lerpSpeed_ = 0.999f;
	sdepth_ = false;
Nicolas Pope's avatar
Nicolas Pope committed
	ftime_ = (float)glfwGetTime();
	pause_ = false;

#ifdef HAVE_OPENVR
	vr_mode_ = false;
#endif
	//channel_ = Channel::Left;
	channels_ += c;
	//channels_ += Channel::Depth;
	width_ = 0;
	height_ = 0;
	// Create pose window...
	//posewin_ = new PoseWindow(screen, src_->getURI());
	//posewin_->setTheme(screen->windowtheme);
	//posewin_->setVisible(false);
	posewin_ = nullptr;
	renderer_ = nullptr;
	post_pipe_ = nullptr;
	record_stream_ = nullptr;
	transform_ix_ = -1;

	/*src->setCallback([this](int64_t ts, ftl::rgbd::Frame &frame) {
		UNIQUE_LOCK(mutex_, lk);
		auto &channel1 = frame.get<GpuMat>(Channel::Colour);
		im1_.create(channel1.size(), channel1.type());
		channel1.download(im1_);
Sebastian Hahta's avatar
Sebastian Hahta committed
		// OpenGL (0,0) bottom left
		cv::flip(im1_, im1_, 0);

		if (channel_ != Channel::Colour && channel_ != Channel::None && frame.hasChannel(channel_)) {
			auto &channel2 = frame.get<GpuMat>(channel_);
			im2_.create(channel2.size(), channel2.type());
			channel2.download(im2_);
			cv::flip(im2_, im2_, 0);
		}
	//auto *host = screen->root();

	// Is virtual camera?
	if (fid == 255) {
		renderer_ = ftl::create<ftl::render::CUDARender>(screen_->root(), std::string("vcam")+std::to_string(vcamcount++));
		// Allow mask to be changed
		fsmask_ = renderer_->value("fsmask", fsmask_);
		renderer_->on("fsmask", [this](const ftl::config::Event &e) {
			fsmask_ = renderer_->value("fsmask", fsmask_);
		});

		intrinsics_ = ftl::create<ftl::Configurable>(renderer_, "intrinsics");
	
		state_.getLeft() = ftl::rgbd::Camera::from(intrinsics_);
		state_.getRight() = state_.getLeft();

		Eigen::Matrix4d pose;
		pose.setIdentity();
		state_.setPose(pose);

		for (auto &t : transforms_) {
			t.setIdentity();
		}
/*template<class T>
static Eigen::Matrix<T,4,4> lookAt
(
    Eigen::Matrix<T,3,1> const & eye,
    Eigen::Matrix<T,3,1> const & center,
    Eigen::Matrix<T,3,1> const & up
)
{
    typedef Eigen::Matrix<T,4,4> Matrix4;
    typedef Eigen::Matrix<T,3,1> Vector3;

    Vector3 f = (center - eye).normalized();
    Vector3 u = up.normalized();
    Vector3 s = f.cross(u).normalized();
    u = s.cross(f);

    Matrix4 res;
    res <<  s.x(),s.y(),s.z(),-s.dot(eye),
            u.x(),u.y(),u.z(),-u.dot(eye),
            -f.x(),-f.y(),-f.z(),f.dot(eye),
            0,0,0,1;

    return res;
}*/

/*static float4 screenProjection(
		const Eigen::Vector3f &pa,  // Screen corner 1
		const Eigen::Vector3f &pb,  // Screen corner 2
		const Eigen::Vector3f &pc,  // Screen corner 3
		const Eigen::Vector3f &pe  // Eye position
		) {

    Eigen::Vector3f va, vb, vc;
    Eigen::Vector3f vr, vu, vn;

    float l, r, b, t, d;

    // Compute an orthonormal basis for the screen.

    //subtract(vr, pb, pa);
    //subtract(vu, pc, pa);
	vr = pb - pa;
	vu = pc - pa;

    //normalize(vr);
    //normalize(vu);
    //cross_product(vn, vr, vu);
    //normalize(vn);
	vr.normalize();
	vu.normalize();
	vn = vr.cross(vu);
	vn.normalize();

    // Compute the screen corner vectors.

    //subtract(va, pa, pe);
    //subtract(vb, pb, pe);
    //subtract(vc, pc, pe);
	va = pa - pe;
	vb = pb - pe;
	vc = pc - pe;

    // Find the distance from the eye to screen plane.

    //d = -dot_product(va, vn);
	d = -va.dot(vn);

    // Find the extent of the perpendicular projection.

    //l = dot_product(vr, va) * n / d;
    //r = dot_product(vr, vb) * n / d;
    //b = dot_product(vu, va) * n / d;
    //t = dot_product(vu, vc) * n / d;

	float n = d;
	l = vr.dot(va) * n / d;
	r = vr.dot(vb) * n / d;
	b = vu.dot(va) * n / d;
	t = vu.dot(vc) * n / d;

	//return nanogui::frustum(l,r,b,t,n,f);
	return make_float4(l,r,b,t);
}*/

Nicolas Pope's avatar
Nicolas Pope committed
ftl::gui::Camera::~Camera() {
	//delete writer_;
	//delete fileout_;
}

static Eigen::Vector3f cudaToEigen(const float3 &v) {
	Eigen::Vector3f e;
	e[0] = v.x;
	e[1] = v.y;
	e[2] = v.z;
	return e;
}

void ftl::gui::Camera::draw(std::vector<ftl::rgbd::FrameSet*> &fss) {
	if (fid_ != 255) return;
	//if (fsid_ >= fss.size()) return;

	//auto &fs = *fss[fsid_];

	UNIQUE_LOCK(mutex_, lk2);
	//state_.getLeft().fx = intrinsics_->value("focal", 700.0f);
	//state_.getLeft().fy = state_.getLeft().fx;
	_draw(fss);
Nicolas Pope's avatar
Nicolas Pope committed

	if (renderer_->value("window_effect", false)) {
		for (auto *fset : fss) {
			for (const auto &f : fset->frames) {
				if (f.hasChannel(Channel::Faces)) {
					std::vector<ftl::codecs::Face> data;
					f.get(Channel::Faces, data);

					if (data.size() > 0) {
						auto &d = *data.rbegin();
						
						//cv::Mat over_depth;
						//over_depth.create(im1_.size(), CV_32F);

						auto cam = ftl::rgbd::Camera::from(intrinsics_);

						float screenWidth = intrinsics_->value("screen_size", 1.2f);  // In meters
						float screenHeight = (9.0f/16.0f) * screenWidth;

						//Eigen::Vector3f pc(-screenWidth/2.0f,-screenHeight/2.0f,0.0);
						Eigen::Vector3f pa(-screenWidth/2.0f,screenHeight/2.0f,0.0);
						//Eigen::Vector3f pb(screenWidth/2.0f,screenHeight/2.0f,0.0);

						float screenDistance = (d.depth > cam.minDepth && d.depth < cam.maxDepth) ? d.depth : intrinsics_->value("screen_dist_default", 1.2f);  // Face distance from screen in meters

						auto pos = f.getLeft().screenToCam(d.box.x+(d.box.width/2), d.box.y+(d.box.height/2), -screenDistance);
						Eigen::Vector3f eye;
						eye[0] = pos.x;
						eye[1] = -pos.y;
						eye[2] = pos.z;

						Eigen::Translation3f trans(eye);
						Eigen::Affine3f t(trans);
						Eigen::Matrix4f viewPose = t.matrix();

						// Top Left norm dist
						Eigen::Vector3f tl = (pa - eye);
						Eigen::Vector3f princ = tl;

						Eigen::Matrix4d windowPose;
						windowPose.setIdentity();

						Eigen::Matrix4d fakepose = viewPose.cast<double>().inverse() * state_.getPose();
						ftl::rgbd::Camera fakecam = cam;
						fakecam.fx = screenDistance; //eye.norm();
						fakecam.fy = fakecam.fx;
						fakecam.cx = (princ[0]) * fakecam.fx / princ[2] / screenWidth * cam.width;
						fakecam.cy = ((princ[1]) * fakecam.fy / princ[2] / screenHeight * cam.height) - cam.height;
						fakecam.fx = fakecam.fx / screenWidth * cam.width;
						fakecam.fy = fakecam.fy / screenHeight * cam.height;

						// Use face tracked window pose for virtual camera
						state_.getLeft() = fakecam;
						transform_ix_ = fset->id;  // Disable keyboard/mouse pose setting
						state_.setPose(transforms_[transform_ix_] * viewPose.cast<double>());

						//ftl::overlay::draw3DLine(state_.getLeft(), im1_, over_depth, state_.getPose().inverse() * Eigen::Vector4d(eye[0],eye[1],eye[2],1), state_.getPose().inverse() * Eigen::Vector4d(0,0,0,1), cv::Scalar(0,0,255,0));
						//ftl::overlay::drawRectangle(state_.getLeft(), im1_, over_depth, windowPose.inverse() * state_.getPose(), cv::Scalar(255,0,0,0), screenWidth, screenHeight);
						//ftl::overlay::drawCamera(state_.getLeft(), im1_, over_depth, fakecam, fakepose, cv::Scalar(255,0,255,255), 1.0,screen_->root()->value("show_frustrum", false));
					}
void ftl::gui::Camera::_draw(std::vector<ftl::rgbd::FrameSet*> &fss) {
	frame_.reset();
	frame_.setOrigin(&state_);
	renderer_->begin(frame_);
	for (auto *fs : fss) {
		if (!usesFrameset(fs->id)) continue;

		// FIXME: Should perhaps remain locked until after end is called?
		// Definitely: causes flashing if not.
		UNIQUE_LOCK(fs->mtx,lk);
		renderer_->submit(fs, Channels<0>(channel_), transforms_[fs->id]);
	}
	renderer_->end();
	if (!post_pipe_) {
		post_pipe_ = ftl::config::create<ftl::operators::Graph>(screen_->root(), "post_filters");
		post_pipe_->append<ftl::operators::FXAA>("fxaa");
	}

	post_pipe_->apply(frame_, frame_, 0);

	_downloadFrames(&frame_);

	if (screen_->root()->value("show_poses", false)) {
		cv::Mat over_col, over_depth;
		over_col.create(im1_.size(), CV_8UC4);
		over_depth.create(im1_.size(), CV_32F);

		for (auto *fs : fss) {
			if (!usesFrameset(fs->id)) continue;
			for (int i=0; i<fs->frames.size(); ++i) {
				auto pose = fs->frames[i].getPose().inverse() * state_.getPose();
				Eigen::Vector4d pos = pose.inverse() * Eigen::Vector4d(0,0,0,1);
				pos /= pos[3];
				auto name = fs->frames[i].get<std::string>("name");
				ftl::overlay::drawCamera(state_.getLeft(), im1_, over_depth, fs->frames[i].getLeftCamera(), pose, cv::Scalar(0,0,255,255), 0.2,screen_->root()->value("show_frustrum", false));
				if (name) ftl::overlay::drawText(state_.getLeft(), im1_, over_depth, *name, pos, 0.5, cv::Scalar(0,0,255,255));
			}
	if (record_stream_ && record_stream_->active()) {
		// TODO: Allow custom channel selection
		ftl::rgbd::FrameSet fs2;
		auto &f = fs2.frames.emplace_back();
		fs2.count = 1;
		fs2.mask = 1;
		fs2.stale = false;
		frame_.swapTo(Channels<0>(Channel::Colour), f);  // Channel::Colour + Channel::Depth
		fs2.timestamp = ftl::timer::get_time();
		fs2.id = 0;
		record_sender_->post(fs2);
		record_stream_->select(0, Channels<0>(Channel::Colour));
		f.swapTo(Channels<0>(Channel::Colour), frame_);
	}
}

void ftl::gui::Camera::_downloadFrames(ftl::rgbd::Frame *frame) {
	if (!frame) return;

	// Use high res colour if available..
	auto &channel1 = (frame->hasChannel(Channel::ColourHighRes)) ? 
			frame->get<GpuMat>(Channel::ColourHighRes) :
			frame->get<GpuMat>(Channel::Colour);
	im1_.create(channel1.size(), channel1.type());
	channel1.download(im1_);

	// OpenGL (0,0) bottom left
	cv::flip(im1_, im1_, 0);

	width_ = im1_.cols;
	height_ = im1_.rows;

	if (channel_ != Channel::Colour && channel_ != Channel::None && frame->hasChannel(channel_)) {
		auto &channel2 = frame->get<GpuMat>(channel_);
		im2_.create(channel2.size(), channel2.type());
		channel2.download(im2_);
		//LOG(INFO) << "Have channel2: " << im2_.type() << ", " << im2_.size();
		cv::flip(im2_, im2_, 0);
	}
}

void ftl::gui::Camera::update(std::vector<ftl::rgbd::FrameSet*> &fss) {
	UNIQUE_LOCK(mutex_, lk);

	//if (fss.size() <= fsid_) return;
	if (fid_ == 255) {
		name_ = "Virtual Camera";
		// Do a draw if not active. If active the draw function will be called
		// directly.
		if (screen_->activeCamera() != this) {
			_draw(fss);
	} else {
		for (auto *fs : fss) {
			if (!usesFrameset(fs->id)) continue;

			ftl::rgbd::Frame *frame = nullptr;

			if (fid_ >= fs->frames.size()) return;
			frame = &fs->frames[fid_];
			_downloadFrames(frame);
			auto n = frame->get<std::string>("name");
			if (n) {
				name_ = *n;
			} else {
				name_ = "No name";
			}
			return;
Nicolas Pope's avatar
Nicolas Pope committed
}

void ftl::gui::Camera::setPose(const Eigen::Matrix4d &p) {
	eye_[0] = p(0,3);
	eye_[1] = p(1,3);
	eye_[2] = p(2,3);

	double sx = Eigen::Vector3d(p(0,0), p(1,0), p(2,0)).norm();
	double sy = Eigen::Vector3d(p(0,1), p(1,1), p(2,1)).norm();
	double sz = Eigen::Vector3d(p(0,2), p(1,2), p(2,2)).norm();

	Eigen::Matrix4d rot = p;
	rot(0,3) = 0.0;
	rot(1,3) = 0.0;
	rot(2,3) = 0.0;
	rot(0,0) = rot(0,0) / sx;
	rot(1,0) = rot(1,0) / sx;
	rot(2,0) = rot(2,0) / sx;
	rot(0,1) = rot(0,1) / sy;
	rot(1,1) = rot(1,1) / sy;
	rot(2,1) = rot(2,1) / sy;
	rot(0,2) = rot(0,2) / sz;
	rot(1,2) = rot(1,2) / sz;
	rot(2,2) = rot(2,2) / sz;
	rotmat_ = rot;
}

void ftl::gui::Camera::mouseMovement(int rx, int ry, int button) {
	//if (!src_->hasCapabilities(ftl::rgbd::kCapMovable)) return;
	if (fid_ < 255) return;
Nicolas Pope's avatar
Nicolas Pope committed
	if (button == 1) {
		float rrx = ((float)ry * 0.2f * delta_);
		//orientation_[2] += std::cos(orientation_[1])*((float)rel[1] * 0.2f * delta_);
		float rry = (float)rx * 0.2f * delta_;
		float rrz = 0.0;


		Eigen::Affine3d r = create_rotation_matrix(rrx, -rry, rrz);
		rotmat_ = rotmat_ * r.matrix();
	}
}

void ftl::gui::Camera::keyMovement(int key, int modifiers) {
	//if (!src_->hasCapabilities(ftl::rgbd::kCapMovable)) return;
	if (fid_ < 255) return;
Nicolas Pope's avatar
Nicolas Pope committed
	if (key == 263 || key == 262) {
		float mag = (modifiers & 0x1) ? 0.01f : 0.1f;
		float scalar = (key == 263) ? -mag : mag;
		neye_ += rotmat_*Eigen::Vector4d(scalar,0.0,0.0,1.0);
		return;
	} else if (key == 264 || key == 265) {
		float mag = (modifiers & 0x1) ? 0.01f : 0.1f;
		float scalar = (key == 264) ? -mag : mag;
		neye_ += rotmat_*Eigen::Vector4d(0.0,0.0,scalar,1.0);
		return;
	} else if (key == 266 || key == 267) {
		float mag = (modifiers & 0x1) ? 0.01f : 0.1f;
		float scalar = (key == 266) ? -mag : mag;
		neye_ += rotmat_*Eigen::Vector4d(0.0,scalar,0.0,1.0);
		return;
	} else if (key >= '0' && key <= '5') {
		int ix = key - (int)('0');
		transform_ix_ = ix-1;
		return;
Nicolas Pope's avatar
Nicolas Pope committed
	}
}

void ftl::gui::Camera::showPoseWindow() {
	posewin_->setVisible(true);
}

void ftl::gui::Camera::showSettings() {

}

Sebastian Hahta's avatar
Sebastian Hahta committed
#ifdef HAVE_OPENVR
bool ftl::gui::Camera::setVR(bool on) {
Sebastian Hahta's avatar
Sebastian Hahta committed
	if (on == vr_mode_) {
		LOG(WARNING) << "VR mode already enabled";
		return on;
	}
	vr_mode_ = on;
Sebastian Hahta's avatar
Sebastian Hahta committed

	if (on) {
		setChannel(Channel::Right);
		//src_->set("baseline", baseline_);
		state_.getLeft().baseline = baseline_;
Sebastian Hahta's avatar
Sebastian Hahta committed

		Eigen::Matrix3d intrinsic;
		
		intrinsic = getCameraMatrix(screen_->getVR(), vr::Eye_Left);
		CHECK(intrinsic(0, 2) < 0 && intrinsic(1, 2) < 0);
		//src_->set("focal", intrinsic(0, 0));
		//src_->set("centre_x", intrinsic(0, 2));
		//src_->set("centre_y", intrinsic(1, 2));
		state_.getLeft().fx = intrinsic(0,0);
		state_.getLeft().fy = intrinsic(0,0);
		state_.getLeft().cx = intrinsic(0,2);
		state_.getLeft().cy = intrinsic(1,2);
Sebastian Hahta's avatar
Sebastian Hahta committed
		
		intrinsic = getCameraMatrix(screen_->getVR(), vr::Eye_Right);
		CHECK(intrinsic(0, 2) < 0 && intrinsic(1, 2) < 0);
		//src_->set("focal_right", intrinsic(0, 0));
		//src_->set("centre_x_right", intrinsic(0, 2));
		//src_->set("centre_y_right", intrinsic(1, 2));
		state_.getRight().fx = intrinsic(0,0);
		state_.getRight().fy = intrinsic(0,0);
		state_.getRight().cx = intrinsic(0,2);
		state_.getRight().cy = intrinsic(1,2);
Sebastian Hahta's avatar
Sebastian Hahta committed

Sebastian Hahta's avatar
Sebastian Hahta committed
		vr_mode_ = true;
	}
	else {
		vr_mode_ = false;
		setChannel(Channel::Left); // reset to left channel
Sebastian Hahta's avatar
Sebastian Hahta committed
		// todo restore camera params<
Sebastian Hahta's avatar
Sebastian Hahta committed
	}
Sebastian Hahta's avatar
Sebastian Hahta committed
	return vr_mode_;
}
#endif

void ftl::gui::Camera::setChannel(Channel c) {
Sebastian Hahta's avatar
Sebastian Hahta committed
#ifdef HAVE_OPENVR
Sebastian Hahta's avatar
Sebastian Hahta committed
	if (isVR() && (c != Channel::Right)) {
Sebastian Hahta's avatar
Sebastian Hahta committed
		LOG(ERROR) << "Changing channel in VR mode is not possible.";
		return;
	}
#endif

static void visualizeDepthMap(	const cv::Mat &depth, cv::Mat &out,
								const float max_depth)
{
	DCHECK(max_depth > 0.0);

	depth.convertTo(out, CV_8U, 255.0f / max_depth);
	out = 255 - out;
	cv::Mat mask = (depth >= 39.0f); // TODO (mask for invalid pixels)
	
	applyColorMap(out, out, cv::COLORMAP_JET);
	out.setTo(cv::Scalar(255, 255, 255), mask);
	cv::cvtColor(out,out, cv::COLOR_BGR2BGRA);
static void visualizeEnergy(	const cv::Mat &depth, cv::Mat &out,
								const float max_depth)
{
	DCHECK(max_depth > 0.0);

	depth.convertTo(out, CV_8U, 255.0f / max_depth);
	//out = 255 - out;
	//cv::Mat mask = (depth >= 39.0f); // TODO (mask for invalid pixels)
	
	applyColorMap(out, out, cv::COLORMAP_JET);
	//out.setTo(cv::Scalar(255, 255, 255), mask);
	cv::cvtColor(out,out, cv::COLOR_BGR2BGRA);
static void drawEdges(	const cv::Mat &in, cv::Mat &out,
						const int ksize = 3, double weight = -1.0, const int threshold = 32,
						const int threshold_type = cv::THRESH_TOZERO)
{
	cv::Mat edges;
	cv::Laplacian(in, edges, 8, ksize);
	cv::threshold(edges, edges, threshold, 255, threshold_type);

	cv::Mat edges_color(in.size(), CV_8UC4);
	cv::addWeighted(edges, weight, out, 1.0, 0.0, out, CV_8UC4);
Iiro Rastas's avatar
Iiro Rastas committed
cv::Mat ftl::gui::Camera::visualizeActiveChannel() {
	cv::Mat result;
	switch(channel_) {
		case Channel::Smoothing:
		case Channel::Confidence:
			visualizeEnergy(im2_, result, 1.0);
			break;
		case Channel::Density:
		case Channel::Energy:
			visualizeEnergy(im2_, result, 10.0);
			break;
		case Channel::Depth:
			visualizeDepthMap(im2_, result, 7.0);
			if (screen_->root()->value("showEdgesInDepth", false)) drawEdges(im1_, result);
			break;
		case Channel::Right:
			result = im2_;
	}
	return result;
}

bool ftl::gui::Camera::thumbnail(cv::Mat &thumb) {
	UNIQUE_LOCK(mutex_, lk);
	/*src_->grab(1,9);*/
	cv::Mat sel = (channel_ != Channel::None && channel_ != Channel::Colour && !im2_.empty()) ? visualizeActiveChannel() : im1_;
	if (sel.empty()) return false;
	cv::resize(sel, thumb, cv::Size(320,180));
Sebastian Hahta's avatar
Sebastian Hahta committed
	cv::flip(thumb, thumb, 0);
	return true;
}
Sebastian Hahta's avatar
Sebastian Hahta committed

void ftl::gui::Camera::active(bool a) {
	if (a) {

	} else {
		neye_[0] = eye_[0];
		neye_[1] = eye_[1];
		neye_[2] = eye_[2];
	}
}

Nicolas Pope's avatar
Nicolas Pope committed
const GLTexture &ftl::gui::Camera::captureFrame() {
	float now = (float)glfwGetTime();
	delta_ = now - ftime_;
	ftime_ = now;

	//if (src_ && src_->isReady()) {
	if (width_ > 0 && height_ > 0) {
		UNIQUE_LOCK(mutex_, lk);
Sebastian Hahta's avatar
Sebastian Hahta committed

		if (screen_->isVR()) {
Nicolas Pope's avatar
Nicolas Pope committed
			#ifdef HAVE_OPENVR
Nicolas Pope's avatar
Nicolas Pope committed
			vr::VRCompositor()->WaitGetPoses(rTrackedDevicePose_, vr::k_unMaxTrackedDeviceCount, NULL, 0 );

Sebastian Hahta's avatar
Sebastian Hahta committed
			if ((channel_ == Channel::Right) && rTrackedDevicePose_[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid )
Nicolas Pope's avatar
Nicolas Pope committed
			{
Sebastian Hahta's avatar
Sebastian Hahta committed
				Eigen::Matrix4d eye_l = ConvertSteamVRMatrixToMatrix4(
					vr::VRSystem()->GetEyeToHeadTransform(vr::Eye_Left));
				
Sebastian Hahta's avatar
Sebastian Hahta committed
				Eigen::Matrix4d eye_r = ConvertSteamVRMatrixToMatrix4(
					vr::VRSystem()->GetEyeToHeadTransform(vr::Eye_Left));

				float baseline_in = 2.0 * eye_l(0, 3);
				
Sebastian Hahta's avatar
Sebastian Hahta committed
				if (baseline_in != baseline_) {
					baseline_ = baseline_in;
					//src_->set("baseline", baseline_);
					state_.getLeft().baseline = baseline_;
Sebastian Hahta's avatar
Sebastian Hahta committed
				}
				Eigen::Matrix4d pose = ConvertSteamVRMatrixToMatrix4(rTrackedDevicePose_[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking);
Sebastian Hahta's avatar
Sebastian Hahta committed
				Eigen::Vector3d ea = pose.block<3, 3>(0, 0).eulerAngles(0, 1, 2);
Sebastian Hahta's avatar
Sebastian Hahta committed
				
				// NOTE: If modified, should be verified with VR headset!
				Eigen::Matrix3d R;
Sebastian Hahta's avatar
Sebastian Hahta committed
				R =		Eigen::AngleAxisd(ea[0], Eigen::Vector3d::UnitX()) *
						Eigen::AngleAxisd(-ea[1], Eigen::Vector3d::UnitY()) *
						Eigen::AngleAxisd(-ea[2], Eigen::Vector3d::UnitZ()); 
Sebastian Hahta's avatar
Sebastian Hahta committed
				
Sebastian Hahta's avatar
Sebastian Hahta committed
				//double rd = 180.0 / 3.141592;
				//LOG(INFO) << "rotation x: " << ea[0] *rd << ", y: " << ea[1] * rd << ", z: " << ea[2] * rd;
				// pose.block<3, 3>(0, 0) = R;
				
				rotmat_.block(0, 0, 3, 3) = R;
			
Nicolas Pope's avatar
Nicolas Pope committed
			} else {
Sebastian Hahta's avatar
Sebastian Hahta committed
				//LOG(ERROR) << "No VR Pose";
Nicolas Pope's avatar
Nicolas Pope committed
			}
			#endif
Sebastian Hahta's avatar
Sebastian Hahta committed
		}
Nicolas Pope's avatar
Nicolas Pope committed

Sebastian Hahta's avatar
Sebastian Hahta committed
		eye_[0] += (neye_[0] - eye_[0]) * lerpSpeed_ * delta_;
		eye_[1] += (neye_[1] - eye_[1]) * lerpSpeed_ * delta_;
		eye_[2] += (neye_[2] - eye_[2]) * lerpSpeed_ * delta_;
Nicolas Pope's avatar
Nicolas Pope committed

Sebastian Hahta's avatar
Sebastian Hahta committed
		Eigen::Translation3d trans(eye_);
		Eigen::Affine3d t(trans);
		Eigen::Matrix4d viewPose = t.matrix() * rotmat_;
		if (isVirtual()) {
			if (transform_ix_ == -1) {
				state_.setPose(viewPose);
			} else if (transform_ix_ >= 0) {
				transforms_[transform_ix_] = viewPose;
			}
		}
Sebastian Hahta's avatar
Sebastian Hahta committed
	
		//src_->grab();
		// When switching from right to depth, client may still receive
		// right images from previous batch (depth.channels() == 1 check)
Sebastian Hahta's avatar
Sebastian Hahta committed

		/* todo: does not work
		if (channel_ == Channel::Deviation &&
			depth_.rows > 0 && depth_.channels() == 1)
				stats_ = new StatisticsImage(depth_.size());
			stats_->update(depth_);
Sebastian Hahta's avatar
Sebastian Hahta committed
		}*/
Nicolas Pope's avatar
Nicolas Pope committed

		cv::Mat tmp;

		switch(channel_) {
			case Channel::Smoothing:
Nicolas Pope's avatar
Nicolas Pope committed
			case Channel::Confidence:
Sebastian Hahta's avatar
Sebastian Hahta committed
				if (im2_.rows == 0) { break; }
				visualizeEnergy(im2_, tmp, screen_->root()->value("float_image_max", 1.0f));
Sebastian Hahta's avatar
Sebastian Hahta committed
				texture2_.update(tmp);
Nicolas Pope's avatar
Nicolas Pope committed
				break;
Sebastian Hahta's avatar
Sebastian Hahta committed
			
			case Channel::Density:
			case Channel::Energy:
Sebastian Hahta's avatar
Sebastian Hahta committed
				if (im2_.rows == 0) { break; }
				visualizeEnergy(im2_, tmp, 10.0);
				texture2_.update(tmp);
				break;
Sebastian Hahta's avatar
Sebastian Hahta committed
			
			case Channel::Depth:
				if (im2_.rows == 0 || im2_.type() != CV_32F) { break; }
Sebastian Hahta's avatar
Sebastian Hahta committed
				visualizeDepthMap(im2_, tmp, 7.0);
				if (screen_->root()->value("showEdgesInDepth", false)) drawEdges(im1_, tmp);
				texture2_.update(tmp);
Nicolas Pope's avatar
Nicolas Pope committed
				break;
			
			case Channel::Deviation:
Sebastian Hahta's avatar
Sebastian Hahta committed
				if (im2_.rows == 0) { break; }/*
Nicolas Pope's avatar
Nicolas Pope committed
				//imageSize = Vector2f(depth.cols, depth.rows);
				stats_->getStdDev(tmp);
				tmp.convertTo(tmp, CV_8U, 1000.0);
Nicolas Pope's avatar
Nicolas Pope committed
				applyColorMap(tmp, tmp, cv::COLORMAP_HOT);
Sebastian Hahta's avatar
Sebastian Hahta committed
				texture2_.update(tmp);*/
Nicolas Pope's avatar
Nicolas Pope committed
				break;

Iiro Rastas's avatar
Iiro Rastas committed
			//case Channel::Flow:
			case Channel::ColourNormals:
			case Channel::Right:
					if (im2_.rows == 0 || im2_.type() != CV_8UC4) { break; }
Iiro Rastas's avatar
Iiro Rastas committed
					texture2_.update(im2_);
					break;
Nicolas Pope's avatar
Nicolas Pope committed
			default:
Sebastian Hahta's avatar
Sebastian Hahta committed
				break;
				/*if (rgb_.rows == 0) { break; }
Nicolas Pope's avatar
Nicolas Pope committed
				//imageSize = Vector2f(rgb.cols,rgb.rows);
				texture_.update(rgb_);
Nicolas Pope's avatar
Nicolas Pope committed
				#ifdef HAVE_OPENVR
Nicolas Pope's avatar
Nicolas Pope committed
				if (screen_->hasVR() && depth_.channels() >= 3) {
Nicolas Pope's avatar
Nicolas Pope committed
					LOG(INFO) << "DRAW RIGHT";
Nicolas Pope's avatar
Nicolas Pope committed
					textureRight_.update(depth_);
Nicolas Pope's avatar
Nicolas Pope committed
				}
				#endif
Sebastian Hahta's avatar
Sebastian Hahta committed
				*/
		}

		if (im1_.rows != 0) {
			//imageSize = Vector2f(rgb.cols,rgb.rows);
			texture1_.update(im1_);
Sebastian Hahta's avatar
Sebastian Hahta committed
	return texture1_;
Iiro Rastas's avatar
Iiro Rastas committed
void ftl::gui::Camera::snapshot(const std::string &filename) {
	UNIQUE_LOCK(mutex_, lk);
Iiro Rastas's avatar
Iiro Rastas committed
	cv::Mat blended;
	cv::Mat visualized = visualizeActiveChannel();
Iiro Rastas's avatar
Iiro Rastas committed
	if (!visualized.empty()) {
		double alpha = screen_->root()->value("blending", 0.5);
		cv::addWeighted(im1_, alpha, visualized, 1.0-alpha, 0, blended);
	} else {
		blended = im1_;
	}
	cv::Mat flipped;
	cv::flip(blended, flipped, 0);
	cv::cvtColor(flipped, flipped, cv::COLOR_BGRA2BGR);
Iiro Rastas's avatar
Iiro Rastas committed
	cv::imwrite(filename, flipped);
Iiro Rastas's avatar
Iiro Rastas committed
void ftl::gui::Camera::startVideoRecording(const std::string &filename) {
	if (!record_stream_) {
		record_stream_ = ftl::create<ftl::stream::File>(screen_->root(), "video2d");
		record_stream_->setMode(ftl::stream::File::Mode::Write);
		record_sender_ = ftl::create<ftl::stream::Sender>(screen_->root(), "videoEncode");
		record_sender_->setStream(record_stream_);
	}
	if (record_stream_->active()) return;
	record_stream_->set("filename", filename);
	record_stream_->begin();
Iiro Rastas's avatar
Iiro Rastas committed
}

void ftl::gui::Camera::stopVideoRecording() {
	if (record_stream_ && record_stream_->active()) record_stream_->end();