From 5249b277ecd795cc76f17efdafb035161980ecd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Tue, 25 Feb 2025 17:41:29 +0100 Subject: [PATCH] Add integer resample --- loadrunable.cpp | 40 ++++++++++++++++++++++++++++++++ loadrunable.h | 5 ++++ rawimage.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++-- rawimage.h | 1 + 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/loadrunable.cpp b/loadrunable.cpp index c304705..9978c4f 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -191,6 +191,17 @@ void ConvertRunable::run() QFileInfo info(m_outfile); info.dir().mkpath("."); + if(m_params.binning > 1) + { + rawimage->resizeInt(m_params.binning, m_params.average); + } + else if(m_params.resize.isValid() && !m_params.resize.isEmpty()) + { + QSize imgSize(rawimage->width(), rawimage->height()); + imgSize = imgSize.scaled(m_params.resize, m_params.aspect); + rawimage->resize(imgSize.width(), imgSize.height()); + } + if(rawimage) { if(m_format == "xisf") @@ -323,4 +334,33 @@ ConvertRunable::ConvertParams::ConvertParams(const QVariantMap &map) if(map.contains("compressionType")) compressionType = map["compressionType"].toString(); + + if(map.contains("binning")) + binning = map["binning"].toInt(); + + if(map.contains("average")) + average = map["average"].toBool(); + + if(map.contains("resize")) + { + QVariantMap size = map["resize"].toMap(); + if(size.contains("width") && size.contains("height")) + { + int w = size["width"].toInt(); + int h = size["height"].toInt(); + resize = QSize(w, h); + } + } + + if(map.contains("aspect")) + { + QString aspectStr = map["aspect"].toString(); + if(aspectStr == "keep") + aspect = Qt::KeepAspectRatio; + else if(aspectStr == "expand") + aspect = Qt::KeepAspectRatioByExpanding; + else if(aspectStr == "ignore") + aspect = Qt::IgnoreAspectRatio; + } + } diff --git a/loadrunable.h b/loadrunable.h index ba8d3b0..9f11439 100644 --- a/loadrunable.h +++ b/loadrunable.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "imageinfodata.h" class Image; @@ -26,6 +27,10 @@ public: { int compressionLevel = -1; QString compressionType; + int binning = 0; + bool average = true; + QSize resize; + Qt::AspectRatioMode aspect = Qt::KeepAspectRatio; ConvertParams(){} ConvertParams(const QVariantMap &map); }; diff --git a/rawimage.cpp b/rawimage.cpp index 8dc8c25..4620c44 100644 --- a/rawimage.cpp +++ b/rawimage.cpp @@ -9,10 +9,9 @@ using F16 = qfloat16; #else #include -using F16 = uint16_t; +using F16 = _Float16; #endif - int THUMB_SIZE = 128; int THUMB_SIZE_BORDER = 138; int THUMB_SIZE_BORDER_Y = 158; @@ -755,6 +754,64 @@ void RawImage::resize(uint32_t w, uint32_t h) } } +template +void integerResample(uint32_t w, uint32_t h, uint32_t ch, uint32_t oldw, uint32_t down, bool avg, const uint8_t *in_, uint8_t *out_) +{ + const T *in = reinterpret_cast(in_); + T *out = reinterpret_cast(out_); + uint32_t down2 = down * down; + + U m = std::numeric_limits::max(); + if constexpr(std::is_floating_point_v)m = down2; + + for(uint64_t i = 0; i < h; i++) + { + for(uint64_t o = 0; o < w; o++) + { + for(uint64_t p = 0; p < ch; p++) + { + U pix = 0; + for(uint32_t y = 0; y < down; y++) + for(uint32_t x = 0; x < down; x++) + pix += in[((i * down) + y) * oldw * ch + ((o * down) + x) * ch + p]; + + if (avg) + out[(i * w + o) * ch + p] = pix / down2; + else + out[(i * w + o) * ch + p] = std::min(pix, m); + } + } + } +} + +void RawImage::resizeInt(int downsample, bool avg) +{ + uint32_t oldw = m_width; + std::unique_ptr old_pixels = std::move(m_pixels); + allocate(m_width / downsample, m_height / downsample, m_channels, m_type); + + switch(m_type) + { + case RawImage::UINT8: + integerResample(m_width, m_height, m_ch, oldw, downsample, avg, old_pixels.get(), m_pixels.get()); + break; + case RawImage::UINT16: + integerResample(m_width, m_height, m_ch, oldw, downsample, avg, old_pixels.get(), m_pixels.get()); + break; + case RawImage::UINT32: + integerResample(m_width, m_height, m_ch, oldw, downsample, avg, old_pixels.get(), m_pixels.get()); + break; + case RawImage::FLOAT32: + integerResample(m_width, m_height, m_ch, oldw, downsample, avg, old_pixels.get(), m_pixels.get()); + break; + case RawImage::FLOAT64: + integerResample(m_width, m_height, m_ch, oldw, downsample, avg, old_pixels.get(), m_pixels.get()); + break; + default: + break; + } +} + std::pair RawImage::unitScale() const { float min = *std::min_element(m_stats.m_min, m_stats.m_min + 4); diff --git a/rawimage.h b/rawimage.h index 6677a0d..ed72e8f 100644 --- a/rawimage.h +++ b/rawimage.h @@ -111,6 +111,7 @@ public: float thumbAspect() const; bool pixel(int x, int y, double &r, double &g, double &b) const; void resize(uint32_t w, uint32_t h); + void resizeInt(int downsample, bool avg); std::pair unitScale() const; void flip();