Commit 01394738 authored by David Flynn's avatar David Flynn
Browse files

encoder/m43953: signal bounding box using SPS

 - calculates the sequence bounding box at the start of encoding
   (in original coordinates as a decoder may reconstruct it)
 - signals bounding box in SPS
 - disables signalling of geometry box origin (always 0)
parent 8dbb5a7f
......@@ -48,7 +48,7 @@ namespace pcc {
//============================================================================
// Quantise the geometry of a point cloud, retaining unique points only.
// Points in the @src point cloud are translated by @offset, quantised by a
// Points in the @src point cloud are translated by -@offset, quantised by a
// multiplicitive @scaleFactor with rounding, then clamped to @clamp.
//
// The destination and source point clouds may be the same object.
......@@ -58,8 +58,8 @@ namespace pcc {
inline void
quantizePositionsUniq(
const float scaleFactor,
const PCCVector3D offset,
const PCCBox3<int32_t> clamp,
const PCCVector3<int> offset,
const PCCBox3<int> clamp,
const PCCPointSet3& src,
PCCPointSet3* dst)
{
......@@ -68,12 +68,12 @@ quantizePositionsUniq(
std::set<PCCVector3<int32_t>> uniquePoints;
int numSrcPoints = src.getPointCount();
for (int i = 0; i < numSrcPoints; ++i) {
const PCCVector3D point = (src[i] + offset) * scaleFactor;
const PCCVector3D& point = src[i];
PCCVector3<int32_t> quantizedPoint;
for (int k = 0; k < 3; k++) {
quantizedPoint[k] =
PCCClip(int32_t(std::round(point[k])), clamp.min[k], clamp.max[k]);
double k_pos = std::round((point[k] - offset[k]) * scaleFactor);
quantizedPoint[k] = PCCClip(int32_t(k_pos), clamp.min[k], clamp.max[k]);
}
uniquePoints.insert(quantizedPoint);
......@@ -97,7 +97,7 @@ quantizePositionsUniq(
//============================================================================
// Quantise the geometry of a point cloud, retaining duplicate points.
// Points in the @src point cloud are translated by @offset, then quantised
// Points in the @src point cloud are translated by -@offset, then quantised
// by a multiplicitive @scaleFactor with rounding.
//
// The destination and source point clouds may be the same object.
......@@ -107,8 +107,8 @@ quantizePositionsUniq(
inline void
quantizePositions(
const float scaleFactor,
const PCCVector3D offset,
const PCCBox3<int32_t> clamp,
const PCCVector3<int> offset,
const PCCBox3<int> clamp,
const PCCPointSet3& src,
PCCPointSet3* dst)
{
......@@ -127,11 +127,12 @@ quantizePositions(
};
for (int i = 0; i < numSrcPoints; ++i) {
const PCCVector3D point = (src[i] + offset) * scaleFactor;
const PCCVector3D point = src[i];
auto& dstPoint = (*dst)[i];
for (int k = 0; k < 3; ++k)
dstPoint[k] =
PCCClip(std::round(point[k]), clampD.min[k], clampD.max[k]);
for (int k = 0; k < 3; ++k) {
double k_pos = std::round((point[k] - offset[k]) * scaleFactor);
dstPoint[k] = PCCClip(k_pos, clampD.min[k], clampD.max[k]);
}
}
// don't copy attributes if dst already has them
......@@ -351,12 +352,16 @@ inline int
recolour(
const PCCPointSet3& source,
float sourceToTargetScaleFactor,
PCCVector3D targetToSourceOffset,
PCCVector3<int> targetToSourceOffset,
PCCPointSet3* target)
{
PCCVector3D combinedOffset;
for (int k = 0; k < 3; k++)
combinedOffset[k] = targetToSourceOffset[k];
if (source.hasColors()) {
bool ok = PCCTransfertColors(
source, sourceToTargetScaleFactor, targetToSourceOffset, *target);
source, sourceToTargetScaleFactor, combinedOffset, *target);
if (!ok) {
std::cout << "Error: can't transfer colors!" << std::endl;
......@@ -366,7 +371,7 @@ recolour(
if (source.hasReflectances()) {
bool ok = PCCTransfertReflectances(
source, sourceToTargetScaleFactor, targetToSourceOffset, *target);
source, sourceToTargetScaleFactor, combinedOffset, *target);
if (!ok) {
std::cout << "Error: can't transfer reflectance!" << std::endl;
......
......@@ -91,8 +91,6 @@ private:
// Current identifier of payloads with the same geometry
int _sliceId;
PCCVector3D minPositions;
// The point cloud currently being decoded
PCCPointSet3 _currentPointCloud;
......
......@@ -84,16 +84,14 @@ private:
void encodeGeometryBrick(PayloadBuffer* buf);
void computeMinPositions(const PCCPointSet3& inputPointCloud);
void quantization(const PCCPointSet3& inputPointCloud);
private:
// todo(df): minPositions is unscaled -- which isn't quite correct.
PCCVector3D minPositions;
PCCBox3<uint32_t> boundingBox;
PCCPointSet3 pointCloud;
// Size of the current slice
PCCVector3<int> _sliceBoxWhd;
// The active parameter sets
const SequenceParameterSet* _sps;
const GeometryParameterSet* _gps;
......
......@@ -176,9 +176,6 @@ PCCTMC3Decoder3::decodeGeometryBrick(const PayloadBuffer& buf)
int gbhSize;
GeometryBrickHeader gbh = parseGbh(*_gps, buf, &gbhSize);
_sliceId = gbh.geom_slice_id;
minPositions.x() = gbh.geomBoxOrigin.x();
minPositions.y() = gbh.geomBoxOrigin.y();
minPositions.z() = gbh.geomBoxOrigin.z();
EntropyDecoder arithmeticDecoder;
arithmeticDecoder.setBuffer(int(buf.size()) - gbhSize, buf.data() + gbhSize);
......@@ -259,7 +256,7 @@ PCCTMC3Decoder3::inverseQuantization(PCCPointSet3& pointCloud)
for (size_t i = 0; i < pointCount; ++i) {
auto& point = pointCloud[i];
for (size_t k = 0; k < 3; ++k) {
point[k] = point[k] * invScale + minPositions[k];
point[k] = point[k] * invScale + _sps->seq_bounding_box_xyz0[k];
}
}
}
......
......@@ -52,9 +52,6 @@ namespace pcc {
void
PCCTMC3Encoder3::init()
{
minPositions = 0.0;
boundingBox.min = uint32_t(0);
boundingBox.max = uint32_t(0);
pointCloud.clear();
}
......@@ -69,6 +66,23 @@ PCCTMC3Encoder3::compress(
{
init();
// Determine input bounding box (for SPS metadata) if not manually set
if (params->sps.seq_bounding_box_whd == PCCVector3<int>{0}) {
const auto& bbox = inputPointCloud.computeBoundingBox();
for (int k = 0; k < 3; k++) {
params->sps.seq_bounding_box_xyz0[k] = int(bbox.min[k]);
// somehow determine the decoder's reconstructed points bounding box
// and update sps accordingly.
auto max_k = bbox.max[k] - bbox.min[k];
max_k = std::round(max_k * params->sps.seq_source_geom_scale_factor);
max_k = std::round(max_k / params->sps.seq_source_geom_scale_factor);
// NB: plus one to convert to range
params->sps.seq_bounding_box_whd[k] = int(max_k) + 1;
}
}
// fixup parameter set IDs
params->sps.sps_seq_parameter_set_id = 0;
params->gps.gps_seq_parameter_set_id = 0;
......@@ -82,8 +96,8 @@ PCCTMC3Encoder3::compress(
params->sps.profileCompatibility.profile_compatibility_flags = 0;
params->sps.level = 0;
// the encoder writes out the minPositions in the GBH:
params->gps.geom_box_present_flag = true;
// the sps is currently used for the bounding box
params->gps.geom_box_present_flag = false;
// fixup attribute parameters
for (auto it : params->attributeIdxMap) {
......@@ -163,8 +177,8 @@ PCCTMC3Encoder3::compress(
if (recolourNeeded) {
recolour(
inputPointCloud, _sps->seq_source_geom_scale_factor, minPositions,
&pointCloud);
inputPointCloud, _sps->seq_source_geom_scale_factor,
_sps->seq_bounding_box_xyz0, &pointCloud);
}
// dump recoloured point cloud
......@@ -228,19 +242,17 @@ void
PCCTMC3Encoder3::encodeGeometryBrick(PayloadBuffer* buf)
{
// todo(df): confirm minimum of 1 isn't needed
uint32_t maxBB =
std::max({1u, boundingBox.max[0], boundingBox.max[1], boundingBox.max[2]});
int32_t maxBB =
std::max({1, _sliceBoxWhd[0], _sliceBoxWhd[1], _sliceBoxWhd[2]});
// the current node dimension (log2) encompasing maxBB
int nodeSizeLog2 = ceillog2(maxBB + 1);
GeometryBrickHeader gbh;
gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id;
gbh.geomBoxOrigin.x() = int(minPositions.x());
gbh.geomBoxOrigin.y() = int(minPositions.y());
gbh.geomBoxOrigin.z() = int(minPositions.z());
gbh.geom_slice_id = _sliceId;
gbh.geom_tile_id = _tileId;
gbh.geomBoxOrigin = PCCVector3<int>{0};
gbh.geom_box_log2_scale = 0;
gbh.geom_max_node_size_log2 = nodeSizeLog2;
gbh.geom_num_points = int(pointCloud.getPointCount());
......@@ -284,7 +296,7 @@ PCCTMC3Encoder3::reconstructedPointCloud(PCCPointSet3* reconstructedCloud)
const auto quantizedPoint = pointCloud[i];
auto& point = (*reconstructedCloud)[i];
for (size_t k = 0; k < 3; ++k) {
point[k] = quantizedPoint[k] * invScale + minPositions[k];
point[k] = quantizedPoint[k] * invScale + _sps->seq_bounding_box_xyz0[k];
}
if (pointCloud.hasColors()) {
reconstructedCloud->setColor(i, pointCloud.getColor(i));
......@@ -296,40 +308,19 @@ PCCTMC3Encoder3::reconstructedPointCloud(PCCPointSet3* reconstructedCloud)
}
//----------------------------------------------------------------------------
void
PCCTMC3Encoder3::computeMinPositions(const PCCPointSet3& inputPointCloud)
{
const size_t inputPointCount = inputPointCloud.getPointCount();
minPositions = inputPointCloud[0];
for (size_t i = 1; i < inputPointCount; ++i) {
const auto point = inputPointCloud[i];
for (int k = 0; k < 3; ++k) {
if (minPositions[k] > point[k]) {
minPositions[k] = point[k];
}
}
}
}
//----------------------------------------------------------------------------
// translates and scales inputPointCloud, storing the result in
// this->pointCloud for use by the encoding process.
void
PCCTMC3Encoder3::quantization(const PCCPointSet3& inputPointCloud)
{
// if sps sequence width/height/depth is set, don't auto compute bbox
bool computeBBox = _sps->seq_bounding_box_whd == PCCVector3<int>{0};
if (computeBBox)
computeMinPositions(inputPointCloud);
else {
for (int k = 0; k < 3; k++)
minPositions[k] = _sps->seq_bounding_box_xyz0[k];
}
// Currently the sequence width/height/depth must be set
assert(_sps->seq_bounding_box_whd != PCCVector3<int>{0});
// Clamp all points to [clampBox.min, clampBox.max] after translation
// and quantisation.
PCCBox3<int32_t> clampBox{{0, 0, 0}, {INT32_MAX, INT32_MAX, INT32_MAX}};
if (!computeBBox) {
if (_sps->seq_bounding_box_whd != PCCVector3<int>{0}) {
// todo(df): this is icky (not to mention rounding issues)
// NB: the sps seq_bounding_box_* uses unscaled co-ordinates => convert
// NB: minus 1 to convert to max x/y/z position
......@@ -341,33 +332,30 @@ PCCTMC3Encoder3::quantization(const PCCPointSet3& inputPointCloud)
if (_gps->geom_unique_points_flag) {
quantizePositionsUniq(
_sps->seq_source_geom_scale_factor, -minPositions, clampBox,
inputPointCloud, &pointCloud);
_sps->seq_source_geom_scale_factor, _sps->seq_bounding_box_xyz0,
clampBox, inputPointCloud, &pointCloud);
} else {
quantizePositions(
_sps->seq_source_geom_scale_factor, -minPositions, clampBox,
inputPointCloud, &pointCloud);
_sps->seq_source_geom_scale_factor, _sps->seq_bounding_box_xyz0,
clampBox, inputPointCloud, &pointCloud);
}
if (!computeBBox) {
boundingBox.min = uint32_t(0);
for (int k = 0; k < 3; k++)
boundingBox.max[k] = clampBox.max[k];
return;
}
// The new maximum bounds of the offset cloud
PCCVector3<int> maxBound{0};
const size_t pointCount = pointCloud.getPointCount();
boundingBox.min = uint32_t(0);
boundingBox.max = uint32_t(0);
for (size_t i = 0; i < pointCount; ++i) {
const PCCVector3D point = pointCloud[i];
for (int k = 0; k < 3; ++k) {
const uint32_t coord = uint32_t(point[k]);
if (boundingBox.max[k] < coord) {
boundingBox.max[k] = coord;
}
const int k_coord = int(point[k]);
assert(k_coord >= 0);
if (maxBound[k] < k_coord)
maxBound[k] = k_coord;
}
}
// todo(df): don't update maxBound if something is forcing the value?
_sliceBoxWhd = maxBound;
}
//============================================================================
......
......@@ -71,16 +71,17 @@ write(const SequenceParameterSet& sps)
bs.writeUn(24, sps.profileCompatibility.profile_compatibility_flags);
bs.writeUn(8, sps.level);
bool seq_bounding_box_present_flag = false;
bool seq_bounding_box_present_flag = true;
bs.write(seq_bounding_box_present_flag);
if (seq_bounding_box_present_flag) {
// seq_bounding_box_x0
// seq_bounding_box_y0
// seq_bounding_box_z0
// seq_bounding_box_scale
// seq_bounding_box_w
// seq_bounding_box_h
// seq_bounding_box_d
bs.writeSe(sps.seq_bounding_box_xyz0.x());
bs.writeSe(sps.seq_bounding_box_xyz0.y());
bs.writeSe(sps.seq_bounding_box_xyz0.z());
int seq_bounding_box_scale = 1;
bs.writeUe(seq_bounding_box_scale);
bs.writeUe(sps.seq_bounding_box_whd.x());
bs.writeUe(sps.seq_bounding_box_whd.y());
bs.writeUe(sps.seq_bounding_box_whd.z());
}
// todo(df): determine encoding of scale factor
bs.writeF(sps.seq_source_geom_scale_factor);
......@@ -131,13 +132,14 @@ parseSps(const PayloadBuffer& buf)
bool seq_bounding_box_present_flag = bs.read();
if (seq_bounding_box_present_flag) {
// seq_bounding_box_x0
// seq_bounding_box_y0
// seq_bounding_box_z0
// seq_bounding_box_scale
// seq_bounding_box_w
// seq_bounding_box_h
// seq_bounding_box_d
bs.readSe(&sps.seq_bounding_box_xyz0.x());
bs.readSe(&sps.seq_bounding_box_xyz0.y());
bs.readSe(&sps.seq_bounding_box_xyz0.z());
int seq_bounding_box_scale;
bs.readUe(&seq_bounding_box_scale);
bs.readUe(&sps.seq_bounding_box_whd.x());
bs.readUe(&sps.seq_bounding_box_whd.y());
bs.readUe(&sps.seq_bounding_box_whd.z());
}
bs.readF(&sps.seq_source_geom_scale_factor);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment