Skip to content
Snippets Groups Projects
Commit 38a96e16 authored by Nicolas Pope's avatar Nicolas Pope
Browse files

WIP MLS for rendering

parent c3cb8131
No related branches found
No related tags found
1 merge request!354Add full 3D MLS and carving
Pipeline #33553 passed
...@@ -59,6 +59,9 @@ class CUDARender : public ftl::render::FSRenderer { ...@@ -59,6 +59,9 @@ class CUDARender : public ftl::render::FSRenderer {
ftl::cuda::TextureObject<int> contrib_; ftl::cuda::TextureObject<int> contrib_;
//ftl::cuda::TextureObject<half4> normals_; //ftl::cuda::TextureObject<half4> normals_;
cv::cuda::GpuMat colour_scale_; cv::cuda::GpuMat colour_scale_;
cv::cuda::GpuMat mls_contrib_;
cv::cuda::GpuMat mls_centroid_;
cv::cuda::GpuMat mls_normals_;
std::list<cv::cuda::GpuMat*> screen_buffers_; std::list<cv::cuda::GpuMat*> screen_buffers_;
std::list<cv::cuda::GpuMat*> depth_buffers_; std::list<cv::cuda::GpuMat*> depth_buffers_;
......
...@@ -308,11 +308,11 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre ...@@ -308,11 +308,11 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre
); );
} }
ftl::cuda::apply_colour_scaling(colour_scale_, f.create<cv::cuda::GpuMat>(Channel::Colour), 3, stream_); //ftl::cuda::apply_colour_scaling(colour_scale_, f.create<cv::cuda::GpuMat>(Channel::Colour), 3, stream_);
} }
} }
if (!colour_scale_.empty()) ftl::utility::show_image(colour_scale_, "CScale", 1.0f, ftl::utility::ImageVisualisation::HEAT_MAPPED); //if (!colour_scale_.empty()) ftl::utility::show_image(colour_scale_, "CScale", 1.0f, ftl::utility::ImageVisualisation::HEAT_MAPPED);
// For each source depth map // For each source depth map
for (size_t i=0; i < scene_->frames.size(); ++i) { for (size_t i=0; i < scene_->frames.size(); ++i) {
...@@ -424,17 +424,21 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre ...@@ -424,17 +424,21 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre
// Now merge new render to any existing frameset render, detecting collisions // Now merge new render to any existing frameset render, detecting collisions
ftl::cuda::touch_merge(depth_out_, out.createTexture<float>(_getDepthChannel()), collisions_, 1024, touch_dist_, stream_); ftl::cuda::touch_merge(depth_out_, out.createTexture<float>(_getDepthChannel()), collisions_, 1024, touch_dist_, stream_);
// For each source depth map, verify results // Generate actual depth map using MLS with mesh as estimate
/*if (value("post_carve_result", false)) { float mls_smoothing = value("mls_smooth", 0.005f);
if (value("mls_full", true)) {
// Clear buffers
mls_centroid_.create(params_.camera.height, params_.camera.width, CV_32FC4);
mls_contrib_.create(params_.camera.height, params_.camera.width, CV_32F);
mls_normals_.create(params_.camera.height, params_.camera.width, CV_16FC4);
mls_centroid_.setTo(cv::Scalar(0,0,0,0), cvstream);
mls_contrib_.setTo(cv::Scalar(0), cvstream);
mls_normals_.setTo(cv::Scalar(0,0,0,0), cvstream);
for (size_t i=0; i < scene_->frames.size(); ++i) { for (size_t i=0; i < scene_->frames.size(); ++i) {
//if (!scene_->hasFrame(i)) continue;
auto &f = scene_->frames[i].cast<ftl::rgbd::Frame>(); auto &f = scene_->frames[i].cast<ftl::rgbd::Frame>();
//auto *s = scene_->sources[i];
if (!f.has(Channel::Colour)) { if (!f.has(Channel::Colour)) continue;
//LOG(ERROR) << "Missing required channel";
continue;
}
// We have the needed depth data? // We have the needed depth data?
if (use_depth && !f.hasOwn(Channel::Depth) && !f.hasOwn(Channel::GroundTruth)) { if (use_depth && !f.hasOwn(Channel::Depth) && !f.hasOwn(Channel::GroundTruth)) {
...@@ -442,31 +446,39 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre ...@@ -442,31 +446,39 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre
} }
//auto pose = MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>()); //auto pose = MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>());
// VCAM to Original
auto transformR = MatrixConversion::toCUDA(f.getPose().cast<float>().inverse() * t.cast<float>().inverse()) * poseInverse_; auto transformR = MatrixConversion::toCUDA(f.getPose().cast<float>().inverse() * t.cast<float>().inverse()) * poseInverse_;
//auto transform = pose_ * MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>()); // Original to VCAM
auto transform = pose_ * MatrixConversion::toCUDA(t.cast<float>() * f.getPose().cast<float>());
ftl::cuda::depth_carve( ftl::cuda::mls_gather(
out.create<cv::cuda::GpuMat>(_getDepthChannel()), f.get<cv::cuda::GpuMat>(Channel::Normals),
mls_normals_,
out.get<cv::cuda::GpuMat>(_getDepthChannel()),
f.get<cv::cuda::GpuMat>(Channel::Depth), f.get<cv::cuda::GpuMat>(Channel::Depth),
mls_centroid_,
mls_contrib_,
mls_smoothing,
transformR, transformR,
transform,
params_.camera, params_.camera,
f.getLeft(), f.getLeft(),
stream_ stream_
); );
} }
}*/
//filters_->filter(out, src, stream);
// Generate normals for final virtual image // Now reduce MLS results to new depth+normals
/*ftl::cuda::normals( ftl::cuda::mls_reduce(
out.createTexture<half4>(_getNormalsChannel()), mls_centroid_,
temp_.createTexture<half4>(Channel::Normals), mls_normals_,
out.getTexture<float>(_getDepthChannel()), mls_contrib_,
value("normal_radius", 1), value("normal_smoothing", 0.02f), out.create<cv::cuda::GpuMat>(_getNormalsChannel()),
params_.camera, pose_.getFloat3x3(), poseInverse_.getFloat3x3(), stream_);*/ out.create<cv::cuda::GpuMat>(_getDepthChannel()),
params_.camera,
stream_
);
float mls_smoothing = value("mls_smooth", 0.01f); } else {
int mls_radius = value("mls_radius", 0); int mls_radius = value("mls_radius", 0);
if (mls_radius == 0) { if (mls_radius == 0) {
...@@ -491,6 +503,7 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre ...@@ -491,6 +503,7 @@ void CUDARender::_mesh(ftl::rgbd::Frame &out, const Eigen::Matrix4d &t, cudaStre
stream_ stream_
); );
} }
}
ftl::cuda::transform_normals( ftl::cuda::transform_normals(
out.createTexture<half4>(_getNormalsChannel()), out.createTexture<half4>(_getNormalsChannel()),
......
#include "carver.hpp" #include "carver.hpp"
#include <cudatl/fixed.hpp> #include <cudatl/fixed.hpp>
#include <ftl/cuda/weighting.hpp>
__device__ inline float depthErrorCoef(const ftl::rgbd::Camera &cam, float disps=1.0f) { __device__ inline float depthErrorCoef(const ftl::rgbd::Camera &cam, float disps=1.0f) {
return disps / (cam.baseline*cam.fx); return disps / (cam.baseline*cam.fx);
...@@ -103,9 +104,9 @@ __global__ void reverse_check_kernel( ...@@ -103,9 +104,9 @@ __global__ void reverse_check_kernel(
} }
// We found a match, so do a colour check // We found a match, so do a colour check
float idiff = 0.0f; //float idiff = 127.0f;
//if (match) { //if (match) {
// Generate colour scaling /* // Generate colour scaling
const float ximgscale = float(cwidth) / float(ointrin.width); const float ximgscale = float(cwidth) / float(ointrin.width);
ox = float(ox) * ximgscale; ox = float(ox) * ximgscale;
const float yimgscale = float(cheight) / float(ointrin.height); const float yimgscale = float(cheight) / float(ointrin.height);
...@@ -126,10 +127,10 @@ __global__ void reverse_check_kernel( ...@@ -126,10 +127,10 @@ __global__ void reverse_check_kernel(
//const float scaleZ = (vcol.z == 0) ? 1.0f : float(ocol.z) / float(vcol.z); //const float scaleZ = (vcol.z == 0) ? 1.0f : float(ocol.z) / float(vcol.z);
//scale = (0.2126f*scaleZ + 0.7152f*scaleY + 0.0722f*scaleX); //scale = (0.2126f*scaleZ + 0.7152f*scaleY + 0.0722f*scaleX);
//} //}
colour_scale[x+pitch*y] = int8_t(max(-127.0f,min(127.0f,idiff))); colour_scale[x+pitch*y] = int8_t(max(-127.0f,min(127.0f,idiff)));*/
// Too much carving means just outright remove the point. // Too much carving means just outright remove the point.
depth_in[y*pitch4+x] = (count < 0 || fabsf(idiff) > 50.0f) ? 0.0f : d; depth_in[y*pitch4+x] = (count < 0) ? 0.0f : d;
} }
void ftl::cuda::depth_carve( void ftl::cuda::depth_carve(
...@@ -170,6 +171,193 @@ void ftl::cuda::depth_carve( ...@@ -170,6 +171,193 @@ void ftl::cuda::depth_carve(
cudaSafeCall( cudaGetLastError() ); cudaSafeCall( cudaGetLastError() );
} }
// ==== Multi image MLS ========================================================
/*
* Gather points for Moving Least Squares, from each source image
*/
template <int SEARCH_RADIUS>
__global__ void mls_gather_kernel(
const half4* __restrict__ normals_in,
half4* __restrict__ normals_out,
const float* __restrict__ depth_origin,
const float* __restrict__ depth_in,
float4* __restrict__ centroid_out,
float* __restrict__ contrib_out,
float smoothing,
float4x4 o_2_in,
float4x4 in_2_o,
ftl::rgbd::Camera camera_origin,
ftl::rgbd::Camera camera_in,
int npitch_out,
int cpitch_out,
int wpitch_out,
int dpitch_o,
int dpitch_i,
int npitch_in
) {
const int x = blockIdx.x*blockDim.x + threadIdx.x;
const int y = blockIdx.y*blockDim.y + threadIdx.y;
if (x < 0 || y < 0 || x >= camera_origin.width || y >= camera_origin.height) return;
float3 nX = make_float3(normals_out[y*npitch_out+x]);
float3 aX = make_float3(centroid_out[y*cpitch_out+x]);
float contrib = contrib_out[y*wpitch_out+x];
float d0 = depth_origin[x+y*dpitch_o];
if (d0 <= camera_origin.minDepth || d0 >= camera_origin.maxDepth) return;
float3 X = camera_origin.screenToCam((int)(x),(int)(y),d0);
int2 s = camera_in.camToScreen<int2>(o_2_in * X);
// Neighbourhood
for (int v=-SEARCH_RADIUS; v<=SEARCH_RADIUS; ++v) {
for (int u=-SEARCH_RADIUS; u<=SEARCH_RADIUS; ++u) {
const float d = (s.x+u >= 0 && s.x+u < camera_in.width && s.y+v >= 0 && s.y+v < camera_in.height) ? depth_in[s.x+u+(s.y+v)*dpitch_i] : 0.0f;
if (d <= camera_in.minDepth || d >= camera_in.maxDepth) continue;
// Point and normal of neighbour
const float3 Xi = in_2_o * camera_in.screenToCam(s.x+u, s.y+v, d);
const float3 Ni = in_2_o.getFloat3x3() * make_float3(normals_in[s.x+u+(s.y+v)*npitch_in]);
// Gauss approx weighting function using point distance
const float w = (Ni.x+Ni.y+Ni.z > 0.0f) ? ftl::cuda::spatialWeighting(X,Xi,smoothing) : 0.0f;
aX += Xi*w;
nX += Ni*w;
contrib += w;
}
}
normals_out[y*npitch_out+x] = make_half4(nX, 0.0f);
centroid_out[y*cpitch_out+x] = make_float4(aX, 0.0f);
contrib_out[y*wpitch_out+x] = contrib;
}
/**
* Convert accumulated values into estimate of depth and normals at pixel.
*/
__global__ void mls_reduce_kernel(
const float4* __restrict__ centroid,
const half4* __restrict__ normals,
const float* __restrict__ contrib_out,
half4* __restrict__ normals_out,
float* __restrict__ depth,
ftl::rgbd::Camera camera,
int npitch_in,
int cpitch_in,
int wpitch,
int npitch,
int dpitch
) {
const int x = blockIdx.x*blockDim.x + threadIdx.x;
const int y = blockIdx.y*blockDim.y + threadIdx.y;
if (x >= 0 && y >= 0 && x < camera.width && y < camera.height) {
float3 nX = make_float3(normals[y*npitch_in+x]);
float3 aX = make_float3(centroid[y*cpitch_in+x]);
float contrib = contrib_out[y*wpitch+x];
//depth[x+y*dpitch] = X.z;
normals_out[x+y*npitch] = make_half4(0.0f, 0.0f, 0.0f, 0.0f);
float d0 = depth[x+y*dpitch];
if (d0 < camera.minDepth || d0 > camera.maxDepth) return;
float3 X = camera.screenToCam((int)(x),(int)(y),d0);
nX /= contrib; // Weighted average normal
aX /= contrib; // Weighted average point (centroid)
// Signed-Distance Field function
float fX = nX.x * (X.x - aX.x) + nX.y * (X.y - aX.y) + nX.z * (X.z - aX.z);
// Calculate new point using SDF function to adjust depth (and position)
X = X - nX * fX;
depth[x+y*dpitch] = X.z;
normals_out[x+y*npitch] = make_half4(nX / length(nX), 0.0f);
}
}
#define T_PER_BLOCK 8
void ftl::cuda::mls_gather(
const cv::cuda::GpuMat &normals_in, // Source frame
cv::cuda::GpuMat &normals_out,
const cv::cuda::GpuMat &depth_origin, // Rendered image
const cv::cuda::GpuMat &depth_in,
cv::cuda::GpuMat &centroid_out,
cv::cuda::GpuMat &contrib_out,
float smoothing,
const float4x4 &o_2_in,
const float4x4 &in_2_o,
const ftl::rgbd::Camera &camera_origin, // Virtual camera
const ftl::rgbd::Camera &camera_in,
cudaStream_t stream
) {
const dim3 gridSize((depth_origin.cols + T_PER_BLOCK - 1)/T_PER_BLOCK, (depth_origin.rows + T_PER_BLOCK - 1)/T_PER_BLOCK);
const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK);
normals_out.create(depth_origin.size(), CV_16FC4);
centroid_out.create(depth_origin.size(), CV_32FC4);
contrib_out.create(depth_origin.size(), CV_32F);
mls_gather_kernel<2><<<gridSize, blockSize, 0, stream>>>(
normals_in.ptr<half4>(),
normals_out.ptr<half4>(),
depth_origin.ptr<float>(),
depth_in.ptr<float>(),
centroid_out.ptr<float4>(),
contrib_out.ptr<float>(),
smoothing,
o_2_in,
in_2_o,
camera_origin,
camera_in,
normals_out.step1()/4,
centroid_out.step1()/4,
contrib_out.step1(),
depth_origin.step1(),
depth_in.step1(),
normals_in.step1()/4
);
cudaSafeCall( cudaGetLastError() );
}
void ftl::cuda::mls_reduce(
const cv::cuda::GpuMat &centroid,
const cv::cuda::GpuMat &normals,
const cv::cuda::GpuMat &contrib,
cv::cuda::GpuMat &normals_out,
cv::cuda::GpuMat &depth,
const ftl::rgbd::Camera &camera,
cudaStream_t stream
) {
const dim3 gridSize((depth.cols + T_PER_BLOCK - 1)/T_PER_BLOCK, (depth.rows + T_PER_BLOCK - 1)/T_PER_BLOCK);
const dim3 blockSize(T_PER_BLOCK, T_PER_BLOCK);
normals_out.create(depth.size(), CV_16FC4);
mls_reduce_kernel<<<gridSize, blockSize, 0, stream>>>(
centroid.ptr<float4>(),
normals.ptr<half4>(),
contrib.ptr<float>(),
normals_out.ptr<half4>(),
depth.ptr<float>(),
camera,
normals.step1()/4,
centroid.step1()/4,
contrib.step1(),
normals_out.step1()/4,
depth.step1()
);
cudaSafeCall( cudaGetLastError() );
}
// ==== Apply colour scale ===================================================== // ==== Apply colour scale =====================================================
template <int RADIUS> template <int RADIUS>
...@@ -191,23 +379,27 @@ __global__ void apply_colour_scaling_kernel( ...@@ -191,23 +379,27 @@ __global__ void apply_colour_scaling_kernel(
int sy = (float(sheight) / float(cheight)) * float(y); int sy = (float(sheight) / float(cheight)) * float(y);
float s = 0.0f; float s = 0.0f;
int count = 0;
//float mindiff = 100.0f; //float mindiff = 100.0f;
for (int v=-RADIUS; v<=RADIUS; ++v) { for (int v=-RADIUS; v<=RADIUS; ++v) {
#pragma unroll #pragma unroll
for (int u=-RADIUS; u<=RADIUS; ++u) { for (int u=-RADIUS; u<=RADIUS; ++u) {
float ns = (sx >= RADIUS && sy >= RADIUS && sx < swidth-RADIUS && sy < sheight-RADIUS) ? scale[sx+u+(sy+v)*spitch] : 0.0f; float ns = (sx >= RADIUS && sy >= RADIUS && sx < swidth-RADIUS && sy < sheight-RADIUS) ? scale[sx+u+(sy+v)*spitch] : 0.0f;
if (fabsf(ns) < 30) {
s += ns; s += ns;
++count;
}
} }
} }
s /= float((2*RADIUS+1)*(2*RADIUS+1)); if (count > 0) s /= float(count);
uchar4 c = colour[x+y*cpitch]; uchar4 c = colour[x+y*cpitch];
colour[x+y*cpitch] = make_uchar4( colour[x+y*cpitch] = make_uchar4(
max(0.0f, min(255.0f, float(c.x) + 0.0722f*s)), max(0.0f, min(255.0f, float(c.x) + s)),
max(0.0f, min(255.0f, float(c.y) + 0.7152f*s)), max(0.0f, min(255.0f, float(c.y) + s)),
max(0.0f, min(255.0f, float(c.z) + 0.2126f*s)), max(0.0f, min(255.0f, float(c.z) + s)),
255.0f 255.0f
); );
} }
......
...@@ -28,6 +28,31 @@ void apply_colour_scaling( ...@@ -28,6 +28,31 @@ void apply_colour_scaling(
int radius, int radius,
cudaStream_t stream); cudaStream_t stream);
void mls_reduce(
const cv::cuda::GpuMat &centroid,
const cv::cuda::GpuMat &normals,
const cv::cuda::GpuMat &contrib,
cv::cuda::GpuMat &normals_out,
cv::cuda::GpuMat &depth,
const ftl::rgbd::Camera &camera,
cudaStream_t stream
);
void mls_gather(
const cv::cuda::GpuMat &normals_in, // Source frame
cv::cuda::GpuMat &normals_out,
const cv::cuda::GpuMat &depth_origin, // Rendered image
const cv::cuda::GpuMat &depth_in,
cv::cuda::GpuMat &centroid_out,
cv::cuda::GpuMat &contrib_out,
float smoothing,
const float4x4 &o_2_in,
const float4x4 &in_2_o,
const ftl::rgbd::Camera &camera_origin, // Virtual camera
const ftl::rgbd::Camera &camera_in,
cudaStream_t stream
);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment