#include "MultibandRasterRenderer.h" #include "RasterDataProvider.h" #include #include #include MultibandRasterRenderer::MultibandRasterRenderer(RasterDataProvider* provider) : RasterRendererBase(provider) { } void MultibandRasterRenderer::stretchTo8bit(const std::vector& in, std::vector& out, float minVal, float maxVal) { size_t n = in.size(); out.resize(n); if (maxVal <= minVal) { std::fill(out.begin(), out.end(), 0); return; } float denom = 1.0f / (maxVal - minVal); for (size_t i = 0; i < n; ++i) { float v = (in[i] - minVal) * denom; v = std::min(std::max(v, 0.0f), 1.0f); out[i] = static_cast(v * 255.0f); } } void MultibandRasterRenderer::computeHistogram(const std::vector& in, std::vector& hist, float& minVal, float& maxVal) { if (in.empty()) { minVal = 0.0f; maxVal = 1.0f; hist.clear(); return; } minVal = in[0]; maxVal = in[0]; for (size_t i = 0; i < in.size(); ++i) { if (in[i] < minVal) minVal = in[i]; if (in[i] > maxVal) maxVal = in[i]; } if (maxVal <= minVal) { hist.assign(256, 0); hist[0] = static_cast(in.size()); minVal = 0.0f; maxVal = 1.0f; return; } const int numBins = 65536; hist.assign(numBins, 0); for (size_t i = 0; i < in.size(); ++i) { ++hist[static_cast(in[i])]; } } void MultibandRasterRenderer::findStretchValuesByRatio(const std::vector& hist, float ratio, float& minVal, float& maxVal) { if (hist.empty()) return; long totalPixels = 0; for (size_t i = 0; i < hist.size(); ++i) { totalPixels += hist[i]; } if (totalPixels == 0) return; long targetCount = static_cast(totalPixels * ratio); long cumulative = 0; for (size_t i = 0; i < hist.size(); ++i) { cumulative += hist[i]; if (cumulative >= targetCount) { minVal = static_cast(i); break; } } cumulative = 0; for (size_t i = hist.size(); i > 0; --i) { cumulative += hist[i - 1]; if (cumulative >= targetCount) { maxVal = static_cast(i - 1); break; } } } void MultibandRasterRenderer::stretchTo8bitByHistogram(const std::vector& in, std::vector& out, float minVal, float maxVal) { size_t n = in.size(); out.resize(n); if (maxVal <= minVal) { std::fill(out.begin(), out.end(), 0); return; } float denom = 1.0f / (maxVal - minVal); for (size_t i = 0; i < n; ++i) { float v = (in[i] - minVal) * denom; v = std::min(std::max(v, 0.0f), 1.0f); out[i] = static_cast(v * 255.0f); } } QImage MultibandRasterRenderer::render() { if (!m_provider) return QImage(); int bands = m_provider->bandCount(); int w = m_provider->width(); int h = m_provider->height(); if (w <= 0 || h <= 0) return QImage(); // Find nearest bands for requested wavelengths if wavelengths available std::vector wavelengths = m_provider->bandWavelengths(); auto chooseBandIndexForWave = [&](double wave)->int { if (wavelengths.empty()) { // fallback: select R,G,B as first three bands if (bands >= 3) return (wave==m_params.rWave?0:(wave==m_params.gWave?1:2)); if (bands >= 1) return 0; return -1; } int best = -1; double bestDiff = 1e12; for (int i = 0; i < (int)wavelengths.size(); ++i) { if (wavelengths[i] < 0) continue; double d = std::abs(wavelengths[i] - wave); if (d < bestDiff) { bestDiff = d; best = i; } } if (best >= 0) return best; // fallback return std::min(2, bands-1); }; int rIdx = chooseBandIndexForWave(m_params.rWave); int gIdx = chooseBandIndexForWave(m_params.gWave); int bIdx = chooseBandIndexForWave(m_params.bWave); std::vector rbuf, gbuf, bbuf; if (rIdx >= 0) m_provider->readBandAsFloat(rIdx, rbuf); if (gIdx >= 0) m_provider->readBandAsFloat(gIdx, gbuf); if (bIdx >= 0) m_provider->readBandAsFloat(bIdx, bbuf); std::vector r8, g8, b8; // Compute histogram-based stretch for each channel float ratio = m_stretchRatio; // R channel stretch if (!rbuf.empty()) { std::vector rHist; float rMin, rMax; computeHistogram(rbuf, rHist, rMin, rMax); float rStretchMin = rMin, rStretchMax = rMax; findStretchValuesByRatio(rHist, ratio, rStretchMin, rStretchMax); stretchTo8bitByHistogram(rbuf, r8, rStretchMin, rStretchMax); } // G channel stretch if (!gbuf.empty()) { std::vector gHist; float gMin, gMax; computeHistogram(gbuf, gHist, gMin, gMax); float gStretchMin = gMin, gStretchMax = gMax; findStretchValuesByRatio(gHist, ratio, gStretchMin, gStretchMax); stretchTo8bitByHistogram(gbuf, g8, gStretchMin, gStretchMax); } // B channel stretch if (!bbuf.empty()) { std::vector bHist; float bMin, bMax; computeHistogram(bbuf, bHist, bMin, bMax); float bStretchMin = bMin, bStretchMax = bMax; findStretchValuesByRatio(bHist, ratio, bStretchMin, bStretchMax); stretchTo8bitByHistogram(bbuf, b8, bStretchMin, bStretchMax); } QImage out(w, h, QImage::Format_RGB888); for (int y = 0; y < h; ++y) { unsigned char* scan = out.scanLine(y); for (int x = 0; x < w; ++x) { int idx = y * w + x; unsigned char rc = (r8.size() > (size_t)idx) ? r8[idx] : 0; unsigned char gc = (g8.size() > (size_t)idx) ? g8[idx] : 0; unsigned char bc = (b8.size() > (size_t)idx) ? b8[idx] : 0; scan[x*3 + 0] = rc; scan[x*3 + 1] = gc; scan[x*3 + 2] = bc; } } return out; }