* get image returns optional<Mat> instead of unique_ptr<Mat>

* introduce complexity

* rename image load function

* add example for a basic reader for binary image files

* fix windows build?

* add a status bar underneath the menu bar

* use status bar in custom_0 example app

* clang formats

* packing w/ pragma push

* add "Save As" functions to image views

* resize over reserve

* rm local override uri

* add simple thread pool

* rename to simple_thread_pool

* get rid of useless renderlib

* document version inc

* extract hardcoded values to in-header

* clang format patch

* clone registered image in custom_0

* document binary-file header

* minor fixes

* clang format

* rm unused render cmake
This commit is contained in:
m-aXimilian
2026-01-23 23:00:35 +00:00
committed by Maximilian Kueffner
parent e3e161ce52
commit b37814204f
52 changed files with 712 additions and 207 deletions
+1
View File
@@ -7,6 +7,7 @@ message(STATUS "OpenCV_LIBs from: " ${OpenCV_LIBS})
set(IMAGELIBSRC
IPixelariumImage.hpp
IPixelariumImage.cpp
PixelariumImageFactory.hpp
PixelariumImageFactory.cpp
impl/PixelariumJpg.hpp
+15
View File
@@ -0,0 +1,15 @@
#include "IPixelariumImage.hpp"
#include <opencv2/imgcodecs.hpp>
bool pixelarium::imaging::IPixelariumImageCvMat::SaveImage(const std::string& uri)
{
auto current_image = this->TryGetImage();
if (!current_image.has_value())
{
return false;
}
return cv::imwrite(uri, current_image.value());
}
+60 -4
View File
@@ -2,7 +2,6 @@
#include <filesystem>
#include <functional>
#include <memory>
#include <opencv2/core/mat.hpp>
#include <string>
@@ -38,6 +37,7 @@ struct IImageQuery
/// @brief This aims to be a generic image abstraction
/// meant for codec specific implementation.
template <class Data>
class IPixelariumImage
{
public:
@@ -47,19 +47,19 @@ class IPixelariumImage
/// @return A unique pointer to a Mat object containing the image data,
/// or nullptr if the image is not found or cannot be retrieved.
/// May throw exceptions for multidimensional images.
virtual std::unique_ptr<cv::Mat> TryGetImage() = 0;
virtual std::optional<Data> TryGetImage() = 0;
/// @brief Attempts to retrieve the image.
/// @param query The query object defining the images to retrieve.
/// @return A unique pointer to a Mat object containing the image data,
/// or nullptr if the image is not found or cannot be retrieved.
virtual std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery& query) = 0;
virtual std::optional<Data> TryGetImage(const IImageQuery& query) = 0;
/// @brief Attempts to retrieve a collection of images based on a query.
/// @param query The query object defining the images to retrieve.
/// @return A vector of unique pointers to cv::Mat objects. Each element is an image.
/// Returns an empty vector if no images are found or if an error occurs.
virtual std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery& query) = 0;
virtual std::vector<std::optional<Data>> TryGetImages(const IImageQuery& query) = 0;
/// @brief Checks if the image is empty.
/// @return true if the image is empty, false otherwise.
@@ -92,4 +92,60 @@ class IPixelariumImage
protected:
std::filesystem::path uri_;
};
class IPixelariumImageCvMat : public IPixelariumImage<cv::Mat>
{
public:
virtual ~IPixelariumImageCvMat() = default;
/// @brief Attempts to retrieve the image.
/// @return A unique pointer to a Mat object containing the image data,
/// or nullptr if the image is not found or cannot be retrieved.
/// May throw exceptions for multidimensional images.
virtual std::optional<cv::Mat> TryGetImage() = 0;
/// @brief Attempts to retrieve the image.
/// @param query The query object defining the images to retrieve.
/// @return A unique pointer to a Mat object containing the image data,
/// or nullptr if the image is not found or cannot be retrieved.
virtual std::optional<cv::Mat> TryGetImage(const IImageQuery& query) = 0;
/// @brief Attempts to retrieve a collection of images based on a query.
/// @param query The query object defining the images to retrieve.
/// @return A vector of unique pointers to cv::Mat objects. Each element is an image.
/// Returns an empty vector if no images are found or if an error occurs.
virtual std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery& query) = 0;
/// @brief Checks if the image is empty.
/// @return true if the image is empty, false otherwise.
virtual bool Empty() const noexcept = 0;
/// @brief Saves an image to the resource identifier given by uri.
/// @return true if saving was successful, false otherwise.
virtual bool SaveImage(const std::string& uri);
// default implemented
public:
/// @brief Gets the resource identifier as a file path.
/// @return @c std::filesystem::path of the underlying resource.
virtual std::filesystem::path Uri() const noexcept { return this->uri_; }
/// @brief Gets the resource name.
/// @note Implementations of IPixelariumImage that live in memory
/// should override this to get something meaningful as the name
/// cannot be fetched from the resource uri in that case.
/// @return The name of the underlying resource.
virtual std::string Name() const noexcept
{
if (!this->uri_.empty())
{
return this->uri_.filename().string();
}
return {};
}
public:
const static ImageFileType type_{ImageFileType::kAbstract};
};
} // namespace pixelarium::imaging
+2 -1
View File
@@ -3,13 +3,14 @@
#include <cctype>
#include <memory>
#include "imaging/IPixelariumImage.hpp"
#include "imaging/impl/PixelariumMem.hpp"
#include "impl/PixelariumCzi.hpp"
#include "impl/PixelariumJpg.hpp"
#include "impl/PixelariumPng.hpp"
#include "impl/PixelariumTiff.hpp"
/*static*/ std::unique_ptr<pixelarium::imaging::IPixelariumImage>
/*static*/ std::unique_ptr<pixelarium::imaging::IPixelariumImageCvMat>
pixelarium::imaging::PixelariumImageFactory::CreateImage(const std::string& uri, const Log& log)
{
const auto res{std::filesystem::path(uri)};
+1 -1
View File
@@ -37,6 +37,6 @@ class PixelariumImageFactory
using Log = utils::log::ILog;
public:
static std::unique_ptr<IPixelariumImage> CreateImage(const std::string& uri, const Log& log);
static std::unique_ptr<IPixelariumImageCvMat> CreateImage(const std::string& uri, const Log& log);
};
} // namespace pixelarium::imaging
+10 -8
View File
@@ -4,6 +4,8 @@
#include <filesystem>
#include <format>
#include <memory>
#include <opencv2/imgcodecs.hpp>
#include <optional>
#include <stdexcept>
#include <utility>
@@ -48,8 +50,8 @@ constexpr int try_get_index_match(const pixelarium::imaging::CziParams& params,
return index;
}
std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData> bitmap, libCZI::PixelType pixeltype,
const pixelarium::utils::log::ILog& log)
std::optional<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData> bitmap, libCZI::PixelType pixeltype,
const pixelarium::utils::log::ILog& log)
{
size_t pixel_size{0};
int target_type;
@@ -94,21 +96,21 @@ std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData>
break;
}
if (pixel_size < 0) return nullptr;
if (pixel_size < 0) return std::nullopt;
log.Info(std::format("{}: source pixel type {}, target cv pixel type {}, pixel size {}", __PRETTY_FUNCTION__,
pixel_pair.first, pixel_pair.second, pixel_size));
size_t height{bitmap->GetHeight()};
size_t width{bitmap->GetWidth()};
auto fill_mat = std::make_unique<cv::Mat>(height, width, target_type);
auto fill_mat = cv::Mat(height, width, target_type);
auto bitmap_info = bitmap->Lock();
for (size_t h{0}; h < height; ++h)
{
unsigned char* source_row = ((unsigned char*)bitmap_info.ptrDataRoi) + bitmap_info.stride * h;
unsigned char* target_row = fill_mat->ptr(h);
unsigned char* target_row = fill_mat.ptr(h);
for (size_t w{0}; w < width; ++w)
{
@@ -139,7 +141,7 @@ std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData>
return fill_mat;
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::SubblockToCvMat(int index)
std::optional<cv::Mat> pixelarium::imaging::PixelariumCzi::SubblockToCvMat(int index)
{
log_.Info(std::format("{}: constructing bitmap with index {}", __PRETTY_FUNCTION__, index));
auto block = this->czi_reader_->ReadSubBlock(index);
@@ -170,9 +172,9 @@ pixelarium::imaging::PixelariumCzi::PixelariumCzi(const std::string& uri, const
});
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage() { return SubblockToCvMat(0); }
std::optional<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage() { return SubblockToCvMat(0); }
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage(const IImageQuery& query)
std::optional<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage(const IImageQuery& query)
{
const auto czi_query = static_cast<const CziParams&>(query);
int index = try_get_index_match(czi_query, *this->czi_reader_);
+6 -5
View File
@@ -18,7 +18,7 @@ struct CziParams : public IImageQuery
};
/// @brief Implements support for .czi-images in the realm of IPixelariumImage
class PixelariumCzi : public IPixelariumImage
class PixelariumCzi : public IPixelariumImageCvMat
{
using Log = pixelarium::utils::log::ILog;
@@ -31,16 +31,17 @@ class PixelariumCzi : public IPixelariumImage
// IPixelariumImage member implementations
public:
std::unique_ptr<cv::Mat> TryGetImage() override;
std::optional<cv::Mat> TryGetImage() override;
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override;
std::optional<cv::Mat> TryGetImage(const IImageQuery&) override;
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not implemented.");
}
public:
bool Empty() const noexcept override { return this->is_empty_; }
const libCZI::SubBlockStatistics& GetStatistics() const { return this->image_statistics_; }
@@ -49,7 +50,7 @@ class PixelariumCzi : public IPixelariumImage
const static ImageFileType type_{ImageFileType::kCzi};
private:
std::unique_ptr<cv::Mat> SubblockToCvMat(int index);
std::optional<cv::Mat> SubblockToCvMat(int index);
private:
// this should be set by each image getter
+2 -4
View File
@@ -1,7 +1,5 @@
#include "PixelariumJpg.hpp"
#include <filesystem>
#include <memory>
#include <opencv2/imgcodecs.hpp>
#include <string>
@@ -16,11 +14,11 @@ pixelarium::imaging::PixelariumJpg::PixelariumJpg(const std::string& uri)
this->uri_ = std::filesystem::path(uri);
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumJpg::TryGetImage()
std::optional<cv::Mat> pixelarium::imaging::PixelariumJpg::TryGetImage()
{
try
{
auto img = std::make_unique<cv::Mat>(cv::imread(this->uri_.string()));
auto img = cv::Mat(cv::imread(this->uri_.string()));
this->is_empty_ = false;
+5 -4
View File
@@ -8,27 +8,28 @@
namespace pixelarium::imaging
{
/// @brief Implements support for .jpg-images in the realm of IPixelariumImage
class PixelariumJpg : public IPixelariumImage
class PixelariumJpg : public IPixelariumImageCvMat
{
public:
explicit PixelariumJpg(const std::string& url);
// IPixelariumImage member implementations
public:
std::unique_ptr<cv::Mat> TryGetImage() override;
std::optional<cv::Mat> TryGetImage() override;
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override
std::optional<cv::Mat> TryGetImage(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with jpg.");
}
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with jpg.");
}
public:
bool Empty() const noexcept override { return this->is_empty_; }
public:
+2 -2
View File
@@ -12,7 +12,7 @@ pixelarium::imaging::PixelariumMem::PixelariumMem(const cv::Mat& img, const std:
this->uri_ = std::filesystem::path();
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumMem::TryGetImage()
std::optional<cv::Mat> pixelarium::imaging::PixelariumMem::TryGetImage()
{
// ToDo: this craving for a revision of the whole concept:
// the interface requires a unique_ptr here. This concept was designed to "create an in-memory image on demand" sort
@@ -22,5 +22,5 @@ std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumMem::TryGetImage()
// So, returning a unique_ptr from it in the following semantic essentially calls the
// copy constructor of cv::Mat. This is potentially not "super bad", but at least it requires attention at some
// point.
return std::make_unique<cv::Mat>(this->img_);
return this->img_;
}
+4 -4
View File
@@ -9,7 +9,7 @@
namespace pixelarium::imaging
{
/// @brief Implements support for in-memory images in the realm of IPixelariumImage
class PixelariumMem : public IPixelariumImage
class PixelariumMem : public IPixelariumImageCvMat
{
using Log = pixelarium::utils::log::ILog;
@@ -18,11 +18,11 @@ class PixelariumMem : public IPixelariumImage
// IPixelariumImage member implementations
public:
std::unique_ptr<cv::Mat> TryGetImage() override;
std::optional<cv::Mat> TryGetImage() override;
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override { throw std::runtime_error("Not implemented."); }
std::optional<cv::Mat> TryGetImage(const IImageQuery&) override { throw std::runtime_error("Not implemented."); }
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery&) override
{
throw std::runtime_error("Not implemented.");
}
+2 -2
View File
@@ -16,11 +16,11 @@ pixelarium::imaging::PixelariumPng::PixelariumPng(const std::string& uri)
this->uri_ = std::filesystem::path(uri);
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumPng::TryGetImage()
std::optional<cv::Mat> pixelarium::imaging::PixelariumPng::TryGetImage()
{
try
{
auto img = std::make_unique<cv::Mat>(cv::imread(this->uri_.string()));
auto img = cv::Mat(cv::imread(this->uri_.string()));
this->is_empty_ = false;
+4 -4
View File
@@ -8,22 +8,22 @@
namespace pixelarium::imaging
{
/// @brief Implements support for .png-images in the realm of IPixelariumImage
class PixelariumPng : public IPixelariumImage
class PixelariumPng : public IPixelariumImageCvMat
{
public:
explicit PixelariumPng(const std::string& url);
// IPixelariumImage member implementations
public:
std::unique_ptr<cv::Mat> TryGetImage() override;
std::optional<cv::Mat> TryGetImage() override;
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override
std::optional<cv::Mat> TryGetImage(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with png.");
}
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with png.");
+2 -2
View File
@@ -16,11 +16,11 @@ pixelarium::imaging::PixelariumTiff::PixelariumTiff(const std::string& uri, cons
this->uri_ = std::filesystem::path(uri);
}
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumTiff::TryGetImage()
std::optional<cv::Mat> pixelarium::imaging::PixelariumTiff::TryGetImage()
{
try
{
auto img = std::make_unique<cv::Mat>(cv::imread(this->uri_.string()));
auto img = cv::Mat(cv::imread(this->uri_.string()));
this->is_empty_ = false;
+4 -4
View File
@@ -9,7 +9,7 @@
namespace pixelarium::imaging
{
/// @brief Implements support for .tiff-images in the realm of IPixelariumImage
class PixelariumTiff : public IPixelariumImage
class PixelariumTiff : public IPixelariumImageCvMat
{
using Log = pixelarium::utils::log::ILog;
@@ -18,15 +18,15 @@ class PixelariumTiff : public IPixelariumImage
// IPixelariumImage member implementations
public:
std::unique_ptr<cv::Mat> TryGetImage() override;
std::optional<cv::Mat> TryGetImage() override;
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override
std::optional<cv::Mat> TryGetImage(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with tiff.");
}
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
std::vector<std::optional<cv::Mat>> TryGetImages(const IImageQuery&) override
{
// ToDo: proper error
throw std::runtime_error("Not possible with tiff.");