fix:TextInput support hot update;feat:add zero color and update

algorithm
This commit is contained in:
2026-01-29 09:56:10 +08:00
parent db0580ead1
commit 01b988fcd7
22 changed files with 2022 additions and 1452 deletions

View File

@@ -5,6 +5,7 @@
#include "backend.h"
#include "data_backend.h"
#include "serial/serial_backend.h"
#include <qcolor.h>
#include <qnumeric.h>
AppBackend::AppBackend(QObject* parent)
@@ -51,6 +52,13 @@ void AppBackend::setShowGrid(bool on) {
emit showGridChanged(on);
}
void AppBackend::setUseHeatmap(bool on) {
if (m_useHeatmap == on)
return;
m_useHeatmap = on;
emit useHeatmapChanged(on);
}
void AppBackend::setSensorCol(int c) {
if (m_serial->connected()) {
return;
@@ -93,6 +101,13 @@ void AppBackend::setRangeMax(int v) {
emit rangeChanged(m_rangeMin, m_rangeMax);
}
void AppBackend::setColorZero(const QColor& color) {
if (m_colorZero == color)
return;
m_colorZero = color;
emit colorZeroChanged(m_colorZero);
}
void AppBackend::setColorLow(const QColor& color) {
if (m_colorLow == color)
return;

View File

@@ -7,6 +7,7 @@
#include <QObject>
#include <QString>
#include <QColor>
#include <qcolor.h>
#include <qtmetamacros.h>
#include "data_backend.h"
@@ -18,12 +19,14 @@ class AppBackend : public QObject {
Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
Q_PROPERTY(bool showGrid READ showGrid WRITE setShowGrid NOTIFY showGridChanged);
Q_PROPERTY(bool useHeatmap READ useHeatmap WRITE setUseHeatmap NOTIFY useHeatmapChanged);
Q_PROPERTY(SerialBackend* serial READ serial CONSTANT)
Q_PROPERTY(DataBackend* data READ data CONSTANT)
Q_PROPERTY(int sensorCol READ sensorCol WRITE setSensorCol NOTIFY sensorColChanged);
Q_PROPERTY(int sensorRow READ sensorRow WRITE setSensorRow NOTIFY sensorRowChanged);
Q_PROPERTY(int rangeMin READ rangeMin WRITE setRangeMin NOTIFY rangeMinChanged);
Q_PROPERTY(int rangeMax READ rangeMax WRITE setRangeMax NOTIFY rangeMaxChanged);
Q_PROPERTY(QColor colorZero READ colorZero WRITE setColorZero NOTIFY colorZeroChanged);
Q_PROPERTY(QColor colorLow READ colorLow WRITE setColorLow NOTIFY colorLowChanged);
Q_PROPERTY(QColor colorMid READ colorMid WRITE setColorMid NOTIFY colorMidChanged);
Q_PROPERTY(QColor colorHigh READ colorHigh WRITE setColorHigh NOTIFY colorHighChanged);
@@ -43,6 +46,8 @@ public:
bool showGrid() const { return m_showGrid; }
void setShowGrid(bool on);
bool useHeatmap() const { return m_useHeatmap; }
void setUseHeatmap(bool on);
int sensorCol() const { qInfo() << "col:" << m_sensorCol; return m_sensorCol; }
int sensorRow() const { qInfo() << "row:" << m_sensorRow; return m_sensorRow; }
void setSensorRow(int r);
@@ -51,9 +56,11 @@ public:
int rangeMax() const { return m_rangeMax; }
void setRangeMin(int v);
void setRangeMax(int v);
QColor colorZero() const { return m_colorZero; }
QColor colorLow() const { return m_colorLow; }
QColor colorMid() const { return m_colorMid; }
QColor colorHigh() const { return m_colorHigh; }
void setColorZero(const QColor& color);
void setColorLow(const QColor& color);
void setColorMid(const QColor& color);
void setColorHigh(const QColor& color);
@@ -63,11 +70,13 @@ signals:
void languageChanged();
void connectedChanged();
void showGridChanged(bool on);
void useHeatmapChanged(bool on);
void sensorColChanged(int c);
void sensorRowChanged(int r);
void rangeMinChanged(int v);
void rangeMaxChanged(int v);
void rangeChanged(int minV, int maxV);
void colorZeroChanged(const QColor& color);
void colorLowChanged(const QColor& color);
void colorMidChanged(const QColor& color);
void colorHighChanged(const QColor& color);
@@ -78,10 +87,12 @@ private:
QString m_language = QStringLiteral("zh_CN");
bool m_showGrid = true;
bool m_useHeatmap = false;
int m_sensorRow = 12;
int m_sensorCol = 7;
int m_rangeMin = 0;
int m_rangeMax = 1000;
QColor m_colorZero = QColor::fromRgbF(0.10, 0.75, 1.00);
QColor m_colorLow = QColor::fromRgbF(0.10, 0.75, 1.00);
QColor m_colorMid = QColor::fromRgbF(0.10, 0.95, 0.35);
QColor m_colorHigh = QColor::fromRgbF(1.00, 0.22, 0.10);

View File

@@ -127,6 +127,8 @@ bool DataBackend::importXlsx(const QString& path) {
cells[r][c] = v;
}
}
return true;
}
void DataBackend::startPlayback(int intervalMs) {

View File

@@ -5,48 +5,217 @@
#ifndef TACTILEIPC3D_GLOBALHELPER_H
#define TACTILEIPC3D_GLOBALHELPER_H
#include <algorithm>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <algorithm>
#include <QCoreApplication>
#include <QDir>
#include <qset.h>
#include <qsettings.h>
const QString APP_VERSION = "0.4.0";
class GlobalHelper {
public:
const std::string fuck = "fuck you lsp!!!";
static GlobalHelper* Instance() {
public :
static GlobalHelper *Instance() {
static GlobalHelper ins;
return &ins;
}
static void transToMultiMatrix(const cv::Mat& raw_data, float min_threshold,
float max_range, cv::Size display_res, cv::Mat& out_matrix) {
static void transToMultiMatrix(const cv::Mat &raw_data, float min_threshold,
float max_range, cv::Size display_res,
cv::Mat &out_matrix) {
CV_Assert(raw_data.type() == CV_32F);
const float safe_max = std::max(max_range, 1e-6f);
const float safe_span = std::max(safe_max - min_threshold, 1e-6f);
cv::Mat saturate_mask_u8;
cv::compare(raw_data, max_range, saturate_mask_u8, cv::CMP_GE);
cv::Mat zero_mask_u8;
cv::compare(raw_data, 0.0f, zero_mask_u8, cv::CMP_LE);
cv::Mat raw = raw_data.clone();
raw.setTo(0.0f, raw < min_threshold);
cv::min(raw, safe_max, raw);
double maxVal = 0.0;
cv::minMaxLoc(raw, nullptr, &maxVal);
if (maxVal > 0.0) {
cv::GaussianBlur(raw, raw, cv::Size(3, 3), 0.8, 0.8, cv::BORDER_DEFAULT);
}
cv::Mat peak_norm = (raw - min_threshold) / safe_span;
cv::max(peak_norm, 0.0f, peak_norm);
cv::min(peak_norm, 1.0f, peak_norm);
const float safe_range = std::max(max_range, 1e-6f);
cv::Mat norm_data = raw / safe_range;
cv::min(norm_data, 1.0f, norm_data);
cv::medianBlur(raw, raw, 3);
cv::GaussianBlur(raw, raw, cv::Size(5, 5), 1.2, 1.2, cv::BORDER_DEFAULT);
cv::Mat norm_data = (raw - min_threshold) / safe_span;
cv::max(norm_data, 0.0f, norm_data);
cv::min(norm_data, 1.0f, norm_data);
cv::pow(norm_data, 0.7, norm_data);
cv::pow(norm_data, 1.4, norm_data);
cv::Mat smoothed;
cv::resize(norm_data, smoothed, display_res, 0.0, 0.0, cv::INTER_CUBIC);
cv::max(smoothed, 0.0f, smoothed);
cv::min(smoothed, 1.0f, smoothed);
cv::GaussianBlur(smoothed, smoothed, cv::Size(31, 31), 0.0, 0.0, cv::BORDER_DEFAULT);
const int min_dim =
std::max(1, std::min(display_res.width, display_res.height));
const double sigma = std::max(1.0, 0.02 * min_dim);
int ksize = std::max(3, (static_cast<int>(std::ceil(sigma * 6)) | 1));
cv::GaussianBlur(smoothed, smoothed, cv::Size(ksize, ksize), sigma, sigma,
cv::BORDER_DEFAULT);
cv::max(smoothed, 0.0f, smoothed);
cv::min(smoothed, 1.0f, smoothed);
smoothed *= safe_range;
cv::Mat peak_resized;
cv::resize(peak_norm, peak_resized, display_res, 0.0, 0.0,
cv::INTER_CUBIC);
cv::max(smoothed, peak_resized, smoothed);
if (!saturate_mask_u8.empty()) {
cv::Mat mask_f;
saturate_mask_u8.convertTo(mask_f, CV_32F, 1.0 / 255.0);
cv::Mat mask_resized;
cv::resize(mask_f, mask_resized, display_res, 0.0, 0.0,
cv::INTER_CUBIC);
// Soften the threshold to avoid blocky plateaus.
const double mask_sigma = std::max(0.5, 0.008 * min_dim);
int mask_ksize =
std::max(3, (static_cast<int>(std::ceil(mask_sigma * 6)) | 1));
cv::GaussianBlur(mask_resized, mask_resized,
cv::Size(mask_ksize, mask_ksize), mask_sigma,
mask_sigma, cv::BORDER_DEFAULT);
cv::max(mask_resized, 0.0f, mask_resized);
cv::min(mask_resized, 1.0f, mask_resized);
smoothed = cv::max(smoothed, mask_resized);
}
if (!zero_mask_u8.empty()) {
cv::Mat zero_f;
zero_mask_u8.convertTo(zero_f, CV_32F, 1.0 / 255.0);
cv::Mat zero_resized;
cv::resize(zero_f, zero_resized, display_res, 0.0, 0.0,
cv::INTER_CUBIC);
const double zero_sigma = std::max(0.5, 0.006 * min_dim);
int zero_ksize =
std::max(3, (static_cast<int>(std::ceil(zero_sigma * 6)) | 1));
cv::GaussianBlur(zero_resized, zero_resized,
cv::Size(zero_ksize, zero_ksize), zero_sigma,
zero_sigma, cv::BORDER_DEFAULT);
cv::max(zero_resized, 0.0f, zero_resized);
cv::min(zero_resized, 1.0f, zero_resized);
cv::Mat zero_bin;
cv::threshold(zero_resized, zero_bin, 0.5, 255.0,
cv::THRESH_BINARY);
zero_bin.convertTo(zero_bin, CV_8U);
smoothed.setTo(0.0f, zero_bin);
}
smoothed *= safe_max;
out_matrix = smoothed;
}
static void SaveGridConfig(bool b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("display/grid", b);
}
static void SaveAxisConfig(bool b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("display/axis", b);
}
static void SaveSurfaceConfig(bool b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("display/surface", b);
}
static void GetGridConfig(bool& b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
b = settings.value("display/grid", b).toBool();
}
static void GetAxisConfig(bool& b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
b = settings.value("display/axis", b).toBool();
}
static void GetSurfaceConfig(bool b) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
b = settings.value("display/surface", b).toBool();
}
static void SaveLastRow(int value) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("spec/row", value);
}
static void GetLastRow(int& value) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
value = settings.value("spec/row", value).toInt();
}
static void GetLastCol(int value) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("spec/col", value);
}
static void GetLastCol(int& value) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
value = settings.value("spec/col", value).toInt();
}
static void SaveZeroColor(QString color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("color/zero", color);
}
static void GetZeroColor(QString& color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
color = settings.value("color/zero", color).toString();
}
static void SaveLowColor(QString color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("color/low", color);
}
static void GetLowColor(QString& color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
color = settings.value("color/low", color).toString();
}
static void SaveMidColor(QString color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("color/mid", color);
}
static void GetMidColor(QString& color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
color = settings.value("color/mid", color).toString();
}
static void SaveHighColor(QString color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
settings.setValue("color/high", color);
}
static void GetHighColor(QString& color) {
QSettings settings(GlobalHelper::GetConfigFilePath(), QSettings::IniFormat);
color = settings.value("color/high", color).toString();
}
static QString GetConfigFilePath() {
return QCoreApplication::applicationDirPath() + QDir::separator() + "conf.ini";
}
static QString GetAppVersion() {
return APP_VERSION;
}
private:
GlobalHelper() {}
GlobalHelper() {
}
};
#endif //TACTILEIPC3D_GLOBALHELPER_H
#endif // TACTILEIPC3D_GLOBALHELPER_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,11 @@
#include "serial_backend.h"
#include "piezoresistive_a_protocol.h"
#include "serial_qt_transport.h"
#include <QDebug>
#include <QCoreApplication>
#include <QDir>
#include <QStringList>
#include <QMetaObject>
#include <QtGlobal>
#include <qcontainerfwd.h>
@@ -14,13 +16,20 @@ SerialBackend::SerialBackend(QObject *parent)
: QObject(parent), m_packetQueue(2048), m_frameQueue(2048), m_readThread(&m_packetQueue), m_decodeThread(&m_packetQueue, &m_frameQueue)
{
m_request.dataLength = 24;
m_spec.model = QStringLiteral("PZR-A");
auto codec = std::make_shared<PiezoresistiveACodec>();
auto decoder = std::make_shared<PiezoresistiveADecoder>();
auto format = std::make_shared<PiezoresistiveAFormat>();
m_manager.registerProtocol(codec->name(), {codec, decoder, format});
m_manager.setActiveProtocol(codec->name());
const QString pluginDir = QDir(QCoreApplication::applicationDirPath())
.filePath(QStringLiteral("plugins/decoders"));
QStringList errors;
const QStringList loaded = m_manager.loadPlugins(pluginDir, &errors);
for (const QString& err : errors) {
qWarning().noquote() << err;
}
if (!loaded.isEmpty()) {
m_spec.model = m_manager.activeProtocol();
} else {
qWarning() << "No protocol plugins loaded.";
m_spec.model = QStringLiteral("UNKNOWN");
}
m_sendWorker = new SerialSendWorker();
m_sendWorker->moveToThread(&m_sendThread);
@@ -175,6 +184,10 @@ void SerialBackend::setProtocol(const QString &name)
if (!m_manager.setActiveProtocol(name))
return;
updateProtocolBindings_();
if (m_spec.model != name) {
m_spec.model = name;
emit sensorModelChanged();
}
emit protocolChanged();
}

View File

@@ -1,4 +1,8 @@
#include "serial_manager.h"
#include "protocol_plugin.h"
#include <QDir>
#include <QPluginLoader>
void SerialManager::registerProtocol(const QString& name, const ProtocolBundle& bundle) {
if (name.isEmpty())
@@ -15,8 +19,76 @@ bool SerialManager::setActiveProtocol(const QString& name) {
return true;
}
SerialManager::ProtocolBundle SerialManager::activeBundle() const {
ProtocolBundle SerialManager::activeBundle() const {
if (!m_protocols.contains(m_activeName))
return {};
return m_protocols.value(m_activeName);
}
QStringList SerialManager::loadPlugins(const QString& dirPath, QStringList* errors) {
QStringList loaded;
if (!m_pluginLoaders.empty()) {
return loaded;
}
QDir dir(dirPath);
if (!dir.exists()) {
if (errors)
errors->append(QStringLiteral("Plugin dir not found: %1").arg(dirPath));
return loaded;
}
QStringList filters;
#if defined(Q_OS_WIN)
filters << QStringLiteral("*.dll");
#elif defined(Q_OS_MAC)
filters << QStringLiteral("*.dylib");
#else
filters << QStringLiteral("*.so");
#endif
const QStringList entries = dir.entryList(filters, QDir::Files);
for (const QString& fileName : entries) {
const QString path = dir.absoluteFilePath(fileName);
auto loader = std::make_unique<QPluginLoader>(path);
QObject* instance = loader->instance();
if (!instance) {
if (errors)
errors->append(QStringLiteral("Load failed: %1 (%2)").arg(path, loader->errorString()));
continue;
}
auto* plugin = qobject_cast<IProtocolPlugin*>(instance);
if (!plugin) {
if (errors)
errors->append(QStringLiteral("Invalid plugin: %1").arg(path));
loader->unload();
continue;
}
if (plugin->apiVersion() != kProtocolPluginApiVersion) {
if (errors)
errors->append(QStringLiteral("API mismatch: %1").arg(path));
loader->unload();
continue;
}
const ProtocolBundle bundle = plugin->createBundle();
if (!bundle.codec || !bundle.decoder || !bundle.format) {
if (errors)
errors->append(QStringLiteral("Missing components: %1").arg(path));
loader->unload();
continue;
}
const QString name = plugin->protocolName();
if (!m_protocols.contains(name)) {
registerProtocol(name, bundle);
loaded.append(name);
m_pluginLoaders.push_back(std::move(loader));
} else {
loader->unload();
}
}
return loaded;
}

View File

@@ -3,22 +3,18 @@
#include <QHash>
#include <QString>
#include <QStringList>
#include <QPluginLoader>
#include <vector>
#include <memory>
#include "serial_codec.h"
#include "serial_decoder.h"
#include "serial_format.h"
#include "protocol_bundle.h"
class SerialManager {
public:
struct ProtocolBundle {
std::shared_ptr<ISerialCodec> codec;
std::shared_ptr<ISerialDecoder> decoder;
std::shared_ptr<ISerialFormat> format;
};
void registerProtocol(const QString& name, const ProtocolBundle& bundle);
bool setActiveProtocol(const QString& name);
QStringList loadPlugins(const QString& dirPath, QStringList* errors = nullptr);
QString activeProtocol() const { return m_activeName; }
ProtocolBundle activeBundle() const;
@@ -26,6 +22,7 @@ public:
private:
QHash<QString, ProtocolBundle> m_protocols;
QString m_activeName;
std::vector<std::unique_ptr<QPluginLoader>> m_pluginLoaders;
};
#endif // TACTILEIPC3D_SERIAL_MANAGER_H