baoshiwei
2025-04-22 88fc0f9f9b7fd3eb81c958ca41ed822cf3657c47
refactor: 重构中药识别项目
分为onnx版和openvino版
已添加19个文件
已复制5个文件
已重命名10个文件
23487 ■■■■■ 文件已修改
onnx/cam_util.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/config/herb_ai.yaml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/herb_ai.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/herb_ai.spec 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/herb_ai_.py 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/identifier.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/logger_config.py 补丁 | 查看 | 原始文档 | blame | 历史
onnx/model/herb_identify.onnx 补丁 | 查看 | 原始文档 | blame | 历史
onnx/model/hl.onnx 补丁 | 查看 | 原始文档 | blame | 历史
onnx/model/loading.onnx 补丁 | 查看 | 原始文档 | blame | 历史
onnx/model/safety_det.onnx 补丁 | 查看 | 原始文档 | blame | 历史
onnx/model/safety_det_.onnx 补丁 | 查看 | 原始文档 | blame | 历史
onnx/safety_detect.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/test.py 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/config/herb_ai.yaml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/herb_ai.py 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/identifier.py 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/logger_config.py 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/feeder_id/best.bin 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/feeder_id/best.xml 4756 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/feeder_id/metadata.yaml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/herb_id/best.bin 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/herb_id/best.xml 4486 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/herb_id/metadata.yaml 669 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/load_id/best.bin 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/load_id/best.xml 4756 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/load_id/metadata.yaml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/safe_det/best.bin 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/safe_det/best.xml 7975 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/model/safe_det/metadata.yaml 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/openvino_test.py 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/readme 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/safety_detect.py 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
openvino/test.py 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
onnx/cam_util.py
ÎļþÃû´Ó cam_util.py ÐÞ¸Ä
@@ -22,14 +22,23 @@
        for device in webcams:
            name = getattr(device, 'Name', None)
            pnp_class = getattr(device, 'PNPClass', None)
            if pnp_class == 'Camera':
                # å°†è®¾å¤‡åå­—和索引添加到字典中
                print(f"{name},{pnp_class}")
            if name is not None and self.cam1 in name:
                # å°†è®¾å¤‡åå­—和索引添加到字典中
                webcam_dict[self.cam1] = index
                index += 1
            elif name is not None and self.cam2 in name:
                # å°†è®¾å¤‡åå­—和索引添加到字典中
                webcam_dict[self.cam2] = index
                index += 1
            self.webcam_list = webcam_dict
        print(webcam_dict)
        # æŒ‰åç§°é‡æ–°æŽ’序
        webcam_dict = dict(sorted(webcam_dict.items(), key=lambda x: x[0]))
        print(webcam_dict)
        return webcam_dict
onnx/config/herb_ai.yaml
ÎļþÃû´Ó config/herb_ai.yaml ÐÞ¸Ä
@@ -7,7 +7,7 @@
log:
  path: "./log/herb_ai.log"
model:
  safe: './model/safety_det.onnx'
  safe: './model/safety_det_.onnx'
  cls: './model/herb_identify.onnx'
cam:
  cam1: 0
onnx/herb_ai.py
ÎļþÃû´Ó herb_ai.py ÐÞ¸Ä
@@ -304,6 +304,12 @@
        width = cv2.getWindowImageRect("AICamera")[2]
        height = cv2.getWindowImageRect("AICamera")[3]
        print("width", width, "height", height)
        # å¦‚æžœheight小于1则赋值100
        if height < 1:
            height = 100
        # è°ƒæ•´å›¾åƒå¤§å°ä»¥é€‚应窗口
        resized_frame = cv2.resize(draw_img, (width, height))
@@ -480,7 +486,7 @@
    load_identifier = IDENTIFIER("model/loading.onnx")
    hoister_position = IDENTIFIER("model/hl.onnx")
    safety_detect = SAFETY_DETECT("model/safety_det.onnx")
    safety_detect = SAFETY_DETECT("model/safety_det_.onnx")
    config = read_config()
    PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)
onnx/herb_ai.spec
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
    ['herb_ai.py'],
    pathex=[],
    binaries=[],
    datas=[],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
    optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
    pyz,
    a.scripts,
    [],
    exclude_binaries=True,
    name='herb_ai',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)
coll = COLLECT(
    exe,
    a.binaries,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='herb_ai',
)
onnx/herb_ai_.py
copy from herb_ai.py copy to onnx/herb_ai_.py
Îļþ´Ó herb_ai.py ¸´ÖÆ
@@ -10,6 +10,7 @@
import win32gui
import multiprocessing
from safety_detect import SAFETY_DETECT
from cam_util import CAM_UTIL
from identifier import IDENTIFIER
import os
from logger_config import logger
@@ -22,34 +23,11 @@
def variance_of_laplacian(image):
    # è®¡ç®—输入图像的拉普拉斯响应的方差
    return cv2.Laplacian(image, cv2.CV_64F).var()
def clean_directory(path, days_threshold, max_files):
    """清理超过时间或数量的文件"""
    now = time.time()
    threshold = now - days_threshold * 24 * 3600
    files = []
    for f in os.listdir(path):
        file_path = os.path.join(path, f)
        if os.path.isfile(file_path):
            files.append((file_path, os.path.getmtime(file_path)))
    # æŒ‰ä¿®æ”¹æ—¶é—´é™åºæŽ’序,保留最新文件
    files.sort(key=lambda x: x[1], reverse=True)
    # åˆ é™¤è¿‡æœŸæ–‡ä»¶
    for file_info in files:
        if file_info[1] < threshold:
            os.remove(file_info[0])
    # ä¿ç•™æœ€æ–°æ–‡ä»¶ï¼Œåˆ é™¤å¤šä½™æ–‡ä»¶
    for file_info in files[max_files:]:
        os.remove(file_info[0])
# è°ƒç”¨å¦ä¸€ä¸ªé•¿ç„¦é•œå¤´ï¼Œæ‹æ‘„清晰的局部药材图片
def get_image():
    herb_identifier = IDENTIFIER("model/herb_identify.onnx")
    logger.info("识别线程启动")
    global is_loaded, class_count, class_count_max, class_sum
    camera2_index = config['cam']['cam2']
    camera2_index = 1
    print("第二个摄像头索引:" + str(camera2_index))
    # æ‰“开摄像头
    capture = cv2.VideoCapture(camera2_index, cv2.CAP_DSHOW)
@@ -76,7 +54,7 @@
            break
        count += 1
        if count == config['cam']['frames']:
        if count == 10:
            herb_probabilities = herb_identifier(frame2)
            top_five_classes = np.argsort(herb_probabilities, axis=1)[0][-5:][::-1]
            name = ""
@@ -90,17 +68,16 @@
            # è®¡ç®—拉普拉斯响应的方差
            laplacian = variance_of_laplacian(frame2)
            # ç”Ÿæˆä¿å­˜æ–‡ä»¶åï¼Œä»¥å½“前时间命名
            save_name2 = time.strftime("%Y%m%d%H%M%S", time.localtime()) + "_" +name +"_["+ str(round(laplacian, 2)) +"]"+  ".jpg"
            save_name2 = name +"_["+ str(round(laplacian, 2)) +"]_"+ time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".jpg"
            logger.info(f"识别结果转换为保存图片名称:, {save_name2}")
            # åˆ¤æ–­å›¾åƒçš„æ¸…晰度
            # ä¿å­˜è°ƒæ•´å°ºå¯¸åŽçš„图片
            if laplacian > 200:
                c_ = save_path + "2/c/"
                # åˆ¤æ–­æ–‡ä»¶æ˜¯å¦å­˜åœ¨ï¼Œä¸å­˜åœ¨åˆ™åˆ›å»º
                if not os.path.exists(c_):
                    os.makedirs(c_)
                cv2.imwrite(c_ + save_name2, frame2)
                # æ–°å¢žæ¸…理调用
                clean_directory(c_, config['cam']['days_threshold'], config['cam']['max_files'])
                # æ¸…晰条件下累计识别结果中药材名称出现的次数
                # ç´¯è®¡æ¯ç§è¯æä¸è®ºåæ¬¡å‡ºçŽ°çš„æ¬¡æ•°,累计每种药材置信度最高的次数,累计每种药材的置信度总和
                # class_count = {}
@@ -127,11 +104,10 @@
                is_loaded = True
            else:
                n_ = save_path + "2/n/"
                # åˆ¤æ–­æ–‡ä»¶æ˜¯å¦å­˜åœ¨ï¼Œä¸å­˜åœ¨åˆ™åˆ›å»º
                if not os.path.exists(n_):
                    os.makedirs(n_)
                cv2.imwrite(n_ + save_name2, frame2)
                # æ–°å¢žæ¸…理调用
                clean_directory(n_, config['cam']['days_threshold'], config['cam']['max_files'])
            # cv2.imshow("Camera", resized_frame2)
            print("保存图片:", save_name2)
            break
@@ -139,30 +115,19 @@
    capture.release()
def send_result():
    global is_loaded,class_count, class_count_max, class_sum
    # å¯¹class_count进行排序,按照值从大到小排序,返回值最大的前五个
    sorted_class_count = dict(sorted(class_count.items(), key=lambda x: x[1], reverse=True)[:5])
    # å¯¹class_count_max进行排序,按照值从大到小排序,返回值最大的前五个
    sorted_class_count_max = dict(sorted(class_count_max.items(), key=lambda x: x[1], reverse=True)[:5])
    # å¯¹ class_sum进行排序,按照值从大到小排序,返回值最大的前五个
    sorted_class_sum = dict(sorted(class_sum.items(), key=lambda x: x[1], reverse=True)[:5])
    # å°†ä¸‰ç§ç»Ÿè®¡ç»“果输出到日志中
    logger.info("class_count:"+str(class_count))
    logger.info("sorted_class_count:"+str(sorted_class_count))
    logger.info("class_count_max:"+str(class_count_max))
    logger.info("sorted_class_count_max:"+str(sorted_class_count_max))
    logger.info("class_sum:"+str(class_sum))
    logger.info("sorted_class_sum:"+str(sorted_class_sum))
    is_loaded = False
    count_msg = "airecognize," + f"{sorted_class_count}"
    logger.info("发送药材识别结果:"+str(count_msg))
    l.send_msg(count_msg)
    l.send_msg("airecognize," + f"{class_count}")
    pass
def load_identify():
    global is_loaded
    global is_loaded, frame
    # æ‘„像头索引号,通常为0表示第一个摄像头
    camera_index = config['cam']['cam1']
    camera_index = 0
    print("第一个摄像头索引:" + str(camera_index))
    # æ‰“开摄像头
    cap = cv2.VideoCapture(camera_index, cv2.CAP_DSHOW)
@@ -182,24 +147,21 @@
    # è®¡æ—¶å™¨
    frame_count = 0
    start_time = time.time()
    stime = time.time()
    sstime = time.time()
    if not os.path.exists(save_path):
        os.makedirs(save_path)
    # ä¸Šæ¬¡è¯†åˆ«ç»“æžœ
    class_old = "1"
    # ç´¯è®¡æ¬¡æ•°
    count = 0
    # ä¸Šæ–™çŠ¶æ€
    status = "没有上料"
    # åˆ›å»ºçª—口并设置为可调整大小
    cv2.namedWindow("AICamera", cv2.WINDOW_NORMAL)
    # å¾ªçŽ¯è¯»å–æ‘„åƒå¤´ç”»é¢
    while True:
        logger.info("循环读取摄像头画面")
        # logger.info("循环读取摄像头画面")
        # ç¡çœ 100毫秒
        time.sleep(config['cam']['sleep'])
        time.sleep(0.1)
        ret, frame = cap.read()
        if not ret:
            print("无法读取摄像头画面")
@@ -207,12 +169,41 @@
            break
        # èŽ·å–å½“å‰æ—¶é—´
        current_time = time.time()
        # æ¯éš”3秒取一帧图像
        # æ¯éš”n秒取一帧图像
        if current_time - sstime >= config['cam']['sleep']:
            sstime = current_time
            thread1 = threading.Thread(target=method_name)
            thread1.start()
            # frame = draw_img
        # print(status)
        # è®¡ç®—帧速率
        # frame_count += 1
        # end_time = time.time()
        # elapsed_time = end_time - start_time
        # fps = frame_count / elapsed_time
        # # print(f"FPS: {fps:.2f}")
        # # å°†FPS绘制在图像上
        # cv2.putText(frame, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2,
        #             cv2.LINE_AA)
        # æ˜¾ç¤ºç”»é¢
        cv2.imshow("AICamera", frame)
        # æ£€æµ‹æŒ‰é”®ï¼Œå¦‚果按下q键则退出循环
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    # å…³é—­æ‘„像头
    cap.release()
    # å…³é—­æ‰€æœ‰çª—口
    cv2.destroyAllWindows()
def method_name(  ):
    global is_loaded,count,class_old,stime,frame
        # å®‰å…¨æ£€æµ‹
        boxes, scores, class_ids = safety_detect(frame)
        draw_img = safety_detect.draw_detections(frame, boxes, scores, class_ids)
    print(boxes, scores, class_ids)
        det_res = {}
        if class_ids is not None:
            # éåކclass_ids è½¬æ¢æˆç±»åˆ«åç§°
@@ -224,14 +215,10 @@
                    det_res[class_name] = det_res[class_name] if det_res[class_name] > scores[i] else scores[i]
                else:
                    det_res[class_name] = scores[i]
        print(det_res)
        logger.info(f"安全检测识别结果, {det_res}")
        # å¦‚æžœcass_ids中包含0,则表示有安全检测到人体
        if 0 in class_ids:
            res_ = "aidetect," + f"{det_res}"
            logger.info("发送安全检测结果:"+str(res_))
            l.send_msg(res_)
        l.send_msg("aidetect," + f"{det_res}")
        # ä¸Šæ–™è¯†åˆ«
        probabilities = load_identifier(frame)
        # æ‰¾åˆ°æœ€å¤§æ¦‚率的类别
@@ -251,6 +238,7 @@
            status = "正在上料"
            # æ¯éš”3秒取一帧图像
            # å¦‚果距离上一次保存已经过去1秒,则保存当前画面
        current_time = time.time()
            if current_time - stime >= 10.0:
                save_name = time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".jpg"
                # ä¿å­˜è°ƒæ•´å°ºå¯¸åŽçš„图片
@@ -258,8 +246,6 @@
                if not os.path.exists(path_):
                    os.makedirs(path_)
                cv2.imwrite(path_ + save_name, frame)
                # æ–°å¢žæ¸…理调用
                clean_directory(path_, config['cam']['days_threshold'], config['cam']['max_files'])
                # é‡ç½®è®¡æ—¶å™¨
                stime = time.time()
@@ -274,48 +260,6 @@
            if class_ == "meishangliao" and count == 1000:
                is_loaded = False
                logger.info("长时间未上料,重置正在上料状态")
        # print(status)
        # ä¸Šæ–™æœºä½ç½®è¯†åˆ«
        probabilities2 = hoister_position(frame);
        predicted_class2 = np.argmax(probabilities2, axis=1)[0]
        max_probability2 = np.max(probabilities2, axis=1)[0]
        class_2 = hoister_position.class_names[predicted_class2]
        print(f"-----------{class_2}:{predicted_class2}: {max_probability2}")
        logger.info(f"-----------{class_2}:{predicted_class2}: {max_probability2}")
        if predicted_class2 == 0:
            feeder_res = {class_2: max_probability2}
            class_feeder = "aifeeder," + f"{feeder_res}"
            print("send_msg", class_feeder)
            logger.info("发送上料机位置识别结果:"+str(class_feeder))
            l.send_msg(class_feeder)
        # è®¡ç®—帧速率
        frame_count += 1
        end_time = time.time()
        elapsed_time = end_time - start_time
        fps = frame_count / elapsed_time
        # print(f"FPS: {fps:.2f}")
        # å°†FPS绘制在图像上
        cv2.putText(draw_img, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2,
                    cv2.LINE_AA)
        # æ˜¾ç¤ºç”»é¢
        # èŽ·å–å½“å‰çª—å£å¤§å°
        width = cv2.getWindowImageRect("AICamera")[2]
        height = cv2.getWindowImageRect("AICamera")[3]
        # è°ƒæ•´å›¾åƒå¤§å°ä»¥é€‚应窗口
        resized_frame = cv2.resize(draw_img, (width, height))
        cv2.imshow("AICamera", resized_frame)
        # æ£€æµ‹æŒ‰é”®ï¼Œå¦‚果按下q键则退出循环
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    # å…³é—­æ‘„像头
    cap.release()
    # å…³é—­æ‰€æœ‰çª—口
    cv2.destroyAllWindows()
# è¯»å–配置文件
@@ -386,7 +330,7 @@
    def OnCopyData(self, hwnd, msg, wparam, lparam):
        try:
            # è®°å½•开始时间
            start_time = time.time()
            startTime = time.time()
            pCDS = ctypes.cast(lparam, PCOPYDATASTRUCT)
            s = ctypes.string_at(pCDS.contents.lpData).decode()
            strArr = s.split(",")
@@ -426,9 +370,9 @@
            logger.info(f"识别结果:{res}")
            self.send_msg(msg)
            # è®°å½•结束时间
            end_time = time.time()
            endTime = time.time()
            # è®¡ç®—执行时间
            execution_time = end_time - start_time
            execution_time = endTime - startTime
            # æ‰“印执行时间
            print(f"程序执行时间为:{execution_time}秒")
            logger.info(f"程序执行时间为:{execution_time,}秒")
@@ -468,6 +412,12 @@
    class_count_max = {}
    # ç´¯è®¡æ¯ç§è¯æçš„置信度总和
    class_sum = {}
    # ä¸Šæ¬¡è¯†åˆ«ç»“æžœ
    class_old = "1"
    # ç´¯è®¡æ¬¡æ•°
    count = 0
    stime = time.time()
    frame = None
    # cam1 = "USB Camera"
    # cam2 = "USB ZOOM Camera"
    # camUtil = CAM_UTIL(cam1, cam2)
@@ -477,9 +427,8 @@
    # æ˜¯å¦ä¸Šè¿‡æ–™
    is_loaded = False
    # åŠ è½½ONNX模型
    herb_identifier = IDENTIFIER("model/herb_identify.onnx")
    load_identifier = IDENTIFIER("model/loading.onnx")
    hoister_position = IDENTIFIER("model/hl.onnx")
    safety_detect = SAFETY_DETECT("model/safety_det.onnx")
    config = read_config()
    PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)
onnx/identifier.py
ÎļþÃû´Ó identifier.py ÐÞ¸Ä
@@ -14,7 +14,7 @@
        return self.idengify(image)
    def initialize_model(self, path):
        self.session = onnxruntime.InferenceSession(path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
        self.session = onnxruntime.InferenceSession(path, providers=['CPUExecutionProvider'])
        self.class_names = eval(self.session.get_modelmeta().custom_metadata_map['names'])
        # Get model info
        self.get_input_details()
onnx/logger_config.py
onnx/model/herb_identify.onnx
Binary files differ
onnx/model/hl.onnx
Binary files differ
onnx/model/loading.onnx
Binary files differ
onnx/model/safety_det.onnx
Binary files differ
onnx/model/safety_det_.onnx
Binary files differ
onnx/safety_detect.py
ÎļþÃû´Ó safety_detect.py ÐÞ¸Ä
@@ -18,7 +18,7 @@
        return self.detect_objects(image)
    def initialize_model(self, path):
        self.session = onnxruntime.InferenceSession(path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
        self.session = onnxruntime.InferenceSession(path, providers=['CPUExecutionProvider'])
        self.class_names = eval(self.session.get_modelmeta().custom_metadata_map['names'])
        # Get model info
        self.get_input_details()
onnx/test.py
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
import cv2
import win32com.client
import re
def get_camera_index_by_hardware_id():
    # èŽ·å–æ‰€æœ‰æ‘„åƒå¤´ç¡¬ä»¶ä¿¡æ¯
    wmi = win32com.client.GetObject("winmgmts:")
    cameras = []
    wmi_instances_of = wmi.InstancesOf("Win32_PnPEntity")
    for item in wmi_instances_of:
        if "Camera" ==   getattr(item, 'PNPClass', None):
            # æå–设备实例路径(如 USB\VID_046D&PID_0825\...)
            device_id = item.DeviceID
            cameras.append({
                "name": item.Name,
                "device_id": device_id
            })
    # éåކ OpenCV ç´¢å¼•,获取硬件信息
    opencv_indices = []
    for index in range(0, 10):
        cap = cv2.VideoCapture(index, cv2.CAP_DSHOW)  # ä½¿ç”¨ DirectShow æŽ¥å£
        if not cap.isOpened():
            continue
        # èŽ·å– OpenCV æ•获设备的硬件路径(需转换格式)
        cap_props = cap.getBackendName()
        hw_info = str(cap.get(cv2.CAP_PROP_HW_DEVICE))  # éƒ¨åˆ†é©±åŠ¨æ”¯æŒ
        # åŒ¹é…è®¾å¤‡å®žä¾‹è·¯å¾„中的关键标识符(如 VID/PID)
        for cam in cameras:
            # è½¬æ¢æ ¼å¼ï¼ˆä¾‹å¦‚:将 USB\VID_XXXX&PID_XXXX ä¸Žç¡¬ä»¶è·¯å¾„匹配)
            if re.search(cam["device_id"].split("\\")[-1], hw_info, re.IGNORECASE):
                opencv_indices.append({
                    "index": index,
                    "name": cam["name"],
                    "device_id": cam["device_id"]
                })
                break
        cap.release()
    return opencv_indices
# æµ‹è¯•代码
cameras = get_camera_index_by_hardware_id()
for cam in cameras:
    print(f"Index: {cam['index']} | Name: {cam['name']}")
openvino/config/herb_ai.yaml
copy from config/herb_ai.yaml copy to openvino/config/herb_ai.yaml
Îļþ´Ó config/herb_ai.yaml ¸´ÖÆ
@@ -7,12 +7,12 @@
log:
  path: "./log/herb_ai.log"
model:
  safe: './model/safety_det.onnx'
  safe: './model/safety_det_.onnx'
  cls: './model/herb_identify.onnx'
cam:
  cam1: 0
  cam2: 1
  sleep: 0.1
  frames: 50
  days_threshold: 7
  max_files: 100
  days_threshold: 100
  max_files: 10000
openvino/herb_ai.py
copy from herb_ai.py copy to openvino/herb_ai.py
Îļþ´Ó herb_ai.py ¸´ÖÆ
@@ -11,6 +11,7 @@
import multiprocessing
from safety_detect import SAFETY_DETECT
from identifier import IDENTIFIER
import os
from logger_config import logger
import threading
@@ -46,7 +47,7 @@
# è°ƒç”¨å¦ä¸€ä¸ªé•¿ç„¦é•œå¤´ï¼Œæ‹æ‘„清晰的局部药材图片
def get_image():
    herb_identifier = IDENTIFIER("model/herb_identify.onnx")
    herb_identifier = IDENTIFIER("./model/herb_id")
    logger.info("识别线程启动")
    global is_loaded, class_count, class_count_max, class_sum
    camera2_index = config['cam']['cam2']
@@ -179,9 +180,7 @@
    print("摄像头分辨率:", width, "x", height)
    logger.info(f"摄像头分辨率:, {width}, x, {height}")
    # ç›®æ ‡å›¾åƒå°ºå¯¸
    # è®¡æ—¶å™¨
    frame_count = 0
    start_time = time.time()
    stime = time.time()
    if not os.path.exists(save_path):
        os.makedirs(save_path)
@@ -197,7 +196,7 @@
    # å¾ªçŽ¯è¯»å–æ‘„åƒå¤´ç”»é¢
    while True:
        logger.info("循环读取摄像头画面")
        start_time = time.time()
        # ç¡çœ 100毫秒
        time.sleep(config['cam']['sleep'])
        ret, frame = cap.read()
@@ -211,7 +210,7 @@
        # å®‰å…¨æ£€æµ‹
        boxes, scores, class_ids = safety_detect(frame)
        draw_img = safety_detect.draw_detections(frame, boxes, scores, class_ids)
        draw_img = safety_detect.draw_detections(frame, class_ids, scores,boxes )
        det_res = {}
        if class_ids is not None:
@@ -277,7 +276,7 @@
        # print(status)
        # ä¸Šæ–™æœºä½ç½®è¯†åˆ«
        probabilities2 = hoister_position(frame);
        probabilities2 = hoister_position(frame)
        predicted_class2 = np.argmax(probabilities2, axis=1)[0]
        max_probability2 = np.max(probabilities2, axis=1)[0]
        class_2 = hoister_position.class_names[predicted_class2]
@@ -291,10 +290,8 @@
            logger.info("发送上料机位置识别结果:"+str(class_feeder))
            l.send_msg(class_feeder)
        # è®¡ç®—帧速率
        frame_count += 1
        end_time = time.time()
        elapsed_time = end_time - start_time
        fps = frame_count / elapsed_time
        fps = (1 / (end_time - start_time))
        # print(f"FPS: {fps:.2f}")
        # å°†FPS绘制在图像上
        cv2.putText(draw_img, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2,
@@ -303,6 +300,11 @@
        # èŽ·å–å½“å‰çª—å£å¤§å°
        width = cv2.getWindowImageRect("AICamera")[2]
        height = cv2.getWindowImageRect("AICamera")[3]
        # print("width", width, "height", height)
        # å¦‚æžœheight小于1则赋值100
        if height < 1:
            height = 100
        # è°ƒæ•´å›¾åƒå¤§å°ä»¥é€‚应窗口
        resized_frame = cv2.resize(draw_img, (width, height))
@@ -335,21 +337,6 @@
        ('cbData', ctypes.wintypes.DWORD),
        ('lpData', ctypes.c_char_p)
    ]
# logging.info("准备加载安全检测模型..")
# print("准备加载安全检测模型..")
# model_safe = SAFETY_DETECT(config['model']['safe'])
#
# logging.info("安全检测模型加载成功。")
# print("安全检测模型加载成功。")
# logging.info("准备加载药材识别模型..")
# print("准备加载药材识别模型..")
# model_cls = HERB_IDENTIFY(config['model']['cls'])
# logging.info("药材识别模型加载成功。")
# print("药材识别模型加载成功。")
class Listener:
    def __init__(self):
@@ -462,6 +449,8 @@
        return 0
if __name__ == '__main__':
    # ç´¯è®¡æ¯ç§è¯æä¸è®ºåæ¬¡å‡ºçŽ°çš„æ¬¡æ•°
    class_count = {}
    # ç´¯è®¡æ¯ç§è¯æç½®ä¿¡åº¦æœ€é«˜çš„æ¬¡æ•°
@@ -478,9 +467,10 @@
    is_loaded = False
    # åŠ è½½ONNX模型
    load_identifier = IDENTIFIER("model/loading.onnx")
    hoister_position = IDENTIFIER("model/hl.onnx")
    safety_detect = SAFETY_DETECT("model/safety_det.onnx")
    print("加载模型===============")
    load_identifier = IDENTIFIER("./model/load_id")
    hoister_position = IDENTIFIER("./model/feeder_id")
    safety_detect = SAFETY_DETECT("./model/safe_det")
    config = read_config()
    PCOPYDATASTRUCT = ctypes.POINTER(COPYDATASTRUCT)
openvino/identifier.py
copy from identifier.py copy to openvino/identifier.py
Îļþ´Ó identifier.py ¸´ÖÆ
@@ -1,7 +1,8 @@
import time
import cv2
import numpy as np
import onnxruntime
import yaml
from openvino.runtime import Core
class IDENTIFIER:
@@ -12,13 +13,29 @@
    def __call__(self, image):
        return self.idengify(image)
    def read_config(self, path):
        file_path = path+'/metadata.yaml'
        with open(file_path, 'r', encoding="utf-8") as file:
            config = yaml.safe_load(file)
        return config
    def initialize_model(self, path):
        self.session = onnxruntime.InferenceSession(path, providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
        self.class_names = eval(self.session.get_modelmeta().custom_metadata_map['names'])
        model_path = path + '/best.xml'
        # Initialize OpenVINO Runtime
        self.core = Core()
        # Load the model
        self.model = self.core.read_model(model=model_path)
        # Compile the model
        self.compiled_model = self.core.compile_model(model=self.model, device_name="CPU")
        # Get input and output layers
        self.input_layer = self.compiled_model.input(0)
        N,C,self.input_width,self.input_height = self.input_layer.shape
        self.output_layer = self.compiled_model.output(0)
        # Get class names
        self.class_names = CLASSES = self.read_config(path)['names']
        # Get model info
        self.get_input_details()
        self.get_output_details()
        # self.get_input_details()
        # self.get_output_details()
    def idengify(self, image):
        input_tensor = self.prepare_input(image)
@@ -26,9 +43,9 @@
        # Perform inference on the image
        outputs = self.inference(input_tensor)
        self.herb_probabilities = outputs[0]
        return self.herb_probabilities
        return outputs
    def prepare_input(self, image):
        self.img_height, self.img_width = image.shape[:2]
@@ -48,25 +65,25 @@
        return input_tensor
    def inference(self, input_tensor):
        start = time.perf_counter()
        outputs = self.session.run(self.output_names, {self.input_names[0]: input_tensor})
        ir = self.compiled_model.create_infer_request()
        outs = ir.infer(input_tensor)[self.output_layer]
        # print(f"Inference time: {(time.perf_counter() - start)*1000:.2f} ms")
        return outputs
        return outs
    def get_input_details(self):
        model_inputs = self.session.get_inputs()
        self.input_names = [model_inputs[i].name for i in range(len(model_inputs))]
    # def get_input_details(self):
    #     model_inputs = self.session.get_inputs()
    #     self.input_names = [model_inputs[i].name for i in range(len(model_inputs))]
    #
    #     self.input_shape = model_inputs[0].shape
    #     self.input_height = self.input_shape[2]
    #     self.input_width = self.input_shape[3]
        self.input_shape = model_inputs[0].shape
        self.input_height = self.input_shape[2]
        self.input_width = self.input_shape[3]
    def get_output_details(self):
        model_outputs = self.session.get_outputs()
        self.output_names = [model_outputs[i].name for i in range(len(model_outputs))]
    # def get_output_details(self):
    #     model_outputs = self.session.get_outputs()
    #     self.output_names = [model_outputs[i].name for i in range(len(model_outputs))]
    # ç­‰æ¯”例缩放图片
    def ratioresize(self, im, color=114):
openvino/logger_config.py
copy from logger_config.py copy to openvino/logger_config.py
openvino/model/feeder_id/best.bin
Binary files differ
openvino/model/feeder_id/best.xml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
openvino/model/feeder_id/metadata.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
description: Ultralytics YOLO11n-cls model trained on D:\项目资料\智能干燥设备\上料机位置\image3
author: Ultralytics
date: '2025-04-21T17:41:27.908573'
version: 8.3.53
license: AGPL-3.0 License (https://ultralytics.com/license)
docs: https://docs.ultralytics.com
stride: 1
task: classify
batch: 1
imgsz:
- 640
- 640
names:
  0: high
  1: low
openvino/model/herb_id/best.bin
Binary files differ
openvino/model/herb_id/best.xml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
openvino/model/herb_id/metadata.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,669 @@
description: Ultralytics YOLOv8m-cls model trained on D:\res_pic2
author: Ultralytics
date: '2025-04-18T13:34:07.698889'
version: 8.3.53
license: AGPL-3.0 License (https://ultralytics.com/license)
docs: https://docs.ultralytics.com
stride: 1
task: classify
batch: 1
imgsz:
- 640
- 640
names:
  0: Choulingdancao
  1: Dayezizhu
  2: aidicha
  3: aiye
  4: anxixiang
  5: awei
  6: badou
  7: baibeiyegen
  8: baibiandou
  9: baibu
  10: baifan
  11: baifuzi
  12: baiguo
  13: baihe
  14: baihelingzhi
  15: baihuadan
  16: baihuasheshecao
  17: baiji
  18: baijiangcao
  19: bailian
  20: baimagu
  21: baimaogen
  22: baiqian
  23: baishao
  24: baishihua
  25: baishiying
  26: baishouwu
  27: baitouweng
  28: baiwei
  29: baixianpi
  30: baiying
  31: baizhi
  32: baizhu
  33: bajiaofeng
  34: bajiaohuixiang
  35: bajiaolian
  36: bajitian
  37: banbianlian
  38: banfenghe
  39: banmao
  40: banxia
  41: banzhilian
  42: baomadingxiang
  43: baqia
  44: beidougen
  45: beiliujinu
  46: beishashen
  47: bianxu
  48: biba(bo)
  49: bichengqie
  50: biejia
  51: bimazi
  52: binglang
  53: bohe
  54: bohuohui
  55: buguzhi
  56: buzhaye
  57: cangerzi
  58: cangzhu
  59: caodoukou
  60: caoguo
  61: cebaiye
  62: chaihu
  63: changchunhua
  64: changshan
  65: chanhua
  66: chansha
  67: chansu
  68: chantui
  69: chenpi
  70: chenxiang
  71: cheqiancao
  72: cheqianzi
  73: chishao
  74: chishizhi
  75: chixiaodou
  76: chonglou
  77: chongweizi
  78: chongyayao
  79: chouwutong
  80: chuanbeimu
  81: chuanlianzi
  82: chuanmutong
  83: chuanposhi
  84: chuanshanjia
  85: chuanshanlong
  86: chuanwu
  87: chuanxinlian
  88: chuanxiong
  89: chuipencao
  90: chunpi
  91: chushizi
  92: cishi
  93: ciweipi
  94: ciwujia
  95: cixiancai
  96: congzi
  97: cuiyuncao
  98: cujiangcao
  99: dabogu
  100: dadouhuangjuan
  101: dafeiyangcao
  102: dafengai
  103: dafengzi
  104: dafupi
  105: dahuang
  106: daji
  107: dandouchi
  108: danfan
  109: danggui
  110: dangshen
  111: dangyao
  112: dannanxing
  113: danshen
  114: danzhuye
  115: daodou
  116: daokoucao
  117: daoya
  118: daqingye
  119: dasuan
  120: daxueteng
  121: dayeanye
  122: dazao
  123: dengxincao
  124: dengzhanxixin
  125: diburong
  126: diercao
  127: difengpi
  128: difuzi
  129: digupi
  130: dihuang
  131: dijincao
  132: dinggongteng
  133: dingxiang
  134: direngen
  135: dongchongxiacao
  136: dongfengju
  137: dongguapi
  138: dongkuizi
  139: donglingcao
  140: doukou
  141: duanxueliu
  142: duhuo
  143: duzhong
  144: duzhongye
  145: ebushicao
  146: eshen
  147: eshu
  148: fanbaicao
  149: fangfeng
  150: fangji
  151: fangjieshi
  152: fanshiliuye
  153: fanxieye
  154: feilongzhangxue
  155: feizi
  156: fenge
  157: fengfang
  158: fenghuangyi
  159: fengweicao
  160: fengxiangzhi
  161: fengyanguo
  162: foshou
  163: fuling
  164: fulonggan
  165: fupenzi
  166: fuping
  167: fushen
  168: fuxiaomai
  169: fuzi
  170: gancao
  171: gangbangui
  172: gangmeigen
  173: gangrengen
  174: ganjiang
  175: ganqi
  176: gansong
  177: gansui
  178: gaoben
  179: gaoliangjiang
  180: gegen
  181: gejie
  182: gonglaomu
  183: gouguye
  184: gouji
  185: gouqi
  186: goushen
  187: gouteng
  188: gualou
  189: guangdonghaitongpi
  190: guangdongliujinu
  191: guangdongwangbuliuxing
  192: guanghuoxiang
  193: guangzao
  194: guanhuangbo
  195: guanyejinsitao
  196: guanzhong
  197: guazijin
  198: guihua
  199: guijia
  200: guijianyu
  201: guipi
  202: guizhencao
  203: guizhi
  204: gujingcao
  205: gusuibu
  206: haigeke
  207: hailong
  208: haima
  209: haipiaoxiao
  210: haishen
  211: haitongpi
  212: haizao
  213: hancai
  214: hantaoye
  215: hehuamhua
  216: hehuanpi
  217: heidou
  218: heshi
  219: heshouwu
  220: hetaoren
  221: heye
  222: hezi
  223: hongdji
  224: hongdoukou
  225: honghua
  226: hongjingtian
  227: hongqi
  228: hongqu
  229: hongshen
  230: hongtiankui
  231: houpu
  232: houpuhua
  233: huaihua
  234: huaijiao
  235: huajiao
  236: huajuhong
  237: huangjing
  238: huangjingzi
  239: huanglian
  240: huangpihe
  241: huangqi
  242: huangqin
  243: huangshukui
  244: huangteng
  245: huangyaozi
  246: huashi
  247: hubeibeimu
  248: huercao
  249: hujiao
  250: hujisheng
  251: hulucha
  252: huomaren
  253: huotanmu
  254: hutuiziye
  255: huzhang
  256: jiangcan
  257: jianghuang
  258: jiangxiang
  259: jianhua
  260: jiaogulan
  261: jicai
  262: jidanhua
  263: jiegeng
  264: jigucao
  265: jiguxiang
  266: jili
  267: jindenglong
  268: jineijin
  269: jinfeicao
  270: jingjie
  271: jingtiansanqi
  272: jingucao
  273: jinguolan
  274: jinqiaomai
  275: jinsicao
  276: jintiesuo
  277: jinyingzi
  278: jinyinhua
  279: jishiteng
  280: jiubiying
  281: jiucengta
  282: jiujiechangpu
  283: jiulixiang
  284: jiulongteng
  285: jiuxiangchong
  286: jixuecao
  287: jixueteng
  288: jiyancao
  289: juanbai
  290: juemingzi
  291: juhe
  292: juhua
  293: juqu
  294: juqu2
  295: ketengzi
  296: kuandonghua
  297: kuanjinteng
  298: kudiding
  299: kudingcha
  300: kugua
  301: kulianpi
  302: kumaicai
  303: kumu
  304: kunbu
  305: kushen
  306: kushilian
  307: kuxingren
  308: lajiao
  309: laliao
  310: lanbuzheng
  311: langdu
  312: langyupi
  313: laoguancao
  314: leigongteng
  315: leiwan
  316: lianfang
  317: liangmianzhen
  318: liangtoujian
  319: lianqiancao
  320: lianqiao
  321: lianzi
  322: lianzixin
  323: liaogewang
  324: lilu
  325: lingxiangcao
  326: lingxiaohua
  327: lingzhi
  328: liushenqu
  329: liuyuehan
  330: lizhihe
  331: longchi
  332: longdan
  333: longgu
  334: longkui
  335: longliye
  336: longyanrou
  337: loulu
  338: luganshi
  339: lugen
  340: luobumaye
  341: luofumu
  342: luohanguo
  343: luole
  344: luoshiteng
  345: lurong
  346: luxiancao
  347: luying
  348: lvcao
  349: lvdou
  350: mabiancao
  351: mabo
  352: machixian
  353: madouling
  354: mahuang
  355: mahuanggen
  356: maidong
  357: maiya
  358: manjingzi
  359: manshanhong
  360: maozhaocao
  361: maqianzi
  362: maweilian
  363: meiguihua
  364: meihua
  365: mengchong
  366: mianbixie
  367: mianbixiepian
  368: mimenghua
  369: mohanlian
  370: molihua
  371: mubiezi
  372: mudanpi
  373: mudingxiang
  374: muer
  375: mufangji
  376: mugua
  377: muhao
  378: muhudie
  379: mujingye
  380: mujinhua
  381: mujinpi
  382: muli
  383: mumianhua
  384: muxiang
  385: muzei
  386: nanbanlangen
  387: nanguazi
  388: nanshanzha
  389: nanshashen
  390: nanwuweizi
  391: naosha
  392: naoyanghua
  393: niubangzi
  394: niudali
  395: niuduteng
  396: niuhuang
  397: niuxi
  398: nuodaogen
  399: nvzhenzi
  400: oujie
  401: pangdahai
  402: peilan
  403: pianjianghuang
  404: pijiuhua
  405: pipaye
  406: pugongying
  407: qiancao
  408: qianghuo
  409: qianhu
  410: qianjinba
  411: qianjinzi
  412: qianliguang
  413: qiannianjian
  414: qianniuzi
  415: qianrihong
  416: qianshi
  417: qingfengteng
  418: qingguo
  419: qinghao
  420: qingmuxiang
  421: qingniudan
  422: qingpi
  423: qingtiankui
  424: qingyangshe
  425: qingyedan
  426: qinjiao
  427: qinpi
  428: qiyelian
  429: qiyeyizhihua
  430: quanshen
  431: qumai
  432: rendongteng
  433: renshen
  434: renshenye
  435: ricaogen
  436: rongshuye
  437: roucongrong
  438: roudoukou
  439: ruiren
  440: sanbaicao
  441: sanbaicaogen
  442: sanfensan
  443: sangbaipi
  444: sangshen
  445: sangye
  446: sangzhipian
  447: sankezhen
  448: sanleng
  449: sanqi
  450: sanqipian
  451: sanyaku
  452: shaji
  453: shancigu
  454: shandayan
  455: shandougen
  456: shanglu
  457: shannai
  458: shanyao
  459: shanzha
  460: shanzhanye
  461: shanzhima
  462: shanzhuyu
  463: sharen
  464: shegan
  465: sheliugu
  466: shemei
  467: shencha
  468: shengjiangpi
  469: shengma
  470: shenjincao
  471: shetui
  472: shicancao
  473: shichangpu
  474: shidi
  475: shidiaolan
  476: shihu
  477: shihu2
  478: shijueming
  479: shijunzi
  480: shiliupi
  481: shinanteng
  482: shinanye
  483: shishangbai
  484: shisuan
  485: shiwei
  486: shouwuteng
  487: shuangshen
  488: shudihuang
  489: shuifeiji
  490: shuizhi
  491: shuqicao
  492: sigualuo
  493: sijiqing
  494: siyeshen
  495: songmu
  496: songxiang
  497: suanzaoren
  498: sumu
  499: suoluozi
  500: suoyang
  501: taibaimi
  502: taizishen
  503: tanxiang
  504: taoren
  505: taozhi
  506: tiandiding
  507: tiandong
  508: tianguadi
  509: tianguazi
  510: tianhuafen
  511: tianhusui
  512: tiankuizi
  513: tianma
  514: tiannanxing
  515: tianxianteng
  516: tianzhuhuang
  517: tiebaojin
  518: tiexian
  519: tongcao
  520: tougucao
  521: tubeimu
  522: tubiechong
  523: tujingpi
  524: tuniuexi
  525: walengzi
  526: wangbuliuxing
  527: wasong
  528: weilingxian
  529: wenjing
  530: wubeizi
  531: wugenteng
  532: wuhuaguo
  533: wuhuaguo2
  534: wuhuanzi
  535: wujiapi
  536: wujiuzi
  537: wulingzhi
  538: wumei
  539: wushaoshe
  540: wutongzi
  541: wuyao
  542: wuzhimaotao
  543: wuzhuyu
  544: xiakucao
  545: xiangfu
  546: xiangru
  547: xiangsizi
  548: xiangyuan
  549: xianhecao
  550: xianmao
  551: xiaobogu
  552: xiaobopi
  553: xiaohuixiang
  554: xiaoji
  555: xiaotongcao
  556: xiatianwu
  557: xiebai
  558: xiecao
  559: xiguapi
  560: xiheliu
  561: xihuangcao
  562: xinyi
  563: xionghuang
  564: xishuguo
  565: xixiancao
  566: xixin
  567: xiyangshen
  568: xuancaogen
  569: xuanshen
  570: xuchangqing
  571: xuduan
  572: xuefengteng
  573: xueshangyizhihao
  574: xueyutan
  575: xungufeng
  576: yadanzi
  577: yanduzhong
  578: yangqishi
  579: yangticao
  580: yanhusuo
  581: yanwo
  582: yazhangmupi
  583: yazhicao
  584: yejuhua
  585: yexiazhu
  586: yimucao
  587: yinchaihu
  588: yinchen
  589: yiner
  590: yingchunhua
  591: yingsuke
  592: yingtaohe
  593: yinxingye
  594: yinyanghuo
  595: yiyiren
  596: yizhi
  597: yizhihuanghua
  598: yizhijian
  599: yousongjie
  600: yuanbaocao
  601: yuanhua
  602: yuansuizi
  603: yuanzhi
  604: yuejihua
  605: yuganzi
  606: yujin
  607: yuliren
  608: yumixu
  609: yuxingcao
  610: yuyejinhua
  611: yuyuliang
  612: yuzhizi
  613: yuzhouloulu
  614: yuzhu
  615: zaojiao
  616: zaojiao1
  617: zaojiaoci
  618: zaojiaoci1
  619: zelan
  620: zeqi
  621: zexie
  622: zhangmu
  623: zhebeimu
  624: zhenzhumu
  625: zhigancao
  626: zhihuangqi
  627: zhijuzi
  628: zhimu
  629: zhiqiao
  630: zhishanzhuyu
  631: zhishi
  632: zhizhuxiang
  633: zhizi
  634: zhongjiefeng
  635: zhongrushi
  636: zhujieshen
  637: zhuling
  638: zhumagen
  639: zhuru
  640: zhushagen
  641: zhuyazao
  642: zhuzishen
  643: zibeichi
  644: zicao
  645: zicaorong
  646: ziheche
  647: zishaohua
  648: zisugeng
  649: zisuye
  650: zisuzi
  651: ziyuan
  652: zizhuye
  653: zonglv
  654: zoumajian
  655: zoumatai
openvino/model/load_id/best.bin
Binary files differ
openvino/model/load_id/best.xml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
openvino/model/load_id/metadata.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
description: Ultralytics YOLO11n-cls model trained on D:\项目资料\智能干燥设备\上料检测模型\tongjitang2
author: Ultralytics
date: '2025-04-21T17:26:08.188697'
version: 8.3.53
license: AGPL-3.0 License (https://ultralytics.com/license)
docs: https://docs.ultralytics.com
stride: 1
task: classify
batch: 1
imgsz:
- 640
- 640
names:
  0: meishangliao
  1: shangliao
openvino/model/safe_det/best.bin
Binary files differ
openvino/model/safe_det/best.xml
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
openvino/model/safe_det/metadata.yaml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,98 @@
description: Ultralytics best model trained on D:/项目资料/智能干燥设备/安全连锁模型/datasets/datasets/data.yaml
author: Ultralytics
date: '2025-04-17T16:29:33.343378'
version: 8.3.53
license: AGPL-3.0 License (https://ultralytics.com/license)
docs: https://docs.ultralytics.com
stride: 32
task: detect
batch: 1
imgsz:
- 640
- 640
names:
  0: person
  1: bicycle
  2: car
  3: motorcycle
  4: airplane
  5: bus
  6: train
  7: truck
  8: boat
  9: traffic light
  10: fire hydrant
  11: stop sign
  12: parking meter
  13: bench
  14: bird
  15: cat
  16: dog
  17: horse
  18: sheep
  19: cow
  20: elephant
  21: bear
  22: zebra
  23: giraffe
  24: backpack
  25: umbrella
  26: handbag
  27: tie
  28: suitcase
  29: frisbee
  30: skis
  31: snowboard
  32: sports ball
  33: kite
  34: baseball bat
  35: baseball glove
  36: skateboard
  37: surfboard
  38: tennis racket
  39: bottle
  40: wine glass
  41: cup
  42: fork
  43: knife
  44: spoon
  45: bowl
  46: banana
  47: apple
  48: sandwich
  49: orange
  50: broccoli
  51: carrot
  52: hot dog
  53: pizza
  54: donut
  55: cake
  56: chair
  57: couch
  58: potted plant
  59: bed
  60: dining table
  61: toilet
  62: tv
  63: laptop
  64: mouse
  65: remote
  66: keyboard
  67: cell phone
  68: microwave
  69: oven
  70: toaster
  71: sink
  72: refrigerator
  73: book
  74: clock
  75: vase
  76: scissors
  77: teddy bear
  78: hair drier
  79: toothbrush
  80: basket
  81: herb
  82: hoister
  83: netBoard
  84: roller
openvino/openvino_test.py
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
import numpy as np
import cv2, time
import yaml
from openvino.runtime import Core
# è¯»å–配置文件
def read_config(file_path='model/safe_det/metadata.yaml'):
    with open(file_path, 'r',encoding="utf-8") as file:
        config = yaml.safe_load(file)
    return config
MODEL_NAME = "model/best.xml"
CLASSES = read_config()['names']
colors = np.random.uniform(0, 255, size=(len(CLASSES), 3))
def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
    label = f'{CLASSES[class_id]} ({confidence:.2f})'
    color = colors[class_id]
    cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)
    cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
# å®žä¾‹åŒ–Core对象
core = Core()
# è½½å…¥å¹¶ç¼–译模型
# åŠ è½½æ¨¡åž‹
model_path = "model/safe_det/best.xml"  # æ›¿æ¢ä¸ºä½ çš„æ¨¡åž‹è·¯å¾„
model = core.read_model(model=model_path)
net = core.compile_model(model=model, device_name="CPU")
# èŽ·å¾—æ¨¡åž‹è¾“å‡ºèŠ‚ç‚¹
output_node = net.outputs[0]  # yolov8n只有一个输出节点
ir = net.create_infer_request()
cap = cv2.VideoCapture(0)
while True:
    start = time.time()
    ret, frame = cap.read()
    if not ret:
        break
    [height, width, _] = frame.shape
    length = max((height, width))
    image = np.zeros((length, length, 3), np.uint8)
    image[0:height, 0:width] = frame
    scale = length / 640
    blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
    outputs = ir.infer(blob)[output_node]
    outputs = np.array([cv2.transpose(outputs[0])])
    rows = outputs.shape[1]
    boxes = []
    scores = []
    class_ids = []
    for i in range(rows):
        classes_scores = outputs[0][i][4:]
        (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
        if maxScore >= 0.25:
            box = [outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]),
                   outputs[0][i][2], outputs[0][i][3]]
            boxes.append(box)
            scores.append(maxScore)
            class_ids.append(maxClassIndex)
    result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5)
    for i in range(len(result_boxes)):
        index = result_boxes[i]
        box = boxes[index]
        draw_bounding_box(frame, class_ids[index], scores[index], round(box[0] * scale), round(box[1] * scale),
                          round((box[0] + box[2]) * scale), round((box[1] + box[3]) * scale))
    end = time.time()
    print("start", start)
    print("end", end)
    print("time",end - start)
    # show FPS
    fps = (1 / (end - start))
    fps_label = "%.2f FPS" % fps
    cv2.putText(frame, fps_label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
    cv2.imshow('YOLOv8 OpenVINO Infer Demo on AIxBoard', frame)
    # wait key for ending
    if cv2.waitKey(1) > -1:
        cap.release()
        cv2.destroyAllWindows()
        break
openvino/readme
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
pyinstaller .\herb_ai.py --collect-all openvino
openvino/safety_detect.py
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,103 @@
import cv2
import numpy as np
import yaml
from openvino.runtime import Core
class SAFETY_DETECT:
    def __init__(self, path, conf_thres=0.35, iou_thres=0.5):
        self.conf_threshold = conf_thres
        self.iou_threshold = iou_thres
        # Initialize model
        self.initialize_model(path)
        self.color_palette = [(np.random.randint(0, 255), np.random.randint(0, 255), np.random.randint(0, 255)) for _ in
                              range(100)]
    def __call__(self, image):
        return self.detect_objects(image)
    def read_config(self, path):
        file_path = path+'/metadata.yaml'
        with open(file_path, 'r', encoding="utf-8") as file:
            config = yaml.safe_load(file)
        return config
    def initialize_model(self, path):
        model_path = path + '/best.xml'
        # Initialize OpenVINO Runtime
        self.core = Core()
        # Load the model
        self.model = self.core.read_model(model=model_path)
        # Compile the model
        self.compiled_model = self.core.compile_model(model=self.model, device_name="CPU")
        # Get input and output layers
        self.input_layer = self.compiled_model.input(0)
        self.output_layer = self.compiled_model.output(0)
        # Get class names
        self.class_names = CLASSES = self.read_config(path)['names']
    def detect_objects(self, frame):
        # èŽ·å¾—æ¨¡åž‹è¾“å‡ºèŠ‚ç‚¹
        ir = self.compiled_model.create_infer_request()
        [height, width, _] = frame.shape
        length = max((height, width))
        image = np.zeros((length, length, 3), np.uint8)
        image[0:height, 0:width] = frame
        self.scale = length / 640
        blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
        outputs = ir.infer(blob)[self.output_layer]
        outputs = np.array([cv2.transpose(outputs[0])])
        rows = outputs.shape[1]
        boxes = []
        scores = []
        class_ids = []
        for i in range(rows):
            classes_scores = outputs[0][i][4:]
            (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
            if maxScore >= 0.25:
                box = [outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]),
                       outputs[0][i][2], outputs[0][i][3]]
                boxes.append(box)
                scores.append(maxScore)
                class_ids.append(maxClassIndex)
        return boxes, scores, class_ids
    def draw_bounding_box(self, img, class_id, confidence, x, y, x_plus_w, y_plus_h):
        label = f'{self.class_names[class_id]} ({confidence:.2f})'
        color = self.color_palette[class_id]
        cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)
        cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
    def draw_detections(self, frame, class_ids, scores, boxes):
        result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5)
        for i in range(len(result_boxes)):
            index = result_boxes[i]
            box = boxes[index]
            self.draw_bounding_box(frame, class_ids[index], scores[index], round(box[0] * self.scale), round(box[1] * self.scale),
                              round((box[0] + box[2]) * self.scale), round((box[1] + box[3]) * self.scale))
        return frame
openvino/test.py
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
import time
import cv2
import numpy as np
from openvino.runtime import Core
def preprocess_image(image, input_size=(640, 640)):
    img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)  # è½¬æ¢ä¸º RGB
    img_resized = cv2.resize(img, input_size)  # è°ƒæ•´å¤§å°
    img_normalized = img_resized / 255.0  # å½’一化
    img_transposed = np.transpose(img_normalized, (2, 0, 1))  # HWC -> CHW
    img_batch = np.expand_dims(img_transposed, axis=0).astype(np.float32)  # å¢žåŠ  batch ç»´åº¦
    return img_batch, img_resized
def postprocess(output, conf_threshold=0.5, iou_threshold=0.4):
    # è§£æžè¾“出
    boxes = []
    scores = []
    class_ids = []
    for detection in output[0]:
        confidence = detection[4]
        if confidence > conf_threshold:
            class_id = np.argmax(detection[5:])
            cx, cy, w, h = detection[:4]  # ä¸­å¿ƒç‚¹å’Œå®½é«˜
            x_min = int((cx - w / 2) * original_image.shape[1])  # è½¬æ¢å›žåŽŸå§‹å›¾åƒå°ºå¯¸
            y_min = int((cy - h / 2) * original_image.shape[0])
            width = int(w * original_image.shape[1])
            height = int(h * original_image.shape[0])
            boxes.append([x_min, y_min, width, height])
            scores.append(confidence)
            class_ids.append(class_id)
    # éžæžå¤§å€¼æŠ‘制 (NMS)
    indices = cv2.dnn.NMSBoxes(boxes, scores, conf_threshold, iou_threshold)
    final_boxes = []
    for idx in indices:
        box = boxes[idx]
        final_boxes.append({
            "box": box,
            "score": scores[idx],
            "class_id": class_ids[idx]
        })
    return final_boxes
def draw_detections(image, detections):
    for det in detections:
        x_min, y_min, width, height = det["box"]
        class_id = det["class_id"]
        score = det["score"]
        # ç¡®ä¿åæ ‡å’Œå°ºå¯¸æ˜¯æ•´æ•°
        x_min = int(x_min)
        y_min = int(y_min)
        width = int(width)
        height = int(height)
        # ç»˜åˆ¶è¾¹ç•Œæ¡†
        cv2.rectangle(image, (x_min, y_min), (x_min + width, y_min + height), (0, 255, 0), 2)
        # æ˜¾ç¤ºç±»åˆ«å’Œç½®ä¿¡åº¦
        label = f"Class {class_id}: {score:.2f}"
        cv2.putText(image, label, (x_min, y_min - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
    return image
if __name__ == "__main__":
    # åˆå§‹åŒ– OpenVINO Runtime
    core = Core()
    # åŠ è½½æ¨¡åž‹
    model_path = "model/safe_det/best.xml"  # æ›¿æ¢ä¸ºä½ çš„æ¨¡åž‹è·¯å¾„
    model = core.read_model(model=model_path)
    compiled_model = core.compile_model(model=model, device_name="CPU")  # è®¾å¤‡å¯ä»¥æ˜¯ "CPU", "GPU", "MYRIAD" ç­‰
    # èŽ·å–è¾“å…¥å’Œè¾“å‡ºå±‚
    input_layer = compiled_model.input(0)
    output_layer = compiled_model.output(0)
    # æ‰“印输入输出信息
    print(f"Input shape: {input_layer.shape}")
    print(f"Output shape: {output_layer.shape}")
    # é¢„处理图像,改为从摄像头获取
    cap = cv2.VideoCapture(0)
    # åˆå§‹åŒ–变量
    start_time = time.time()  # è®°å½•开始时间
    frame_count = 0  # å¸§è®¡æ•°å™¨
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        input_data, original_image = preprocess_image(frame)
        # æŽ¨ç†
        results = compiled_model([input_data])[output_layer]
        # è¾“出结果
        print(results)
        detections = postprocess(results)
        # æ‰“印检测结果
        for det in detections:
            print(det)
        draw_img = draw_detections(frame, detections)
        # è®¡ç®—FPS
        frame_count += 1
        elapsed_time = time.time() - start_time
        fps = frame_count / elapsed_time
        # start_time = time.time()  # é‡ç½®å¼€å§‹æ—¶é—´
        # frame_count = 0  # é‡ç½®å¸§è®¡æ•°å™¨
        # æ˜¾ç¤ºFPS
        cv2.putText(draw_img, f"FPS: {fps:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv2.imshow("Detections", draw_img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break