Compare commits
3 Commits
54d285cbc8
...
0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| c9495680d6 | |||
| 4882dc1a67 | |||
| bc9f2824ed |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,7 +11,7 @@ TactileIpc3D_autogen/
|
|||||||
*.ninja
|
*.ninja
|
||||||
*.ninja_deps
|
*.ninja_deps
|
||||||
*.ninja_log
|
*.ninja_log
|
||||||
|
OpenCV/
|
||||||
# Qt generated files
|
# Qt generated files
|
||||||
*.moc
|
*.moc
|
||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ set(CMAKE_AUTOUIC ON)
|
|||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
add_subdirectory(3rdpart/QXlsx/QXlsx)
|
|
||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS
|
find_package(Qt6 COMPONENTS
|
||||||
Core
|
Core
|
||||||
@@ -28,6 +25,10 @@ find_package(Qt6 COMPONENTS
|
|||||||
LinguistTools
|
LinguistTools
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(QT_VERSION_MAJOR 6)
|
||||||
|
add_subdirectory(3rdpart/QXlsx/QXlsx)
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
|
||||||
qt_standard_project_setup()
|
qt_standard_project_setup()
|
||||||
|
|
||||||
add_executable(TactileIpc3D
|
add_executable(TactileIpc3D
|
||||||
@@ -62,8 +63,10 @@ add_executable(TactileIpc3D
|
|||||||
src/ringbuffer.cpp
|
src/ringbuffer.cpp
|
||||||
src/sparkline_plotitem.h
|
src/sparkline_plotitem.h
|
||||||
src/sparkling_plotitem.cpp
|
src/sparkling_plotitem.cpp
|
||||||
|
src/globalhelper.h
|
||||||
|
src/globalhelper.h
|
||||||
)
|
)
|
||||||
target_link_libraries(TactileIpc3D
|
target_link_libraries(TactileIpc3D PRIVATE
|
||||||
Qt6::Core
|
Qt6::Core
|
||||||
Qt6::Gui
|
Qt6::Gui
|
||||||
Qt6::Widgets
|
Qt6::Widgets
|
||||||
@@ -76,7 +79,9 @@ target_link_libraries(TactileIpc3D
|
|||||||
Qt6::QuickDialogs2
|
Qt6::QuickDialogs2
|
||||||
QXlsx::QXlsx
|
QXlsx::QXlsx
|
||||||
)
|
)
|
||||||
|
target_include_directories(TactileIpc3D PRIVATE
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/3rdpart/OpenCV/include
|
||||||
|
)
|
||||||
set(TS_FILES
|
set(TS_FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/i18n/app_zh_CN.ts
|
${CMAKE_CURRENT_SOURCE_DIR}/i18n/app_zh_CN.ts
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/i18n/app_en_US.ts
|
${CMAKE_CURRENT_SOURCE_DIR}/i18n/app_en_US.ts
|
||||||
@@ -109,31 +114,17 @@ qt_add_resources(TactileIpc3D i18n_resources
|
|||||||
FILES ${QM_FILES}
|
FILES ${QM_FILES}
|
||||||
)
|
)
|
||||||
|
|
||||||
#if (WIN32 AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
set(runtime_out_dir "${CMAKE_BINARY_DIR}/out")
|
||||||
# set(DEBUG_SUFFIX)
|
set_target_properties(TactileIpc3D PROPERTIES
|
||||||
# if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")
|
RUNTIME_OUTPUT_DIRECTORY "${runtime_out_dir}"
|
||||||
# set(DEBUG_SUFFIX "d")
|
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${runtime_out_dir}/Debug"
|
||||||
# endif ()
|
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${runtime_out_dir}/Release"
|
||||||
# set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")
|
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${runtime_out_dir}/RelWithDebInfo"
|
||||||
# if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
|
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${runtime_out_dir}/MinSizeRel"
|
||||||
# set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
|
)
|
||||||
# if (NOT EXISTS "${QT_INSTALL_PATH}/bin")
|
|
||||||
# set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")
|
include(GNUInstallDirs)
|
||||||
# endif ()
|
install(TARGETS TactileIpc3D
|
||||||
# endif ()
|
RUNTIME DESTINATION bin
|
||||||
# if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")
|
)
|
||||||
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
|
||||||
# COMMAND ${CMAKE_COMMAND} -E make_directory
|
|
||||||
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
|
|
||||||
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
|
||||||
# COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
# "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll"
|
|
||||||
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
|
|
||||||
# endif ()
|
|
||||||
# foreach (QT_LIB Core Gui Widgets)
|
|
||||||
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
|
||||||
# COMMAND ${CMAKE_COMMAND} -E copy
|
|
||||||
# "${QT_INSTALL_PATH}/bin/Qt6${QT_LIB}${DEBUG_SUFFIX}.dll"
|
|
||||||
# "$<TARGET_FILE_DIR:${PROJECT_NAME}>")
|
|
||||||
# endforeach (QT_LIB)
|
|
||||||
#endif ()
|
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ QSGNode* SparklinePlotItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeDat
|
|||||||
|
|
||||||
当前限制:
|
当前限制:
|
||||||
|
|
||||||
- `xlsx` 仅提示未实现(不会写出文件)
|
- `xlsx` 通过QXlsx是实现但是缺少传感器没有测试
|
||||||
- `zip` 未实现压缩逻辑(请视为暂不支持)
|
- `zip` 未实现压缩逻辑(请视为暂不支持)
|
||||||
|
|
||||||
相关代码:`src/data_backend.cpp`(`exportHandler` / `buildCsv_` / `buildJson_`),`qml/content/SaveAsExportDialog.qml`
|
相关代码:`src/data_backend.cpp`(`exportHandler` / `buildCsv_` / `buildJson_`),`qml/content/SaveAsExportDialog.qml`
|
||||||
|
|||||||
1
VERSION.txt
Normal file
1
VERSION.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1.0.0
|
||||||
52
installer/TactileIpc3D.iss
Normal file
52
installer/TactileIpc3D.iss
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#define MyAppName "TactileIpc3D"
|
||||||
|
#define MyAppVersion "0.2.0"
|
||||||
|
#define MyAppPublisher "TactileIpc3D"
|
||||||
|
#define MyAppExeName "TactileIpc3D.exe"
|
||||||
|
#define SourceDir "..\\build\Desktop_Qt_6_8_3_MinGW_64_bit-Release\\out\Release"
|
||||||
|
#define OutputDir "..\\dist"
|
||||||
|
#define AssetsDir "assets"
|
||||||
|
#define AppIconFile AssetsDir + "\\App.ico"
|
||||||
|
#define WizardSmallFile AssetsDir + "\\WizardSmall.bmp"
|
||||||
|
#define WizardLargeFile AssetsDir + "\\WizardLarge.bmp"
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
AppId={{1E4C86D4-4E53-4B8A-9F7F-1D56E8E04353}}
|
||||||
|
AppName={#MyAppName}
|
||||||
|
AppVersion={#MyAppVersion}
|
||||||
|
AppPublisher={#MyAppPublisher}
|
||||||
|
DefaultDirName={autopf}\{#MyAppName}
|
||||||
|
DefaultGroupName={#MyAppName}
|
||||||
|
OutputDir={#OutputDir}
|
||||||
|
OutputBaseFilename={#MyAppName}-Setup-{#MyAppVersion}
|
||||||
|
Compression=lzma
|
||||||
|
SolidCompression=yes
|
||||||
|
WizardStyle=modern
|
||||||
|
SetupLogging=yes
|
||||||
|
ArchitecturesAllowed=x64
|
||||||
|
ArchitecturesInstallIn64BitMode=x64
|
||||||
|
#ifexist AppIconFile
|
||||||
|
SetupIconFile={#AppIconFile}
|
||||||
|
#endif
|
||||||
|
#ifexist WizardSmallFile
|
||||||
|
WizardSmallImageFile={#WizardSmallFile}
|
||||||
|
#endif
|
||||||
|
#ifexist WizardLargeFile
|
||||||
|
WizardImageFile={#WizardLargeFile}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Languages]
|
||||||
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
; Name: "chinesesimp"; MessagesFile: "compiler:Languages\\ChineseSimplified.isl"
|
||||||
|
|
||||||
|
[Tasks]
|
||||||
|
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||||
|
|
||||||
|
[Files]
|
||||||
|
Source: "{#SourceDir}\\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||||
|
|
||||||
|
[Icons]
|
||||||
|
Name: "{group}\\{#MyAppName}"; Filename: "{app}\\{#MyAppExeName}"
|
||||||
|
Name: "{autodesktop}\\{#MyAppName}"; Filename: "{app}\\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: postinstall nowait skipifsilent
|
||||||
6
installer/assets/README.txt
Normal file
6
installer/assets/README.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Place installer assets here:
|
||||||
|
- App.ico
|
||||||
|
- WizardSmall.bmp
|
||||||
|
- WizardLarge.bmp
|
||||||
|
|
||||||
|
If these files are missing, the Inno Setup script will skip the custom icon/images.
|
||||||
616
qml/content/ColorPickerDialog.qml
Normal file
616
qml/content/ColorPickerDialog.qml
Normal file
@@ -0,0 +1,616 @@
|
|||||||
|
// ColorPickerWindow.qml
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Window
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls.Material
|
||||||
|
import TactileIPC 1.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: root
|
||||||
|
width: 360
|
||||||
|
height: 650
|
||||||
|
visible: false
|
||||||
|
modality: Qt.ApplicationModal
|
||||||
|
flags: Qt.Dialog
|
||||||
|
title: qsTr("颜色选择")
|
||||||
|
Material.theme: Backend.lightMode ? Material.Light : Material.Dark
|
||||||
|
Material.accent: Material.Green
|
||||||
|
Material.primary: Material.Green
|
||||||
|
|
||||||
|
readonly property bool isDark: !Backend.lightMode
|
||||||
|
readonly property color windowBg: isDark ? "#1F1F1F" : "#F7F7F7"
|
||||||
|
readonly property color panelBorder: isDark ? "#2E2E2E" : "#D9D9D9"
|
||||||
|
readonly property color surfaceBorder: isDark ? "#343434" : "#CFCFCF"
|
||||||
|
readonly property color textPrimary: isDark ? "#EDEDED" : "#1F1F1F"
|
||||||
|
readonly property color textSecondary: isDark ? "#D8D8D8" : "#616161"
|
||||||
|
readonly property color textMuted: isDark ? "#BEBEBE" : "#6E6E6E"
|
||||||
|
readonly property color controlBg: isDark ? "#2A2A2A" : "#FFFFFF"
|
||||||
|
readonly property color controlBorder: isDark ? "#3A3A3A" : "#CFCFCF"
|
||||||
|
readonly property color highlightBg: isDark ? "#55FFFFFF" : "#33000000"
|
||||||
|
readonly property color highlightText: isDark ? "#111111" : "#FFFFFF"
|
||||||
|
readonly property color indicatorBorder: isDark ? "#6A6A6A" : "#9E9E9E"
|
||||||
|
readonly property color accentColor: Material.color(Material.Green)
|
||||||
|
|
||||||
|
// ===== API =====
|
||||||
|
property color color: "#FF7032D2" // AARRGGBB
|
||||||
|
signal accepted(color c)
|
||||||
|
signal rejected()
|
||||||
|
|
||||||
|
function openWith(c) {
|
||||||
|
syncFromColor(c ?? root.color)
|
||||||
|
visible = true
|
||||||
|
requestActivate()
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onEscapePressed: {
|
||||||
|
visible = false
|
||||||
|
rejected()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== internal HSV(A) =====
|
||||||
|
property real h: 0.75 // 0..1
|
||||||
|
property real s: 0.45
|
||||||
|
property real v: 0.82
|
||||||
|
property real a: 1.0
|
||||||
|
|
||||||
|
property bool _lock: false
|
||||||
|
|
||||||
|
function clamp01(x) { return Math.max(0, Math.min(1, x)) }
|
||||||
|
function clampInt(x, lo, hi) { return Math.max(lo, Math.min(hi, Math.round(x))) }
|
||||||
|
|
||||||
|
function hsvToRgb(hh, ss, vv) {
|
||||||
|
const h6 = (hh % 1) * 6
|
||||||
|
const c = vv * ss
|
||||||
|
const x = c * (1 - Math.abs((h6 % 2) - 1))
|
||||||
|
const m = vv - c
|
||||||
|
let r1=0, g1=0, b1=0
|
||||||
|
if (0 <= h6 && h6 < 1) { r1=c; g1=x; b1=0 }
|
||||||
|
else if (1 <= h6 && h6 < 2) { r1=x; g1=c; b1=0 }
|
||||||
|
else if (2 <= h6 && h6 < 3) { r1=0; g1=c; b1=x }
|
||||||
|
else if (3 <= h6 && h6 < 4) { r1=0; g1=x; b1=c }
|
||||||
|
else if (4 <= h6 && h6 < 5) { r1=x; g1=0; b1=c }
|
||||||
|
else { r1=c; g1=0; b1=x }
|
||||||
|
return { r: r1 + m, g: g1 + m, b: b1 + m }
|
||||||
|
}
|
||||||
|
|
||||||
|
function rgbToHsv(r, g, b) {
|
||||||
|
const max = Math.max(r, g, b)
|
||||||
|
const min = Math.min(r, g, b)
|
||||||
|
const d = max - min
|
||||||
|
let hh = 0
|
||||||
|
if (d !== 0) {
|
||||||
|
if (max === r) hh = ((g - b) / d) % 6
|
||||||
|
else if (max === g) hh = (b - r) / d + 2
|
||||||
|
else hh = (r - g) / d + 4
|
||||||
|
hh /= 6
|
||||||
|
if (hh < 0) hh += 1
|
||||||
|
}
|
||||||
|
const ss = (max === 0) ? 0 : d / max
|
||||||
|
const vv = max
|
||||||
|
return { h: hh, s: ss, v: vv }
|
||||||
|
}
|
||||||
|
|
||||||
|
function toHex2(v01) {
|
||||||
|
const n = clampInt(clamp01(v01) * 255, 0, 255)
|
||||||
|
const s = n.toString(16).toUpperCase()
|
||||||
|
return (s.length === 1) ? ("0" + s) : s
|
||||||
|
}
|
||||||
|
|
||||||
|
function colorToHexAARRGGBB(c) {
|
||||||
|
return "#" + toHex2(c.a) + toHex2(c.r) + toHex2(c.g) + toHex2(c.b)
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHex(str) {
|
||||||
|
let t = ("" + str).trim()
|
||||||
|
if (t.startsWith("0x") || t.startsWith("0X")) t = t.slice(2)
|
||||||
|
if (t.startsWith("#")) t = t.slice(1)
|
||||||
|
if (t.length === 6) {
|
||||||
|
const rr = parseInt(t.slice(0,2), 16)
|
||||||
|
const gg = parseInt(t.slice(2,4), 16)
|
||||||
|
const bb = parseInt(t.slice(4,6), 16)
|
||||||
|
if ([rr,gg,bb].some(x => isNaN(x))) return null
|
||||||
|
return Qt.rgba(rr/255, gg/255, bb/255, 1)
|
||||||
|
}
|
||||||
|
if (t.length === 8) {
|
||||||
|
const aa = parseInt(t.slice(0,2), 16)
|
||||||
|
const rr = parseInt(t.slice(2,4), 16)
|
||||||
|
const gg = parseInt(t.slice(4,6), 16)
|
||||||
|
const bb = parseInt(t.slice(6,8), 16)
|
||||||
|
if ([aa,rr,gg,bb].some(x => isNaN(x))) return null
|
||||||
|
return Qt.rgba(rr/255, gg/255, bb/255, aa/255)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncFromHSV() {
|
||||||
|
if (_lock) return
|
||||||
|
_lock = true
|
||||||
|
const rgb = hsvToRgb(h, s, v)
|
||||||
|
color = Qt.rgba(rgb.r, rgb.g, rgb.b, a)
|
||||||
|
|
||||||
|
// 更新 UI
|
||||||
|
hexField.text = colorToHexAARRGGBB(color)
|
||||||
|
alphaPercent.text = clampInt(a*100, 0, 100) + "%"
|
||||||
|
|
||||||
|
rField.value = clampInt(color.r * 255, 0, 255)
|
||||||
|
gField.value = clampInt(color.g * 255, 0, 255)
|
||||||
|
bField.value = clampInt(color.b * 255, 0, 255)
|
||||||
|
|
||||||
|
// HSV 显示用度/百分比
|
||||||
|
hField.value = clampInt(h * 360, 0, 360)
|
||||||
|
sField.value = clampInt(s * 100, 0, 100)
|
||||||
|
vField.value = clampInt(v * 100, 0, 100)
|
||||||
|
|
||||||
|
svCanvas.requestPaint()
|
||||||
|
hueCanvas.requestPaint()
|
||||||
|
alphaCanvas.requestPaint()
|
||||||
|
_lock = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncFromColor(c) {
|
||||||
|
if (_lock) return
|
||||||
|
_lock = true
|
||||||
|
const hsv = rgbToHsv(c.r, c.g, c.b)
|
||||||
|
h = hsv.h; s = hsv.s; v = hsv.v; a = c.a
|
||||||
|
color = Qt.rgba(c.r, c.g, c.b, a)
|
||||||
|
|
||||||
|
hexField.text = colorToHexAARRGGBB(color)
|
||||||
|
alphaPercent.text = clampInt(a*100, 0, 100) + "%"
|
||||||
|
|
||||||
|
rField.value = clampInt(c.r * 255, 0, 255)
|
||||||
|
gField.value = clampInt(c.g * 255, 0, 255)
|
||||||
|
bField.value = clampInt(c.b * 255, 0, 255)
|
||||||
|
|
||||||
|
hField.value = clampInt(h * 360, 0, 360)
|
||||||
|
sField.value = clampInt(s * 100, 0, 100)
|
||||||
|
vField.value = clampInt(v * 100, 0, 100)
|
||||||
|
|
||||||
|
svCanvas.requestPaint()
|
||||||
|
hueCanvas.requestPaint()
|
||||||
|
alphaCanvas.requestPaint()
|
||||||
|
_lock = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRGB(r255, g255, b255) {
|
||||||
|
if (_lock) return
|
||||||
|
const rr = clampInt(r255, 0, 255) / 255
|
||||||
|
const gg = clampInt(g255, 0, 255) / 255
|
||||||
|
const bb = clampInt(b255, 0, 255) / 255
|
||||||
|
const hsv = rgbToHsv(rr, gg, bb)
|
||||||
|
h = hsv.h; s = hsv.s; v = hsv.v
|
||||||
|
syncFromHSV()
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyHSV(hDeg, sPct, vPct) {
|
||||||
|
if (_lock) return
|
||||||
|
h = clamp01(hDeg / 360)
|
||||||
|
s = clamp01(sPct / 100)
|
||||||
|
v = clamp01(vPct / 100)
|
||||||
|
syncFromHSV()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始同步
|
||||||
|
Component.onCompleted: syncFromColor(root.color)
|
||||||
|
|
||||||
|
// ====== UI: 深色窗口面板(不是卡片)======
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 0
|
||||||
|
color: root.windowBg
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.panelBorder
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// 顶部:标题 + 勾选(参考图右上角)
|
||||||
|
// RowLayout {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// spacing: 8
|
||||||
|
|
||||||
|
// Label {
|
||||||
|
// text: root.title
|
||||||
|
// color: root.textPrimary
|
||||||
|
// font.pixelSize: 14
|
||||||
|
// font.weight: Font.DemiBold
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// CheckBox {
|
||||||
|
// id: alphaToggle
|
||||||
|
// checked: true
|
||||||
|
|
||||||
|
// contentItem: Label {
|
||||||
|
// text: qsTr("实时预览")
|
||||||
|
// color: root.textSecondary
|
||||||
|
// verticalAlignment: Text.AlignVCenter
|
||||||
|
// elide: Text.ElideRight
|
||||||
|
// }
|
||||||
|
|
||||||
|
// indicator: Rectangle {
|
||||||
|
// implicitWidth: 16
|
||||||
|
// implicitHeight: 16
|
||||||
|
// radius: 3
|
||||||
|
// border.width: 1
|
||||||
|
// border.color: root.indicatorBorder
|
||||||
|
// color: alphaToggle.checked ? root.accentColor : "transparent"
|
||||||
|
|
||||||
|
// // 选中勾
|
||||||
|
// Canvas {
|
||||||
|
// anchors.fill: parent
|
||||||
|
// onPaint: {
|
||||||
|
// const ctx = getContext("2d")
|
||||||
|
// ctx.clearRect(0,0,width,height)
|
||||||
|
// if (!alphaToggle.checked) return
|
||||||
|
// ctx.strokeStyle = "white"
|
||||||
|
// ctx.lineWidth = 2
|
||||||
|
// ctx.lineCap = "round"
|
||||||
|
// ctx.beginPath()
|
||||||
|
// ctx.moveTo(width*0.25, height*0.55)
|
||||||
|
// ctx.lineTo(width*0.45, height*0.72)
|
||||||
|
// ctx.lineTo(width*0.78, height*0.30)
|
||||||
|
// ctx.stroke()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// ToolButton {
|
||||||
|
// text: "✕"
|
||||||
|
// onClicked: { root.visible = false; root.rejected() }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// HSV 面板
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 185
|
||||||
|
radius: 8
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.surfaceBorder
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: svCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d")
|
||||||
|
const w = width, hh = height
|
||||||
|
ctx.clearRect(0,0,w,hh)
|
||||||
|
|
||||||
|
const rgbHue = root.hsvToRgb(root.h, 1, 1)
|
||||||
|
|
||||||
|
// X: white -> hue
|
||||||
|
const gx = ctx.createLinearGradient(0,0,w,0)
|
||||||
|
gx.addColorStop(0, "rgb(255,255,255)")
|
||||||
|
gx.addColorStop(1, "rgb(" + Math.round(rgbHue.r*255) + "," + Math.round(rgbHue.g*255) + "," + Math.round(rgbHue.b*255) + ")")
|
||||||
|
ctx.fillStyle = gx
|
||||||
|
ctx.fillRect(0,0,w,hh)
|
||||||
|
|
||||||
|
// Y: transparent -> black
|
||||||
|
const gy = ctx.createLinearGradient(0,0,0,hh)
|
||||||
|
gy.addColorStop(0, "rgba(0,0,0,0)")
|
||||||
|
gy.addColorStop(1, "rgba(0,0,0,1)")
|
||||||
|
ctx.fillStyle = gy
|
||||||
|
ctx.fillRect(0,0,w,hh)
|
||||||
|
|
||||||
|
// handle
|
||||||
|
const x = root.s * w
|
||||||
|
const y = (1 - root.v) * hh
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, y, 7, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.95)"
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, y, 6, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.strokeStyle = "rgba(0,0,0,0.55)"
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
function apply(mx, my) {
|
||||||
|
root.s = root.clamp01(mx / width)
|
||||||
|
root.v = root.clamp01(1 - (my / height))
|
||||||
|
root.syncFromHSV()
|
||||||
|
}
|
||||||
|
onPressed: (e) => apply(e.x, e.y)
|
||||||
|
onPositionChanged: (e) => { if (pressed) apply(e.x, e.y) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hue 彩虹条(参考图那种)
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
radius: 8
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.surfaceBorder
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: hueCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d")
|
||||||
|
const w = width, hh = height
|
||||||
|
ctx.clearRect(0,0,w,hh)
|
||||||
|
const grad = ctx.createLinearGradient(0,0,w,0)
|
||||||
|
for (let i=0; i<=6; i++) {
|
||||||
|
const t = i/6
|
||||||
|
const rgb = root.hsvToRgb(t, 1, 1)
|
||||||
|
grad.addColorStop(t, "rgb(" + Math.round(rgb.r*255) + "," + Math.round(rgb.g*255) + "," + Math.round(rgb.b*255) + ")")
|
||||||
|
}
|
||||||
|
ctx.fillStyle = grad
|
||||||
|
ctx.fillRect(0,0,w,hh)
|
||||||
|
|
||||||
|
const x = root.h * w
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, hh/2, 7, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.95)"
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, hh/2, 6, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.strokeStyle = "rgba(0,0,0,0.55)"
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
function apply(mx) {
|
||||||
|
root.h = root.clamp01(mx / width)
|
||||||
|
root.syncFromHSV()
|
||||||
|
}
|
||||||
|
onPressed: (e) => apply(e.x)
|
||||||
|
onPositionChanged: (e) => { if (pressed) apply(e.x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha 条(棋盘 + 渐变 + 右侧圆点)
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 16
|
||||||
|
radius: 8
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.surfaceBorder
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
// checker
|
||||||
|
Canvas {
|
||||||
|
id: checkerCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d")
|
||||||
|
const w = width, hh = height
|
||||||
|
ctx.clearRect(0,0,w,hh)
|
||||||
|
const s = 8
|
||||||
|
for (let y=0; y<hh; y+=s) {
|
||||||
|
for (let x=0; x<w; x+=s) {
|
||||||
|
const on = ((x/s + y/s) % 2) === 0
|
||||||
|
ctx.fillStyle = on ? "rgba(255,255,255,0.16)" : "rgba(0,0,0,0.0)"
|
||||||
|
ctx.fillRect(x,y,s,s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: alphaCanvas
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d")
|
||||||
|
const w = width, hh = height
|
||||||
|
ctx.clearRect(0,0,w,hh)
|
||||||
|
|
||||||
|
const rgb = root.hsvToRgb(root.h, root.s, root.v)
|
||||||
|
const grad = ctx.createLinearGradient(0,0,w,0)
|
||||||
|
grad.addColorStop(0, "rgba(" + Math.round(rgb.r*255) + "," + Math.round(rgb.g*255) + "," + Math.round(rgb.b*255) + ",0)")
|
||||||
|
grad.addColorStop(1, "rgba(" + Math.round(rgb.r*255) + "," + Math.round(rgb.g*255) + "," + Math.round(rgb.b*255) + ",1)")
|
||||||
|
ctx.fillStyle = grad
|
||||||
|
ctx.fillRect(0,0,w,hh)
|
||||||
|
|
||||||
|
const x = root.a * w
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, hh/2, 7, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.95)"
|
||||||
|
ctx.stroke()
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(x, hh/2, 6, 0, Math.PI*2)
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
ctx.strokeStyle = "rgba(0,0,0,0.55)"
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
function apply(mx) {
|
||||||
|
root.a = root.clamp01(mx / width)
|
||||||
|
root.syncFromHSV()
|
||||||
|
}
|
||||||
|
onPressed: (e) => apply(e.x)
|
||||||
|
onPositionChanged: (e) => { if (pressed) apply(e.x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下方:色块 + Hex + 透明度百分比
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// 预览色块(带棋盘底)
|
||||||
|
Rectangle {
|
||||||
|
width: 44
|
||||||
|
height: 44
|
||||||
|
radius: 8
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.surfaceBorder
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
anchors.fill: parent
|
||||||
|
onPaint: {
|
||||||
|
const ctx = getContext("2d")
|
||||||
|
const w = width, hh = height
|
||||||
|
ctx.clearRect(0,0,w,hh)
|
||||||
|
const s = 10
|
||||||
|
for (let y=0; y<hh; y+=s) {
|
||||||
|
for (let x=0; x<w; x+=s) {
|
||||||
|
const on = ((x/s + y/s) % 2) === 0
|
||||||
|
ctx.fillStyle = on ? "rgba(255,255,255,0.14)" : "rgba(0,0,0,0.0)"
|
||||||
|
ctx.fillRect(x,y,s,s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: root.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: hexField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: "#FF7032D2"
|
||||||
|
placeholderText: "#AARRGGBB"
|
||||||
|
inputMethodHints: Qt.ImhPreferUppercase | Qt.ImhNoPredictiveText
|
||||||
|
|
||||||
|
// 用 palette,而不是 color/selectionColor/selectedTextColor
|
||||||
|
palette.text: root.textPrimary
|
||||||
|
palette.placeholderText: root.textMuted
|
||||||
|
palette.highlight: root.highlightBg
|
||||||
|
palette.highlightedText: root.highlightText
|
||||||
|
palette.base: root.controlBg // 输入框底色(有的 style 会用它)
|
||||||
|
palette.buttonText: root.textPrimary
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
radius: 8
|
||||||
|
color: root.controlBg
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.controlBorder
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
const c = root.parseHex(text)
|
||||||
|
if (c) root.syncFromColor(c)
|
||||||
|
else text = root.colorToHexAARRGGBB(root.color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 54
|
||||||
|
height: 44
|
||||||
|
radius: 8
|
||||||
|
color: root.controlBg
|
||||||
|
border.width: 1
|
||||||
|
border.color: root.controlBorder
|
||||||
|
Label {
|
||||||
|
id: alphaPercent
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "100%"
|
||||||
|
color: root.textPrimary
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RGB / HSV 数值区(像参考图那样两行块)
|
||||||
|
GridLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
columns: 3
|
||||||
|
columnSpacing: 8
|
||||||
|
rowSpacing: 8
|
||||||
|
|
||||||
|
// ---- Row1: RGB ----
|
||||||
|
Label { text: "RGB"; color: root.textMuted; Layout.alignment: Qt.AlignVCenter }
|
||||||
|
SpinBox {
|
||||||
|
id: rField
|
||||||
|
from: 0; to: 255; editable: true
|
||||||
|
value: 112
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onValueModified: root.applyRGB(value, gField.value, bField.value)
|
||||||
|
}
|
||||||
|
SpinBox {
|
||||||
|
id: gField
|
||||||
|
from: 0; to: 255; editable: true
|
||||||
|
value: 50
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onValueModified: root.applyRGB(rField.value, value, bField.value)
|
||||||
|
}
|
||||||
|
Item { width: 1; height: 1 } // 占位,让下一行对齐
|
||||||
|
SpinBox {
|
||||||
|
id: bField
|
||||||
|
from: 0; to: 255; editable: true
|
||||||
|
value: 210
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
onValueModified: root.applyRGB(rField.value, gField.value, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Row2: HSV ----
|
||||||
|
Label { text: "HSV"; color: root.textMuted; Layout.alignment: Qt.AlignVCenter }
|
||||||
|
SpinBox {
|
||||||
|
id: hField
|
||||||
|
from: 0; to: 360; editable: true
|
||||||
|
value: 263
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onValueModified: root.applyHSV(value, sField.value, vField.value)
|
||||||
|
}
|
||||||
|
SpinBox {
|
||||||
|
id: sField
|
||||||
|
from: 0; to: 100; editable: true
|
||||||
|
value: 64
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onValueModified: root.applyHSV(hField.value, value, vField.value)
|
||||||
|
}
|
||||||
|
Item { width: 1; height: 1 }
|
||||||
|
SpinBox {
|
||||||
|
id: vField
|
||||||
|
from: 0; to: 100; editable: true
|
||||||
|
value: 51
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.columnSpan: 2
|
||||||
|
onValueModified: root.applyHSV(hField.value, sField.value, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部按钮(像窗口)
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: { root.visible = false; root.rejected() }
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("OK")
|
||||||
|
highlighted: true
|
||||||
|
onClicked: { root.visible = false; root.accepted(root.color) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每次 HSV 改变,UI 同步
|
||||||
|
onHChanged: if (!_lock) syncFromHSV()
|
||||||
|
onSChanged: if (!_lock) syncFromHSV()
|
||||||
|
onVChanged: if (!_lock) syncFromHSV()
|
||||||
|
onAChanged: if (!_lock) syncFromHSV()
|
||||||
|
}
|
||||||
@@ -469,8 +469,7 @@ Rectangle {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
lowColorDialog.selectedColor = Backend.colorLow
|
lowColorDialog.openWith(Backend.colorLow)
|
||||||
lowColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,8 +477,7 @@ Rectangle {
|
|||||||
text: root.tr("选择")
|
text: root.tr("选择")
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
lowColorDialog.selectedColor = Backend.colorLow
|
lowColorDialog.openWith(Backend.colorLow)
|
||||||
lowColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,8 +501,7 @@ Rectangle {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
midColorDialog.selectedColor = Backend.colorMid
|
midColorDialog.openWith(Backend.colorMid)
|
||||||
midColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,8 +509,7 @@ Rectangle {
|
|||||||
text: root.tr("选择")
|
text: root.tr("选择")
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
midColorDialog.selectedColor = Backend.colorMid
|
midColorDialog.openWith(Backend.colorMid)
|
||||||
midColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -537,8 +533,7 @@ Rectangle {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
highColorDialog.selectedColor = Backend.colorHigh
|
highColorDialog.openWith(Backend.colorHigh)
|
||||||
highColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -546,8 +541,7 @@ Rectangle {
|
|||||||
text: root.tr("选择")
|
text: root.tr("选择")
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
highColorDialog.selectedColor = Backend.colorHigh
|
highColorDialog.openWith(Backend.colorHigh)
|
||||||
highColorDialog.open()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,22 +590,22 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorDialog {
|
ColorPickerDialog {
|
||||||
id: lowColorDialog
|
id: lowColorDialog
|
||||||
title: root.tr("选择低色")
|
title: root.tr("选择低色")
|
||||||
onAccepted: Backend.colorLow = selectedColor
|
onAccepted: Backend.colorLow = c
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorDialog {
|
ColorPickerDialog {
|
||||||
id: midColorDialog
|
id: midColorDialog
|
||||||
title: root.tr("选择中色")
|
title: root.tr("选择中色")
|
||||||
onAccepted: Backend.colorMid = selectedColor
|
onAccepted: Backend.colorMid = c
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorDialog {
|
ColorPickerDialog {
|
||||||
id: highColorDialog
|
id: highColorDialog
|
||||||
title: root.tr("选择高色")
|
title: root.tr("选择高色")
|
||||||
onAccepted: Backend.colorHigh = selectedColor
|
onAccepted: Backend.colorHigh = c
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveAsExportDialog {
|
SaveAsExportDialog {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<file>qml/content/LeftPanel.qml</file>
|
<file>qml/content/LeftPanel.qml</file>
|
||||||
<file>qml/content/RightPanel.qml</file>
|
<file>qml/content/RightPanel.qml</file>
|
||||||
<file>qml/content/CollapsiblePanel.qml</file>
|
<file>qml/content/CollapsiblePanel.qml</file>
|
||||||
|
<file>qml/content/ColorPickerDialog.qml</file>
|
||||||
<file>shaders/dots.frag</file>
|
<file>shaders/dots.frag</file>
|
||||||
<file>shaders/dots.vert</file>
|
<file>shaders/dots.vert</file>
|
||||||
<file>shaders/bg.frag</file>
|
<file>shaders/bg.frag</file>
|
||||||
|
|||||||
49
src/globalhelper.h
Normal file
49
src/globalhelper.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Created by Lenn on 2026/1/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TACTILEIPC3D_GLOBALHELPER_H
|
||||||
|
#define TACTILEIPC3D_GLOBALHELPER_H
|
||||||
|
|
||||||
|
#include <opencv2/core.hpp>
|
||||||
|
#include <opencv2/imgproc.hpp>
|
||||||
|
|
||||||
|
class GlobalHelper {
|
||||||
|
public:
|
||||||
|
const std::string fuck = "fuck you lsp!!!";
|
||||||
|
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_image) {
|
||||||
|
CV_Assert(raw_data.type() == CV_32F);
|
||||||
|
|
||||||
|
cv::Mat raw = raw_data.clone();
|
||||||
|
raw.setTo(0.0f, raw < min_threshold);
|
||||||
|
|
||||||
|
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 norm_data = raw / max_range;
|
||||||
|
cv::min(norm_data, 1.0f, norm_data);
|
||||||
|
cv::max(norm_data, 0.0f, norm_data);
|
||||||
|
|
||||||
|
cv::pow(norm_data, 0.7, norm_data);
|
||||||
|
|
||||||
|
cv::Mat smoothed;
|
||||||
|
cv::resize(norm_data, smoothed, display_res, 0.0, 0.0, cv::INTER_CUBIC);
|
||||||
|
|
||||||
|
cv::GaussianBlur(smoothed, smoothed, cv::Size(31, 31), 0.0, 0.0, cv::BORDER_DEFAULT);
|
||||||
|
|
||||||
|
cv::transpose(smoothed, out_image);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
GlobalHelper() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //TACTILEIPC3D_GLOBALHELPER_H
|
||||||
Reference in New Issue
Block a user