17track物流查询平台 last-event-id 参数逆向分析

7xrWpJ.png

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请在公众号【K哥爬虫】联系作者立即删除!

逆向目标

目标:17xx 物流查询平台 last-event-id 参数逆向分析

网站:aHR0cHM6Ly93d3cuMTd0cmFjay5uZXQvemgtY24=

抓包分析

打开 F12 ,映入眼帘的就是我们熟悉的 debugger , 我们直接看它触发 debugger 的 js 文件:

7xv4uJ.png

7xvCOG.png

又是经典的 ob 混淆, 这里直接借用 v佬 的插件快速还原,工具地址如下:

Github 仓库:https://github.com/cilame/v_jstools

在线分析工具:https://astexplorer.net

看了一下也不需要我们做另外的预处理操作了,只需要把代码 ob 混淆的部分放入工具内就可以还原了:

7xvjlt.png

还原后,过 debugger 就容易多了,只需要将下面这几个关于代码检测的函数都删除掉,都是些无关的代码,检测代码格式化 、debugger 等:

7xvnVb.png

7xvIJe.png

7xvfTP.png

然后再通过工具替换代码,这边选用 ReRes 工具进行替换,写好规则保存勾选就好了:

https://github.com/annnhan/ReRes

7xvihw.png

7xrU2P.png

我们就可以正常抓包分析代码了,目标参数:

7xvsY6.png

通过搜索 last-event-id 就可以定位到,其就在我们解完混淆的文件里:

7xv2dO.png

7xvFwQ.png

解完混淆后代码就清晰可见,缺啥扣啥,一步步来就好了,代码也不多,可见 AST 解混淆的重要性。

注意点:

  • _0x308754 = YQ.configs.md5 来自首页 html 中,通过搜索可以确定:

7xvZOf.png

  • 请求需要携带 cookie 值 _yq_bid 并且要和生成 last-event-id 中的 _yq_bid 一致。

附上完整的 JS 代码:

var _0x199099 = [];
var _0x19d69d = "";
var _0x308754 = "17";
var _0x58ecad = 0;
var _0x269b49 = "";
var _0x288444 = 5;
function _0x5879b4(_0x56b807, _0x3603af) {
    var _0x2f5b4a = 1315423911 ^ _0x3603af << 16;
    var _0x4844e9;
    var _0x4d42c4;
    for (_0x4844e9 = _0x56b807.length - 1; _0x4844e9 >= 0; _0x4844e9--) {
        _0x4d42c4 = _0x56b807.charCodeAt(_0x4844e9);
        _0x2f5b4a ^= (_0x2f5b4a << 5) + _0x4d42c4 + (_0x2f5b4a >> 2);
    }
    return _0x4243f2(4),
    Math.abs(_0x2f5b4a & 2147483647);
};

function _0x4243f2(_0x8916b) {
    _0x199099[3] = _0x8916b;
}


function _0x1d212e(_0x3ffdba) {
    if (!_0x3ffdba)
        return 0;
    var _0x9920fa = 5381;
    var _0x55570f = _0x3ffdba.length;
    while (_0x55570f) {
        _0x9920fa = _0x9920fa * 33 ^ _0x3ffdba.charCodeAt(--_0x55570f);
    }
    return _0x9920fa >>> 0;
};

function _0x39b7cc(_0x18dcad) {
    return _0x18dcad.split("").reverse().join("");
};


function _0x402770(_0x1e4f12) {
    var _0x3bcbe3 = "";
    for (var _0x5f5a6c = 0; _0x5f5a6c < _0x1e4f12.length; _0x5f5a6c++) {
        if (_0x3bcbe3 == "")
            _0x3bcbe3 = _0x1e4f12.charCodeAt(_0x5f5a6c).toString(16);
        else
            _0x3bcbe3 += _0x1e4f12.charCodeAt(_0x5f5a6c).toString(16);
    }
    return _0x3bcbe3;
};

;function _0x4293c9(_0x5b936d) {
    function _0x44c5b9(_0x185712, _0x240a39, _0xc135ae, _0x4da978, _0x511583) {
        return _0x56f850(_0x185712 - 152, _0x240a39 - 498, _0xc135ae - 247, _0x4da978 - -820, _0x240a39);
    }
    var _0x147e74 = _0x5b936d;
    while (_0x147e74.length < 8) {
        _0x147e74 = "0" + _0x147e74;
    }
    return _0x147e74;
}

;function _0x59789d(_0x20b526, _0x117056, _0x2c2317) {
    var _0x26536c = _0x5879b4(_0x20b526, _0x117056);
    if (_0x2c2317) {
        _0x199099[5] = _0x4293c9(_0x26536c.toString(16));
        return;
    }
    _0x199099[4] = _0x4293c9(_0x26536c.toString(16));
};

function _0x187331(_0xcae6a6) {
    var _0x59eb35 = _0xcae6a6;

    var _0x46a854 = Math.random();
    _0x59eb35 = Math.round(_0x46a854 * _0xcae6a6);
    _0x288444 = _0x288444 * _0x288444;
    
    _0x199099[1] = _0x59eb35.toString(16);
    _0x199099[2] = _0x59eb35.toString(16).length;
    return _0x59eb35;
};

function createGUID(e, t) {
    var o = (new Date).getTime();
    return (e || "G-xxxxxxxxxxxxxxxx").replace(t || /[xy]/g, function(e) {
        var t = (o + 16 * Math.random()) % 16 | 0;
        return ("x" == e ? t : 7 & t | 8).toString(16).toUpperCase()
    })
}




function get_last_event_id(_0x19d69d, YQ_md5){
    _yq_bid = createGUID();
    _0x4566f3 = undefined;
    _0x59789d(_0x19d69d, _0x19d69d.length, !![])
    _0x6de72e = _0x187331(43)


    var _0x5d4d80 = "yq-";
    _0x58ecad = _0x6de72e;

    // 指纹信息 24: screen.colorDepth
    cancas_fp = '24\r\nzh-CN\r\n-480\r\n1067x1707\r\ndata:image/png;base64,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+nvXGm0L1ZPFO/6e271RWX1vkJZz3/SeYr3dMepg//0Tlim4B7Uuw3J9yH/jEWsd5OOBfOXt/pbQcnpY2wjobgO1nILe7efv5v3q6SmP+JRXnQiLnzbW0tr4s9eB5ej6bs7/bt/7II91t7FZvl9YYfGJ3Gzo+meh/K9//nbC4vPni/5As2oSDxdU95fuhc+DEhZPDXlVO/fF+h6rGWldCYuPYrrozX/BoZ723wuvByURdatEhJnJfRfWvSQHn3mwBO5EWA82ogdztLoU1oM5AxwFwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEMAwhImVQgUBEAAwkINgAAICEPg/wHI0p2WviCNVgAAAABJRU5ErkJggg=='

    var _0x2b62a6 = _0x1d212e(cancas_fp);
    var _0x5d74a6 = _0x1d212e(_0x4566f3);

    if (_0x6de72e == 0)
    _0x5d4d80 += "random";
    else {
    _0x5d4d80 = "dropdown-menu-footer yq-user-footer clearfix";   // 目测可以写死或者随机取
    }
    _0x269b49 = _yq_bid;


    _0x5d4d80 = _0x269b49;
    (_0x58ecad = _0x58ecad * 50,
    _0x5d4d80 += ":" + false + ":" + _0x2b62a6 + ":" + _0x6de72e + ":" + _0x58ecad);
    _0x5d4d80 += "/" + Date.now().toString(16) + "/11/" + true + "/" + new Date().getTimezoneOffset().toString() + "/" + _0x2b62a6 + "/" + YQ_md5 + "/" + _0x5d74a6;
    _0x59789d(_0x5d4d80, _0x6de72e);
    _0x5d4d80 = _0x402770(_0x39b7cc(_0x5d4d80));
    _0x199099[0] = _0x5d4d80;
    return [_0x199099.join(""), _yq_bid]

};

console.log(get_last_event_id('{"data":[{"num":"LZ025387152CN","fc":0,"sc":0}],"guid":"","timeZoneOffset":-480}', '22c342b'));

结果验证

7xvdic.png

# -*- coding: utf-8 -*- """ Traffic Monitoring System v2.5 (Camera Version) Features: - Real-time camera object detection - YOLOv8 object detection - ByteTrack tracking - Matching colors for boxes and trajectories - Huawei Cloud IoT data reporting - Movable table - Trajectory display """ import os import sys import cv2 import numpy as np import torch import supervision as sv from ultralytics import YOLO from typing import Dict, Optional, Tuple, List import warnings import time import logging import socket import json from pathlib import Path from collections import defaultdict, deque # Import Huawei IoT SDK with encoding handling try: from iot_device_sdk_python.client.client_conf import ClientConf from iot_device_sdk_python.client.connect_auth_info import ConnectAuthInfo from iot_device_sdk_python.iot_device import IotDevice from iot_device_sdk_python.client.request.service_property import ServiceProperty except ImportError as e: logging.error(f"Huawei IoT SDK import error: {str(e)}") sys.exit(1) # Configure global logging with UTF-8 encoding logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(), logging.FileHandler('traffic_monitor.log', encoding='utf-8', mode='a') ] ) logger = logging.getLogger("TrafficMonitor") class Config: """System configuration parameters""" MODEL_PATH = r"C:\Users\yuanb\Desktop\物联网设计大赛无pyqt同时MQTT传输\runs\detect\train_v8\weights\best.pt" CLASS_NAMES = { 0: 'Pedestrian', 1: 'Person', 2: 'Bicycle', 3: 'Car', 4: 'Van', 5: 'Truck', 6: 'Tricycle', 7: 'CoveredTricycle', 8: 'Bus', 9: 'Motorcycle' } # Color palette for different classes CLASS_COLORS = { 0: (255, 0, 0), # Red - Pedestrian 1: (0, 255, 0), # Green - Person 2: (0, 0, 255), # Blue - Bicycle 3: (255, 255, 0), # Yellow - Car 4: (255, 0, 255), # Magenta - Van 5: (0, 255, 255), # Cyan - Truck 6: (255, 128, 0), # Orange - Tricycle 7: (128, 0, 255), # Purple - CoveredTricycle 8: (0, 128, 255), # Light Blue - Bus 9: (255, 0, 128) # Pink - Motorcycle } IOT_CONFIG = { "server_uri": "117.78.5.125", "port": 1883, "device_id": "681eeebc9314d118511a5690_DEV4", "secret": "Wjy15640916538", "service_id": "鲁班猫4", "use_tls": False, "keep_alive": 300, "clean_session": False } REPORT_INTERVAL = 10 MIN_REPORT_INTERVAL = 30 LINE_COLOR = sv.Color(r=0, g=255, b=0) TEXT_COLOR = (255, 255, 255) # White text for better visibility FONT_SCALE = 0.7 TABLE_POSITION = (10, 400) # Initial position, will be updated by mouse TABLE_ROW_HEIGHT = 30 TABLE_COL_WIDTH = 180 # Increased width TABLE_COLORS = { 'header': (0, 100, 255), 'row_even': (50, 50, 50), 'row_odd': (80, 80, 80), 'text': (255, 255, 255) } TRACK_HISTORY_LENGTH = 30 # Number of trajectory points to keep class LineCounter: """Improved counting logic with bidirectional counting and classification""" def __init__(self, start_point: sv.Point, end_point: sv.Point): self.start = start_point self.end = end_point self.tracker_state = {} self.counts = { 'Inbound_Vehicle': 0, 'Outbound_Vehicle': 0, 'Inbound_Pedestrian': 0, 'Outbound_Pedestrian': 0, 'Total_Vehicles': 0, 'Total_Pedestrians': 0 } self.class_mapping = { 'Vehicle': {3, 4, 5, 6, 7, 8, 9}, 'Pedestrian': {0, 1} } self.history = [] def _get_side(self, point: sv.Point) -> bool: """Calculate which side of the line the point is on (cross product method)""" vector_line = (self.end.x - self.start.x, self.end.y - self.start.y) vector_point = (point.x - self.start.x, point.y - self.start.y) cross_product = vector_line[0] * vector_point[1] - vector_line[1] * vector_point[0] return cross_product > 0 def update(self, detections: sv.Detections): """Update counter state""" current_counts = { 'Inbound_Vehicle': 0, 'Outbound_Vehicle': 0, 'Inbound_Pedestrian': 0, 'Outbound_Pedestrian': 0, } for xyxy, _, confidence, class_id, tracker_id in detections: if tracker_id is None or confidence < 0.5: continue # Calculate center point x1, y1, x2, y2 = xyxy center = sv.Point(x=int((x1 + x2) / 2), y=int((y1 + y2) / 2)) current_side = self._get_side(center) # Initialize new object if tracker_id not in self.tracker_state: self.tracker_state[tracker_id] = current_side continue # Check if crossed the line if self.tracker_state[tracker_id] != current_side: if class_id in self.class_mapping['Vehicle']: direction = 'Inbound' if current_side else 'Outbound' current_counts[f'{direction}_Vehicle'] += 1 self.counts[f'{direction}_Vehicle'] += 1 self.counts['Total_Vehicles'] += 1 elif class_id in self.class_mapping['Pedestrian']: direction = 'Inbound' if current_side else 'Outbound' current_counts[f'{direction}_Pedestrian'] += 1 self.counts[f'{direction}_Pedestrian'] += 1 self.counts['Total_Pedestrians'] += 1 self.tracker_state[tracker_id] = current_side if any(current_counts.values()): self.history.append({ 'timestamp': time.time(), 'counts': current_counts.copy() }) def get_counts(self) -> Dict[str, int]: """Get current statistics""" return self.counts.copy() def get_recent_counts(self, seconds=10) -> Dict[str, int]: """Get counts from recent specified time period""" recent_counts = { 'Inbound_Vehicle': 0, 'Outbound_Vehicle': 0, 'Inbound_Pedestrian': 0, 'Outbound_Pedestrian': 0 } cutoff = time.time() - seconds for record in reversed(self.history): if record['timestamp'] < cutoff: break for key in recent_counts: recent_counts[key] += record['counts'].get(key, 0) return recent_counts class HuaweiIoTClient: """Huawei Cloud IoT Client""" def __init__(self, config: dict): self.config = config self.device = None self.max_retries = 5 self.base_reconnect_delay = 5 self.last_report_time = 0 self._initialize_client() def _initialize_client(self): """Initialize client connection""" try: auth_info = ConnectAuthInfo() auth_info.server_uri = self.config["server_uri"] auth_info.port = self.config["port"] auth_info.id = self.config["device_id"] auth_info.secret = self.config["secret"] self.config["use_tls"] = False client_conf = ClientConf(auth_info) client_conf.clean_session = self.config["clean_session"] client_conf.keep_alive = self.config["keep_alive"] client_conf.will_topic = f"$oc/devices/{self.config['device_id']}/sys/events/down" client_conf.will_message = json.dumps({ "type": "ABNORMAL_DISCONNECT", "timestamp": time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) }) self.device = IotDevice(client_conf) self._connect_with_retry() except Exception as e: logger.error(f"Client initialization failed: {str(e)}") raise def _check_network(self) -> bool: """Check network connectivity""" try: with socket.create_connection( (self.config["server_uri"], self.config["port"]), timeout=10 ): return True except Exception as e: logger.warning(f"Network check failed: {str(e)}") return False def _connect_with_retry(self): """Exponential backoff reconnection mechanism""" retry_count = 0 while retry_count < self.max_retries: try: if not self._check_network(): raise ConnectionError("Network unavailable") result = self.device.connect() if result == 0: logger.info(f"Connection successful (attempt {retry_count + 1}/{self.max_retries})") return True wait_time = min(self.base_reconnect_delay * (2 ** retry_count), 60) logger.warning(f"Connection failed, retrying in {wait_time} seconds... (error code: {result})") time.sleep(wait_time) retry_count += 1 except Exception as e: wait_time = min(self.base_reconnect_delay * (2 ** retry_count), 60) logger.error(f"Connection exception: {str(e)}, retrying in {wait_time} seconds") time.sleep(wait_time) retry_count += 1 logger.error("Max retries reached, giving up") return False def is_connected(self) -> bool: """Check connection status""" try: return (self.device is not None and hasattr(self.device, 'get_client') and self.device.get_client().is_connected()) except Exception as e: logger.warning(f"Connection status check exception: {str(e)}") return False def report_traffic_data(self, counts: Dict[str, int]) -> bool: """Data reporting method""" current_time = time.time() if current_time - self.last_report_time < Config.MIN_REPORT_INTERVAL: return False if not self.is_connected(): logger.warning("Connection lost, attempting to reconnect...") if not self._connect_with_retry(): return False try: service = ServiceProperty() service.service_id = self.config["service_id"] service.properties = { "vehicle_in": counts.get('Inbound_Vehicle', 0), "vehicle_out": counts.get('Outbound_Vehicle', 0), "vehicle_total": counts.get('Total_Vehicles', 0), "person_in": counts.get('Inbound_Pedestrian', 0), "person_out": counts.get('Outbound_Pedestrian', 0), "person_total": counts.get('Total_Pedestrians', 0), "timestamp": int(time.time() * 1000) } service.event_time = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) result = self.device.get_client().report_properties([service]) if result == 0: self.last_report_time = current_time logger.info(f"Data reported successfully: {service.properties}") return True logger.error(f"Reporting failed, return code: {result}") return False except Exception as e: logger.error(f"Reporting exception: {str(e)}") return False class TrafficMonitor: """Main traffic monitoring program""" def __init__(self): # Hardware configuration self.device = 'cuda' if torch.cuda.is_available() else 'cpu' logger.info(f"Running on: {self.device.upper()}") # Model loading self.model = self._load_model() self.tracker = sv.ByteTrack() self.line_counter = None self.frame_count = 0 self.current_tracks = {} self.track_history = defaultdict(lambda: deque(maxlen=Config.TRACK_HISTORY_LENGTH)) # Visualization tools with custom color settings self.box_annotator = sv.BoundingBoxAnnotator(color_lookup=sv.ColorLookup.TRACK) self.label_annotator = sv.LabelAnnotator(color_lookup=sv.ColorLookup.TRACK) self.line_annotator = sv.LineZoneAnnotator( thickness=2, text_thickness=1, text_scale=0.5 ) # Table properties self.table_position = list(Config.TABLE_POSITION) self.is_dragging = False self.drag_offset = (0, 0) # Huawei Cloud connection try: self.iot_client = HuaweiIoTClient(Config.IOT_CONFIG) except Exception as e: logger.error(f"Huawei IoT client initialization failed: {str(e)}") self.iot_client = None def _load_model(self) -> YOLO: """Load YOLO model""" try: model = YOLO(Config.MODEL_PATH) model.fuse() logger.info(f"Model loaded successfully, detection classes: {model.names}") return model except Exception as e: logger.error(f"Model loading failed: {str(e)}") sys.exit(1) def set_counting_line(self, start: Tuple[int, int], end: Tuple[int, int]): """Set counting line coordinates""" self.line_counter = LineCounter( start_point=sv.Point(*start), end_point=sv.Point(*end) ) logger.info(f"Counting line set: {start} -> {end}") def _draw_stats(self, frame: np.ndarray, counts: Dict[str, int]) -> np.ndarray: """Draw statistics on frame""" stats = [ f"Inbound Vehicle: {counts['Inbound_Vehicle']}", f"Outbound Vehicle: {counts['Outbound_Vehicle']}", f"Total Vehicles: {counts['Total_Vehicles']}", f"Inbound Pedestrian: {counts['Inbound_Pedestrian']}", f"Outbound Pedestrian: {counts['Outbound_Pedestrian']}", f"Total Pedestrians: {counts['Total_Pedestrians']}" ] for i, text in enumerate(stats): cv2.putText( frame, text, (10, 30 + i * 30), cv2.FONT_HERSHEY_SIMPLEX, Config.FONT_SCALE, Config.TEXT_COLOR, 2 ) return frame def _draw_data_table(self, frame: np.ndarray, counts: Dict[str, int], recent_counts: Dict[str, int]) -> np.ndarray: """Draw movable data table""" x, y = self.table_position row_height = Config.TABLE_ROW_HEIGHT col_width = Config.TABLE_COL_WIDTH # Calculate table dimensions num_cols = 3 num_rows = 5 # Header + 4 data rows table_width = num_cols * col_width table_height = num_rows * row_height # Draw table background cv2.rectangle(frame, (x, y), (x + table_width, y + table_height), (40, 40, 40), -1) # Table header headers = ["Metric", "Total", "Last 10s"] for i, header in enumerate(headers): cv2.rectangle(frame, (x + i * col_width, y), (x + (i + 1) * col_width, y + row_height), Config.TABLE_COLORS['header'], -1) cv2.putText(frame, header, (x + i * col_width + 10, y + int(row_height * 0.7)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, Config.TABLE_COLORS['text'], 1) # Data rows rows = [ ("Inbound Vehicle", counts['Inbound_Vehicle'], recent_counts['Inbound_Vehicle']), ("Outbound Vehicle", counts['Outbound_Vehicle'], recent_counts['Outbound_Vehicle']), ("Inbound Pedestrian", counts['Inbound_Pedestrian'], recent_counts['Inbound_Pedestrian']), ("Outbound Pedestrian", counts['Outbound_Pedestrian'], recent_counts['Outbound_Pedestrian']) ] for row_idx, (label, total, recent) in enumerate(rows): bg_color = Config.TABLE_COLORS['row_even'] if row_idx % 2 == 0 else Config.TABLE_COLORS['row_odd'] # Draw row background cv2.rectangle(frame, (x, y + (row_idx + 1) * row_height), (x + table_width, y + (row_idx + 2) * row_height), bg_color, -1) # Draw cell content cv2.putText(frame, label, (x + 10, y + (row_idx + 1) * row_height + int(row_height * 0.7)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, Config.TABLE_COLORS['text'], 1) cv2.putText(frame, str(total), (x + col_width + 10, y + (row_idx + 1) * row_height + int(row_height * 0.7)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, Config.TABLE_COLORS['text'], 1) cv2.putText(frame, str(recent), (x + 2 * col_width + 10, y + (row_idx + 1) * row_height + int(row_height * 0.7)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, Config.TABLE_COLORS['text'], 1) # Draw drag handle (small rectangle at top-right) handle_size = 20 cv2.rectangle(frame, (x + table_width - handle_size, y), (x + table_width, y + handle_size), (0, 255, 255), -1) return frame def _handle_table_drag(self, event, x, y, flags, param): """Mouse callback for table dragging""" table_x, table_y = self.table_position table_width = 3 * Config.TABLE_COL_WIDTH table_height = 5 * Config.TABLE_ROW_HEIGHT handle_size = 20 # Check if mouse is in drag handle area handle_rect = (table_x + table_width - handle_size, table_y, table_x + table_width, table_y + handle_size) if event == cv2.EVENT_LBUTTONDOWN: if (handle_rect[0] <= x <= handle_rect[2] and handle_rect[1] <= y <= handle_rect[3]): self.is_dragging = True self.drag_offset = (x - table_x, y - table_y) elif event == cv2.EVENT_LBUTTONUP: self.is_dragging = False elif event == cv2.EVENT_MOUSEMOVE: if self.is_dragging: # Update table position with offset new_x = x - self.drag_offset[0] new_y = y - self.drag_offset[1] # Keep table within frame bounds frame_height, frame_width = param.shape[:2] new_x = max(0, min(new_x, frame_width - table_width)) new_y = max(0, min(new_y, frame_height - table_height)) self.table_position = [new_x, new_y] def _draw_tracks(self, frame: np.ndarray, detections: sv.Detections) -> np.ndarray: """Draw object trajectories with matching colors""" for xyxy, _, confidence, class_id, tracker_id in detections: if tracker_id is None or confidence < 0.5: continue # Get color based on class color = Config.CLASS_COLORS.get(class_id, (255, 255, 255)) # Default to white if class not found # Calculate center point x1, y1, x2, y2 = xyxy center = (int((x1 + x2) / 2), int((y1 + y2) / 2)) # Update track history self.track_history[tracker_id].append(center) # Draw trajectory line points = list(self.track_history[tracker_id]) for i in range(1, len(points)): cv2.line(frame, points[i - 1], points[i], color, thickness=2) # Draw bounding box with same color cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), color, 2) # Display ID and class label = f"{Config.CLASS_NAMES.get(class_id, 'Unknown')} ID:{tracker_id}" cv2.putText(frame, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) return frame def _update_track_info(self, detections: sv.Detections): """Update tracking object information""" current_tracks = {} for xyxy, _, confidence, class_id, tracker_id in detections: if tracker_id is not None: current_tracks[tracker_id] = (class_id, confidence) self.current_tracks = current_tracks def process_frame(self, frame: np.ndarray) -> np.ndarray: """Process single frame""" try: # Object detection results = self.model(frame, imgsz=640, verbose=False)[0] detections = sv.Detections.from_ultralytics(results) # Object tracking with ByteTrack detections = self.tracker.update_with_detections(detections) self._update_track_info(detections) # Initialize count results counts = { 'Inbound_Vehicle': 0, 'Outbound_Vehicle': 0, 'Inbound_Pedestrian': 0, 'Outbound_Pedestrian': 0, 'Total_Vehicles': 0, 'Total_Pedestrians': 0 } recent_counts = { 'Inbound_Vehicle': 0, 'Outbound_Vehicle': 0, 'Inbound_Pedestrian': 0, 'Outbound_Pedestrian': 0 } if self.line_counter: # Update counter self.line_counter.update(detections) counts = self.line_counter.get_counts() recent_counts = self.line_counter.get_recent_counts(seconds=10) # Draw counting line cv2.line( frame, (self.line_counter.start.x, self.line_counter.start.y), (self.line_counter.end.x, self.line_counter.end.y), Config.LINE_COLOR.as_bgr(), 2 ) # Periodic data reporting if self.frame_count % Config.REPORT_INTERVAL == 0 and self.iot_client: self.iot_client.report_traffic_data(counts) # Draw object trajectories and boxes (now handled together in _draw_tracks) frame = self._draw_tracks(frame, detections) # Display statistics and table frame = self._draw_stats(frame, counts) frame = self._draw_data_table(frame, counts, recent_counts) # Set mouse callback for table dragging cv2.setMouseCallback("Traffic Monitoring", self._handle_table_drag, frame) self.frame_count += 1 return frame except Exception as e: logger.error(f"Frame processing exception: {str(e)}") return frame def interactive_line_setup(frame: np.ndarray) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]: """Interactive counting line setup""" points = [] instructions = [ "1. Click to set line start point", "2. Click to set line end point", "3. Press ESC to confirm" ] def mouse_callback(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: points.append((x, y)) cv2.circle(frame, (x, y), 5, (0, 0, 255), -1) if len(points) > 1: cv2.line(frame, points[0], points[1], (0, 255, 0), 2) cv2.namedWindow("Set Counting Line") cv2.setMouseCallback("Set Counting Line", mouse_callback) for i, text in enumerate(instructions): cv2.putText(frame, text, (10, 30 + i * 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2) while True: cv2.imshow("Set Counting Line", frame) key = cv2.waitKey(1) if key == 27 or len(points) >= 2: # ESC key or two points selected break cv2.destroyAllWindows() return (points[0], points[1]) if len(points) >= 2 else None def main(): """Main program entry""" try: # Open default camera (index 0) cap = cv2.VideoCapture(0) if not cap.isOpened(): logger.error("Unable to open camera") return # Set camera resolution (optional, adjust as needed) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # Initialize monitor monitor = TrafficMonitor() # Read a few frames to allow camera to adjust for _ in range(5): ret, frame = cap.read() if not ret: logger.error("Failed to capture initial frames from camera") return # Set counting line using a frame from the camera line_points = interactive_line_setup(frame.copy()) if line_points: monitor.set_counting_line(*line_points) else: logger.info("No counting line set, will only perform object detection") # Main loop while cap.isOpened(): ret, frame = cap.read() if not ret: logger.warning("Camera frame read failed") break # Process frame processed_frame = monitor.process_frame(frame) # Display results cv2.imshow("Traffic Monitoring", processed_frame) key = cv2.waitKey(1) if key == ord('q') or key == 27: # 'q' or ESC to quit logger.info("Program terminated by user") break elif key == ord('r'): # 'r' to reset counting line line_points = interactive_line_setup(frame.copy()) if line_points: monitor.set_counting_line(*line_points) except KeyboardInterrupt: logger.info("Program interrupted by user") except Exception as e: logger.critical(f"Program exception: {str(e)}", exc_info=True) finally: # Release resources if 'cap' in locals() and cap.isOpened(): cap.release() cv2.destroyAllWindows() logger.info("Program exited") if __name__ == "__main__": # Check required dependencies try: import iot_device_sdk_python except ImportError: logger.error("Huawei IoT SDK not found, please install: pip install iot_device_sdk_python") sys.exit(1) # Ignore warning messages warnings.filterwarnings("ignore", category=UserWarning) main()为我修改这个代码改为画两条线,第一个点和第二个点是第一条线,第三个点和第四个点是第二条线,同时计算第一个点的正向行走人数-第二个点正向行走的绝对值,第二个点-第一个点正向行走的绝对值,第一条线正、逆向行走人数,总人数。第二条线正、逆向行走人数,总人数,尽量减少源代码的修改,MQTT协议传送部分不要过大改动
08-16
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值