Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
a48b685
eyecam: 開いた目より大きくなった瞳(暗くなって開いた瞳孔)を、大きさだけで捨て続けない
Oct 20, 2026
77c3acb
eyecam: ユーザー校正の細めを、そのかぶりの開いた目からの深さでも覚え、ライブではその深さで細めを出す
Oct 20, 2026
9022e50
replay: 目のまぶたの「疑い」(LidDoubt)を調べる診断を足す(FEO_DOUBT_DIAG、既定では何も変わらない)
Oct 20, 2026
4a276bc
まぶた: 目のサーバーが 1 秒開いていると読んだら、カメラのまぶたへの「疑い」をやり直す
Oct 20, 2026
84f7dcf
チェック担当の指摘を直す: 大きくなった瞳を取り直すときのゲート、細めの深さの上下限、丸さ
Oct 20, 2026
b91c3da
eyecam: 細めの深さの上下限を NaN で落ちない形にする(チェック担当の指摘)
Oct 20, 2026
1a8b136
eyecam: 取り直す大きな瞳は「いつもより平たい」ものだけ落とす(機械学習セッションの再生で)
Oct 20, 2026
3a2f770
0.8.2-beta.1: 版を上げる(Cargo.toml・Cargo.lock)
Oct 21, 2026
27d8702
視線: 片目だけ閉じて読まれ続けたら止めずにもう片方の目で動かす(#32)
Oct 21, 2026
36253c5
README.ja: 片目だけ閉じて読まれ続けるときの視線の扱いを書き足す(#32)
Oct 21, 2026
1e4eef6
視線: 片目タイマーは 1 サンプルだけ開いて読まれても戻さない(チェック担当の指摘、#32)
Oct 21, 2026
1fbb2f9
視線: 目ごとの視線をどれだけ使うかを選べるようにする(v2 の左右別々)
Oct 21, 2026
9ca44e1
パネル: 目ごとの視線のヒントを 1 行に収まる形に(チェック担当の指摘)
Oct 21, 2026
ce2e69b
0.8.2-beta.1: 更新履歴を書く
Oct 21, 2026
cde7b8e
eyecam: 閉じた目で下まぶたの線が大きく下に外れたら、最後に瞳ありで見た下まぶたの線を使う(issue #38)
Oct 22, 2026
2a17dba
eyecam: 虹彩の半径が瞳に対して大きすぎるかぶりでは、虹彩の縁を「虹彩から出て最初の明るさの立ち上がり」で測る(issue #38)
Oct 22, 2026
f166df4
eyecam: 虹彩から出て最初の立ち上がりを取る強さの下限を 0.5 から 0.35 にする(issue #38)
Oct 22, 2026
e87b058
eyecam: 虹彩の縁の測り方を切り替えたときは、開いた目の iris box の明るさも覚え直す(チェック担当の指摘)
Oct 22, 2026
cfeaf67
更新履歴: 度付きインサートで閉じた目が少し開いて読まれる・虹彩が大きく測られる件の直しを 0.8.2-beta.1 に書く(issue …
Oct 22, 2026
11cef85
更新履歴: #38 の行の「ほかは変わらない」を、半目 5.3 → 5.4 % を添えた「ほぼ同じ」に弱める(チェック担当の指摘)
Oct 22, 2026
9ff2eb3
パネル: 「目ごとの視線」を 5 % 刻みにする
Oct 23, 2026
c1173e0
本体: 目のデータが少ないときのログで、取りこぼし 0 件が「-0」と出るのを直す
Oct 24, 2026
c2369e8
eyecam: かぶりの校正の見開きで、高い範囲の線が普段の段から上がった分を幅にし、0.9 より大きい幅は見開きとみなさない
Oct 24, 2026
d88758d
eyecam: 瞳が丸ごと見えているのに上まぶたの線が瞳の上端より下に出たら、瞳の上でもう一度探す
Oct 24, 2026
32e3b67
eyecam: 見開きの幅の上限を 1.1 にし(履歴の中央値から除くのは 0.9 のまま)、確かめたことだけをコメントに書く
Oct 24, 2026
09ce02b
eyecam: 上まぶたの線を探し直すのは瞳の短半径の半分より下のときだけにし、元の線より inlier の割合が低い線には替えない
Oct 24, 2026
d9eb864
0.8.2-beta.2: 版を上げる(Cargo.toml・Cargo.lock)
Oct 24, 2026
8e2ea9c
0.8.2-beta.2: 更新履歴に、度付きインサートで上まぶたの線と見開きの幅を取り違える件の直しを書く
Oct 24, 2026
5b08e6f
パネル: 目のカメラの校正中は、視線の合わせ直しと目合わせを始めない
Oct 24, 2026
6dbbdc7
eyecam: 止まった目の映像が戻ったときと、近接センサーがかぶったに変わったときも、新しいかぶりとして覚え直す
Oct 24, 2026
6c17600
eyecam: かぶり直しの見分けで、瞳の割合に加えて虹彩の半径が履歴に近いかも見る(空の HMD の偽の瞳対策)
Oct 24, 2026
33d8d67
パネル: eyecam-rec の status.json の last_session_aborted を読む(最後の録画が途中で終わったか)
Oct 25, 2026
d0a8ba2
パネル: 「AI の学習に協力する」を足す(詳細 › 動作確認から、半目の読み直し(AI)の学習用の録画を最後まで案内する)
Oct 25, 2026
9f735b8
ドキュメント: 「AI の学習に協力する」の画面ごとの仕様、置くファイル、更新履歴(Unreleased)を書く
Oct 25, 2026
030f9c3
eyecam: 学習用の手順 protocol_contrib.txt、左右を見る段の音、status.json に HMD を外した回数を足す
Oct 25, 2026
fa8519d
パネル: 「AI の学習に協力する」を「細めの学習用に撮る」に作り直す(ボタン 1 つで 1 本撮り、~/eyecam/contrib/ …
Oct 25, 2026
0c499e4
ドキュメント: 「細めの学習用に撮る」の仕様、eyecam の新しい手順と status.json の項目、更新履歴(Unreleased…
Oct 25, 2026
5f843bd
パネル: 「細めの学習用に撮る」のシートに目的の 1 行と、まとめたファイルが .tar.zst(7-Zip などで開ける)だという一言を足す
Oct 25, 2026
07ce873
パネル: 「細めの学習用に撮る」の録画が学習に使えるかを確かめ、校正と設定の写しも置く
Oct 25, 2026
e4c9258
パネル: 「細めの学習用に撮る」のシートを開くたびにフォルダを読み直し、まとめる前に空きをその場で確かめる
Oct 25, 2026
e3cd066
パネル: 「細めの学習用に撮る」は本体に目のデータが来ているときだけ撮れるようにし、片目の映像が無い録画のわけを分ける
Oct 25, 2026
7efe7ec
eyecam: かぶり校正の見開きの高さを、見開きの段ごとの中央値のうち一番低いものにする
Oct 25, 2026
658bf15
eyecam: 見開きの高さのコメントの、上を見たときの数字を感度ごとに直す
Oct 25, 2026
af9ba75
eyecam: 見開きの高さのコメントを折り返す
Oct 25, 2026
3e79932
更新履歴: Unreleased の節を作り、かぶり校正の見開きの高さを段ごとの中央値の一番低いものにした件を日英で書く
Oct 25, 2026
319bf9e
パネル: 「細めの学習用に撮る」の送り方を Google ドライブなどの共有リンクに、左右を見る段を「左を見て / 右を見て」にする
Oct 25, 2026
9c44cfe
見開きの届きにくさの直し(eyecam-widen-reach)を合わせる
Oct 25, 2026
0320293
0.8.2-beta.3: 版を上げ、更新履歴の節の名前を変えて見開きの直しを要約に足す
Oct 25, 2026
59d9698
eyecam: 片方のカメラのスロットが 4 つそろわないリングではロックしない(右目が 22.5 fps のまま校正・録画が通っていた)
Oct 25, 2026
397f5bb
パネル: 「細めの学習用に撮る」で、片目のカメラの枚数がもう片方の 9 割に届かない録画をはじく
Oct 25, 2026
fc0559d
eyecam: 同じスロットのリングがまたアンバランスになったら、もう探し直さない(ロックと探し直しの繰り返しを止める)
Oct 25, 2026
501002c
片目が遅い録画をはじく細め撮影のチェック(eyecam-contrib-uneven)を合わせる
Oct 25, 2026
ea93e8d
更新履歴: beta.3 の節に、目のカメラのつかみ方の偏りの直しを足す
Oct 25, 2026
2b6161d
まぶたの拒否権の重みを、白い帯・暗さ・ずらしを描き足して学習し直したものに入れ替える
Oct 26, 2026
a08d0fb
eyecam: 大きく見開いた目で上まぶたの線が瞳の上の縁に乗ったときも、瞳の上で探し直す(ABOVE_PUPIL_B 0.5 -> 1.2)
Oct 26, 2026
88bc68c
まぶたの拒否権の重みの入れ替え(eyecam-veto-r)を合わせる
Oct 26, 2026
fc56f4f
見開いた目の上まぶたの線の探し直し(eyecam-widen-echo2)を合わせる
Oct 26, 2026
cc8b978
0.8.2-beta.4: 版を上げ、更新履歴に見開きの探し直しと半目の読み直し(AI)の重みの入れ替えを書く
Oct 26, 2026
342b4aa
目のプレビューの映像に、eyecam が見つけた上下のまぶたの線を重ねる
Oct 26, 2026
ac784d0
目のプレビューにまぶたの線を重ねる(eyecam-lid-preview)を合わせる
Oct 26, 2026
d9dc6fa
更新履歴: 目のプレビューのまぶたの線を Unreleased に書く
Oct 26, 2026
cb5af11
目のプレビュー: まぶたの線と「カメラ まぶた」を、生の値以外ではなめらかにして描く
Oct 26, 2026
4c98e6d
目のプレビューのまぶたの線のなめらかさ(eyecam-lid-preview)を合わせる
Oct 26, 2026
37f480f
更新履歴: 目のプレビューのまぶたの線をなめらかにして描くこと、「生の値」では読んだままなことを書く
Oct 26, 2026
1026d5f
目のプレビュー: まぶたの線のなめらかさの前に 3 枚の中央値を入れて、1 枚だけの跳ねを消す
Oct 26, 2026
9457fe1
目のプレビューのまぶたの線の中央値(eyecam-lid-preview)を合わせる
Oct 26, 2026
ad31233
目のプレビュー: カメラ映像に重ねる印(まぶた・瞳・探す範囲)をそれぞれスイッチで出したり消したりできるようにする
Oct 27, 2026
92e9a08
目のプレビュー: まぶたを線ではなく、瞳の列に点 1 つずつで描く
Oct 27, 2026
ef9eb61
目のプレビューの印のスイッチと、まぶたの点(eyecam-preview-toggles)を合わせる
Oct 27, 2026
44a951d
目のプレビュー: 英語の映像の下の説明を短くして、いちばん小さい字にならないようにする
Oct 27, 2026
d0e11e4
0.8.2-beta.5: 版を上げ、更新履歴をまとめる
Oct 27, 2026
b472bc9
0.8.2: 版を上げ、beta.2〜5 の更新履歴を 1 つにまとめて、録画をくれた人への謝辞を足す
Oct 29, 2026
ee8276c
0.8.2: 更新履歴で、見開きの再探索のしきい値を 1.2 倍の書き方にそろえる
Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions CHANGELOG.ja.md

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "frameeyeosc"
version = "0.8.1"
version = "0.8.2"
edition = "2024"
license = "MIT"
description = "Sends Steam Frame eye tracking (gaze and eyelids) to VRChat over OSC"
Expand Down
11 changes: 6 additions & 5 deletions README.ja.md

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions README.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions panel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_executable(frameeyeosc-panel
src/changelog.cpp
src/command.cpp
src/config.cpp
src/contrib.cpp
src/diag.cpp
src/draw.cpp
src/eyecam.cpp
Expand Down Expand Up @@ -155,6 +156,7 @@ add_executable(panel-test tests/panel_test.cpp
src/changelog.cpp
src/command.cpp
src/config.cpp
src/contrib.cpp
src/diag.cpp
src/draw.cpp
src/eyecam.cpp
Expand Down Expand Up @@ -211,6 +213,18 @@ target_compile_options(eyecam-test PRIVATE -Wall -Wextra)
target_link_libraries(eyecam-test PRIVATE Threads::Threads)
add_test(NAME eyecam COMMAND eyecam-test)

# "Help train the AI" (contrib.{h,cpp}: the steps and their sizes against eyecam's protocol files, info.txt, following a
# step's recording and the re-wear in eyecam-rec's status, the screens, the tar headers, and on folders in $TMPDIR
# making, moving into, packing (unpacked again with tar and zstd) and deleting a contribution, and a whole session):
# panel/build/contrib-test
add_executable(contrib-test tests/contrib_test.cpp src/contrib.cpp src/eyecam.cpp src/i18n.cpp src/json.cpp
src/setup_tools.cpp src/recorder.cpp)
target_include_directories(contrib-test PRIVATE src)
target_compile_definitions(contrib-test PRIVATE EYECAM_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/../tools/eyecam")
target_compile_options(contrib-test PRIVATE -Wall -Wextra)
target_link_libraries(contrib-test PRIVATE Threads::Threads)
add_test(NAME contrib COMMAND contrib-test)

# The diagnostics page's texts and code (diag.{h,cpp}: the cards, the diagnostic code, SteamOS's version, SHA-256),
# without cairo: panel/build/diag-test
add_executable(diag-test tests/diag_test.cpp src/diag.cpp src/eyecam.cpp src/i18n.cpp src/json.cpp src/status.cpp
Expand Down
42 changes: 32 additions & 10 deletions panel/README.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions panel/src/action_socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ Decision decide(Action action, const State& state) {
return {Code::BusyRecenter, "busy (a re-center is running; use --action stop)", Effect::None};
}
if (state.fitActive) return {Code::BusyFit, "busy (a fit is running; use --action stop)", Effect::None};
// The eye cameras calibrating: the user looks where its steps say (up and down too), so a fit's dot would
// pull the eyes away from them and measure the wrong look (the fit buttons are grey meanwhile). Told with
// the eye cameras' code and "calibrating", which frame-aux-shortcuts shows as their calibration
if (state.camerasCalibrating) {
return {Code::NoCameras, "busy (the eye cameras are calibrating)", Effect::None};
}
// The buttons are grey while frameeyeosc doesn't run; without eye data (the headset off, most often)
// nothing could be measured
if (!state.running) return {Code::NoFrameeyeosc, "frameeyeosc is not running", Effect::None};
Expand Down
10 changes: 7 additions & 3 deletions panel/src/action_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ enum class Code {
NoEyeData = 9, ///< frameeyeosc runs, but no eye data comes in (the headset off, or eye tracking stopped)
BusyRecenter = 10, ///< a re-center is running (also the automatic one after putting the headset on)
NoCameras = 11, ///< relearn: the eye cameras aren't in use or not ready (off, not set up, eyecam-rec not running
///< or busy, no eye video), or eyecam-rec said no
///< or busy, no eye video), or eyecam-rec said no. Also recenter, fit and relearn while the eye
///< cameras calibrate, with "calibrating" in the text (what frame-aux-shortcuts looks for)
};

/** The actions (more can follow: pause / resume sending, the eye cameras' calibration, the gaze dots). */
Expand Down Expand Up @@ -92,6 +93,8 @@ struct State {
/** The eye cameras drive the eyelids (or learn to) and eyecam-rec reads them live, idle with the eye video
* (eyecam::relearnAllowed: what the "Relearn my eyes" button needs) */
bool camerasReady = false;
/** The eye cameras are calibrating (eyecam::calibrationUnderWay): the fit buttons are grey meanwhile */
bool camerasCalibrating = false;
};

/** What the panel then does. */
Expand All @@ -115,8 +118,9 @@ struct Decision {
* Decide what an action does now, with the conditions of the button it stands for: the fit buttons need frameeyeosc
* running and their values not locked, and not while a fit runs (they are hidden then; only "Stop" shows). The
* re-center also needs a gaze fit, like the automatic one after putting the headset on, and both need eye data.
* Relearning needs the eye cameras ready, and waits for a fit too (the fit measures the eyelids). Checked in that
* order: busy, frameeyeosc, eye data, then the action's own.
* Relearning needs the eye cameras ready, and waits for a fit too (the fit measures the eyelids). None of the three
* starts while the eye cameras calibrate (the user looks where its steps say). Checked in that order: busy (a fit,
* then the calibration), frameeyeosc, eye data, then the action's own.
* @param action the action
* @param state the panel's state now
* @return the code, the reply's text and what to do
Expand Down
11 changes: 11 additions & 0 deletions panel/src/auto_recenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ Step Watcher::update(double now, const Inputs& in) {
}
}
wasRunning_ = in.running;
// (a calibration over: the next one is said again)
if (!in.camerasCalibrating) calibLogged_ = false;
// How long an eye has read shut on Valve's eye server while tracked (a blink is not long enough)
if (!(in.running && tracking_ && (in.valveShut[0] || in.valveShut[1]))) {
shutSince_ = NAN;
Expand Down Expand Up @@ -144,6 +146,15 @@ Step Watcher::update(double now, const Inputs& in) {
} else if (in.fitActive) {
step.log = disarm("an eye fit was started");
} else if (in.running && tracking_ && onFor_ >= kSettleSec && !dashboardOpen && now - closedAt_ >= kClosedSec) {
// Would start now, but the eye cameras are calibrating: the user looks where its steps say (up and down too),
// so the dot would pull the eyes away from them and measure the wrong look. Waits for its end, said once
if (in.camerasCalibrating) {
if (!calibLogged_) {
calibLogged_ = true;
step.log = "auto re-center: waiting for the eye cameras' calibration to end";
}
return step;
}
// Would start now, but SteamVR's startup dashboard is still to come: started now, it would be stopped as it
// opens. Said once
if (startupWait_) {
Expand Down
10 changes: 7 additions & 3 deletions panel/src/auto_recenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct Inputs {
bool valveShut[2] = {false, false}; ///< Valve's eye server reads the eye below kOpenFloor (left, right)
bool camerasWarming = false; ///< the eye cameras' eyelids wait for eyecam-rec's warm-up
///< (eyecam::recenterAwaitsWarmup)
bool camerasCalibrating = false; ///< the eye cameras are calibrating (eyecam::calibrationUnderWay)
};

/** What to do after an update. */
Expand All @@ -80,9 +81,11 @@ struct Step {
* the dashboard stopped is tried again, kDashboardRetries times at most in a wearing (fitEnded); any other end is
* final for the wearing. While Valve's eye server reads an eye shut
* (it can get stuck at 0 for a whole wear) and the eye cameras are still warming up, no sample would count, so it
* waits for the warm-up (up to kCameraWaitSec): the eye camera's eyelid counts for that eye after it. Time while
* frameeyeosc is not running counts for nothing (a restart while worn does not look like putting the headset on); the time since the last
* update counts for the state seen then, so a suspend right after taking the headset off counts as off.
* waits for the warm-up (up to kCameraWaitSec): the eye camera's eyelid counts for that eye after it. While the eye
* cameras calibrate (the user looking up and down as told), it waits for the calibration to end, however long.
* Time while frameeyeosc is not running counts for nothing (a restart while worn does not look like putting the
* headset on); the time since the last update counts for the state seen then, so a suspend right after taking the
* headset off counts as off.
*/
class Watcher {
public:
Expand Down Expand Up @@ -146,6 +149,7 @@ class Watcher {
double startupFrom_ = 0.0; ///< ...since the connect or the wake...
const char* startupAfter_ = ""; ///< ...which ("connecting" / "waking up")...
bool startupLogged_ = false; ///< ...and a re-center has waited for it (said once)
bool calibLogged_ = false; ///< a re-center has waited for the eye cameras' calibration running now (said once)
double shutSince_ = NAN; ///< since when an eye has read shut on Valve's eye server (NaN: neither does)
double holdSince_ = NAN; ///< since when this wearing's start is held back for the eye cameras (NaN: it isn't)
double clearSince_ = NAN; ///< ...and since when that no longer holds (NaN: it still does)
Expand Down
1 change: 1 addition & 0 deletions panel/src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ const std::vector<SettingSpec>& settingSpecs() {
{key::kGazeDeadzone, SettingType::Number, 0.005, "", 0.0, 0.2, 0.005, 3},
{key::kGazeHoldBelow, SettingType::Number, 0.5, "", 0.05, 1.0, 0.05, 2},
{key::kIndependentEyes, SettingType::Bool, 0, "", 0, 1, 1, 0},
{key::kOwnEyeGaze, SettingType::Number, 0.0, "", 0.0, 1.0, 0.05, 2},
{key::kLidMinCutoff, SettingType::Number, 6.0, "", 0.5, 30.0, 0.5, 1},
{key::kLidBeta, SettingType::Number, 5.0, "", 0.0, 30.0, 0.5, 1},
{key::kLidClosed, SettingType::Number, 0.30, "", 0.0, 1.5, 0.01, 2},
Expand Down
2 changes: 2 additions & 0 deletions panel/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ constexpr const char* kGazeDCutoff = "gaze_d_cutoff";
constexpr const char* kGazeDeadzone = "gaze_deadzone";
constexpr const char* kGazeHoldBelow = "gaze_hold_below";
constexpr const char* kIndependentEyes = "independent_eyes";
/** With independent_eyes in v2: how much of each eye's own sideways gaze is sent, 0 (the default) to 1. */
constexpr const char* kOwnEyeGaze = "own_eye_gaze";
constexpr const char* kLidMinCutoff = "lid_min_cutoff";
constexpr const char* kLidBeta = "lid_beta";
constexpr const char* kLidClosed = "lid_closed";
Expand Down
Loading