Compare commits
2 Commits
5372a7806c
...
3.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a31cc0f7f | |||
| 55609b7b3b |
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ icon
|
|||||||
ignore_*
|
ignore_*
|
||||||
resources
|
resources
|
||||||
*.bkp
|
*.bkp
|
||||||
|
.qwen
|
||||||
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|||||||
@ -97,6 +97,11 @@ void TwoMotionCaptureCoordinator::getLocBeforeStart()
|
|||||||
|
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
|
std::vector<double> pos;
|
||||||
|
pos.push_back(0);
|
||||||
|
pos.push_back(0);
|
||||||
|
m_locBeforeStart = pos;
|
||||||
|
|
||||||
disconnect(conn);
|
disconnect(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
280
HPPA/HPPA.cpp
280
HPPA/HPPA.cpp
@ -553,6 +553,20 @@ HPPA::HPPA(QWidget* parent)
|
|||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
m_ImageStretchThread = new QThread(this);
|
||||||
|
m_ImageStretchWorker = new ImageStretchWorker();
|
||||||
|
m_ImageStretchWorker->moveToThread(m_ImageStretchThread);
|
||||||
|
// 注册QPixmap类型用于跨线程信号槽
|
||||||
|
qRegisterMetaType<QPixmap>("QPixmap&");
|
||||||
|
qRegisterMetaType<cv::Mat>("cv::Mat");
|
||||||
|
qRegisterMetaType<cv::Mat>("cv::Mat");
|
||||||
|
connect(m_ImageStretchWorker, &ImageStretchWorker::imageReady,
|
||||||
|
this, &HPPA::onStretchedImageReady, Qt::QueuedConnection);
|
||||||
|
connect(m_ImageStretchWorker, &ImageStretchWorker::processingError,
|
||||||
|
this, &HPPA::onStretchProcessingError, Qt::QueuedConnection);
|
||||||
|
m_ImageStretchThread->start();
|
||||||
|
|
||||||
|
|
||||||
//光谱仪操作
|
//光谱仪操作
|
||||||
m_Imager = nullptr;
|
m_Imager = nullptr;
|
||||||
m_RecordThread = nullptr;
|
m_RecordThread = nullptr;
|
||||||
@ -632,6 +646,7 @@ void HPPA::setTimedDataCollectionHyperCamParm(int camType, double f, double e, Q
|
|||||||
{
|
{
|
||||||
disconnectImagerAndCleanup();
|
disconnectImagerAndCleanup();
|
||||||
ui.mActionPica_L->setChecked(true);
|
ui.mActionPica_L->setChecked(true);
|
||||||
|
selectingImager(ui.mActionPica_L);
|
||||||
|
|
||||||
AppSettings::instance().setFrameRate(f);
|
AppSettings::instance().setFrameRate(f);
|
||||||
AppSettings::instance().setIntegrationTime(e);
|
AppSettings::instance().setIntegrationTime(e);
|
||||||
@ -647,6 +662,7 @@ void HPPA::setTimedDataCollectionHyperCamParm(int camType, double f, double e, Q
|
|||||||
{
|
{
|
||||||
disconnectImagerAndCleanup();
|
disconnectImagerAndCleanup();
|
||||||
ui.mActionPica_NIR->setChecked(true);
|
ui.mActionPica_NIR->setChecked(true);
|
||||||
|
selectingImager(ui.mActionPica_NIR);
|
||||||
|
|
||||||
AppSettings::instance().setFrameRate(f);
|
AppSettings::instance().setFrameRate(f);
|
||||||
AppSettings::instance().setIntegrationTime(e);
|
AppSettings::instance().setIntegrationTime(e);
|
||||||
@ -667,10 +683,6 @@ void HPPA::setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds
|
|||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
//唤醒单反相机
|
|
||||||
m_pc3D->slrPowerDown();
|
|
||||||
m_pc3D->slrPowerOn();
|
|
||||||
|
|
||||||
m_singleLensReflexCameraWindow->setDataFolder(folder);
|
m_singleLensReflexCameraWindow->setDataFolder(folder);
|
||||||
m_singleLensReflexCameraWindow->setCaptureInterval(captureIntervalSeconds);
|
m_singleLensReflexCameraWindow->setCaptureInterval(captureIntervalSeconds);
|
||||||
|
|
||||||
@ -678,8 +690,6 @@ void HPPA::setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds
|
|||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
m_pc3D->d65LampPowerOn();
|
|
||||||
|
|
||||||
m_depthCameraWindow->setDataFolder(folder);
|
m_depthCameraWindow->setDataFolder(folder);
|
||||||
m_depthCameraWindow->setCaptureInterval(captureIntervalSeconds);
|
m_depthCameraWindow->setCaptureInterval(captureIntervalSeconds);
|
||||||
|
|
||||||
@ -1186,6 +1196,14 @@ HPPA::~HPPA()
|
|||||||
{
|
{
|
||||||
s_instance = nullptr;
|
s_instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_ImageStretchThread->quit();
|
||||||
|
m_ImageStretchThread->wait(3000);
|
||||||
|
delete m_ImageStretchWorker;
|
||||||
|
m_ImageStretchWorker = nullptr;
|
||||||
|
delete m_ImageStretchThread;
|
||||||
|
m_ImageStretchThread = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPPA::removeLayerByTreeIndex()
|
void HPPA::removeLayerByTreeIndex()
|
||||||
@ -2388,9 +2406,9 @@ void HPPA::onconnect()
|
|||||||
ui.gain_lineEdit->setValidator(new QRegExpValidator(rx));*/
|
ui.gain_lineEdit->setValidator(new QRegExpValidator(rx));*/
|
||||||
|
|
||||||
//获取相机参数并显示到界面中
|
//获取相机参数并显示到界面中
|
||||||
m_hic->setFrameRate(AppSettings::instance().frameRate());
|
onFramerateChanged(AppSettings::instance().frameRate());
|
||||||
m_hic->setIntegrationTime(AppSettings::instance().integrationTime());
|
onIntegrationTimeChanged(AppSettings::instance().integrationTime());
|
||||||
m_hic->setGain(AppSettings::instance().gain());
|
onGainChanged(AppSettings::instance().gain());
|
||||||
}
|
}
|
||||||
catch (std::exception const& e)
|
catch (std::exception const& e)
|
||||||
{
|
{
|
||||||
@ -2619,8 +2637,8 @@ void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QSt
|
|||||||
m_recordFrameCounter->updateFrameCount(static_cast<RasterLayer*>(mapLayer), m_Imager->getFrameCounter());
|
m_recordFrameCounter->updateFrameCount(static_cast<RasterLayer*>(mapLayer), m_Imager->getFrameCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
//if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
//return;
|
//return;
|
||||||
//获取绘图控件
|
//获取绘图控件
|
||||||
@ -2630,14 +2648,20 @@ void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QSt
|
|||||||
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
||||||
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//界面中显示已经采集的帧数
|
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//界面中显示已经采集的帧数
|
||||||
|
|
||||||
//创建需要显示的图像--opencv版本
|
|
||||||
ImageProcessor imageProcessor;
|
|
||||||
//cv::Mat rgbImage(*m_Imager->getRgbImage()->m_matRgbImage, cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());//2022.3.18重构的
|
|
||||||
cv::Mat rgbImage(*m_Imager->getMatRgbImage(), cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());
|
cv::Mat rgbImage(*m_Imager->getMatRgbImage(), cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());
|
||||||
cv::Mat rgbImageStretched = imageProcessor.CStretch(rgbImage, 0.02);
|
showQuickPreview(fileNumber, filePath, rgbImage);
|
||||||
|
|
||||||
//在界面中显示图像
|
|
||||||
currentImageViewer[0]->SetImage(&QPixmap::fromImage(imageProcessor.Mat2QImage(rgbImageStretched)));//绘制图像
|
if (m_ImageStretchWorker) {
|
||||||
|
// 深拷贝图像数据,因为原始数据可能在处理完成前被修改
|
||||||
|
cv::Mat rgbImageCopy = rgbImage.clone();
|
||||||
|
QMetaObject::invokeMethod(m_ImageStretchWorker, "processImage",
|
||||||
|
Qt::QueuedConnection,
|
||||||
|
Q_ARG(cv::Mat, rgbImageCopy),
|
||||||
|
Q_ARG(int, fileNumber),
|
||||||
|
Q_ARG(QString, filePath),
|
||||||
|
Q_ARG(float, 0.02f));
|
||||||
|
}
|
||||||
|
|
||||||
//20241225
|
//20241225
|
||||||
//保存拉伸后的rgb
|
//保存拉伸后的rgb
|
||||||
@ -2656,6 +2680,43 @@ void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QSt
|
|||||||
//currentImageViewer[0]->SetImage(&QPixmap::fromImage(CuttedImage));//绘制图像
|
//currentImageViewer[0]->SetImage(&QPixmap::fromImage(CuttedImage));//绘制图像
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HPPA::showQuickPreview(int fileNumber, const QString& filePath, const cv::Mat& rgbImage)
|
||||||
|
{
|
||||||
|
// 可以显示一个简单缩放的预览图,或者显示"处理中..."的提示
|
||||||
|
// 这里简单地跳过,等待拉伸后的图像
|
||||||
|
// 如果需要快速预览,可以进行简单的缩放显示
|
||||||
|
|
||||||
|
/*
|
||||||
|
QWidget* currentWidget = m_MapLayerStore->widgetForLayer(filePath);
|
||||||
|
if (!currentWidget) return;
|
||||||
|
|
||||||
|
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
||||||
|
if (currentImageViewer.isEmpty()) return;
|
||||||
|
|
||||||
|
// 显示一个简单的灰度或缩放版本作为预览
|
||||||
|
cv::Mat preview;
|
||||||
|
cv::resize(rgbImage, preview, cv::Size(), 0.25, 0.25); // 缩小到25%
|
||||||
|
// ... 转换并显示
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void HPPA::onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap)
|
||||||
|
{
|
||||||
|
QWidget* currentWidget = m_MapLayerStore->widgetForLayer(filePath);
|
||||||
|
if (!currentWidget) return;
|
||||||
|
QList<Mapcavas*> currentImageViewer = currentWidget->findChildren<Mapcavas*>();
|
||||||
|
if (currentImageViewer.isEmpty()) return;
|
||||||
|
// 在界面中显示拉伸后的图像
|
||||||
|
currentImageViewer[0]->SetImage(&pixmap);
|
||||||
|
}
|
||||||
|
// 处理错误的回调
|
||||||
|
void HPPA::onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error)
|
||||||
|
{
|
||||||
|
qDebug() << "Image stretch error for file" << filePath << ":" << error;
|
||||||
|
// 可以选择显示错误信息或保留之前的图像
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HPPA::focusPlotSpectralImg(int state)
|
void HPPA::focusPlotSpectralImg(int state)
|
||||||
{
|
{
|
||||||
if (!m_Imager) return;
|
if (!m_Imager) return;
|
||||||
@ -2813,7 +2874,8 @@ void HPPA::onLayerCreatedFromFile(const QString& baseName, const QString& filePa
|
|||||||
|
|
||||||
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
if (ui.mAction3DPlantPhenotypeScenario->isChecked())
|
||||||
{
|
{
|
||||||
addLayer(baseName, filePath, false, false);
|
//addLayer(baseName, filePath, false, false);
|
||||||
|
addLayer(baseName, filePath, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2969,3 +3031,185 @@ void HPPA::onBandSelectionChanged(double rWave, double gWave, double bWave)
|
|||||||
|
|
||||||
mapcavas[0]->freshmap();
|
mapcavas[0]->freshmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
ImageStretchWorker::ImageStretchWorker(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageStretchWorker::~ImageStretchWorker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImageStretchWorker::processImage(const cv::Mat& rgbImage, int fileNumber, const QString& filePath, float ratio)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (rgbImage.empty()) {
|
||||||
|
emit processingError(fileNumber, filePath, "Empty image");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行耗时的拉伸操作
|
||||||
|
cv::Mat rgbImageStretched = CStretch(rgbImage, ratio);
|
||||||
|
|
||||||
|
// 转换为QImage再转为QPixmap
|
||||||
|
QImage qimg = Mat2QImage(rgbImageStretched);
|
||||||
|
QPixmap pixmap = QPixmap::fromImage(qimg);
|
||||||
|
|
||||||
|
emit imageReady(fileNumber, filePath, pixmap);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
emit processingError(fileNumber, filePath, QString::fromStdString(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<cv::Point2f> ImageStretchWorker::CHistogram(const cv::Mat& img)
|
||||||
|
{
|
||||||
|
cv::Mat mimg = img.clone();
|
||||||
|
int rows = mimg.rows;
|
||||||
|
int cols = mimg.cols;
|
||||||
|
int maxValue = 65535;
|
||||||
|
|
||||||
|
std::vector<long int> hisnum(maxValue, 0);
|
||||||
|
for (int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < cols; ++j)
|
||||||
|
{
|
||||||
|
unsigned short gv = mimg.at<unsigned short>(i, j);
|
||||||
|
if (gv >= maxValue)
|
||||||
|
{
|
||||||
|
++hisnum[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++hisnum[gv];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long int pnum = rows * cols;
|
||||||
|
std::vector<cv::Point2f> hisp;
|
||||||
|
hisp.reserve(hisnum.size());
|
||||||
|
for (size_t i = 0; i < hisnum.size(); ++i)
|
||||||
|
{
|
||||||
|
float p = static_cast<float>(hisnum[i]) / pnum;
|
||||||
|
hisp.push_back(cv::Point2f(static_cast<float>(i), p));
|
||||||
|
}
|
||||||
|
return hisp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ImageStretchWorker::MaxRatio(const std::vector<cv::Point2f>& data, float ratio)
|
||||||
|
{
|
||||||
|
float maxp = 0;
|
||||||
|
uint outnum = 0;
|
||||||
|
for (int i = static_cast<int>(data.size()) - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
maxp += data[i].y;
|
||||||
|
if (maxp >= ratio)
|
||||||
|
{
|
||||||
|
outnum = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint ImageStretchWorker::MinRatio(const std::vector<cv::Point2f>& data, float ratio)
|
||||||
|
{
|
||||||
|
float minp = 0;
|
||||||
|
uint outnum = 0;
|
||||||
|
for (size_t i = 0; i < data.size(); ++i)
|
||||||
|
{
|
||||||
|
minp += data[i].y;
|
||||||
|
if (minp >= ratio)
|
||||||
|
{
|
||||||
|
outnum = static_cast<uint>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat ImageStretchWorker::CStretchDeal(const cv::Mat& img, uint minnum, uint maxnum)
|
||||||
|
{
|
||||||
|
cv::Mat mimg = img.clone();
|
||||||
|
int rows = mimg.rows;
|
||||||
|
int cols = mimg.cols;
|
||||||
|
cv::Mat nimg = cv::Mat::zeros(rows, cols, CV_8U);
|
||||||
|
|
||||||
|
float dertnum = static_cast<float>(maxnum - minnum);
|
||||||
|
|
||||||
|
for (int i = 0; i < rows; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < cols; ++j)
|
||||||
|
{
|
||||||
|
unsigned short a = mimg.at<unsigned short>(i, j);
|
||||||
|
if (a <= minnum)
|
||||||
|
nimg.at<uchar>(i, j) = 0;
|
||||||
|
else if (a >= maxnum)
|
||||||
|
nimg.at<uchar>(i, j) = 255;
|
||||||
|
else
|
||||||
|
nimg.at<uchar>(i, j) = static_cast<uchar>(255 * (a - minnum) / dertnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nimg;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat ImageStretchWorker::CStretch(const cv::Mat& img, float ratio)
|
||||||
|
{
|
||||||
|
cv::Mat mimg = img.clone();
|
||||||
|
cv::Mat bgr[3];
|
||||||
|
cv::split(mimg, bgr);
|
||||||
|
|
||||||
|
std::vector<cv::Point2f> hb = CHistogram(bgr[0]);
|
||||||
|
std::vector<cv::Point2f> hg = CHistogram(bgr[1]);
|
||||||
|
std::vector<cv::Point2f> hr = CHistogram(bgr[2]);
|
||||||
|
|
||||||
|
uint minb = MinRatio(hb, ratio);
|
||||||
|
uint ming = MinRatio(hg, ratio);
|
||||||
|
uint minr = MinRatio(hr, ratio);
|
||||||
|
uint maxb = MaxRatio(hb, ratio);
|
||||||
|
uint maxg = MaxRatio(hg, ratio);
|
||||||
|
uint maxr = MaxRatio(hr, ratio);
|
||||||
|
|
||||||
|
cv::Mat b = CStretchDeal(bgr[0], minb, maxb);
|
||||||
|
cv::Mat g = CStretchDeal(bgr[1], ming, maxg);
|
||||||
|
cv::Mat r = CStretchDeal(bgr[2], minr, maxr);
|
||||||
|
|
||||||
|
cv::Mat newbgr;
|
||||||
|
newbgr.create(img.rows, img.cols, CV_32FC3);
|
||||||
|
cv::Mat nbgr[3] = { b, g, r };
|
||||||
|
cv::merge(nbgr, 3, newbgr);
|
||||||
|
return newbgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage ImageStretchWorker::Mat2QImage(const cv::Mat& cvImg)
|
||||||
|
{
|
||||||
|
QImage qImg;
|
||||||
|
if (cvImg.channels() == 3)
|
||||||
|
{
|
||||||
|
cv::Mat rgbImg;
|
||||||
|
cv::cvtColor(cvImg, rgbImg, cv::COLOR_BGR2RGB);
|
||||||
|
qImg = QImage(rgbImg.data,
|
||||||
|
rgbImg.cols, rgbImg.rows,
|
||||||
|
static_cast<int>(rgbImg.step),
|
||||||
|
QImage::Format_RGB888).copy(); // 使用copy()确保数据独立
|
||||||
|
}
|
||||||
|
else if (cvImg.channels() == 1)
|
||||||
|
{
|
||||||
|
qImg = QImage(cvImg.data,
|
||||||
|
cvImg.cols, cvImg.rows,
|
||||||
|
static_cast<int>(cvImg.step),
|
||||||
|
QImage::Format_Indexed8).copy();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qImg = QImage(cvImg.data,
|
||||||
|
cvImg.cols, cvImg.rows,
|
||||||
|
static_cast<int>(cvImg.step),
|
||||||
|
QImage::Format_RGB888).copy();
|
||||||
|
}
|
||||||
|
return qImg;
|
||||||
|
}
|
||||||
|
|||||||
33
HPPA/HPPA.h
33
HPPA/HPPA.h
@ -88,6 +88,8 @@
|
|||||||
|
|
||||||
#include "PowerControl3D.h"
|
#include "PowerControl3D.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#define PI 3.1415926
|
#define PI 3.1415926
|
||||||
|
|
||||||
QT_CHARTS_USE_NAMESPACE//QChartView 使用 需要加宏, 否则无法使用
|
QT_CHARTS_USE_NAMESPACE//QChartView 使用 需要加宏, 否则无法使用
|
||||||
@ -194,6 +196,26 @@ private:
|
|||||||
QPixmap m_pixmap;
|
QPixmap m_pixmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImageStretchWorker : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit ImageStretchWorker(QObject* parent = nullptr);
|
||||||
|
~ImageStretchWorker();
|
||||||
|
public slots:
|
||||||
|
void processImage(const cv::Mat& rgbImage, int fileNumber, const QString& filePath, float ratio = 0.02f);
|
||||||
|
signals:
|
||||||
|
void imageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
||||||
|
void processingError(int fileNumber, const QString& filePath, const QString& error);
|
||||||
|
private:
|
||||||
|
cv::Mat CStretch(const cv::Mat& img, float ratio);
|
||||||
|
cv::Mat CStretchDeal(const cv::Mat& img, uint minnum, uint maxnum);
|
||||||
|
std::vector<cv::Point2f> CHistogram(const cv::Mat& img);
|
||||||
|
uint MaxRatio(const std::vector<cv::Point2f>& data, float ratio);
|
||||||
|
uint MinRatio(const std::vector<cv::Point2f>& data, float ratio);
|
||||||
|
QImage Mat2QImage(const cv::Mat& cvImg);
|
||||||
|
};
|
||||||
|
|
||||||
class HPPA : public QMainWindow
|
class HPPA : public QMainWindow
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -325,6 +347,13 @@ private:
|
|||||||
|
|
||||||
void initTimedDataCollection();
|
void initTimedDataCollection();
|
||||||
|
|
||||||
|
QThread* m_ImageStretchThread = nullptr;
|
||||||
|
ImageStretchWorker* m_ImageStretchWorker = nullptr;
|
||||||
|
|
||||||
|
// 用于临时显示的未拉伸图像(可选,用于快速预览)
|
||||||
|
void showQuickPreview(int fileNumber, const QString& filePath, const cv::Mat& rgbImage);
|
||||||
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
|
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
|
||||||
void focusPlotSpectralImg(int state);
|
void focusPlotSpectralImg(int state);
|
||||||
@ -408,6 +437,10 @@ public Q_SLOTS:
|
|||||||
void setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder);
|
void setTimedDataCollectionCamParm(int camType, int captureIntervalSeconds, QString folder);
|
||||||
void setTimedDataCollectionMotorParm(QString pathLineFilePath);
|
void setTimedDataCollectionMotorParm(QString pathLineFilePath);
|
||||||
void onStartTimedDataCollection(int camType);
|
void onStartTimedDataCollection(int camType);
|
||||||
|
|
||||||
|
void onStretchedImageReady(int fileNumber, const QString& filePath, QPixmap& pixmap);
|
||||||
|
void onStretchProcessingError(int fileNumber, const QString& filePath, const QString& error);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent* event) override;
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#include "RasterDataProvider.h"
|
#include "RasterDataProvider.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
MultibandRasterRenderer::MultibandRasterRenderer(RasterDataProvider* provider)
|
MultibandRasterRenderer::MultibandRasterRenderer(RasterDataProvider* provider)
|
||||||
: RasterRendererBase(provider)
|
: RasterRendererBase(provider)
|
||||||
@ -26,6 +27,96 @@ void MultibandRasterRenderer::stretchTo8bit(const std::vector<float>& in, std::v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultibandRasterRenderer::computeHistogram(const std::vector<float>& in, std::vector<long>& 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<long>(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<int>(in[i])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultibandRasterRenderer::findStretchValuesByRatio(const std::vector<long>& 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<long>(totalPixels * ratio);
|
||||||
|
|
||||||
|
long cumulative = 0;
|
||||||
|
for (size_t i = 0; i < hist.size(); ++i)
|
||||||
|
{
|
||||||
|
cumulative += hist[i];
|
||||||
|
if (cumulative >= targetCount)
|
||||||
|
{
|
||||||
|
minVal = static_cast<float>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulative = 0;
|
||||||
|
for (size_t i = hist.size(); i > 0; --i)
|
||||||
|
{
|
||||||
|
cumulative += hist[i - 1];
|
||||||
|
if (cumulative >= targetCount)
|
||||||
|
{
|
||||||
|
maxVal = static_cast<float>(i - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultibandRasterRenderer::stretchTo8bitByHistogram(const std::vector<float>& in, std::vector<unsigned char>& 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<unsigned char>(v * 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QImage MultibandRasterRenderer::render()
|
QImage MultibandRasterRenderer::render()
|
||||||
{
|
{
|
||||||
if (!m_provider) return QImage();
|
if (!m_provider) return QImage();
|
||||||
@ -65,11 +156,39 @@ QImage MultibandRasterRenderer::render()
|
|||||||
if (bIdx >= 0) m_provider->readBandAsFloat(bIdx, bbuf);
|
if (bIdx >= 0) m_provider->readBandAsFloat(bIdx, bbuf);
|
||||||
|
|
||||||
std::vector<unsigned char> r8, g8, b8;
|
std::vector<unsigned char> r8, g8, b8;
|
||||||
float minV = static_cast<float>(m_params.minValue);
|
|
||||||
float maxV = static_cast<float>(m_params.maxValue);
|
// Compute histogram-based stretch for each channel
|
||||||
if (!rbuf.empty()) stretchTo8bit(rbuf, r8, minV, maxV);
|
float ratio = m_stretchRatio;
|
||||||
if (!gbuf.empty()) stretchTo8bit(gbuf, g8, minV, maxV);
|
|
||||||
if (!bbuf.empty()) stretchTo8bit(bbuf, b8, minV, maxV);
|
// R channel stretch
|
||||||
|
if (!rbuf.empty()) {
|
||||||
|
std::vector<long> 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<long> 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<long> 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);
|
QImage out(w, h, QImage::Format_RGB888);
|
||||||
for (int y = 0; y < h; ++y) {
|
for (int y = 0; y < h; ++y) {
|
||||||
|
|||||||
@ -18,9 +18,22 @@ public:
|
|||||||
MultibandRenderParams params() const { return m_params; }
|
MultibandRenderParams params() const { return m_params; }
|
||||||
void setParams(const MultibandRenderParams& params) { m_params = params; }
|
void setParams(const MultibandRenderParams& params) { m_params = params; }
|
||||||
|
|
||||||
|
void setStretchRatio(float ratio) { m_stretchRatio = ratio; }
|
||||||
|
float stretchRatio() const { return m_stretchRatio; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MultibandRenderParams m_params;
|
MultibandRenderParams m_params;
|
||||||
|
float m_stretchRatio = 0.02f;
|
||||||
|
|
||||||
// Helper to map float buffer to 8-bit with min/max stretch
|
// Helper to map float buffer to 8-bit with min/max stretch
|
||||||
static void stretchTo8bit(const std::vector<float>& in, std::vector<unsigned char>& out, float minVal, float maxVal);
|
static void stretchTo8bit(const std::vector<float>& in, std::vector<unsigned char>& out, float minVal, float maxVal);
|
||||||
|
|
||||||
|
// Helper to compute histogram from float buffer
|
||||||
|
static void computeHistogram(const std::vector<float>& in, std::vector<long>& hist, float& minVal, float& maxVal);
|
||||||
|
|
||||||
|
// Helper to find stretch values by cumulative histogram ratio
|
||||||
|
static void findStretchValuesByRatio(const std::vector<long>& hist, float ratio, float& minVal, float& maxVal);
|
||||||
|
|
||||||
|
// Helper to stretch to 8-bit using histogram-based stretch
|
||||||
|
static void stretchTo8bitByHistogram(const std::vector<float>& in, std::vector<unsigned char>& out, float minVal, float maxVal);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,124 @@
|
|||||||
// 全局变量用于回调函数访问
|
// 全局变量用于回调函数访问
|
||||||
static SingleLensReflexCameraOperation* g_cameraOperation = nullptr;
|
static SingleLensReflexCameraOperation* g_cameraOperation = nullptr;
|
||||||
|
|
||||||
|
// 将Canon EDSDK错误码转换为中文描述
|
||||||
|
QString getEDSDKErrorMessage(EdsError err)
|
||||||
|
{
|
||||||
|
switch (err)
|
||||||
|
{
|
||||||
|
case EDS_ERR_OK:
|
||||||
|
return QString::fromLocal8Bit("操作成功,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_UNIMPLEMENTED:
|
||||||
|
return QString::fromLocal8Bit("功能未实现,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INTERNAL_ERROR:
|
||||||
|
return QString::fromLocal8Bit("内部错误,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_MEM_ALLOC_FAILED:
|
||||||
|
return QString::fromLocal8Bit("内存分配失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_MEM_FREE_FAILED:
|
||||||
|
return QString::fromLocal8Bit("内存释放失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_OPERATION_CANCELLED:
|
||||||
|
return QString::fromLocal8Bit("操作已取消,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INCOMPATIBLE_VERSION:
|
||||||
|
return QString::fromLocal8Bit("版本不兼容,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_NOT_SUPPORTED:
|
||||||
|
return QString::fromLocal8Bit("不支持该操作,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_UNEXPECTED_EXCEPTION:
|
||||||
|
return QString::fromLocal8Bit("意外异常,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_PROTECTION_VIOLATION:
|
||||||
|
return QString::fromLocal8Bit("保护违规,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_MISSING_SUBCOMPONENT:
|
||||||
|
return QString::fromLocal8Bit("缺少子组件,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_SELECTION_UNAVAILABLE:
|
||||||
|
return QString::fromLocal8Bit("选择不可用,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_FILE_IO_ERROR:
|
||||||
|
return QString::fromLocal8Bit("文件IO错误,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_FILE_NOT_FOUND:
|
||||||
|
return QString::fromLocal8Bit("文件未找到,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_FILE_OPEN_ERROR:
|
||||||
|
return QString::fromLocal8Bit("文件打开失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_NOT_FOUND:
|
||||||
|
return QString::fromLocal8Bit("设备未找到,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_BUSY:
|
||||||
|
return QString::fromLocal8Bit("设备忙,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_INVALID:
|
||||||
|
return QString::fromLocal8Bit("设备无效,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_MEMORY_FULL:
|
||||||
|
return QString::fromLocal8Bit("设备内存已满,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_INTERNAL_ERROR:
|
||||||
|
return QString::fromLocal8Bit("设备内部错误,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_NO_DISK:
|
||||||
|
return QString::fromLocal8Bit("设备无存储介质,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_DISK_ERROR:
|
||||||
|
return QString::fromLocal8Bit("设备磁盘错误,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_CF_GATE_CHANGED:
|
||||||
|
return QString::fromLocal8Bit("CF卡仓已改变,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_DIAL_CHANGED:
|
||||||
|
return QString::fromLocal8Bit("拨盘已改变,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICE_NOT_INSTALLED:
|
||||||
|
return QString::fromLocal8Bit("设备未安装,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_SESSION_NOT_OPEN:
|
||||||
|
return QString::fromLocal8Bit("会话未打开,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INVALID_TRANSACTIONID:
|
||||||
|
return QString::fromLocal8Bit("无效的事务ID,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INCOMPLETE_TRANSFER:
|
||||||
|
return QString::fromLocal8Bit("传输不完整,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INVALID_STRAGEID:
|
||||||
|
return QString::fromLocal8Bit("无效的存储ID,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_DEVICEPROP_NOT_SUPPORTED:
|
||||||
|
return QString::fromLocal8Bit("设备属性不支持,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_INVALID_OBJECTFORMATCODE:
|
||||||
|
return QString::fromLocal8Bit("无效的对象格式代码,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_SELF_TEST_FAILED:
|
||||||
|
return QString::fromLocal8Bit("自检失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_UNKNOWN_VENDOR_CODE:
|
||||||
|
return QString::fromLocal8Bit("未知的厂商代码,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_CAPTURE_ALREADY_TERMINATED:
|
||||||
|
return QString::fromLocal8Bit("拍摄已终止,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_PTP_DEVICE_BUSY:
|
||||||
|
return QString::fromLocal8Bit("PTP设备忙,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_UNKNOWN_COMMAND:
|
||||||
|
return QString::fromLocal8Bit("未知命令,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_OPERATION_REFUSED:
|
||||||
|
return QString::fromLocal8Bit("操作被拒绝,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_LENS_COVER_CLOSE:
|
||||||
|
return QString::fromLocal8Bit("镜头盖未关闭,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_LOW_BATTERY:
|
||||||
|
return QString::fromLocal8Bit("电池电量低,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_OBJECT_NOTREADY:
|
||||||
|
return QString::fromLocal8Bit("对象未就绪,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_AF_NG:
|
||||||
|
return QString::fromLocal8Bit("自动对焦失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_MIRROR_UP_NG:
|
||||||
|
return QString::fromLocal8Bit("反光镜升起失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_SENSOR_CLEANING_NG:
|
||||||
|
return QString::fromLocal8Bit("传感器清洁失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_SILENCE_NG:
|
||||||
|
return QString::fromLocal8Bit("静音拍摄失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_NO_CARD_NG:
|
||||||
|
return QString::fromLocal8Bit("未检测到存储卡,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_CARD_NG:
|
||||||
|
return QString::fromLocal8Bit("存储卡错误,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_CARD_PROTECT_NG:
|
||||||
|
return QString::fromLocal8Bit("存储卡被保护,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_MOVIE_CROP_NG:
|
||||||
|
return QString::fromLocal8Bit("短片裁切模式不支持,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_STROBO_CHARGE_NG:
|
||||||
|
return QString::fromLocal8Bit("闪光灯充电失败,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_NO_LENS_NG:
|
||||||
|
return QString::fromLocal8Bit("未安装镜头,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_SPECIAL_MOVIE_MODE_NG:
|
||||||
|
return QString::fromLocal8Bit("特殊短片模式不支持,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_LV_REL_PROHIBIT_MODE_NG:
|
||||||
|
return QString::fromLocal8Bit("实时显示释放被禁止,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_MOVIE_MODE_NG:
|
||||||
|
return QString::fromLocal8Bit("短片模式下不支持,错误码:%1").arg(err);
|
||||||
|
case EDS_ERR_TAKE_PICTURE_RETRUCTED_LENS_NG:
|
||||||
|
return QString::fromLocal8Bit("伸缩镜头不支持,错误码:%1").arg(err);
|
||||||
|
default:
|
||||||
|
return QString::fromLocal8Bit("未知错误: 0x%1").arg(err, 8, 16, QChar('0'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SingleLensReflexCameraWindow::SingleLensReflexCameraWindow(QWidget* parent)
|
SingleLensReflexCameraWindow::SingleLensReflexCameraWindow(QWidget* parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
, m_isCapturing(false)
|
, m_isCapturing(false)
|
||||||
@ -192,7 +310,7 @@ void SingleLensReflexCameraWindow::onImageCaptured(const QString& filePath)
|
|||||||
|
|
||||||
void SingleLensReflexCameraWindow::onError(const QString& errorMsg)
|
void SingleLensReflexCameraWindow::onError(const QString& errorMsg)
|
||||||
{
|
{
|
||||||
QMessageBox::warning(this, QString::fromLocal8Bit("相机错误"), errorMsg);
|
QMessageBox::warning(this, QString::fromLocal8Bit("单反相机错误"), errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleLensReflexCameraWindow::onStartCapture()
|
void SingleLensReflexCameraWindow::onStartCapture()
|
||||||
@ -764,7 +882,7 @@ void SingleLensReflexCameraOperation::OpenSLRCamera()
|
|||||||
err = initializeSDK();
|
err = initializeSDK();
|
||||||
if (err != EDS_ERR_OK)
|
if (err != EDS_ERR_OK)
|
||||||
{
|
{
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("初始化SDK失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("初始化SDK失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -773,7 +891,7 @@ void SingleLensReflexCameraOperation::OpenSLRCamera()
|
|||||||
if (err != EDS_ERR_OK)
|
if (err != EDS_ERR_OK)
|
||||||
{
|
{
|
||||||
terminateSDK();
|
terminateSDK();
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("打开相机失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("打开相机失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +901,7 @@ void SingleLensReflexCameraOperation::OpenSLRCamera()
|
|||||||
{
|
{
|
||||||
closeCamera();
|
closeCamera();
|
||||||
terminateSDK();
|
terminateSDK();
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("设置保存位置失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("设置保存位置失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,7 +947,7 @@ void SingleLensReflexCameraOperation::OpenAndTakePhotoSLRCamera()
|
|||||||
err = initializeSDK();
|
err = initializeSDK();
|
||||||
if (err != EDS_ERR_OK)
|
if (err != EDS_ERR_OK)
|
||||||
{
|
{
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("初始化SDK失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("初始化SDK失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -838,7 +956,7 @@ void SingleLensReflexCameraOperation::OpenAndTakePhotoSLRCamera()
|
|||||||
if (err != EDS_ERR_OK)
|
if (err != EDS_ERR_OK)
|
||||||
{
|
{
|
||||||
terminateSDK();
|
terminateSDK();
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("打开相机失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("打开相机失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +966,7 @@ void SingleLensReflexCameraOperation::OpenAndTakePhotoSLRCamera()
|
|||||||
{
|
{
|
||||||
closeCamera();
|
closeCamera();
|
||||||
terminateSDK();
|
terminateSDK();
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("设置保存位置失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("设置保存位置失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,7 +1052,7 @@ void SingleLensReflexCameraOperation::onCaptureTimer()
|
|||||||
// 如果是设备忙,不发送错误信号,等待下次重试
|
// 如果是设备忙,不发送错误信号,等待下次重试
|
||||||
if (err != EDS_ERR_DEVICE_BUSY)
|
if (err != EDS_ERR_DEVICE_BUSY)
|
||||||
{
|
{
|
||||||
emit ErrorSignal(QString::fromLocal8Bit("拍照失败,错误码: %1").arg(err));
|
emit ErrorSignal(QString::fromLocal8Bit("拍照失败: %1").arg(getEDSDKErrorMessage(err)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -212,13 +212,16 @@ QVariant TaskTreeModel::data(const QModelIndex& index, int role) const
|
|||||||
TaskStatus status = TaskStatus::Waiting;
|
TaskStatus status = TaskStatus::Waiting;
|
||||||
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
if (node->nodeType == TreeNodeType::Task && node->taskData) {
|
||||||
status = node->taskData->status;
|
status = node->taskData->status;
|
||||||
|
return QBrush(QColor("#E2EDFF")); // 深绿色文字
|
||||||
}
|
}
|
||||||
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
else if (node->nodeType == TreeNodeType::SubTask && node->subTaskData) {
|
||||||
status = node->subTaskData->status;
|
status = node->subTaskData->status;
|
||||||
|
return QBrush(QColor("#E2EDFF")); // 深绿色文字
|
||||||
}
|
}
|
||||||
if (status == TaskStatus::Running) {
|
if (status == TaskStatus::Running) {
|
||||||
return QBrush(QColor(0, 100, 0)); // 深绿色文字
|
return QBrush(QColor("#E2EDFF")); // 深绿色文字
|
||||||
}
|
}
|
||||||
|
return QBrush(QColor("#E2EDFF")); // 深绿色文字
|
||||||
}
|
}
|
||||||
else if (role == Qt::FontRole) {
|
else if (role == Qt::FontRole) {
|
||||||
QFont font;
|
QFont font;
|
||||||
@ -615,12 +618,12 @@ QString TaskTreeModel::formatDuration(double minutes) const
|
|||||||
QColor TaskTreeModel::statusColor(TaskStatus status) const
|
QColor TaskTreeModel::statusColor(TaskStatus status) const
|
||||||
{
|
{
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TaskStatus::Waiting: return QColor(255, 255, 230); // 浅黄
|
case TaskStatus::Waiting: return QColor("#121945"); // 浅黄
|
||||||
case TaskStatus::Running: return QColor(200, 255, 200); // 浅绿
|
case TaskStatus::Running: return QColor("#121945"); // 浅绿
|
||||||
case TaskStatus::Finished: return QColor(220, 220, 255); // 浅蓝
|
case TaskStatus::Finished: return QColor("#121945"); // 浅蓝
|
||||||
case TaskStatus::Skiped: return QColor(220, 220, 220); // 浅灰
|
case TaskStatus::Skiped: return QColor("#121945"); // 浅灰
|
||||||
}
|
}
|
||||||
return QColor(255, 255, 255);
|
return QColor("#121945");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString TaskTreeModel::formatCountdown(qint64 seconds) const
|
QString TaskTreeModel::formatCountdown(qint64 seconds) const
|
||||||
|
|||||||
@ -77,8 +77,8 @@ void TimedDataCollection::setupUI()
|
|||||||
// 创建状态标签
|
// 创建状态标签
|
||||||
ui.statusLabel->setStyleSheet(
|
ui.statusLabel->setStyleSheet(
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #f0f0f0;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #ccc;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
" font-size: 12px;"
|
" font-size: 12px;"
|
||||||
@ -215,11 +215,11 @@ void TimedDataCollection::onErrorOccurred(const QString& error)
|
|||||||
ui.statusLabel->setText(QString::fromLocal8Bit("错误: %1").arg(error));
|
ui.statusLabel->setText(QString::fromLocal8Bit("错误: %1").arg(error));
|
||||||
ui.statusLabel->setStyleSheet(
|
ui.statusLabel->setStyleSheet(
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #ffebee;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #f44336;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
" color: #c62828;"
|
" color: #e6eeff;"
|
||||||
"}"
|
"}"
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -354,11 +354,11 @@ void TimedDataCollection::updateStatusBar()
|
|||||||
|
|
||||||
styleSheet =
|
styleSheet =
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #e8f5e9;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #4CAF50;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
" color: #2e7d32;"
|
" color: #e6eeff;"
|
||||||
" font-weight: bold;"
|
" font-weight: bold;"
|
||||||
"}";
|
"}";
|
||||||
}
|
}
|
||||||
@ -381,8 +381,8 @@ void TimedDataCollection::updateStatusBar()
|
|||||||
|
|
||||||
styleSheet =
|
styleSheet =
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #f5f5f5;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #ccc;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
"}";
|
"}";
|
||||||
@ -466,11 +466,11 @@ void TimedDataCollection::startScheduler()
|
|||||||
ui.statusLabel->setText(QString::fromLocal8Bit("调度器已启动,等待任务执行..."));
|
ui.statusLabel->setText(QString::fromLocal8Bit("调度器已启动,等待任务执行..."));
|
||||||
ui.statusLabel->setStyleSheet(
|
ui.statusLabel->setStyleSheet(
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #fff3e0;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #ff9800;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
" color: #e65100;"
|
" color: #e6eeff;"
|
||||||
"}");
|
"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -478,6 +478,12 @@ void TimedDataCollection::startScheduler()
|
|||||||
void TimedDataCollection::stopScheduler()
|
void TimedDataCollection::stopScheduler()
|
||||||
{
|
{
|
||||||
if (m_scheduler) {
|
if (m_scheduler) {
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_taskModel->tasks().size(); i++)
|
||||||
|
{
|
||||||
|
m_taskModel->setTaskAndSubtaskStatus(m_taskModel->tasks()[i].id, TaskStatus::default);
|
||||||
|
}
|
||||||
|
|
||||||
m_scheduler->stop();
|
m_scheduler->stop();
|
||||||
|
|
||||||
m_currentTaskId = -1;
|
m_currentTaskId = -1;
|
||||||
@ -486,11 +492,11 @@ void TimedDataCollection::stopScheduler()
|
|||||||
ui.statusLabel->setText(QString::fromLocal8Bit("调度器已停止"));
|
ui.statusLabel->setText(QString::fromLocal8Bit("调度器已停止"));
|
||||||
ui.statusLabel->setStyleSheet(
|
ui.statusLabel->setStyleSheet(
|
||||||
"QLabel {"
|
"QLabel {"
|
||||||
" background-color: #fce4ec;"
|
" background-color: #3856B8;"
|
||||||
" border: 1px solid #e91e63;"
|
" border: 1px solid #2f6bff;"
|
||||||
" border-radius: 4px;"
|
" border-radius: 4px;"
|
||||||
" padding: 8px;"
|
" padding: 8px;"
|
||||||
" color: #880e4f;"
|
" color: #e6eeff;"
|
||||||
"}");
|
"}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -204,7 +206,7 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonO
|
|||||||
|
|
||||||
TaskExecutor::TaskExecutor(QObject* parent)
|
TaskExecutor::TaskExecutor(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_currentSubTaskIndex(0)
|
, m_currentSubTaskIndex(-1)
|
||||||
, m_isRunning(false)
|
, m_isRunning(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -228,7 +230,7 @@ void TaskExecutor::execute(const TimedTask& task)
|
|||||||
emit taskUpdated(m_task);
|
emit taskUpdated(m_task);
|
||||||
|
|
||||||
|
|
||||||
m_currentSubTaskIndex = 0;
|
m_currentSubTaskIndex = -1;
|
||||||
m_isRunning = true;
|
m_isRunning = true;
|
||||||
|
|
||||||
qDebug() << "TaskExecutor: Starting task" << task.id;
|
qDebug() << "TaskExecutor: Starting task" << task.id;
|
||||||
@ -299,6 +301,17 @@ void TaskExecutor::onSequenceComplete(int status)
|
|||||||
subTask.durationMinutes = (double)subTask.startTime.secsTo(subTask.endTime) / 60;
|
subTask.durationMinutes = (double)subTask.startTime.secsTo(subTask.endTime) / 60;
|
||||||
qDebug() << "TaskExecutor: subtask "<< m_currentSubTaskIndex<< " time consuming(Minutes): "<< subTask.durationMinutes;
|
qDebug() << "TaskExecutor: subtask "<< m_currentSubTaskIndex<< " time consuming(Minutes): "<< subTask.durationMinutes;
|
||||||
|
|
||||||
|
// 拷贝subTask.pathLineFilePath到m_currentFolder
|
||||||
|
if (!subTask.pathLineFilePath.isEmpty() && QFile::exists(subTask.pathLineFilePath)) {
|
||||||
|
QFileInfo fileInfo(subTask.pathLineFilePath);
|
||||||
|
QString destPath = m_currentFolder + QDir::separator() + fileInfo.fileName();
|
||||||
|
if (QFile::copy(subTask.pathLineFilePath, destPath)) {
|
||||||
|
qDebug() << "TaskExecutor: Copied path line file to" << destPath;
|
||||||
|
} else {
|
||||||
|
qDebug() << "TaskExecutor: Failed to copy path line file from" << subTask.pathLineFilePath << "to" << destPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
|
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
|
||||||
emit taskUpdated(m_task);
|
emit taskUpdated(m_task);
|
||||||
}
|
}
|
||||||
@ -309,7 +322,6 @@ void TaskExecutor::onSequenceComplete(int status)
|
|||||||
case SubTaskType::SingleLensReflex:
|
case SubTaskType::SingleLensReflex:
|
||||||
{
|
{
|
||||||
emit switchD65LampSignal(0);
|
emit switchD65LampSignal(0);
|
||||||
emit switchSlrSignal(0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SubTaskType::DepthCamera:
|
case SubTaskType::DepthCamera:
|
||||||
@ -347,11 +359,21 @@ void TaskExecutor::onSequenceComplete(int status)
|
|||||||
|
|
||||||
void TaskExecutor::onBack2Origin()
|
void TaskExecutor::onBack2Origin()
|
||||||
{
|
{
|
||||||
|
// 关闭单反电源
|
||||||
|
switch (m_task.subTasks[m_currentSubTaskIndex].type)
|
||||||
|
{
|
||||||
|
case SubTaskType::SingleLensReflex:
|
||||||
|
{
|
||||||
|
emit switchSlrSignal(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否还有更多子任务
|
// 检查是否还有更多子任务
|
||||||
m_currentSubTaskIndex++;
|
int nestSubTaskIndex = m_currentSubTaskIndex + 1;
|
||||||
if (m_currentSubTaskIndex < m_task.subTasks.size()) {
|
if (nestSubTaskIndex < m_task.subTasks.size()) {
|
||||||
// 执行下一个子任务
|
// 执行下一个子任务
|
||||||
if(m_task.subTasks[m_currentSubTaskIndex].type== SubTaskType::SingleLensReflex)
|
if(m_task.subTasks[nestSubTaskIndex].type== SubTaskType::SingleLensReflex)
|
||||||
{
|
{
|
||||||
printMsgAndTime("Slr task,for weak up,please wait 135 seconds!");
|
printMsgAndTime("Slr task,for weak up,please wait 135 seconds!");
|
||||||
emit switchSlrSignal(0);
|
emit switchSlrSignal(0);
|
||||||
@ -390,7 +412,10 @@ void TaskExecutor::onError(const QString& error)
|
|||||||
|
|
||||||
void TaskExecutor::executeNextSubTask()
|
void TaskExecutor::executeNextSubTask()
|
||||||
{
|
{
|
||||||
if (!m_isRunning || m_currentSubTaskIndex >= m_task.subTasks.size()) {
|
m_currentSubTaskIndex++;
|
||||||
|
|
||||||
|
if (!m_isRunning || m_currentSubTaskIndex >= m_task.subTasks.size())
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,21 +442,24 @@ void TaskExecutor::executeNextSubTask()
|
|||||||
case SubTaskType::HyperSpectual400_1000nm:
|
case SubTaskType::HyperSpectual400_1000nm:
|
||||||
{
|
{
|
||||||
camType = 0;
|
camType = 0;
|
||||||
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("L"), "test");
|
m_currentFolder = makeSubTaskDataFolder("L");
|
||||||
|
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "L");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SubTaskType::HyperSpectual1000_1700nm:
|
case SubTaskType::HyperSpectual1000_1700nm:
|
||||||
{
|
{
|
||||||
camType = 1;
|
camType = 1;
|
||||||
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, makeSubTaskDataFolder("NIR"), "test");
|
m_currentFolder = makeSubTaskDataFolder("NIR");
|
||||||
|
emit hyperCamParm(camType, subTask.frameRate, subTask.exposureTime, m_currentFolder, "NIR");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SubTaskType::SingleLensReflex:
|
case SubTaskType::SingleLensReflex:
|
||||||
{
|
{
|
||||||
camType = 2;
|
camType = 2;
|
||||||
emit camParm(camType, 3, makeSubTaskDataFolder("SLR"));
|
m_currentFolder = makeSubTaskDataFolder("SLR");
|
||||||
|
emit camParm(camType, 3, m_currentFolder);
|
||||||
|
|
||||||
emit switchD65LampSignal(1);
|
emit switchD65LampSignal(1);
|
||||||
|
|
||||||
@ -443,7 +471,8 @@ void TaskExecutor::executeNextSubTask()
|
|||||||
case SubTaskType::DepthCamera:
|
case SubTaskType::DepthCamera:
|
||||||
{
|
{
|
||||||
camType = 3;
|
camType = 3;
|
||||||
emit camParm(camType, 3, makeSubTaskDataFolder("DepthCamera"));
|
m_currentFolder = makeSubTaskDataFolder("DepthCamera");
|
||||||
|
emit camParm(camType, 3, m_currentFolder);
|
||||||
|
|
||||||
emit switchD65LampSignal(1);
|
emit switchD65LampSignal(1);
|
||||||
|
|
||||||
|
|||||||
@ -161,6 +161,7 @@ public slots:
|
|||||||
void onError(const QString& error);
|
void onError(const QString& error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString m_currentFolder;
|
||||||
void executeNextSubTask();
|
void executeNextSubTask();
|
||||||
|
|
||||||
void printMsgAndTime(QString msg);
|
void printMsgAndTime(QString msg);
|
||||||
|
|||||||
@ -6,67 +6,200 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1182</width>
|
<width>1299</width>
|
||||||
<height>576</height>
|
<height>658</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>定时采集</string>
|
<string>定时采集</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<property name="styleSheet">
|
||||||
<item row="0" column="0" colspan="3">
|
<string notr="true">QWidget #contentWidget
|
||||||
<widget class="QTreeView" name="taskTreeView"/>
|
{
|
||||||
</item>
|
background: #192770;
|
||||||
<item row="1" column="0">
|
/*border-radius: 8px 8px 8px 8px;*/
|
||||||
<widget class="QLineEdit" name="taskFileSelect_lineEdit">
|
border: 1px solid #2f6bff;
|
||||||
<property name="readOnly">
|
}
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
QLineEdit {
|
||||||
</widget>
|
background-color: #3856B8;
|
||||||
</item>
|
color: #e6eeff;
|
||||||
<item row="1" column="1">
|
border: 1px solid #2f6bff;
|
||||||
<widget class="QPushButton" name="taskFileSelect_btn">
|
border-radius: 6px;
|
||||||
<property name="text">
|
padding: 4px 8px;
|
||||||
<string>...</string>
|
min-width: 70px;
|
||||||
</property>
|
min-height: 20px;
|
||||||
</widget>
|
font-size: 13px;
|
||||||
</item>
|
}
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QPushButton" name="start_btn">
|
QLabel
|
||||||
<property name="text">
|
{
|
||||||
<string>开始调度</string>
|
background: #243A82;
|
||||||
</property>
|
color: rgb(255, 255, 255);
|
||||||
</widget>
|
border: 1px solid #2f6bff;
|
||||||
</item>
|
border-radius: 6px;
|
||||||
<item row="2" column="2">
|
}
|
||||||
<widget class="QPushButton" name="expandAll_btn">
|
|
||||||
<property name="text">
|
QPushButton
|
||||||
<string>展开</string>
|
{
|
||||||
</property>
|
/*width: 172px;
|
||||||
</widget>
|
height: 56px;*/
|
||||||
</item>
|
font: 10pt "新宋体";
|
||||||
<item row="3" column="1">
|
background-color: qlineargradient(
|
||||||
<widget class="QPushButton" name="stop_btn">
|
spread:pad,
|
||||||
<property name="text">
|
x1:0.5, y1:0, x2:0.5, y2:1,
|
||||||
<string>停止调度</string>
|
stop:0 #283D86,
|
||||||
</property>
|
stop:1 #0F1A40
|
||||||
</widget>
|
);
|
||||||
</item>
|
color: white;
|
||||||
<item row="3" column="2">
|
border: none;
|
||||||
<widget class="QPushButton" name="collapseAll_btn">
|
padding: 8px 8px;
|
||||||
<property name="text">
|
border-radius: 4px;
|
||||||
<string>折叠</string>
|
}
|
||||||
</property>
|
QPushButton:hover
|
||||||
</widget>
|
{
|
||||||
</item>
|
background-color: qlineargradient(
|
||||||
<item row="4" column="0" colspan="3">
|
spread:pad,
|
||||||
<widget class="QLabel" name="statusLabel">
|
x1:0, y1:0, x2:1, y2:0,
|
||||||
<property name="text">
|
stop:0 #3A4875,
|
||||||
<string>TextLabel</string>
|
stop:1 #5F6B91
|
||||||
</property>
|
);
|
||||||
<property name="alignment">
|
}
|
||||||
<set>Qt::AlignCenter</set>
|
/* 按下时的效果 */
|
||||||
</property>
|
QPushButton:pressed
|
||||||
|
{
|
||||||
|
background-color: qlineargradient(
|
||||||
|
spread:pad,
|
||||||
|
x1:0, y1:0, x2:1, y2:0,
|
||||||
|
stop:0 #1A254F,
|
||||||
|
stop:1 #3A466B
|
||||||
|
);
|
||||||
|
/* 可选:添加下压效果 */
|
||||||
|
padding-top: 9px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QWidget" name="contentWidget" native="true">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0" colspan="3">
|
||||||
|
<widget class="QTreeView" name="taskTreeView">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QTreeView
|
||||||
|
{
|
||||||
|
background-color: #121945;
|
||||||
|
border: 0px solid #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
QHeaderView::section
|
||||||
|
{
|
||||||
|
background-color: #121945;
|
||||||
|
color: #ACCDFF;
|
||||||
|
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar:vertical {
|
||||||
|
background: #0b1440;
|
||||||
|
width: 10px;
|
||||||
|
border: 1px solid #1f2a5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar:horizontal {
|
||||||
|
background: #0b1440;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid #1f2a5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::handle:vertical,
|
||||||
|
QScrollBar::handle:horizontal {
|
||||||
|
background: #3a5bd6;
|
||||||
|
border-radius: 4px;
|
||||||
|
min-height: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QScrollBar::handle:vertical:hover,
|
||||||
|
QScrollBar::handle:horizontal:hover {
|
||||||
|
background: #4f73ff;
|
||||||
|
}
|
||||||
|
</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLineEdit" name="taskFileSelect_lineEdit">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QPushButton" name="taskFileSelect_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="start_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>开始调度</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QPushButton" name="expandAll_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>展开</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QPushButton" name="stop_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>停止调度</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QPushButton" name="collapseAll_btn">
|
||||||
|
<property name="text">
|
||||||
|
<string>折叠</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0" colspan="3">
|
||||||
|
<widget class="QLabel" name="statusLabel">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>任务统计</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@ -288,7 +288,7 @@ QPushButton:pressed
|
|||||||
}</string>
|
}</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>版本:3.0.2</string>
|
<string>版本:3.1.0</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
Reference in New Issue
Block a user