轶哥

📚 Having fun with AI Agent. Always learning.

    为Linux启用人脸识别登录/授权
    •   更新:2024-08-05 13:09:21
    •   首发:2022-04-06 22:11:48
    •   教程
    •   7136

    现在新购买默认搭载Windows系统的电脑一般都会提供一个Windows Hello身份认证方案,例如指纹或者人脸识别。Howdy是一个在Linux上模仿Windows Hello的程序,可以实现在系统用户登录锁屏登录sudo su等身份认证时候使用人脸识别。

    安装及调试

    Howdy开源地址:https://github.com/boltgolt/howdy

    Howdy程序本身的使用方法官方已经已经非常详细了,在此仅做补充,更新:直接安装二进制现已经不可行,需要按照官方说明的编译方法进行编译安装。

    除了说明提到的Ubuntu or Linux MintDebianArch LinuxFedoraopenSUSE这些Linux发行版之外,基于这些系统的一系列发行版系统都是可以用的。例如Raspberry Pi OSKali

    支持Windows Hello的笔记本电脑配有红外摄像头和红外光线发射器。红外网络摄像头通常可以在Linux上自动检测到,但默认情况下,红外光线发射器不起作用。为了使它们工作,请安装和配置linux-enable-ir-emitter

    配置中官方有启用说明:

    How to enable your infrared emitter ?

    1. linux-enable-ir-emitter -h (each sub-command also has a help -h)
    2. sudo linux-enable-ir-emitter configure look at the ir emitter and answer to the asked questions. You can specify your infrared camera with the option -d /dev/videoX, by default is /dev/video2.
    3. reboot

    补充一些调试细节:

    你的红外摄像头可能是/dev/video0,但是红外发射器+摄像头可能是/dev/video1。换句话说,这两个地址都可以调用摄像头,但是可能只有后者可以在调用摄像头的同时启动红外发射器。

    配置完成后可以通过linux-enable-ir-emitter test查看红外发射器是否可以正常工作,可以正常工作后可以通过linux-enable-ir-emitter boot设置开机启动。

    配置完红外功能后,再执行howdy test可以实时查看摄像头,拉上窗帘关闭灯看是否还能看清自己的脸。

    通过/lib/security/howdy/config.ini配置文件里面的dark_threshold参数可以调节黑暗阈值,由于红外发射器是闪烁的,某些频率摄像头可能完全看不到物体,可以通过测试不同的值获得更好的黑暗环境下识别的效果。

    常见问题

    Q: 我可以跳过"登录"按钮吗?

    A: 不可以。由于危险的行为和对调用sudo的担忧#170,在5.2.1+版本中删除了dismiss_lockscreen配置项。

    Q: 每次登录桌面都要输入用户名,是否可以设置默认登录用户?

    A: 严格来说这与howdy无关,而是与对应Linux发行版的Desktop程序有关系。常见的LightDM支持通过设置解决该问题。详见后文。

    Q: 提示登录密钥环没有被解锁。(The login keyring did no get unlocked)

    A: “我想说这不是一个问题,而是预期的。默认情况下,密钥环会使用您的密码 解密。 这是保证他们的存储安全的唯一方法。但是,一旦您登录,密钥环就会一直解密,因此我认为面部识别是一种快速再次登录的方式,而不是让您登录的主要方式。无论如何,这非常不安全。”——#39

    B: 实际上也可以通过命令登陆自动解锁。但是需要明文密码,并不安全。例如,在~/.profile中添加:

    echo -n "你的密码" | gnome-keyring-daemon --replace --unlock
    

    LightDM设置默认登录用户名

    执行lightdm --show-config可以看到当前LigntDM配置信息。

    $ lightdm --show-config  
       [Seat:*]
    B  greeter-session=lightdm-greeter
    B  greeter-hide-users=true
    B  session-wrapper=/etc/X11/Xsession
    
    Sources:
    B  /usr/share/lightdm/lightdm.conf.d/01_debian.conf
    B  /usr/share/lightdm/lightdm.conf.d/01_debian.conf
    C  /etc/lightdm/lightdm.conf
    

    可以看到配置文件B中配置了greeter-hide-users=true,我们只需要修改/usr/share/lightdm/lightdm.conf.d/01_debian.conf文件设置greeter-hide-users=false即可展示可选的登录用户信息,默认选中上一次登录的用户。如果配置文件B没有此配置项,那么可以直接在/etc/lightdm/lightdm.conf中添加该配置。

    LightDM 中的default-user配置选项早已在多年前被废弃。如果您的计算机被多人使用,那么默认选中的用户将会是最后一次登录的用户,因此,如果您希望固定默认选中的用户名,可以使用脚本动态修改/var/lib/lightdm/.cache/lightdm-gtk-greeter/state文件来实现固定默认用户的功能。

    1. 创建/usr/local/bin/lightdm-default-user脚本(脚本来自此处):

      #!/bin/sh
      
      # LightDM removed the default-user option.
      # The only recourse now is an ugly kludge. 
      
      # Note that if you want to default to the "Guest Session",
      # you need to specify the last user as "*guest".
      
      /bin/echo -e '[greeter]\nlast-user=*guest' > /var/lib/lightdm/.cache/lightdm-gtk-greeter/state
      
    2. 修改上诉脚本文件中的*guest为您的默认用户的用户名。

    3. 执行chmod 755 /usr/local/bin/lightdm-default-user赋予该脚本可执行权限。

    4. 编辑/etc/lightdm/lightdm.conf文件,添加下述内容,让lightdm在启动时自动运行该脚本:

      [SeatDefaults]
      greeter-setup-script=/usr/local/bin/lightdm-default-user
      

    正如原作者所说,这个方法比较丑陋,但却是目前最完美的解决方案。

    添加对Python3的支持

    轶哥在2022年10月29日使用的howdy仍然是2020年9月发布的2.6.1版本。在这期间howdy一直正常运行,然而随着各个Linux发行版逐步移除对python2的支持,导致howdy在升级了Linux系统后可能出现异常。

    注意: 使用3.0.0 beta版本无需修改下面代码。

    查看无法人脸识别的报错信息:

    cat /var/log/auth.log
    

    提示如下报错:

    Oct 27 23:24:26 [localhost] sudo:     yige : TTY=pts/0 ; PWD=/home/yige/Downloads ; USER=root ; COMMAND=/usr/bin/apt remove nodejs
    Oct 27 23:24:26 [localhost] /lib/security/howdy/pam.py[11808]: Traceback (most recent call last):
    Oct 27 23:24:26 [localhost] /lib/security/howdy/pam.py[11808]:   File "/lib/security/howdy/pam.py", line 10, in <module>
    Oct 27 23:24:26 [localhost] /lib/security/howdy/pam.py[11808]:     import ConfigParser
    Oct 27 23:24:26 [localhost] /lib/security/howdy/pam.py[11808]: ModuleNotFoundError: No module named 'ConfigParser'
    

    可见No module named 'ConfigParser'是由于ConfigParser模块出现异常。

    Python3中,ConfigParser已经更名为configparser

    目前howdy作者还没有发布新版本添加对python3的支持,因此可以通过手工修改/lib/security/howdy/pam.py文件实现兼容(不要遗漏import sys):

    # PAM interface in python, launches compare.py
    
    # Import required modules
    import subprocess
    import os
    import glob
    import sys
    import syslog
    
    # pam-python is running python 2, so we use the old module here
    if sys.version_info.major < 3:
        import ConfigParser
        config = ConfigParser.ConfigParser()
    else:
        import configparser
        config = configparser.ConfigParser()
    
    # Read config from disk
    config.read(os.path.dirname(os.path.abspath(__file__)) + "/config.ini")
    
    ...
    

    将此文件前面几行修改如上即可。重启后howdy即可正常运行。

    出现howdy not found

    先执行sudo ln /lib/security/howdy/cli.py /usr/local/bin/howdy,然后编辑:

    sudo vim /lib/security/howdy/cli.py
    

    import sys后面新增一行:

    sys.path.append('/lib/security/howdy')
    

    出现zsh: segmentation fault sudo pam-auth-update

    由于zsh: segmentation fault sudo pam-auth-update报错导致sudo命令无法使用,因此常规方法是无法恢复的。需要使用U盘引导到恢复模式进入root用户环境卸载howdy然后重新安装。

    出现Camera path is not configured correctly, please edit the 'device_path' config value.

    需要修改/lib/security/howdy/config.ini中的device_path为你的摄像头路径(/dev/videoX)。

    出现OpenCV警告信息

    [ WARN:0@2.157] global ./modules/videoio/src/cap_gstreamer.cpp (2401) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module source reported: Could not read from resource.
    [ WARN:0@2.158] global ./modules/videoio/src/cap_gstreamer.cpp (1356) open OpenCV | GStreamer warning: unable to start pipeline
    [ WARN:0@2.158] global ./modules/videoio/src/cap_gstreamer.cpp (862) isPipelinePlaying OpenCV | GStreamer warning: GStreamer: pipeline have not been created
    

    可以无视,如果介意的话添加到你的shell初始化脚本:

    export OPENCV_LOG_LEVEL=0
    export OPENCV_VIDEOIO_PRIORITY_INTEL_MFX=0
    

    GNOME 锁屏界面异常

    如果是2.6.x版本,可尝试将 /lib/security/howdy/compare.py 文件内容使用https://github.com/boltgolt/howdy/blob/caf244ce297d27d40168c40571b0fad6f7ee2596/src/compare.py代替即可。

    如果是3.0.0beta,参考下面这个没有找到pam.so文件的说明,然后编辑sudo vim /etc/pam.d/gdm-password,添加:auth sufficient /usr/local/lib/x86_64-linux-gnu/security/pam_howdy.so,路径替换为find / -name pam_howdy.so。同时参考避免conda环境影响使用中的内容指明模块路径。查看日志:sudo journalctl -u gdm,测试:sudo systemctl restart gdm

    没有找到pam.so文件

    编辑meson.options,修改option('install_pam_config', type: 'boolean', value: true, description: 'Install pam config file (for Debian/Ubuntu)')

    然后执行meson setup build --reconfigure重新配置和编译。

    避免conda环境影响使用

    编辑sudo vim /usr/local/lib/x86_64-linux-gnu/howdy/compare.py的头部,参考如下:

    #!/usr/bin/env python3
    # Compare incoming video with known faces
    # Running in a local python instance to get around PATH issues
    
    # Import time so we can start timing asap
    import time
    
    # Start timing
    timings = {
        "st": time.time()
    }
    
    # Import required modules
    import sys
    import os
    import json
    import configparser
    import getpass
    import subprocess
    
    # 检查当前Python解释器是否是Conda环境
    if 'conda' in sys.version or 'Continuum' in sys.version:
        print("Detected Conda environment. Switching to system Python 3...")
    
        # 获取当前脚本的路径
        script_path = os.path.abspath(__file__)
    
        # 构造命令使用系统的Python 3重新运行脚本
        command = f'/usr/bin/python3 {script_path}'
    
        # 调用系统的Python 3重新运行脚本
        subprocess.run(command, shell=True)
        sys.exit(0)
    
    print("Using system Python 3")
    
    # 强制添加dlib路径
    dlib_paths = [
        '/usr/local/lib/python3.11/dist-packages',
        '/home/yige/.local/lib/python3.11/site-packages'
    ]
    
    for path in dlib_paths:
        if path not in sys.path:
            sys.path.append(path)
    # 打印 Python 版本
    print(f"Python version: {sys.version}")
    
    # 打印运行的用户
    print(f"Running user: {getpass.getuser()}")
    
    # 尝试获取并打印 pip 版本
    try:
        pip_version = subprocess.check_output([sys.executable, '-m', 'pip', '--version'], text=True)
        print(f"pip version: {pip_version.strip()}")
    except Exception as e:
        print(f"Failed to get pip version: {e}")
    
    # 打印 sys.path
    print("sys.path:")
    for path in sys.path:
        print(f"  {path}")
    
    # 打印环境变量
    print("Environment variables:")
    for key, value in os.environ.items():
        print(f"  {key}: {value}")
    import dlib
    import cv2
    import datetime
    import atexit
    import subprocess
    import snapshot
    import numpy as np
    import _thread as thread
    import paths_factory
    from recorders.video_capture import VideoCapture
    from i18n import _
    

    更新说明

    2022年10月29日

    • 添加查看报错信息的方法
    • 添加对python3的支持
    • 修改文章名称

    2024年08月04日

    • 添加更多异常情况的解决办法。
    • 总而言之,遇到问题自己参考文章内容进行研究,风险自担。
    打赏
    交流区

    暂无内容

    尚未登陆
    发布
      上一篇 (Mac通用控制bug临时解决方案)
    下一篇 (Win11 多用户同时登录远程桌面配置方法)  

    评论回复提醒