fix
1、基于新框架实现点击显示光谱; 2、影像拉伸显示优化; 3、右键菜单新增:移除所有栅格图层;
This commit is contained in:
134
HPPA/HPPA.cpp
134
HPPA/HPPA.cpp
@ -6,7 +6,6 @@
|
|||||||
#include <QFileInfo> // 新增,用于解析路径
|
#include <QFileInfo> // 新增,用于解析路径
|
||||||
|
|
||||||
#include "HPPA.h"
|
#include "HPPA.h"
|
||||||
#include "ImageReaderWriter.h"
|
|
||||||
#include "RasterLayer.h"
|
#include "RasterLayer.h"
|
||||||
#include "LayerTreeLayerNode.h"
|
#include "LayerTreeLayerNode.h"
|
||||||
|
|
||||||
@ -17,6 +16,11 @@ HPPA* HPPA::instance()
|
|||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LayerTreeNode* HPPA::rasterGroupNode() const
|
||||||
|
{
|
||||||
|
return m_RasterGroup;
|
||||||
|
}
|
||||||
|
|
||||||
HPPA::HPPA(QWidget* parent)
|
HPPA::HPPA(QWidget* parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
{
|
{
|
||||||
@ -912,6 +916,61 @@ void HPPA::removeLayerByTreeIndex()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HPPA::removeAllLayersInRasterGroup()
|
||||||
|
{
|
||||||
|
if (!m_LayerTreeModel || !m_RasterGroup) return;
|
||||||
|
|
||||||
|
QVector<LayerTreeNode*> pending;
|
||||||
|
for (int i = 0; i < m_RasterGroup->childCount(); ++i)
|
||||||
|
{
|
||||||
|
pending.push_back(m_RasterGroup->childAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!pending.isEmpty())
|
||||||
|
{
|
||||||
|
LayerTreeNode* node = pending.back();
|
||||||
|
pending.pop_back();
|
||||||
|
if (!node) continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < node->childCount(); ++i)
|
||||||
|
{
|
||||||
|
pending.push_back(node->childAt(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type() != LayerTreeNode::Type::Layer) continue;
|
||||||
|
|
||||||
|
auto* layerNode = static_cast<LayerTreeLayerNode*>(node);
|
||||||
|
MapLayer* mapLayer = layerNode->mapLayer();
|
||||||
|
QWidget* layerWidget = nullptr;
|
||||||
|
|
||||||
|
if (mapLayer && m_MapLayerStore)
|
||||||
|
{
|
||||||
|
layerWidget = m_MapLayerStore->widgetForLayer(mapLayer);
|
||||||
|
m_MapLayerStore->removeLayer(mapLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layerWidget && m_imageViewerTabWidget)
|
||||||
|
{
|
||||||
|
const int tabIndex = m_imageViewerTabWidget->indexOf(layerWidget);
|
||||||
|
if (tabIndex >= 0)
|
||||||
|
{
|
||||||
|
m_imageViewerTabWidget->removeTab(tabIndex);
|
||||||
|
}
|
||||||
|
layerWidget->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (m_RasterGroup->childCount() > 0)
|
||||||
|
{
|
||||||
|
const int row = m_RasterGroup->childCount() - 1;
|
||||||
|
LayerTreeNode* removed = m_LayerTreeModel->removeNode(m_RasterGroup, row);
|
||||||
|
if (removed)
|
||||||
|
{
|
||||||
|
delete removed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HPPA::initPanelToolbar()
|
void HPPA::initPanelToolbar()
|
||||||
{
|
{
|
||||||
mPanelMenu = new QMenu(QString::fromLocal8Bit("面板"), this);//create panel menu
|
mPanelMenu = new QMenu(QString::fromLocal8Bit("面板"), this);//create panel menu
|
||||||
@ -1084,7 +1143,7 @@ void HPPA::onStartRecordStep1()
|
|||||||
|
|
||||||
if (m_RecordState % 2 == 1)
|
if (m_RecordState % 2 == 1)
|
||||||
{
|
{
|
||||||
m_imageViewerTabWidget->clear();
|
//m_imageViewerTabWidget->clear();
|
||||||
|
|
||||||
m_Imager->setFileName2Save(imgPath);
|
m_Imager->setFileName2Save(imgPath);
|
||||||
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
||||||
@ -1109,7 +1168,7 @@ void HPPA::onStartRecordStep1()
|
|||||||
|
|
||||||
if (m_RecordState % 2 == 1)
|
if (m_RecordState % 2 == 1)
|
||||||
{
|
{
|
||||||
m_imageViewerTabWidget->clear();
|
//m_imageViewerTabWidget->clear();
|
||||||
|
|
||||||
ui.action_start_recording->setText(QString::fromLocal8Bit("停止采集"));
|
ui.action_start_recording->setText(QString::fromLocal8Bit("停止采集"));
|
||||||
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}");
|
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(255,0,0);}");
|
||||||
@ -1136,7 +1195,7 @@ void HPPA::onStartRecordStep1()
|
|||||||
|
|
||||||
if (m_RecordState % 2 == 1)
|
if (m_RecordState % 2 == 1)
|
||||||
{
|
{
|
||||||
m_imageViewerTabWidget->clear();
|
//m_imageViewerTabWidget->clear();
|
||||||
|
|
||||||
m_Imager->setFileName2Save(imgPath);
|
m_Imager->setFileName2Save(imgPath);
|
||||||
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
m_Imager->setFrameNumber(this->frame_number->text().toInt());
|
||||||
@ -1201,8 +1260,8 @@ void HPPA::onTabWidgetCurrentChanged(int index)//代码新建一个tab,会调
|
|||||||
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
||||||
|
|
||||||
//先disconnect然后再connect,否则每次切换一次都会connect一次,会累积connect很多次!
|
//先disconnect然后再connect,否则每次切换一次都会connect一次,会累积connect很多次!
|
||||||
disconnect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
|
disconnect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int,int,QVector<double>,QVector<double>)), this, SLOT(onLeftMouseButtonPressed(int,int,QVector<double>,QVector<double>)));
|
||||||
connect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
|
connect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int,int,QVector<double>,QVector<double>)), this, SLOT(onLeftMouseButtonPressed(int,int,QVector<double>,QVector<double>)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPPA::onActionOpenDirectory()
|
void HPPA::onActionOpenDirectory()
|
||||||
@ -1259,8 +1318,11 @@ void HPPA::OnGainSliderChanged(double Gain)
|
|||||||
ui.gain_lineEdit->setText(QString::number(Gain));
|
ui.gain_lineEdit->setText(QString::number(Gain));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPPA::onLeftMouseButtonPressed(int x, int y)
|
void HPPA::onLeftMouseButtonPressed(int x, int y, QVector<double> wavelengths, QVector<double> spectrum)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(x);
|
||||||
|
Q_UNUSED(y);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//正在采集时,不能显示光谱曲线
|
//正在采集时,不能显示光谱曲线
|
||||||
@ -1269,62 +1331,29 @@ void HPPA::onLeftMouseButtonPressed(int x, int y)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spectrum.isEmpty())
|
||||||
FileOperation* fileOperation = new FileOperation();
|
|
||||||
string directory = fileOperation->getDirectoryFromString();
|
|
||||||
string imgPath = directory + "\\" + m_FilenameLineEdit->text().toStdString() + "_" + std::to_string(m_TabWidgetCurrentIndex) + ".bil";
|
|
||||||
|
|
||||||
ImageReaderWriter* ImageReader = new ImageReaderWriter(imgPath.c_str());
|
|
||||||
|
|
||||||
|
|
||||||
if (x < 0 || x>ImageReader->getXCount() || y<0 || y>ImageReader->getyCount() - 1)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float* data = ImageReader->ReadImage(x, y, 1, 1);
|
|
||||||
|
|
||||||
|
|
||||||
QLineSeries* series = new QLineSeries();
|
QLineSeries* series = new QLineSeries();
|
||||||
//series->clear();//////////////////////////////
|
|
||||||
|
|
||||||
|
const int count = qMin(wavelengths.size(), spectrum.size());
|
||||||
QString imagerSelected = mImagerGroup->checkedAction()->objectName();
|
if (count > 0)
|
||||||
if (imagerSelected == "mActionPica_L" || imagerSelected == "mActionCorning_410" || imagerSelected == "mActionPika_XC2")
|
|
||||||
{
|
{
|
||||||
int start = m_Imager->getStartBand();
|
for (int i = 0; i < count; ++i)
|
||||||
for (size_t i = 0; i < m_Imager->getBandCount() - 1; i++)
|
|
||||||
{
|
{
|
||||||
//malloc申请的内存用法1:可以当做数组用
|
series->append(wavelengths[i], spectrum[i]);
|
||||||
series->append(m_Imager->getWavelengthAtBand(i + start), data[i]);
|
|
||||||
|
|
||||||
////malloc申请的内存用法2:指针存取
|
|
||||||
//series->append(m_Imager->getWavelengthAtBand(i), *data);
|
|
||||||
//data++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (imagerSelected == "mActionPica_NIR")
|
|
||||||
{
|
|
||||||
int start = 0;
|
|
||||||
for (size_t i = 0; i < m_Imager->getBandCount() - 1; i++)
|
|
||||||
{
|
|
||||||
//malloc申请的内存用法1:可以当做数组用
|
|
||||||
series->append(m_Imager->getWavelengthAtBand(i + start), data[i]);
|
|
||||||
|
|
||||||
////malloc申请的内存用法2:指针存取
|
|
||||||
//series->append(m_Imager->getWavelengthAtBand(i), *data);
|
|
||||||
//data++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QMessageBox msgBox;
|
for (int i = 0; i < spectrum.size(); ++i)
|
||||||
msgBox.setText(QString::fromLocal8Bit("请选择相机!"));
|
{
|
||||||
msgBox.exec();
|
series->append(i, spectrum[i]);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
series->setPen(QPen(QColor("#FF928A"), 2));
|
series->setPen(QPen(QColor("#FF928A"), 2));
|
||||||
|
|
||||||
m_chart->removeAllSeries();
|
m_chart->removeAllSeries();
|
||||||
@ -1335,11 +1364,6 @@ void HPPA::onLeftMouseButtonPressed(int x, int y)
|
|||||||
QValueAxis* axisY = qobject_cast<QValueAxis*>(m_chart->axisY());
|
QValueAxis* axisY = qobject_cast<QValueAxis*>(m_chart->axisY());
|
||||||
|
|
||||||
setAxis(axisX, axisY);
|
setAxis(axisX, axisY);
|
||||||
|
|
||||||
/*std::cout << "x坐标:" << x << std::endl;
|
|
||||||
std::cout << "y坐标:" << y << std::endl;
|
|
||||||
std::cout << "文件名:" << imgPath << std::endl;*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception&)
|
catch (const std::exception&)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
#include "ui_HPPA.h"
|
#include "ui_HPPA.h"
|
||||||
#include "resononImager.h"
|
#include "resononImager.h"
|
||||||
@ -174,6 +175,7 @@ public:
|
|||||||
~HPPA();
|
~HPPA();
|
||||||
|
|
||||||
static HPPA* instance();
|
static HPPA* instance();
|
||||||
|
LayerTreeNode* rasterGroupNode() const;
|
||||||
|
|
||||||
void CalculateIntegratioinTimeRange();//通过帧率计算积分时间范围,设置slider最大值
|
void CalculateIntegratioinTimeRange();//通过帧率计算积分时间范围,设置slider最大值
|
||||||
|
|
||||||
@ -301,7 +303,7 @@ public Q_SLOTS:
|
|||||||
void OnGainEditingFinished();//
|
void OnGainEditingFinished();//
|
||||||
void OnGainSliderChanged(double Gain);//
|
void OnGainSliderChanged(double Gain);//
|
||||||
|
|
||||||
void onLeftMouseButtonPressed(int x, int y);//点击影像像元显示光谱
|
void onLeftMouseButtonPressed(int x, int y, QVector<double> wavelengths, QVector<double> spectrum);//点击影像像元显示光谱
|
||||||
void setAxis(QValueAxis* axisX, QValueAxis* axisY);
|
void setAxis(QValueAxis* axisX, QValueAxis* axisY);
|
||||||
|
|
||||||
|
|
||||||
@ -329,6 +331,7 @@ public Q_SLOTS:
|
|||||||
|
|
||||||
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex);
|
void onLayerCreatedFromFile(const QString& baseName, const QString& filePath, int fileIndex);
|
||||||
void removeLayerByTreeIndex();
|
void removeLayerByTreeIndex();
|
||||||
|
void removeAllLayersInRasterGroup();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void StartFocusSignal();
|
void StartFocusSignal();
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
@ -130,7 +131,19 @@ void Mapcavas::mousePressEvent(QMouseEvent *event)
|
|||||||
m_bMouseTranslate = true;
|
m_bMouseTranslate = true;
|
||||||
m_lastMousePos = event->pos();
|
m_lastMousePos = event->pos();
|
||||||
|
|
||||||
emit leftMouseButtonPressed(mapToScene(m_lastMousePos).x(), mapToScene(m_lastMousePos).y());
|
const QPointF scenePt = mapToScene(m_lastMousePos);
|
||||||
|
const int x = static_cast<int>(std::floor(scenePt.x()));
|
||||||
|
const int y = static_cast<int>(std::floor(scenePt.y()));
|
||||||
|
|
||||||
|
if (m_rasterLayer && m_rasterLayer->isValidPixel(x, y))
|
||||||
|
{
|
||||||
|
QVector<double> wavelengths;
|
||||||
|
QVector<double> spectrum;
|
||||||
|
if (m_rasterLayer->readPixelSpectrum(x, y, wavelengths, spectrum))
|
||||||
|
{
|
||||||
|
emit leftMouseButtonPressed(x, y, wavelengths, spectrum);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QGraphicsView::mousePressEvent(event);
|
QGraphicsView::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "QGraphicsView"
|
#include "QGraphicsView"
|
||||||
#include "qlabel.h"
|
#include "qlabel.h"
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
class RasterLayer; // forward
|
class RasterLayer; // forward
|
||||||
|
|
||||||
@ -62,6 +63,6 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void leftMouseButtonPressed(int, int);
|
void leftMouseButtonPressed(int, int, QVector<double>, QVector<double>);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
@ -24,7 +24,9 @@ void LayerTreeView::contextMenuEvent(QContextMenuEvent* event)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const QModelIndex idx = indexAt(event->pos());
|
const QModelIndex idx = indexAt(event->pos());
|
||||||
if (!idx.isValid())
|
if (idx.isValid())
|
||||||
|
setCurrentIndex(idx);
|
||||||
|
else
|
||||||
setCurrentIndex(QModelIndex());
|
setCurrentIndex(QModelIndex());
|
||||||
|
|
||||||
QMenu* menu = m_menuProvider->createContextMenu();
|
QMenu* menu = m_menuProvider->createContextMenu();
|
||||||
|
|||||||
@ -17,20 +17,37 @@ QMenu* LayerTreeViewMenuProvider::createContextMenu()
|
|||||||
|
|
||||||
QMenu* menu = new QMenu();
|
QMenu* menu = new QMenu();
|
||||||
|
|
||||||
// Always allow remove when index is valid and points to a Layer
|
if (!m_contextIndex.isValid())
|
||||||
if (m_contextIndex.isValid())
|
|
||||||
{
|
{
|
||||||
// determine node type by looking at model's node
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
const LayerTreeModel* model = static_cast<const LayerTreeModel*>(m_contextIndex.model());
|
const LayerTreeModel* model = static_cast<const LayerTreeModel*>(m_contextIndex.model());
|
||||||
if (model)
|
if (!model)
|
||||||
{
|
{
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
LayerTreeNode* node = static_cast<LayerTreeNode*>(m_contextIndex.internalPointer());
|
LayerTreeNode* node = static_cast<LayerTreeNode*>(m_contextIndex.internalPointer());
|
||||||
if (node && node->type() == LayerTreeNode::Type::Layer)
|
if (!node)
|
||||||
|
{
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->type() == LayerTreeNode::Type::Layer)
|
||||||
{
|
{
|
||||||
QAction* removeAction = new QAction(QStringLiteral("<EFBFBD>Ƴ<EFBFBD>ͼ<EFBFBD><EFBFBD>"), menu);
|
QAction* removeAction = new QAction(QStringLiteral("<EFBFBD>Ƴ<EFBFBD>ͼ<EFBFBD><EFBFBD>"), menu);
|
||||||
connect(removeAction, &QAction::triggered, HPPA::instance(), &HPPA::removeLayerByTreeIndex);
|
connect(removeAction, &QAction::triggered, HPPA::instance(), &HPPA::removeLayerByTreeIndex);
|
||||||
menu->addAction(removeAction);
|
menu->addAction(removeAction);
|
||||||
}
|
}
|
||||||
|
else if (node->type() == LayerTreeNode::Type::Group)
|
||||||
|
{
|
||||||
|
HPPA* app = HPPA::instance();
|
||||||
|
if (app && node == app->rasterGroupNode())
|
||||||
|
{
|
||||||
|
QAction* removeAllAction = new QAction(QStringLiteral("<EFBFBD>Ƴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ<EFBFBD><EFBFBD>"), menu);
|
||||||
|
connect(removeAllAction, &QAction::triggered, app, &HPPA::removeAllLayersInRasterGroup);
|
||||||
|
menu->addAction(removeAllAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
#include "RasterDataProvider.h"
|
#include "RasterDataProvider.h"
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#if HPPA_HAVE_GDAL
|
#if HPPA_HAVE_GDAL
|
||||||
#include <gdal_priv.h>
|
#include <gdal_priv.h>
|
||||||
@ -79,27 +82,126 @@ int RasterDataProvider::height() const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RasterDataProvider::isValidPixel(int x, int y) const
|
||||||
|
{
|
||||||
|
const int w = width();
|
||||||
|
const int h = height();
|
||||||
|
return x >= 0 && y >= 0 && x < w && y < h;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> RasterDataProvider::parseEnviHdrWavelengths() const
|
||||||
|
{
|
||||||
|
std::vector<double> res;
|
||||||
|
|
||||||
|
QFileInfo fi(m_uri);
|
||||||
|
QString hdrPath = fi.path() + "/" + fi.completeBaseName() + ".hdr";
|
||||||
|
QFile hdr(hdrPath);
|
||||||
|
if (!hdr.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text = QString::fromLocal8Bit(hdr.readAll());
|
||||||
|
hdr.close();
|
||||||
|
|
||||||
|
QRegularExpression rx("wavelength\\s*=\\s*\\{([^}]*)\\}", QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption);
|
||||||
|
QRegularExpressionMatch m = rx.match(text);
|
||||||
|
if (!m.hasMatch()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString body = m.captured(1);
|
||||||
|
const QStringList parts = body.split(',', QString::SkipEmptyParts);
|
||||||
|
res.reserve(parts.size());
|
||||||
|
for (const QString& p : parts) {
|
||||||
|
bool ok = false;
|
||||||
|
double v = p.trimmed().toDouble(&ok);
|
||||||
|
if (ok) {
|
||||||
|
res.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<double> RasterDataProvider::bandWavelengths() const
|
std::vector<double> RasterDataProvider::bandWavelengths() const
|
||||||
{
|
{
|
||||||
std::vector<double> res;
|
std::vector<double> res;
|
||||||
#if HPPA_HAVE_GDAL
|
#if HPPA_HAVE_GDAL
|
||||||
if (!m_dataset) return res;
|
if (!m_dataset) return res;
|
||||||
|
|
||||||
|
// 1) Try ENVI dataset-level metadata first: wavelength = { ... }
|
||||||
|
const char* dsWave = m_dataset->GetMetadataItem("wavelength", "ENVI");
|
||||||
|
if (!dsWave) dsWave = m_dataset->GetMetadataItem("Wavelength", "ENVI");
|
||||||
|
if (dsWave) {
|
||||||
|
QString dsWaveStr = QString::fromLocal8Bit(dsWave);
|
||||||
|
dsWaveStr.remove('{').remove('}');
|
||||||
|
const QStringList parts = dsWaveStr.split(',', QString::SkipEmptyParts);
|
||||||
|
res.reserve(parts.size());
|
||||||
|
for (const QString& p : parts) {
|
||||||
|
bool ok = false;
|
||||||
|
double v = p.trimmed().toDouble(&ok);
|
||||||
|
if (ok) res.push_back(v);
|
||||||
|
}
|
||||||
|
if (!res.empty()) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Try per-band metadata
|
||||||
for (int i = 1; i <= m_dataset->GetRasterCount(); ++i) {
|
for (int i = 1; i <= m_dataset->GetRasterCount(); ++i) {
|
||||||
GDALRasterBand* band = m_dataset->GetRasterBand(i);
|
GDALRasterBand* band = m_dataset->GetRasterBand(i);
|
||||||
if (!band) continue;
|
if (!band) continue;
|
||||||
// Attempt to read wavelength from metadata (commonly "Wavelength" or "wavelength")
|
|
||||||
const char* val = band->GetMetadataItem("Wavelength");
|
const char* val = band->GetMetadataItem("Wavelength");
|
||||||
if (!val) val = band->GetMetadataItem("wavelength");
|
if (!val) val = band->GetMetadataItem("wavelength");
|
||||||
if (val) {
|
if (val) {
|
||||||
double v = atof(val);
|
bool ok = false;
|
||||||
res.push_back(v);
|
double v = QString::fromLocal8Bit(val).trimmed().toDouble(&ok);
|
||||||
|
res.push_back(ok ? v : -1.0);
|
||||||
} else {
|
} else {
|
||||||
// push a negative to indicate unknown
|
|
||||||
res.push_back(-1.0);
|
res.push_back(-1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!res.empty()) return res;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 3) Fallback: parse ENVI .hdr directly
|
||||||
|
return parseEnviHdrWavelengths();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RasterDataProvider::readPixelSpectrum(int x, int y, std::vector<double>& outSpectrum) const
|
||||||
|
{
|
||||||
|
#if HPPA_HAVE_GDAL
|
||||||
|
outSpectrum.clear();
|
||||||
|
if (!m_dataset) return false;
|
||||||
|
if (!isValidPixel(x, y)) return false;
|
||||||
|
|
||||||
|
const int bands = m_dataset->GetRasterCount();
|
||||||
|
if (bands <= 0) return false;
|
||||||
|
|
||||||
|
outSpectrum.resize(bands);
|
||||||
|
for (int i = 0; i < bands; ++i) {
|
||||||
|
GDALRasterBand* band = m_dataset->GetRasterBand(i + 1);
|
||||||
|
if (!band) return false;
|
||||||
|
|
||||||
|
float value = 0.0f;
|
||||||
|
CPLErr err = band->RasterIO(
|
||||||
|
GF_Read,
|
||||||
|
x, y,
|
||||||
|
1, 1,
|
||||||
|
&value,
|
||||||
|
1, 1,
|
||||||
|
GDT_Float32,
|
||||||
|
0, 0);
|
||||||
|
|
||||||
|
if (err != CE_None) return false;
|
||||||
|
outSpectrum[i] = static_cast<double>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
Q_UNUSED(x);
|
||||||
|
Q_UNUSED(y);
|
||||||
|
Q_UNUSED(outSpectrum);
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterDataProvider::readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const
|
bool RasterDataProvider::readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const
|
||||||
|
|||||||
@ -24,9 +24,14 @@ public:
|
|||||||
int width() const;
|
int width() const;
|
||||||
int height() const;
|
int height() const;
|
||||||
|
|
||||||
|
bool isValidPixel(int x, int y) const;
|
||||||
|
|
||||||
// Returns per-band wavelength metadata if available. If not available, returns empty vector.
|
// Returns per-band wavelength metadata if available. If not available, returns empty vector.
|
||||||
std::vector<double> bandWavelengths() const;
|
std::vector<double> bandWavelengths() const;
|
||||||
|
|
||||||
|
// Read spectrum of one pixel (x,y) across all bands.
|
||||||
|
bool readPixelSpectrum(int x, int y, std::vector<double>& outSpectrum) const;
|
||||||
|
|
||||||
// Read a single band (0-based index) into a float buffer of size width()*height().
|
// Read a single band (0-based index) into a float buffer of size width()*height().
|
||||||
// Returns true on success.
|
// Returns true on success.
|
||||||
bool readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const;
|
bool readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const;
|
||||||
@ -35,6 +40,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_uri;
|
QString m_uri;
|
||||||
|
std::vector<double> parseEnviHdrWavelengths() const;
|
||||||
#if HPPA_HAVE_GDAL
|
#if HPPA_HAVE_GDAL
|
||||||
GDALDataset* m_dataset = nullptr;
|
GDALDataset* m_dataset = nullptr;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -36,6 +36,40 @@ bool RasterLayer::openDataProvider()
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RasterLayer::isValidPixel(int x, int y)
|
||||||
|
{
|
||||||
|
if (!m_provider) {
|
||||||
|
if (!openDataProvider()) return false;
|
||||||
|
}
|
||||||
|
return m_provider->isValidPixel(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RasterLayer::readPixelSpectrum(int x, int y, QVector<double>& wavelengths, QVector<double>& spectrum)
|
||||||
|
{
|
||||||
|
if (!m_provider) {
|
||||||
|
if (!openDataProvider()) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> wl;
|
||||||
|
std::vector<double> sp;
|
||||||
|
|
||||||
|
if (!m_provider->readPixelSpectrum(x, y, sp)) return false;
|
||||||
|
|
||||||
|
wl = m_provider->bandWavelengths();
|
||||||
|
|
||||||
|
wavelengths = QVector<double>::fromStdVector(wl);
|
||||||
|
spectrum = QVector<double>::fromStdVector(sp);
|
||||||
|
|
||||||
|
if (wavelengths.size() != spectrum.size()) {
|
||||||
|
wavelengths.resize(spectrum.size());
|
||||||
|
for (int i = 0; i < wavelengths.size(); ++i) {
|
||||||
|
wavelengths[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QImage RasterLayer::render(const RenderParams& params)
|
QImage RasterLayer::render(const RenderParams& params)
|
||||||
{
|
{
|
||||||
if (!m_provider) {
|
if (!m_provider) {
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "MapLayer.h"
|
#include "MapLayer.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
class RasterDataProvider;
|
class RasterDataProvider;
|
||||||
class RasterRenderer;
|
class RasterRenderer;
|
||||||
@ -23,12 +24,15 @@ public:
|
|||||||
// Create or open provider based on this layer's uri
|
// Create or open provider based on this layer's uri
|
||||||
bool openDataProvider();
|
bool openDataProvider();
|
||||||
|
|
||||||
|
bool isValidPixel(int x, int y);
|
||||||
|
bool readPixelSpectrum(int x, int y, QVector<double>& wavelengths, QVector<double>& spectrum);
|
||||||
|
|
||||||
struct RenderParams {
|
struct RenderParams {
|
||||||
double rWave = 665.0; // default wavelengths (nm)
|
double rWave = 665.0; // default wavelengths (nm)
|
||||||
double gWave = 560.0;
|
double gWave = 560.0;
|
||||||
double bWave = 490.0;
|
double bWave = 490.0;
|
||||||
double minValue = 0.0; // optional stretch
|
double minValue = 0.0; // optional stretch
|
||||||
double maxValue = 255.0;
|
double maxValue = 4095.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Render the raster using current provider and renderer. Returns an empty QImage on failure.
|
// Render the raster using current provider and renderer. Returns an empty QImage on failure.
|
||||||
|
|||||||
Reference in New Issue
Block a user