Skip to content

support for 06cb:00a2 (enroll on host, match on chip)#261

Open
dmitriy-myz wants to merge 21 commits into
uunicorn:masterfrom
dmitriy-myz:moh-opencv-cleanup
Open

support for 06cb:00a2 (enroll on host, match on chip)#261
dmitriy-myz wants to merge 21 commits into
uunicorn:masterfrom
dmitriy-myz:moh-opencv-cleanup

Conversation

@dmitriy-myz

@dmitriy-myz dmitriy-myz commented Jun 1, 2026

Copy link
Copy Markdown

With claude code resurrected my old work on support for this device.

✔️ it successfully add finger to sensor database directly on linux.
✔️ recognize finger
✔️ reset flow works

Need help to test this for already working sensors (full MoC flow)

closes #253 closes #185 closes #170 closes #139

if anyone interested, documentation in my fork https://github.com/dmitriy-myz/python-validity/tree/moh-opencv-poc/docs/transformation-doc

dmitriy-myz and others added 3 commits March 3, 2021 16:33
…ght we add fingers to db? maybe just match images on hosts as we allready have finger image?
@Burghalim72

Burghalim72 commented Jun 1, 2026

Copy link
Copy Markdown

Works but not user-friendly. For some reason had to factory reset it on Windows, as the script shipped with python-validity returned various errors by itself, and dbus_service also was returning errors. After resetting, enrolling sometimes works, and sometimes spams enroll-stage-passed and eventually enroll-failed. I don't know if I am doing something wrong.

Later I identified enroll-retry-scan every six presses. No idea why six when on Windows it reports such problems immediately.

After around 20 minutes of trying, I was only able to enroll one finger.

@dmitriy-myz

Copy link
Copy Markdown
Author

@Burghalim72 have you tried to specify finger for enrollment? for me it failed because it trying to override same finger e.g.
fprintd-enroll -f right-thumb
fprintd-enroll -f right-index-finger
About reset command: this is true, reset blob most likely not correct

Uses RE from Windows dll

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dmitriy-myz dmitriy-myz force-pushed the moh-opencv-cleanup branch from 1e29c8f to f303917 Compare June 2, 2026 09:07
@Burghalim72

Copy link
Copy Markdown

I identified that enrolling breaks after enrolling one finger, until dbus_service is restarted. So with such hackfix is it possible to enroll all fingers by restarting it ten times, but it is obviously unacceptable on multi-user systems.

@Burghalim72

Burghalim72 commented Jun 2, 2026

Copy link
Copy Markdown

Deleting enrolled fingerprints does not work either. It is "permission denied" as regular user and "unknown method" as root. Factory reset remains broken and bricks the sensor until properly reset on Windows (though fingers enrolled on Linux remain enrolled).

@dmitriy-myz

dmitriy-myz commented Jun 2, 2026

Copy link
Copy Markdown
Author

enrolling breaks after enrolling one finger

fixed, thank you!

@Burghalim72

Burghalim72 commented Jun 2, 2026

Copy link
Copy Markdown

It actually turned out it is possible to delete fingers, but only all of them per user. There is no individual finger deleting option on Windows either, no idea if it is a bug, or the device itself lack the feature.

As for "bricking", I was wrong. I redirected the device to another VM that lacks the driver and didn't even finish booting, and then cancelled the redirection immediately. Then python-validity started working again. I guess what actually happened is that device breaks until it is reconnected.

Factory reset works to an extent with old blob from a few years ago. However, in such case the device actually cannot be used until it is connected to a Windows VM with a proper driver. But once done, factory reset is actually performed and there are no fingers.

@Burghalim72

Burghalim72 commented Jun 2, 2026

Copy link
Copy Markdown

Factory reset still requires booting into Windows to complete it. Maybe there are some other incorrect blobs.

I noticed CPU usage is higher when enrolling fingerprints via this program. When I enroll fingerprints, CPU fan starts spinning, which does not happen in Windows VM.

Enrolling itself seems to be different from Windows Hello as well. The latter not only asks to put a finger on the sensor six times, but sometimes also to put it three more times with different angles. python-validity never asks for this, at least if I understand it correctly.

Error "Exception: Unexpected TLS version 4 0" sometimes appears when running fprintd-verify (enroll just fails with enroll-failed immediately). I didn't manage to identify when it happens yet. Another random error identified later is dbus_service crashing with "[Errno 19] No such device (it may have been disconnected)".

Enrolling fingerprints on Windows Hello (Windows SID is not linked with Linux username via config at the moment) seems to cause individual fingerprints enrolled on Linux to disappear (so maybe individual fingerprints removal can be implemented?), but it doesn't seem to be caused by lack of space on the chip, as fingerprints can be readded on Linux, without affecting Windows ones. I don't know if it has anything to do with python-validity.

@Burghalim72

Copy link
Copy Markdown

With "fix reset flow" commit, reset can now be performed in a loop, but dbus_service doesn't work after it without booting into Windows VM. First time it just stops with no message, second time it is "FileNotFoundError: [Errno 2] No such file or directory: '/var/run/python-validity//6_07f_lenovo_sm_qm.xpfwext'", then more errors and timeouts.

@dmitriy-myz

Copy link
Copy Markdown
Author

I think /usr/bin/validity-sensors-firmware should be run at least once to download firmware. It in install script, so in normal flow it should download it on install.

@Burghalim72

Copy link
Copy Markdown

I see, last time I checked it, it didn't work, so I thought it is some broken command. After running it, reset started working, but for some reason I need to run dbus_service three times after factory reset. First two times there is no output and it just stops after a while, and only on third run it resumes normal operation.

@dmitriy-myz

Copy link
Copy Markdown
Author

Speaking of CPU usage on enroll: this is fine as instead of processing image directly on cpu it emulated in python code which is not efficient.
3 run of service is also kinda expected as after reset sensor rebooted three time:

  1. reset blob + reboot
  2. initial formatting + reboot
  3. firmware upload + reboot

@Burghalim72

Copy link
Copy Markdown

Is emulated code going to be optimized later, if possible in Python?

I think the only issue that remains for sure (aside bugs that appear randomly) is broken deletion of individual fingers, which is annoying as it is not easy task to enroll all 10 fingers perfectly from first try. Can it be fixed?

@dmitriy-myz

dmitriy-myz commented Jun 3, 2026

Copy link
Copy Markdown
Author

About optimization: I think no, enrollment is one-time operation to add finger into device DB So even if it CPU-expensive, I think this is fine. Regular finger recognition is done on chip and it the same as in Windows.

Deletion of all fingers is python-validity/fprintd responsibility as dbus-service only support to delete user from db. But you could stop python3-validity service and use script in this PR to list users/delete individual records

python scripts/enroll_moh_chip.py --list-users
...
2026-06-03 20:11:21,536 INFO     user dbid=4 identity=S-1-5-21-111111111-1111111111-1111111111-1000 fingers=2
2026-06-03 20:11:21,536 INFO       finger dbid=5 subtype=0x02
2026-06-03 20:11:21,536 INFO       finger dbid=6 subtype=0x03
python scripts/enroll_moh_chip.py --delete-dbid 6
...
2026-06-03 20:12:29,781 INFO ✓ deleted dbid=6
python scripts/enroll_moh_chip.py --list-users
...
2026-06-03 20:12:57,187 INFO     user dbid=4 identity=S-1-5-21-111111111-1111111111-1111111111-1000 fingers=1
2026-06-03 20:12:57,187 INFO       finger dbid=5 subtype=0x02

@Burghalim72

Burghalim72 commented Jun 3, 2026

Copy link
Copy Markdown

for me it failed because it trying to override same finger

Is it intended behavior by the way? If yes, maybe it should return enroll-duplicate instead of retry-scan?

Also, is it possible to make backup of the sensor memory contents, and then restore it? Because I may want to spend some time trying to enroll my fingerprints perfectly (which is likely to take a lot of attempts and hours, including for testing after some time passes), but also be able to test the sensor in various modes.

@dmitriy-myz

dmitriy-myz commented Jun 5, 2026

Copy link
Copy Markdown
Author

is it possible to make backup of the sensor memory contents, and then restore it

yes, sensor returns some finger data, but when I put it back it won't recognize finger. I think it should be possible to dump/restore but maybe there's some nuances.

dmitriy-myz and others added 5 commits June 6, 2026 10:16
…native

- Move the ~145-line native-pipeline enroll_moh() implementation out of the
  Sensor class into validitysensor/moh_enrollment.py as a free function
  enroll_moh(sensor, ...). Sensor.enroll_moh is now a thin delegator, so
  existing callers keep working and sensor.py stays device-agnostic.
- Fold moh_extract.py (template serializer, TID derivation, RE scaffold)
  into moh_native.py and delete moh_extract.py, so the MoH pipeline lives
  in a single module.

Lazy imports keep the sensor <-> moh_enrollment dependency acyclic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete dead symbols with zero callers anywhere: ATAN2_FULLSCALE,
subpix_refine_kps, tile_origin_yx, build_v30, find_v30_regions
(leftover from the retired moh_opencv module), _rotate_sample_pair, and
the now-transitively-dead V30_RECORD_LEN constant. Fix the docstrings/
comments that referenced them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
refactor(moh_native): remove unused code
Replace the bit-exact x86 fixed-point emulation in the MoH feature
pipeline with readable native Python/NumPy float math, to test whether a
non-byte-exact template still enrolls and matches on the 06cb:00a2 sensor.

- DoH front-end: real exp-Gaussian + central-diff/[1,2,1] kernels, float
  separable convolution; response rescaled by a fitted RESP_SCALE=17.04 so
  the existing NMS thresholds (t_lo/t_hi) stay valid.
- subpix: numpy.linalg.solve 2x2 Newton step (was Cramer/SAR).
- orientation: math.atan2 + plain binning (was fast_atan2 magic polys).
- descriptor: float cos/sin rotation + plain window sums.
- Dropped: _s32/_sar32/_imul32/_idiv32, EXP_TABLE, COS_Q16/SIN_Q16,
  gauss_tap, build_3tap, the atan2/angle-bin magic, and ~430 lines of dead
  RE scaffold (Minutia/FrameContext/orchestrate/EnrollmentSession/stage_*).
- Byte-format/framing (serialize_v30_section, merge, scaffold, TID,
  envelope) and all public signatures are unchanged.

1659 -> 671 lines. Verified: imports, end-to-end extract_frame_native +
native_template (23136B envelope, TID round-trips). Calibration in
dev/calib_resp_scale.py; design in docs/superpowers/specs/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Drop the now-unused logging import/binding (its only consumer,
  extract_features, was removed in the float rewrite).
- Comment desc_sample_rotate's off-tile 0.0 gradient fill (natural-units
  equivalent of the DLL's mid-gray; flat extension => zero gradient).
- Add tests/test_moh_native_smoke.py: guards the chip-parsed framing path
  (keypoint bounds, v30 record layout, 23136B envelope, TID round-trip,
  subpix rejection) without pinning byte-exact output.
- Remove the brainstorming design doc.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dmitriy-myz and others added 7 commits June 11, 2026 12:21
moh_native.py imports numpy at module top level, so the MoH/a2 enrollment
path hard-requires it. Add python3-numpy to debian Depends and numpy to
setup.py install_requires. (cv2 stays optional — enroll_moh_chip.py has an
ImportError fallback.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the cv2 import; the non-112x112 capture safety-net now always uses
the numpy nearest-neighbour resample (the cv2 bilinear path was optional
with this exact fallback). Captures are 112x112 in practice, so this path
is rarely hit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ure-stop skip

- enroll_moh_chip.py: remove personal paths (/media/sf_vbox-rw, .venv-poc),
  dangling dev/ doc references and RE jargon from help text/docstrings
- moh_native.py: same docstring cleanup; assert -> ValueError for input
  validation; drop dead None-guard in serialize_v30_section; note why both
  NMS thresholds are kept
- moh_enrollment.py: default num_frames 6 -> 4 (the template has 4 v30
  sections filled round-robin, so frames beyond the 4th were captured but
  never used) and align all frame-count docs; drop stale "byte-exact"
  wording (this is the float pipeline)
- sensor.py: comment why MoH devices skip the 0x04 capture-stop (chip
  returns an error after a streamed capture)
- .gitignore: drop personal .claude/ entry

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The template has 4 v30 sections, each holding one placement. Capturing 6
and keeping the 4 frames with the most keypoints (in capture order) lets
weak placements be dropped instead of silently discarding frames 5-6 as
before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The best-N-by-keypoint-count heuristic is a structural stand-in for the
DLL's quality-regression frame pick + cross-frame consensus cull, neither
of which is statically portable. Record the divergence so the next reader
knows it's an approximation, not a reproduction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Burghalim72

Copy link
Copy Markdown

I noticed that if I interrupt enrolling (I place finger wrong/notice my finger became wet or sensor became dirty or whatever, so I press ^C with intention to try again a few seconds later), and then try again, it starts spamming verify-retry-scan, and it takes a few tries until it stops.

Factory reset remains unreliable. I am eventually able to reset by repeating the command, but sometimes from second or third attempt as errors or timeouts appear.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment