Czi rendering (#10)
* add dimension selector sliders to czi view * version doc & version bump * cosmetic * fix build? * multi-dimension selection enabled in czi view * remove the parameterized reset function of the renderer it is not and is conceptually questionable doc updates & some minor improvements auto-update CZI-view when sliders are moved set initial window size fix windows build and msvc build For reasons I don not comprehend, on Windows, we must include =opencv2/core/mat.hpp= as the very last header in the =CvMatRender.hpp=. If this is at any other position building on Windows, compilation will break w/ all kinds of cryptic errors regarding OpenCV. When building w/ msvc =__PRETTY_FUNCTION__= is not defined. =ILog.hpp= now defines it. This should be revised to only be set when the compiler is msvc. For the time being, it is considered sufficient though.
This commit is contained in:
committed by
Maximilian Kueffner
parent
e60203b57d
commit
1ea83d9d11
@@ -24,9 +24,11 @@ add_library(${IMAGELIBLIBNAME}
|
||||
|
||||
target_link_libraries(${IMAGELIBLIBNAME}
|
||||
PUBLIC ${OpenCV_LIBS}
|
||||
PUBLIC pixelariumutilslib
|
||||
PRIVATE libCZIStatic)
|
||||
|
||||
|
||||
target_include_directories(${IMAGELIBLIBNAME}
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/lib
|
||||
PUBLIC ${OpenCV_INCLUDE_DIRS}
|
||||
PUBLIC ${LIBCZI_INCLUDE_DIR})
|
||||
|
||||
@@ -46,15 +46,16 @@ class IPixelariumImage
|
||||
virtual std::unique_ptr<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::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) = 0;
|
||||
virtual std::unique_ptr<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::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) = 0;
|
||||
virtual std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery& query) = 0;
|
||||
|
||||
/// @brief Checks if the image is empty.
|
||||
/// @return true if the image is empty, false otherwise.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "PixelariumImageFactory.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
||||
@@ -10,7 +9,7 @@
|
||||
|
||||
|
||||
/*static*/ std::unique_ptr<pixelarium::imaging::IPixelariumImage>
|
||||
pixelarium::imaging::PixelariumImageFactory::CreateImage(const std::string& uri)
|
||||
pixelarium::imaging::PixelariumImageFactory::CreateImage(const std::string& uri, const Log& log)
|
||||
{
|
||||
const auto res{std::filesystem::path(uri)};
|
||||
const auto target_type{ExtensionToType(res.extension().string())};
|
||||
@@ -30,7 +29,7 @@ pixelarium::imaging::PixelariumImageFactory::CreateImage(const std::string& uri)
|
||||
return std::make_unique<PixelariumJpg>(uri);
|
||||
break;
|
||||
case ImageFileType::CZI:
|
||||
return std::make_unique<PixelariumCzi>(uri);
|
||||
return std::make_unique<PixelariumCzi>(uri, log);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "IPixelariumImage.hpp"
|
||||
#include "utilities/ILog.hpp"
|
||||
namespace pixelarium::imaging
|
||||
{
|
||||
constexpr pixelarium::imaging::ImageFileType ExtensionToType(const std::string& extension)
|
||||
@@ -26,9 +27,12 @@ constexpr pixelarium::imaging::ImageFileType ExtensionToType(const std::string&
|
||||
return pixelarium::imaging::ImageFileType::UNKNOWN;
|
||||
}
|
||||
|
||||
/// @brief Factory for instantiating implementations of IPixelariumImage based on the given file type.
|
||||
class PixelariumImageFactory
|
||||
{
|
||||
using Log = utils::log::ILog;
|
||||
|
||||
public:
|
||||
static std::unique_ptr<IPixelariumImage> CreateImage(const std::string& uri);
|
||||
static std::unique_ptr<IPixelariumImage> CreateImage(const std::string& uri, const Log& log);
|
||||
};
|
||||
} // namespace pixelarium::imaging
|
||||
|
||||
@@ -1,58 +1,95 @@
|
||||
#include "PixelariumCzi.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "libCZI.h"
|
||||
#include "utilities/ILog.hpp"
|
||||
|
||||
pixelarium::imaging::PixelariumCzi::PixelariumCzi(const std::string& uri)
|
||||
bool comp_blockinfo_params(const pixelarium::imaging::CziParams& params, const libCZI::SubBlockInfo& info)
|
||||
{
|
||||
if (!std::filesystem::exists(uri))
|
||||
{
|
||||
throw std::runtime_error("Render file not found.");
|
||||
}
|
||||
bool res{true};
|
||||
|
||||
this->is_empty_ = false;
|
||||
this->uri_ = std::filesystem::path(uri);
|
||||
info.coordinate.EnumValidDimensions(
|
||||
[&](libCZI::DimensionIndex dim, int start) -> bool
|
||||
{
|
||||
if (params.dimension_map.at(dim) == start)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto stream = libCZI::CreateStreamFromFile(this->uri_.wstring().c_str());
|
||||
this->czi_reader_ = libCZI::CreateCZIReader();
|
||||
this->czi_reader_->Open(stream);
|
||||
this->image_statistics_ = this->czi_reader_->GetStatistics();
|
||||
res &= false;
|
||||
return true;
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData> bitmap, libCZI::PixelType pixeltype)
|
||||
|
||||
constexpr int try_get_index_match(const pixelarium::imaging::CziParams& params, libCZI::ICZIReader& reader)
|
||||
{
|
||||
int index{-1};
|
||||
reader.EnumerateSubBlocks(
|
||||
[&](int idx, const libCZI::SubBlockInfo& info) -> bool
|
||||
{
|
||||
if (comp_blockinfo_params(params, info))
|
||||
{
|
||||
index = idx;
|
||||
// returning false will stop the enumeration
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
std::unique_ptr<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;
|
||||
std::pair<std::string, std::string> pixel_pair;
|
||||
|
||||
switch (pixeltype)
|
||||
{
|
||||
case libCZI::PixelType::Gray8:
|
||||
pixel_pair.first = "Gray8";
|
||||
pixel_pair.second = "CV_8U";
|
||||
pixel_size = 1;
|
||||
target_type = CV_8U;
|
||||
break;
|
||||
case libCZI::PixelType::Gray16:
|
||||
pixel_pair.first = "Gray16";
|
||||
pixel_pair.second = "CV_16U";
|
||||
pixel_size = 2;
|
||||
target_type = CV_16U;
|
||||
break;
|
||||
case libCZI::PixelType::Bgr24:
|
||||
pixel_pair.first = "Bgr24";
|
||||
pixel_pair.second = "CV_8UC3";
|
||||
pixel_size = 3;
|
||||
target_type = CV_8UC3;
|
||||
break;
|
||||
case libCZI::PixelType::Bgra32:
|
||||
pixel_pair.first = "Bgra32";
|
||||
pixel_pair.second = "CV_8CU4";
|
||||
target_type = CV_8UC4;
|
||||
case libCZI::PixelType::Gray32:
|
||||
pixel_pair.first = "Gray32";
|
||||
pixel_pair.second = "CV_32S";
|
||||
target_type = CV_32S;
|
||||
case libCZI::PixelType::Gray32Float:
|
||||
pixel_pair.first = "Gray32Float";
|
||||
pixel_pair.second = "CV_32F";
|
||||
target_type = CV_32F;
|
||||
pixel_size = 4;
|
||||
break;
|
||||
// case libCZI::PixelType::Gray64ComplexFloat:
|
||||
// case libCZI::PixelType::Gray64Float:
|
||||
// target_type =
|
||||
// pixel_size = 8;
|
||||
// break;
|
||||
default:
|
||||
pixel_size = -1;
|
||||
break;
|
||||
@@ -60,6 +97,9 @@ std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData>
|
||||
|
||||
if (pixel_size < 0) return nullptr;
|
||||
|
||||
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);
|
||||
@@ -86,6 +126,9 @@ std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData>
|
||||
target_row[3 * w + 1] = source_row[3 * w + 1];
|
||||
target_row[3 * w + 2] = source_row[3 * w + 2];
|
||||
break;
|
||||
case 4:
|
||||
reinterpret_cast<std::int32_t*>(target_row)[w] = reinterpret_cast<std::int32_t*>(source_row)[w];
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown pixel type requested!");
|
||||
break;
|
||||
@@ -97,11 +140,48 @@ std::unique_ptr<cv::Mat> CZISubBlockToCvMat(std::shared_ptr<libCZI::IBitmapData>
|
||||
return fill_mat;
|
||||
}
|
||||
|
||||
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage()
|
||||
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::SubblockToCvMat(int index)
|
||||
{
|
||||
auto block = this->czi_reader_->ReadSubBlock(0);
|
||||
log_.Info(std::format("{}: constructing bitmap with index {}", __PRETTY_FUNCTION__, index));
|
||||
auto block = this->czi_reader_->ReadSubBlock(index);
|
||||
auto bitmap = block->CreateBitmap();
|
||||
auto res = CZISubBlockToCvMat(bitmap, block->GetSubBlockInfo().pixelType);
|
||||
|
||||
return res;
|
||||
return CZISubBlockToCvMat(bitmap, block->GetSubBlockInfo().pixelType, log_);
|
||||
}
|
||||
|
||||
pixelarium::imaging::PixelariumCzi::PixelariumCzi(const std::string& uri, const Log& log) : log_(log)
|
||||
{
|
||||
if (!std::filesystem::exists(uri))
|
||||
{
|
||||
throw std::runtime_error("Render file not found.");
|
||||
}
|
||||
|
||||
this->is_empty_ = false;
|
||||
this->uri_ = std::filesystem::path(uri);
|
||||
|
||||
auto stream = libCZI::CreateStreamFromFile(this->uri_.wstring().c_str());
|
||||
this->czi_reader_ = libCZI::CreateCZIReader();
|
||||
this->czi_reader_->Open(stream);
|
||||
this->image_statistics_ = this->czi_reader_->GetStatistics();
|
||||
|
||||
this->image_statistics_.dimBounds.EnumValidDimensions(
|
||||
[&](libCZI::DimensionIndex dim, int start, int) -> bool
|
||||
{
|
||||
this->dimension_map_[dim] = start;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<cv::Mat> pixelarium::imaging::PixelariumCzi::TryGetImage() { return SubblockToCvMat(0); }
|
||||
|
||||
std::unique_ptr<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_);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
return SubblockToCvMat(0);
|
||||
}
|
||||
|
||||
return SubblockToCvMat(index);
|
||||
}
|
||||
|
||||
@@ -4,19 +4,25 @@
|
||||
#include <string>
|
||||
|
||||
#include "../IPixelariumImage.hpp"
|
||||
#include "utilities/ILog.hpp"
|
||||
#include "libCZI.h"
|
||||
|
||||
namespace pixelarium::imaging
|
||||
{
|
||||
/// @brief An implementation of IImageQuery to work on CZI images.
|
||||
/// @note Check the documentation here https://zeiss.github.io/libczi/pages/mainpage.html#czi-in-a-nutshell
|
||||
struct CziParams : public IImageQuery
|
||||
{
|
||||
|
||||
/// @brief A map providing the start coordinate for each dimension in the CZI
|
||||
std::unordered_map<libCZI::DimensionIndex, int> dimension_map;
|
||||
};
|
||||
|
||||
/// @brief Implements support for .czi-images in the realm of IPixelariumImage
|
||||
class PixelariumCzi : public IPixelariumImage
|
||||
{
|
||||
using Log = pixelarium::utils::log::ILog;
|
||||
public:
|
||||
explicit PixelariumCzi(const std::string& uri);
|
||||
explicit PixelariumCzi(const std::string& uri, const Log& log);
|
||||
~PixelariumCzi()
|
||||
{
|
||||
if (this->czi_reader_)
|
||||
@@ -27,11 +33,7 @@ class PixelariumCzi : public IPixelariumImage
|
||||
public:
|
||||
std::unique_ptr<cv::Mat> TryGetImage() override;
|
||||
|
||||
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override
|
||||
{
|
||||
// ToDo: proper error
|
||||
throw std::runtime_error("Not implemented.");
|
||||
}
|
||||
std::unique_ptr<cv::Mat> TryGetImage(const IImageQuery&) override;
|
||||
|
||||
std::vector<std::unique_ptr<cv::Mat>> TryGetImages(const IImageQuery&) override
|
||||
{
|
||||
@@ -46,6 +48,9 @@ class PixelariumCzi : public IPixelariumImage
|
||||
public:
|
||||
const static ImageFileType type_{ImageFileType::CZI};
|
||||
|
||||
private:
|
||||
std::unique_ptr<cv::Mat> SubblockToCvMat(int index);
|
||||
|
||||
private:
|
||||
// this should be set by each image getter
|
||||
// after a new cv::Mat could be instantiated
|
||||
@@ -54,5 +59,9 @@ class PixelariumCzi : public IPixelariumImage
|
||||
libCZI::SubBlockStatistics image_statistics_;
|
||||
|
||||
std::shared_ptr<libCZI::ICZIReader> czi_reader_;
|
||||
|
||||
std::unordered_map<libCZI::DimensionIndex, int> dimension_map_;
|
||||
|
||||
const Log& log_;
|
||||
};
|
||||
} // namespace pixelarium::imaging
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace pixelarium::imaging
|
||||
{
|
||||
/// @brief Implements support for .jpg-images in the realm of IPixelariumImage
|
||||
class PixelariumJpg : public IPixelariumImage
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace pixelarium::imaging
|
||||
{
|
||||
/// @brief Implements support for .png-images in the realm of IPixelariumImage
|
||||
class PixelariumPng : public IPixelariumImage
|
||||
{
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user