技术部门就是悲催,考勤机坏了不换,直接给技术部门扔锅干活,要求尽快把考勤软件开发出来,时间长短不说要求还不少,不仅支持USB摄像头还得能支持监控摄像头,还要支持多人同时考勤,不能像原来那种识别精度查,速度慢的,一到下班门口就堆人,还要各种巴拉巴拉。。。。

       接锅干活!

       首先,人脸识别算法的问题,到底哪家强咱先不说,我对比了很多,起码虹软SDK的这个离线激活是真省心,每次只需要下载激活一次就能用一年,识别的精度和速度都还是非常OK的。那就从这个玩意下手整起来。

       一、虹软SDK的注册下载

       别告诉我不会,虹软官网,开发者自行去找,使用虹软SDK3.0目前是一年激活一次的那种,SDK提供的是C++和JAVA开发的,python也照样用,ctypes库就搞定了。

       二、界面效果和部分显示代码

       界面效果就这样了,管理啥的都在一起,这是个半成品,因为测试发现还是存在点问题,在老旧机器上的运行效率比较差,我就用VC++重新写了一个新的,这个就算是废弃了,在这里发出来,也就跟大家一起分享一下,算是抛砖引玉,看看有没有什么办法能够降低CPU和内存的占用,提高流畅度。不过,虽然说是半成品,其实也算是完成90%+了,不想买考勤机的完全可以拿去,足够使用!就是机器性能得稍微好点,起码比我这个四核四线程的4代U好就行了。

 检测摄像头,会提示,可以在插好摄像头之后重试连接;

 也支持RTSP摄像头,默认是USB。RTSP要根据不同品牌的监控摄像头设置地址,RTSP不能少。例如大华的就是这样的:rtsp://admin:adminpass@192.168.0.xx:554/cam/realmonitor?channel=1&subtype=0,起码你得能用VLC打开看到播放画面。

也支持不同的算法,但是效果不太好,被我舍弃了,就是那个face_recognition,我也用了人脸模型shape_predictor_68_face_landmarks.dat,程序里都写好了,支持自动下载,

# 检查人脸识别模型
    model_path = os.path.join(config.models_dir, "shape_predictor_68_face_landmarks.dat")
    if not os.path.exists(model_path):
        reply = QMessageBox.question(
            None,
            "模型缺失",
            "需要下载人脸识别模型(约100MB),现在下载吗?",
            QMessageBox.Yes | QMessageBox.No
        )
        if reply == QMessageBox.Yes:
            try:
                import urllib.request
                urllib.request.urlretrieve(
                    "http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2",
                    "model.bz2"
                )
                import bz2
                with bz2.open("model.bz2") as fr, open(model_path, "wb") as fw:
                    fw.write(fr.read())
                os.remove("model.bz2")
            except Exception as e:
                QMessageBox.critical(None, "下载失败", f"模型下载失败:{str(e)}")
                sys.exit(1)
        else:
            sys.exit(0)  # 用户选择不下载时直接退出

支持人员管理,就是没加密码验证;

人脸识别带框,有语音提醒(打卡成功),有界面显示姓名和打卡的区间;

自动显示到考勤列表,可以确认自己打上卡了,支持最多5人同时打卡,这也是虹软SDK的限制。有兴趣的可以去看看SDK的开发者手册,对接入方面有详细介绍。

最下面显示的是实时的时间,星期,调用了天气网的天气,使用了lunardate来计算农历做了汉字和生肖转换。代码如下:

首先是天气:

#-----------------添加天气显示功能-----------------
    def get_weather_info(self, city_code):
        try:
            url = f'http://www.weather.com.cn/weather/{city_code}.shtml'
            headers = {
                'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
            response = requests.get(url, headers=headers)
            response.encoding = 'utf - 8'
            soup = BeautifulSoup(response.text, 'html.parser')

            # 获取天气状况
            weather_status = soup.find('p', class_='wea').text

            # 获取温度相关数据
            tem_p = soup.find('p', class_='tem')
            current_temperature = tem_p.find('span').text if tem_p.find('span') else '无'
            other_temperatures = tem_p.find('i').text if tem_p.find('i') else '无'

            return weather_status, current_temperature, other_temperatures
        except requests.RequestException:
            return None, None, None

下面是星期,汉字月日和生肖年。

def update_display(self):
        current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        current_date = datetime.now().date()
        weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
        weekday = weekdays[current_date.weekday()]

        # 获取天气信息,这里假设城市代码为xxxxxxxx  城市代码你自己去天气网查你本地的!
        weather_status, current_temperature, other_temperatures = self.get_weather_info('xxxxx')
        if other_temperatures!= '无':
            self.time_label.setText(f"{current_time} {weekday} {weather_status} {current_temperature}-{other_temperatures}")
        else:
            self.time_label.setText(f"{current_time} {weekday} {weather_status} {current_temperature}")

        # 获取农历日期
        lunar = lunardate.LunarDate.fromSolarDate(datetime.now().year, datetime.now().month, datetime.now().day)
        lunar_month = lunar.month
        lunar_day = lunar.day

        # 定义农历月份和日期的汉字表示
        lunar_month_names = ["正月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "冬月", "腊月"]
        lunar_day_names = [
            "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
            "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
            "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"
        ]

        # 定义生肖列表
        zodiac_animals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']
        # 获取生肖
        zodiac_index = (lunar.year - 4) % 12
        zodiac = zodiac_animals[zodiac_index]

        # 获取对应的汉字表示
        lunar_month_str = lunar_month_names[lunar_month - 1]
        lunar_day_str = lunar_day_names[lunar_day - 1]

        # 组合成最终的农历日期字符串
        lunar_date_str = f"  农历{zodiac}年{lunar_month_str}{lunar_day_str}"
        self.lunar_date_label.setText(lunar_date_str)

支持考勤查询,自动根据考勤规则计算你是迟到,早退还是未打卡。我这单位是一天三次打卡,不知道你们一天打几次?

界面上的东西大体也就这么多了,第一篇先这样,算是抛砖引玉,第二篇主要聊代码。看看大家是否有需要吧,有需要的话我就直接传代码了,gitee上入库分享。

今天先到这里,目前VC++的也开发玩了,的确是流畅太多了,识别准确率方面没啥差别,但是就是不卡。我找了台双核4线程的十年前的老机器去考勤去了,嗖嗖的。

不得不感慨一下,AI太牛X,大部分代码压根都不用我自己写,只需要详细的对功能一介绍,马上代码就来了,自己再改改调试一下就OK了,码农看来也要失业了哇。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐