You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python Ctypes获取Futronic FS88h指纹扫描仪图像

问题核心原因

你当前无法获取图像的问题出在两个地方:

  1. 对ftrScanGetImage的接口定义错误:该接口并非仅接收设备句柄、返回布尔值,而是需要调用方提前传入预分配好的图像缓冲区指针,布尔返回值仅代表采集是否成功。你代码里还误将restype写为restypes,会导致ctypes解析返回值异常。
  2. 未提前获取图像尺寸参数:不知道单帧图像占用的内存大小,无法分配长度匹配的缓冲区,和你找到的C示例里先获取图像尺寸再分配内存的逻辑对应。
实现步骤
  • 补全SDK依赖的基础类型、图像尺寸结构体定义,避免因结构体内存对齐错误导致调用崩溃。
  • 打开设备后先调用ftrScanGetImageSize接口,获取采集图像的宽、高、单帧字节数。Futronic FS88h输出的是8位单通道灰度图,无需额外做色彩空间转换。
  • 按照获取到的单帧大小,创建ctypes的c_ubyte数组作为接收缓冲区。
  • 检测到手指放置后,将设备句柄、缓冲区指针传入ftrScanGetImage接口完成采集。如果需要未经过SDK优化的原始裸数据,可以替换为C示例中提到的ftrScanGetFrame接口,两者参数完全一致。
  • 采集成功后将缓冲区二进制数据转换为图像数组,用PIL或OpenCV保存为本地可查看的图片文件即可。
  • 操作完成后记得调用ftrScanCloseDevice关闭设备句柄,避免占用设备资源。
完整可运行代码
from ctypes import windll, wintypes
import ctypes
import time
import numpy as np
from PIL import Image

# 加载SDK
lib = ctypes.WinDLL('ftrScanAPI.dll')

# 补全基础类型定义
FTRHANDLE = ctypes.c_void_p
FTR_BYTE = ctypes.c_ubyte
FTR_WORD = ctypes.c_ushort
FTR_DWORD = ctypes.c_ulong
FTR_BOOL = wintypes.BOOL

# 结构体定义
class FTRSCAN_DEVICE_INFO(ctypes.Structure):
    _fields_ = [
        ("dwStructSize", FTR_DWORD),
        ("byDeviceCompatibility", FTR_BYTE),
        ("wPixelSizeX", FTR_WORD),
        ("wPixelSizeY", FTR_WORD)
    ]
PFTRSCAN_DEVICE_INFO = ctypes.POINTER(FTRSCAN_DEVICE_INFO)

class FTRSCAN_FAKE_REPLICA_PARAMETERS(ctypes.Structure):
    _fields_ = [
        ("bCalculated", FTR_BOOL),
        ("nCalculatedSum1", ctypes.c_int),
        ("nCalculatedSumFuzzy", ctypes.c_int),
        ("nCalculatedSumEmpty", ctypes.c_int),
        ("nCalculatedSum2", ctypes.c_int),
        ("dblCalculatedTremor", ctypes.c_double),
        ("dblCalculatedValue", ctypes.c_double),
    ]
PFTRSCAN_FAKE_REPLICA_PARAMETERS = ctypes.POINTER(FTRSCAN_FAKE_REPLICA_PARAMETERS)

class FTRSCAN_FRAME_PARAMETERS(ctypes.Structure):
    _fields_ = [
        ("nContrastOnDose2", ctypes.c_int),
        ("nContrastOnDose4", ctypes.c_int),
        ("nDose", ctypes.c_int),
        ("nBrightnessOnDose1", ctypes.c_int),
        ("nBrightnessOnDose2", ctypes.c_int),
        ("nBrightnessOnDose3", ctypes.c_int),
        ("nBrightnessOnDose4", ctypes.c_int),
        ("FakeReplicaParams", FTRSCAN_FAKE_REPLICA_PARAMETERS),
    ]
PFTRSCAN_FRAME_PARAMETERS = ctypes.POINTER(FTRSCAN_FRAME_PARAMETERS)

# 图像尺寸结构体
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
    _fields_ = [
        ("nWidth", ctypes.c_int),
        ("nHeight", ctypes.c_int),
        ("nImageSize", ctypes.c_int)
    ]

if __name__ == "__main__":
    # 打开设备
    lib.ftrScanOpenDevice.argtypes = []
    lib.ftrScanOpenDevice.restype = FTRHANDLE
    h_device = lib.ftrScanOpenDevice()
    if not h_device:
        raise RuntimeError("设备打开失败,请检查连接和驱动")

    # 获取图像尺寸
    img_size = FTRSCAN_IMAGE_SIZE()
    lib.ftrScanGetImageSize.argtypes = [FTRHANDLE, ctypes.POINTER(FTRSCAN_IMAGE_SIZE)]
    lib.ftrScanGetImageSize.restype = FTR_BOOL
    if not lib.ftrScanGetImageSize(h_device, ctypes.byref(img_size)):
        lib.ftrScanCloseDevice(h_device)
        raise RuntimeError("获取图像尺寸失败")
    print(f"图像参数:宽{img_size.nWidth}px,高{img_size.nHeight}px,单帧大小{img_size.nImageSize}字节")

    # 分配图像缓冲区
    img_buffer = (ctypes.c_ubyte * img_size.nImageSize)()
    frame_parameters = FTRSCAN_FRAME_PARAMETERS()

    # 配置接口参数
    lib.ftrScanIsFingerPresent.argtypes = [FTRHANDLE, PFTRSCAN_FRAME_PARAMETERS]
    lib.ftrScanIsFingerPresent.restype = FTR_BOOL
    lib.ftrScanGetImage.argtypes = [FTRHANDLE, ctypes.POINTER(ctypes.c_ubyte)]
    lib.ftrScanGetImage.restype = FTR_BOOL
    lib.ftrScanCloseDevice.argtypes = [FTRHANDLE]
    lib.ftrScanCloseDevice.restype = FTR_BOOL

    try:
        print("请将手指放在扫描仪上...")
        while True:
            if lib.ftrScanIsFingerPresent(h_device, ctypes.byref(frame_parameters)):
                # 延时100ms等帧稳定
                time.sleep(0.1)
                ret = lib.ftrScanGetImage(h_device, img_buffer)
                if ret:
                    # 转换为图像文件
                    img_arr = np.frombuffer(img_buffer, dtype=np.uint8).reshape((img_size.nHeight, img_size.nWidth))
                    img = Image.fromarray(img_arr, mode='L')
                    img.save("fingerprint.bmp")
                    print("指纹图像已保存为 fingerprint.bmp")
                    break
                else:
                    print("采集失败,请重新放置手指")
            time.sleep(0.05)
    finally:
        # 确保设备被关闭
        lib.ftrScanCloseDevice(h_device)
注意事项
  • 如果需要获取SDK未做降噪、对比度调整的原始采集数据,把代码里的ftrScanGetImage替换为ftrScanGetFrame即可,参数定义无需修改。
  • 不要将图像按RGB三通道解析,FS88h输出的是单通道8位灰度数据,按三通道解析会出现花屏、尺寸不匹配问题。
  • 运行代码前确保ftrScanAPI.dll放在代码同级目录或者系统System32路径下,同时安装好设备官方驱动,否则会出现加载dll失败、找不到设备的问题。

内容的提问来源于stack exchange,提问作者Eduardo Aldana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 16:33:26