{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"},{"sourceId":11008377,"sourceType":"datasetVersion","datasetId":6853423},{"sourceId":11026510,"sourceType":"datasetVersion","datasetId":6866659},{"sourceId":11026619,"sourceType":"datasetVersion","datasetId":6866745},{"sourceId":11038737,"sourceType":"datasetVersion","datasetId":6875721},{"sourceId":11040668,"sourceType":"datasetVersion","datasetId":6877126},{"sourceId":11046992,"sourceType":"datasetVersion","datasetId":6881581},{"sourceId":11055290,"sourceType":"datasetVersion","datasetId":6887597}],"dockerImageVersionId":30918,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os\nfrom tqdm.auto import tqdm\nimport shutil as sh","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:08.980852Z","iopub.execute_input":"2025-03-21T13:19:08.981210Z","iopub.status.idle":"2025-03-21T13:19:09.507514Z","shell.execute_reply.started":"2025-03-21T13:19:08.981151Z","shell.execute_reply":"2025-03-21T13:19:09.506735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!pip install matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.2 Pillow PyYAML>=5.3.1 scipy>=1.4.1 torch>=1.7.0 torchvision>=0.8.1 tqdm>=4.41.0 tensorboard>=2.4.1 seaborn>=0.11.0 pandas thop pycocotools>=2.0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:09.508383Z","iopub.execute_input":"2025-03-21T13:19:09.508762Z","iopub.status.idle":"2025-03-21T13:19:09.512608Z","shell.execute_reply.started":"2025-03-21T13:19:09.508739Z","shell.execute_reply":"2025-03-21T13:19:09.511588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install /kaggle/input/whlwhl/ensemble_boxes-1.0.9-py3-none-any.whl","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:09.513628Z","iopub.execute_input":"2025-03-21T13:19:09.513968Z","iopub.status.idle":"2025-03-21T13:19:14.502615Z","shell.execute_reply.started":"2025-03-21T13:19:09.513933Z","shell.execute_reply":"2025-03-21T13:19:14.501580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\n\nprint(\"PyTorch 版本:\", torch.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:14.503654Z","iopub.execute_input":"2025-03-21T13:19:14.503994Z","iopub.status.idle":"2025-03-21T13:19:17.961621Z","shell.execute_reply.started":"2025-03-21T13:19:14.503953Z","shell.execute_reply":"2025-03-21T13:19:17.960656Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!python /kaggle/input/yolov55/yolov5-5.0/detect.py --source /kaggle/input/global-wheat-detection/test --weights /kaggle/input/yolobest/best.pt --save-txt --save-conf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:17.964159Z","iopub.execute_input":"2025-03-21T13:19:17.964641Z","iopub.status.idle":"2025-03-21T13:19:17.968606Z","shell.execute_reply.started":"2025-03-21T13:19:17.964613Z","shell.execute_reply":"2025-03-21T13:19:17.967531Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def iou(box1, boxes):\n    \"\"\"\n    计算 IoU。\n    :param box1: 单个检测框，形状为 [1, 4]。\n    :param boxes: 多个检测框，形状为 [N, 4]。\n    :return: IoU 值，形状为 [N]。\n    \"\"\"\n    # 计算交集\n    x1 = torch.max(box1[:, 0], boxes[:, 0])\n    y1 = torch.max(box1[:, 1], boxes[:, 1])\n    x2 = torch.min(box1[:, 2], boxes[:, 2])\n    y2 = torch.min(box1[:, 3], boxes[:, 3])\n    intersection = torch.clamp(x2 - x1, min=0) * torch.clamp(y2 - y1, min=0)\n\n    # 计算并集\n    area1 = (box1[:, 2] - box1[:, 0]) * (box1[:, 3] - box1[:, 1])\n    area2 = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])\n    union = area1 + area2 - intersection\n\n    return intersection / union","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:17.969874Z","iopub.execute_input":"2025-03-21T13:19:17.970121Z","iopub.status.idle":"2025-03-21T13:19:17.986653Z","shell.execute_reply.started":"2025-03-21T13:19:17.970101Z","shell.execute_reply":"2025-03-21T13:19:17.985525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def ciou_nms(boxes, scores, score_threshold, iou_threshold):\n    \"\"\"\n    基于 CIoU 的非极大值抑制 (NMS)，考虑置信度阈值与 IoU 阈值\n    \n    参数:\n        boxes: (N, 4) 形状的张量，每一行表示一个框 (x1, y1, x2, y2)\n        scores: (N,) 形状的张量，表示每个框的置信度\n        score_threshold: 置信度阈值，低于该值的框将被剔除\n        iou_threshold: IoU 阈值，高于该值的框将被认为是重叠的并被移除\n    \n    返回:\n        保留的框 (Tensor), 保留的置信度 (Tensor)\n    \"\"\"\n    \n    # **1. 过滤掉低置信度框**\n    valid_mask = scores >= score_threshold\n    boxes, scores = boxes[valid_mask], scores[valid_mask]\n\n    if boxes.numel() == 0:  # 如果没有框，返回空张量\n        return torch.empty((0, 4)), torch.empty((0,))\n\n    # **2. 按置信度排序框**\n    order = scores.argsort(descending=True)\n    keep = []  # 用于存储保留框的索引\n\n    while order.numel() > 0:\n        idx = order[0]  # 获取最高置信度框的索引\n        keep.append(idx)  # 保留这个框的索引\n\n        if order.numel() == 1:  # 如果只剩下一个框，直接结束\n            break\n\n        # **3. 计算当前框与其他框的 CIoU**\n        ciou_values = ciou(boxes[idx].unsqueeze(0), boxes[order[1:]])\n\n        # **4. 过滤掉 IoU 过高的框**\n        remaining_indices = (ciou_values < iou_threshold).nonzero(as_tuple=True)[0]\n        order = order[1:][remaining_indices]  # 只保留 IoU 低于阈值的框\n        \n        keep_boxes = boxes[torch.tensor(keep)]\n        keep_scores = scores[torch.tensor(keep)].unsqueeze(1)  # scores 变为 (N, 1)\n\n    # 拼接：boxes 的 shape (N, 4)，scores 的 shape (N, 1)\n    return torch.cat((keep_boxes, keep_scores), dim=1)\n\ndef ciou(box1, boxes):\n    \"\"\"\n    计算 CIoU。\n    :param box1: 单个检测框，形状为 [1, 4]。\n    :param boxes: 多个检测框，形状为 [N, 4]。\n    :return: CIoU 值，形状为 [N]。\n    \"\"\"\n    # 计算 IoU\n    ious = iou(box1, boxes)\n\n    # 计算中心点距离\n    center_dist = ((box1[:, 0] + box1[:, 2]) / 2 - (boxes[:, 0] + boxes[:, 2]) / 2) ** 2 + \\\n                  ((box1[:, 1] + box1[:, 3]) / 2 - (boxes[:, 1] + boxes[:, 3]) / 2) ** 2\n\n    # 计算最小外接矩形的对角线长度\n    c = ((boxes[:, 2] - boxes[:, 0]) ** 2 + (boxes[:, 3] - boxes[:, 1]) ** 2) ** 0.5\n\n    # 计算宽高比差异\n    v = (4 / (math.pi ** 2)) * torch.pow(torch.atan((box1[:, 2] - box1[:, 0]) / (box1[:, 3] - box1[:, 1])) - \n                                         torch.atan((boxes[:, 2] - boxes[:, 0]) / (boxes[:, 3] - boxes[:, 1])), 2)\n    alpha = v / (v + ious + 1e-9)\n\n    # 计算 CIoU\n    ciou = ious - center_dist / c ** 2 - alpha * v\n\n    return ciou","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:17.987706Z","iopub.execute_input":"2025-03-21T13:19:17.987996Z","iopub.status.idle":"2025-03-21T13:19:18.005685Z","shell.execute_reply.started":"2025-03-21T13:19:17.987965Z","shell.execute_reply":"2025-03-21T13:19:18.004865Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ensemble_boxes import *\ndef run_wbf(boxes, scores, image_size=1024, iou_thr=0.5, skip_box_thr=0.7, weights=None):\n    #boxes = [prediction[image_index]['boxes'].data.cpu().numpy()/(image_size-1) for prediction in predictions]\n    #scores = [prediction[image_index]['scores'].data.cpu().numpy() for prediction in predictions]\n    labels = [np.zeros(score.shape[0]) for score in scores]\n    boxes = [box/(image_size) for box in boxes]\n    boxes, scores, labels = weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    #boxes, scores, labels = nms(boxes, scores, labels, weights=[1,1,1,1,1], iou_thr=0.5)\n    boxes = boxes*(image_size)\n    return boxes, scores, labels\n\ndef TTAImage(image, index):\n    image1 = image.copy()\n    if index==0: \n        rotated_image = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image\n    elif index==1:\n        rotated_image2 = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image2 = cv2.rotate(rotated_image2, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image2\n    elif index==2:\n        rotated_image3 = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image3 = cv2.rotate(rotated_image3, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image3 = cv2.rotate(rotated_image3, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image3\n    elif index == 3:\n        return image1\n    \ndef rotBoxes90(boxes, im_w, im_h):\n    ret_boxes =[]\n    for box in boxes:\n        x1, y1, x2, y2 = box\n        x1, y1, x2, y2 = x1-im_w//2, im_h//2 - y1, x2-im_w//2, im_h//2 - y2\n        x1, y1, x2, y2 = y1, -x1, y2, -x2\n        x1, y1, x2, y2 = int(x1+im_w//2), int(im_h//2 - y1), int(x2+im_w//2), int(im_h//2 - y2)\n        x1a, y1a, x2a, y2a = min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2)\n        ret_boxes.append([x1a, y1a, x2a, y2a])\n    return np.array(ret_boxes)\n\ndef detect1Image(im0, imgsz, model, device, conf_thres, iou_thres):\n    img = letterbox(im0, new_shape=imgsz)[0]\n    # Convert\n    img = img[:, :, ::-1].transpose(2, 0, 1)  # BGR to RGB, to 3x416x416\n    img = np.ascontiguousarray(img)\n\n\n    img = torch.from_numpy(img).to(device)\n    img =  img.float()  # uint8 to fp16/32\n    img /= 255.0   \n    if img.ndimension() == 3:\n        img = img.unsqueeze(0)\n\n    # Inference\n    pred = model(img, augment=True)[0]\n    pre = pred[pred[:,:,4]>0.2]\n    # Apply NMS\n    pred = non_max_suppression(pred, conf_thres, iou_thres)\n   \n    #print(pre)\n    \n    #print(f'shape:{pre.shape}')\n    #conf= pre[:,4]\n\n    #xyxy = pre[:, :4]\n    #print(xyxy.shape)\n    #print(conf.shape)\n    \n    #pre=ciou_nms(xyxy, conf, conf_thres, iou_thres)\n    #pre=[pre]\n    #print(pre)\n\n    \n    boxes = []\n    scores = []\n    for i, det in enumerate(pred):  # detections per image\n        # save_path = 'draw/' + image_id + '.jpg'\n        if det is not None and len(det):\n            # Rescale boxes from img_size to im0 size\n            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()\n\n            # Write results\n            for *xyxy, conf, cls in det:\n                boxes.append([int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3])])\n                scores.append(conf)\n\n    boxes = torch.tensor(boxes, device=device)\n    scores = torch.tensor(scores, device=device)\n\n    return boxes.cpu().numpy(), scores.cpu().numpy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:35:45.204807Z","iopub.execute_input":"2025-03-21T13:35:45.205204Z","iopub.status.idle":"2025-03-21T13:35:45.219071Z","shell.execute_reply.started":"2025-03-21T13:35:45.205151Z","shell.execute_reply":"2025-03-21T13:35:45.217951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def detect():\n    source = '../input/global-wheat-detection/test/'\n    weights = '/kaggle/input/volov510/best.pt'\n    if not os.path.exists(weights):\n        weights = '/kaggle/input/yolov5pt2/best.pt'\n    imgsz = 1024\n    conf_thres = 0.5\n    iou_thres = 0.6\n    is_TTA = True\n    \n    imagenames =  os.listdir(source)\n    \n    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\n\n    # 现在加载模型\n    model = attempt_load(weights, map_location=device)  # 使用 YOLOv5 官方提供的方法\n    model.to(device).eval()\n    # Load model\n    #model = torch.load(weights, map_location=device)['model'].float()  # load to FP32\n    #model.to(device).eval()\n    \n    dataset = LoadImages(source, img_size=imgsz)\n\n    results = []\n    fig, ax = plt.subplots(5, 2, figsize=(30, 70))\n    count = 0\n    # img = torch.zeros((1, 3, imgsz, imgsz), device=device)  # init img\n    #for path, img, im0s, _ in dataset:\n    for name in imagenames:\n        image_id = name.split('.')[0]\n        im01 = cv2.imread('%s/%s.jpg'%(source,image_id))  # BGR\n        assert im01 is not None, 'Image Not Found '\n        # Padded resize\n        im_w, im_h = im01.shape[:2]\n        if is_TTA:\n            enboxes = []\n            enscores = []\n            for i in range(4):\n                im0 = TTAImage(im01, i)\n                boxes, scores = detect1Image(im0, imgsz, model, device, conf_thres, iou_thres)\n                for _ in range(3-i):\n                    boxes = rotBoxes90(boxes, im_w, im_h)\n                    \n                if 1: #i<3:\n                    enboxes.append(boxes)\n                    enscores.append(scores) \n            #boxes, scores = detect1Image(im01, imgsz, model, device, conf_thres, iou_thres)\n            #enboxes.append(boxes)\n            #enscores.append(scores)\n\n            boxes, scores, labels = run_wbf(enboxes, enscores, image_size = im_w, iou_thr=0.6, skip_box_thr=0.5)\n            boxes = boxes.astype(np.int32).clip(min=0, max=im_w)\n        else:\n            boxes, scores = detect1Image(im01, imgsz, model, device, conf_thres, iou_thres)\n\n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n        \n        boxes = boxes[scores >= 0.05].astype(np.int32)\n        scores = scores[scores >=float(0.05)]\n        if count<10:\n            #sample = image.permute(1,2,0).cpu().numpy()\n            for box, score in zip(boxes,scores):\n                cv2.rectangle(im0,\n                              (box[0], box[1]),\n                              (box[2]+box[0], box[3]+box[1]),\n                              (220, 0, 0), 2)\n                cv2.putText(im0, '%.2f'%(score), (box[0], box[1]), cv2.FONT_HERSHEY_SIMPLEX ,  \n                   0.5, (255,255,255), 2, cv2.LINE_AA)\n            ax[count%5][count//5].imshow(im0)\n            count+=1\n            \n        result = {\n            'image_id': image_id,\n            'PredictionString': format_prediction_string(boxes, scores)\n        }\n\n        results.append(result)\n    return results","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:19.416981Z","iopub.execute_input":"2025-03-21T13:19:19.417341Z","iopub.status.idle":"2025-03-21T13:19:19.430659Z","shell.execute_reply.started":"2025-03-21T13:19:19.417307Z","shell.execute_reply":"2025-03-21T13:19:19.429661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def format_prediction_string(boxes, scores):\n    pred_strings = []\n    for j in zip(scores, boxes):\n        pred_strings.append(\"{0:.4f} {1} {2} {3} {4}\".format(j[0], j[1][0], j[1][1], j[1][2], j[1][3]))\n\n    return \" \".join(pred_strings)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:19:19.431526Z","iopub.execute_input":"2025-03-21T13:19:19.431980Z","iopub.status.idle":"2025-03-21T13:19:19.457239Z","shell.execute_reply.started":"2025-03-21T13:19:19.431955Z","shell.execute_reply":"2025-03-21T13:19:19.456039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/yolov552/yolov5-5.0')  \nfrom utils.datasets import *\nimport matplotlib.pyplot as plt\nfrom utils.general import *\nfrom models.experimental import attempt_load  # 确保可以正确加载 YOLOv5 模型\nresults = detect()\ntest_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-21T13:35:48.883436Z","iopub.execute_input":"2025-03-21T13:35:48.883790Z","iopub.status.idle":"2025-03-21T13:35:53.064930Z","shell.execute_reply.started":"2025-03-21T13:35:48.883740Z","shell.execute_reply":"2025-03-21T13:35:53.063837Z"}},"outputs":[],"execution_count":null}]}