Expand ArFramePlayback to allow to be loaded from single file ArFrames saved with "SaveToFile"

This commit is contained in:
Georg Hagen
2025-05-27 00:01:41 +02:00
parent 33f53a533c
commit f042c5f37a
4 changed files with 95 additions and 49 deletions

View File

@@ -19,26 +19,68 @@ namespace OpenVulkano::AR::Playback
if (session->GetCapabilities().IsDepthSupported()) if (session->GetCapabilities().IsDepthSupported())
{ {
auto depth = frameReader.ReadDepthImage(); auto depth = frameReader.ReadDepthImage();
confImgData = std::move(depth.confidence.image); SetDepthImgInfo(depth);
depthImgData = std::move(depth.depth.image);
depthImage.format = session->GetSessionMetadata().depthFormat;
depthImage.intrinsic = frameMetadata.intrinsic.GetForResolution({depth.depth.header.width, depth.depth.header.height});
depthImage.depth.data = depthImgData.get();
depthImage.depth.resolution = {depth.depth.header.width, depth.depth.header.height};
depthImage.confidence.data = confImgData.get();
depthImage.confidence.resolution = {depth.confidence.header.width, depth.confidence.header.height};
} }
if (session->IsLoadColorEnabled()) if (session->IsLoadColorEnabled())
{ {
colorImgData = frameReader.ReadColorImage(); colorImgData = frameReader.ReadColorImage();
colorImage.intrinsic = frameMetadata.intrinsic.GetForResolution({colorImgData.cols, colorImgData.rows}); SetColorImgInfo();
colorImage.format = ArImagePlanar::Format::RGB;
colorImage.luminescenceOrColor = {colorImgData.data, {colorImgData.cols, colorImgData.rows}};
colorImage.luminescenceOrColor.numChannels = colorImgData.channels;
} }
SetSaved(); SetSaved();
} }
ArFramePlayback::ArFramePlayback(const std::shared_ptr<ArSessionPlayback>& session, const std::filesystem::path& imagePath)
: ArFrame(session, 99999) // TODO find better way to generate id
{
ArchiveReader reader(imagePath);
DepthImage dImage;
while(reader.HasNext())
{
reader.GetNextFileAsStream([this, &dImage](const FileDescription& desc, std::istream& data)
{
if (desc.path.find("depth") != std::string::npos)
{
dImage.depth.TryRead(data);
}
else if (desc.path.find("confidence") != std::string::npos)
{
dImage.confidence.TryRead(data);
}
else if (desc.path.find("metadata") != std::string::npos)
{
std::ostringstream buffer;
buffer << data.rdbuf();
std::string str = buffer.str();
frameMetadata = ArFrameMetadata::FromContent(str.data(), str.size());
}
});
}
colorImgData.channels = ColorImg::RGBA; // TODO test if defaulting to NV12
colorImgData.Decode(Utils::ReadFile(imagePath));
SetDepthImgInfo(dImage);
SetSaved();
}
void ArFramePlayback::SetDepthImgInfo(DepthImage& depth)
{
confImgData = std::move(depth.confidence.image);
depthImgData = std::move(depth.depth.image);
depthImage.format = ArDepthFormat::METER_FP32; //TODO session->GetSessionMetadata().depthFormat;
depthImage.intrinsic = frameMetadata.intrinsic.GetForResolution({depth.depth.header.width, depth.depth.header.height});
depthImage.depth.data = depthImgData.get();
depthImage.depth.resolution = {depth.depth.header.width, depth.depth.header.height};
depthImage.confidence.data = confImgData.get();
depthImage.confidence.resolution = {depth.confidence.header.width, depth.confidence.header.height};
}
void ArFramePlayback::SetColorImgInfo()
{
colorImage.intrinsic = frameMetadata.intrinsic.GetForResolution({colorImgData.cols, colorImgData.rows});
colorImage.format = ArImagePlanar::Format::RGB;
colorImage.luminescenceOrColor = {colorImgData.data, {colorImgData.cols, colorImgData.rows}};
colorImage.luminescenceOrColor.numChannels = colorImgData.channels;
}
ArImagePlanar ArFramePlayback::GetCameraImage() ArImagePlanar ArFramePlayback::GetCameraImage()
{ {
return colorImage; return colorImage;

View File

@@ -15,9 +15,18 @@ namespace OpenVulkano::AR::Playback
class ArFramePlayback final : public ArFrame class ArFramePlayback final : public ArFrame
{ {
ArImagePlanar colorImage;
ArDepthImage depthImage;
std::unique_ptr<char[]> confImgData;
std::unique_ptr<float[]> depthImgData;
ColorImg colorImgData;
public: public:
ArFramePlayback(const std::shared_ptr<ArSessionPlayback>& session, ArPlaybackReader& frameReader); ArFramePlayback(const std::shared_ptr<ArSessionPlayback>& session, ArPlaybackReader& frameReader);
ArFramePlayback(const std::shared_ptr<ArSessionPlayback>& session, const std::filesystem::path& imagePath);
ArImagePlanar GetCameraImage() override; ArImagePlanar GetCameraImage() override;
ArDepthImage GetDepthImage() override; ArDepthImage GetDepthImage() override;
@@ -27,11 +36,7 @@ namespace OpenVulkano::AR::Playback
Math::Matrix4f GetCameraProjection(Math::Vector2f viewportSize, float near, float far) override; Math::Matrix4f GetCameraProjection(Math::Vector2f viewportSize, float near, float far) override;
private: private:
ArImagePlanar colorImage; void SetDepthImgInfo(DepthImage& depth);
ArDepthImage depthImage; void SetColorImgInfo();
std::unique_ptr<char[]> confImgData;
std::unique_ptr<float[]> depthImgData;
ColorImg colorImgData;
}; };
} }

View File

@@ -15,64 +15,61 @@
namespace OpenVulkano::AR::Playback namespace OpenVulkano::AR::Playback
{ {
void ArPlaybackReader::ReadColorImage(ColorImg& img) void ColorImg::Decode(const Array<char>& dataIn)
{ {
//BlockProfiler profiler("Load jpeg"); //BlockProfiler profiler("Load jpeg");
std::optional<std::pair<FileDescription, Array<char>>> file = ReadColorImageRaw();
long unsigned int jpegSize = file->second.Size(); long unsigned int jpegSize = dataIn.Size();
unsigned char* compressedImage = reinterpret_cast<uint8_t*>(file->second.Data()); unsigned char* compressedImage = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(dataIn.Data()));
int jpegSubsamp; int jpegSubsamp;
tjhandle jpegDecompressor = tjInitDecompress(); tjhandle jpegDecompressor = tjInitDecompress();
tjDecompressHeader2(jpegDecompressor, compressedImage, jpegSize, &img.cols, &img.rows, &jpegSubsamp); tjDecompressHeader2(jpegDecompressor, compressedImage, jpegSize, &cols, &rows, &jpegSubsamp);
if (img.UseRGB()) if (UseRGB())
{ {
img.channels = 4; channels = 4;
if (!img.data) img.Allocate(); if (!data) Allocate();
tjDecompress2(jpegDecompressor, compressedImage, jpegSize, img.data, img.cols, 0/*pitch*/, img.rows, TJPF_RGBA, TJFLAG_FASTDCT); tjDecompress2(jpegDecompressor, compressedImage, jpegSize, data, cols, 0/*pitch*/, rows, TJPF_RGBA, TJFLAG_FASTDCT);
} }
else if (img.channels == 1) else if (channels == 1)
{ {
if (!img.data) img.Allocate(); if (!data) Allocate();
tjDecompress2(jpegDecompressor, compressedImage, jpegSize, img.data, img.cols, 0/*pitch*/, img.rows, TJPF_GRAY, TJFLAG_FASTDCT); tjDecompress2(jpegDecompressor, compressedImage, jpegSize, data, cols, 0/*pitch*/, rows, TJPF_GRAY, TJFLAG_FASTDCT);
} }
else if (img.channels != 0) else if (channels != 0)
{ {
if (!img.data) img.Allocate(); if (!data) Allocate();
std::array<uint8_t*, 3> planes; std::array<uint8_t*, 3> planes;
size_t chromaSize = img.cols * img.rows / 4; size_t chromaSize = cols * rows / 4;
planes[0] = img.data; planes[0] = data;
if (!img.dataUV) img.dataUV = img.data + (img.cols * img.rows); if (!dataUV) dataUV = data + (cols * rows);
Unique<uint8_t[]> chromaTmp; Unique<uint8_t[]> chromaTmp;
if (img.channels == ColorImg::NV12 && !img.dataPtr) if (channels == ColorImg::NV12 && !dataPtr)
{ {
chromaTmp = std::make_unique<uint8_t[]>(img.cols * img.rows / 2); chromaTmp = std::make_unique<uint8_t[]>(cols * rows / 2);
planes[1] = chromaTmp.get(); planes[1] = chromaTmp.get();
} }
else else
{ {
planes[1] = img.dataUV; planes[1] = dataUV;
if (img.channels == ColorImg::NV12) planes[1] += chromaSize; if (channels == ColorImg::NV12) planes[1] += chromaSize;
} }
planes[2] = planes[1] + chromaSize; planes[2] = planes[1] + chromaSize;
std::array<int, 3> rowSize = { img.cols, img.cols / 2, img.cols / 2 }; std::array<int, 3> rowSize = { cols, cols / 2, cols / 2 };
tjDecompressToYUVPlanes(jpegDecompressor, compressedImage, jpegSize, planes.data(), tjDecompressToYUVPlanes(jpegDecompressor, compressedImage, jpegSize, planes.data(),
img.cols, rowSize.data(), img.rows, TJFLAG_FASTDCT); cols, rowSize.data(), rows, TJFLAG_FASTDCT);
if (img.channels == ColorImg::NV12) if (channels == ColorImg::NV12)
{ {
YuvUtils::NV12FromChromaPlanes(planes[1], img.data + (img.cols * img.rows), chromaSize); YuvUtils::NV12FromChromaPlanes(planes[1], data + (cols * rows), chromaSize);
} }
} }
tjDestroy(jpegDecompressor); tjDestroy(jpegDecompressor);
m_imgReadSize += 1000 + file.value().first.size;
} }
} }
@@ -87,7 +84,7 @@ namespace OpenVulkano::AR::Playback
ColorImg img; ColorImg img;
auto file = m_archiveColor.GetNextFile(); auto file = m_archiveColor.GetNextFile();
img.dataPtr = std::shared_ptr<uint8_t>( img.dataPtr = std::shared_ptr<uint8_t>(
stbi_load_from_memory(reinterpret_cast<stbi_uc*>(file->second.Data()), file->second.Size(), &img.cols, &img.rows, &img.channels, 3), stbi_load_from_memory(reinterpret_cast<stbi_uc*>(data.Data()), data.Size(), &img.cols, &img.rows, &img.channels, 3),
&stbi_image_free); &stbi_image_free);
img.data = img.dataPtr.get(); img.data = img.dataPtr.get();
m_imgReadSize += 1000 + file.value().first.size; m_imgReadSize += 1000 + file.value().first.size;

View File

@@ -37,6 +37,8 @@ namespace OpenVulkano::AR::Playback
} }
bool UseRGB() const { return channels == RGBA; } bool UseRGB() const { return channels == RGBA; }
void Decode(const Array<char>& data);
}; };
class ArPlaybackReader final class ArPlaybackReader final
@@ -72,14 +74,14 @@ namespace OpenVulkano::AR::Playback
{ {
ColorImg img; ColorImg img;
img.channels = ColorImg::RGBA; // TODO test if defaulting to NV12 img.channels = ColorImg::RGBA; // TODO test if defaulting to NV12
ReadColorImage(img); std::optional<std::pair<FileDescription, Array<char>>> file = ReadColorImageRaw();
img.Decode(file->second);
m_imgReadSize += 1000 + file.value().first.size;
return img; return img;
} }
std::optional<std::pair<FileDescription, Array<char>>> ReadColorImageRaw() { return m_archiveColor.GetNextFile(); } std::optional<std::pair<FileDescription, Array<char>>> ReadColorImageRaw() { return m_archiveColor.GetNextFile(); }
void ReadColorImage(ColorImg& img);
DepthImage ReadDepthImage() DepthImage ReadDepthImage()
{ {
DepthImage img; DepthImage img;