第十届泰迪杯数据挖掘挑战赛A题解题思路附代码

                                                            A题:农田害虫图像识别

赛题描述

一、问题背景

病虫害一直是农业生产中无法避免的问题,每年都会由此造成巨大的经济损失。为了对农田病虫害进行有效的预防和控制,需要收集有害生物信息,在此基础上进行虫情分析。由于农田害虫的多样性和信息类型的复杂性,通过人工观察统计的传统害虫监测方式已经难以满足现代大规模农业生产对虫害预防工作的需要。近年来出现的虫情测报灯是虫情信息采集的智能设备,可以在无人监管的情况下,实现自动诱集、杀虫、虫体分散、拍照等作业,并实时地将虫情信息上传至云平台。虫情测报灯的投入使用可帮助植保人员高效地进行虫情分析,提高测报工作效率和准确率,避免农药的滥用和误用,减少农产品的农药残留,改善农田生态环境。

二、解决问题

1. 利用附件1和附件2的信息,建立确定害虫位置及种类的模型和算法。

2. 应用问题1所建立的模型和算法对附件3中提及的图像进行识别,并确定害虫的位置,将结果存放在“result2.csv”文件中(模板文件见附件4中的result2.csv)。

3. 根据问题2得到的结果,对附件3中提及的图像文件中不同种类的害虫数量进行统计,将统计结果存放在“result3.csv”文件中(模板文件见附件4中的result3.csv)。

这种图像处理的问题解法基本都是一样,准备数据,选择模型,训练,预测,完事。

数据准备

在给定的数据中有部分杂乱的数据,我们手动剔除掉了这部分数据,然后对剩余的数据,依据其给定的目标位置信息,对图像进行随机裁剪,作为训练图像。

随机裁剪图像的代码如下:

# -*- coding: utf-8 -*-
import os
import shutil
import cv2
import time
import codecs
import xml.etree.ElementTree as ET
from tqdm import tqdm
import shutil
from tqdm import trange              

from multiprocessing import Pool
import numpy as np


def setDir(filepath):
    '''
    如果文件夹不存在就创建,如果文件存在就清空!
    :param filepath:需要创建的文件夹路径
    :return:
    '''
    if not os.path.exists(filepath):
        os.mkdir(filepath)
    else:
        shutil.rmtree(filepath)
        os.mkdir(filepath)
def bbox_iou(box1, box2):
    """
    :param box1: = [xmin1, ymin1, xmax1, ymax1]
    :param box2: = [xmin2, ymin2, xmax2, ymax2]
    :return: 
    """
    xmin1, ymin1, xmax1, ymax1 = box1
    xmin2, ymin2, xmax2, ymax2 = box2
    # 计算每个矩形的面积
    s1 = (xmax1 - xmin1) * (ymax1 - ymin1)  # b1的面积
    s2 = (xmax2 - xmin2) * (ymax2 - ymin2)  # b2的面积
 
    # 计算相交矩形
    xmin = max(xmin1, xmin2)
    ymin = max(ymin1, ymin2)
    xmax = min(xmax1, xmax2)
    ymax = min(ymax1, ymax2)
 
    w = max(0, xmax - xmin)
    h = max(0, ymax - ymin)
    a1 = w * h  # C∩G的面积
    a2 = s2# + s2 - a1
    iou = a1 / a2 #iou = a1/ (s1 + s2 - a1)
    return iou
def exist_objs_iou(list_1, list_2):
    # 根据iou判断框是否保留,并返回bbox
    return_objs=[]
    s_xmin, s_ymin, s_xmax, s_ymax = list_1[0], list_1[1], list_1[2], list_1[3]
    
    for single_box in list_2:
        xmin, ymin, xmax, ymax, category=int(single_box[0]),int(single_box[1]),int(single_box[2]),int(single_box[3]),int(single_box[4])
        iou = bbox_iou(list_1, [xmin, ymin, xmax, ymax])
        if iou > 0.9:
            if iou == 1:
                x_new=xmin-s_xmin
                y_new=ymin-s_ymin
                return_objs.append([x_new, y_new, x_new+(xmax-xmin), y_new+(ymax-ymin),category])  # 保存新的坐标
            else:
                xlist = np.sort([xmin, xmax, s_xmin, s_xmax])  # 默认从小到大排序
                ylist = np.sort([ymin, ymax, s_ymin, s_ymax])
               
                return_objs.append([xlist[1] - s_xmin, ylist[1] - s_ymin, xlist[2] - s_xmin, ylist[2] - s_ymin, category])
    return return_objs  # 返回新的裁剪图片的坐标和类别

def read_txt(ann_path):
    with open(ann_path, 'r') as f:
        object_lists = []
        info = f.readlines()
        for object_list in info:
            object_lists.append(object_list.split())
    return object_lists

def write_txt(outpath,exiset_obj_list):
    m=1200
    with open(outpath+".txt", 'a+') as f:
        for obj in exiset_obj_list:
            cl=obj[4]
            x_c=(obj[2]+obj[0])/(m*2)
            y_c = (obj[1] + obj[3]) / (m * 2)
            w=(obj[2]-obj[0])/m
            h=(obj[3]-obj[1])/m
            # o1 = [str(obj[0]), str(obj[1]),str(obj[2]),str(obj[3]),str(obj[4])]
            o=[str(cl),str(x_c),str(y_c),str(w),str(h)]
            f.write(" ".join(o) + "\n")
    # with open(outpath+"re.txt", 'a+') as f:
    #     for obj in exiset_obj_list:
    #         o = [str(obj[0]), str(obj[1]),str(obj[2]),str(obj[3]),str(obj[4])]
    #         f.write(" ".join(o) + "\n")

def slice_im(List_subsets, outdir, raw_images_dir, raw_ann_dir, clip_ann_dir, sliceHeight=640, sliceWidth=640,
             zero_frac_thresh=0.2, overlap=0.2, verbose=True):
    cnt = 0
    
    for per_img_name in tqdm(List_subsets):
       
        o_name, _ = os.path.splitext(per_img_name) # 分离文件路径与拓展名,00001.jpg->('00001','.jpg')
        out_name = str(o_name) + '_' + str(cnt) # 00001_0
        image_path = os.path.join(raw_images_dir, per_img_name)# image/00001.jpg

        ann_path = os.path.join(raw_ann_dir, per_img_name[:-4] + '.txt') # labels/00001.txt,里面包含了左上、右下坐标和类别
        #print(ann_path)
        image0 = cv2.imread(image_path, 1)  # color
        ext = '.' + image_path.split('.')[-1] # .jpg
        
        object_list = read_txt(ann_path) # 00001.txt

        index = np.argwhere(image0[:, :, 0]) # 蓝色分量图像
        for i in range(500):
            random_idx = np.random.choice(len(index)) # 随机截取
            slice_idx = index[random_idx]
            #x = slice_idx[0],y = slice_idx[1]

            if slice_idx[0]+sliceWidth<=image0.shape[1] and slice_idx[1]+sliceHeight<=image0.shape[0]:
                
                exiset_obj_list = exist_objs_iou([slice_idx[0], slice_idx[1],slice_idx[0]+sliceWidth,slice_idx[1]+sliceHeight],object_list)
                if exiset_obj_list!=[]:  # 如果为空,说明切出来的这一张图不存在目标
                  
                    window_c = image0[slice_idx[1]:slice_idx[1] + sliceHeight, slice_idx[0]:slice_idx[0] + sliceWidth]
                   
                    outpath = os.path.join(outdir, out_name + '_' +str(slice_idx[0]) + '_' + str(slice_idx[1]) + '_' + str(sliceHeight) + ext)
                    cnt += 1
                    cv2.imwrite(outpath, window_c)
                    outpath_ann =  os.path.join(clip_ann_dir, out_name + '_' +str(slice_idx[0]) + '_' + str(slice_idx[1]) + '_' + str(sliceHeight))
                    write_txt(outpath_ann,exiset_obj_list)


if __name__ == "__main__":
    # 筛选附件1过后所有有虫子的图片的位置
    raw_images_dir = './img1'
    # 对应虫子的位置信息转化为TXT文件后的位置
    raw_ann_dir = './label1'
    # 保存裁剪图片的位置
    slice_voc_dir = './img11'
    # 保存裁剪图片位置信息的TXT文件的位置
    clip_ann_dir = './label11'
    if not os.path.exists(slice_voc_dir):
        os.makedirs(slice_voc_dir)
    if not os.path.exists(clip_ann_dir):
        os.makedirs(clip_ann_dir)

    List_imgs = os.listdir(raw_images_dir)

    slice_im(List_imgs, slice_voc_dir, raw_images_dir, raw_ann_dir, clip_ann_dir, sliceHeight=1200, sliceWidth=1200)

模型选择和训练

我们选择的YOLOv5s模型来训练,然后在训练参数中启用了数据增强的操作,如随机旋转,水平翻转,垂直翻转等等。我们按照8:2的比例来划分训练集和验证集,最终的mAP@.5=0.98左右,结果非常不错,其中的混淆矩阵也非常完成,模型学习到了很好的特征。

图像推理

直接用YOLOv5的检测程序来做就行,最后我们的预测结果也很好。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
国赛目一般来源于科学与工程技术、人文与社会科学等领域经过适当简化加工的实际问。参赛者不需要预先掌握深入的专门知识,只需要学过高等学校的数学基础课程。对于解题思路,可以根据目要求进行以下步骤来完成建模和求解: 1. 理解题目:仔细阅读目,理解问的背景和要求。注意提取关键信息,明确问的目标和约束条件。 2. 建立数学模型:根据目的描述和要求,将实际问转化为数学模型。可以使用已知的数学理论、公式和方法,结合问的特点进行建模。根据问类型,可以将问归类为分类问、优化问、预测问或评价问。 3. 求解模型:根据建立的数学模型,使用适当的数学工具和方法进行求解。可能需要进行数值计算、优化算法或统计分析等操作,以得到问的解答。 4. 分析和检验结果:对求解结果进行分析和检验,验证其合理性和正确性。可以通过对比实际数据或进行敏感性分析来评估模型的准确性和可靠性。 5. 模型的改进:根据对结果的分析和检验,对模型进行改进。可以尝试不同的假设或调整参数,以提高模型的性能和适应性。 综上所述,解题思路主要包括理解题目、建立数学模型、求解模型、分析和检验结果以及模型的改进。具体的解题思路会根据不同的目和问类型有所差异,建议参赛者根据具体目要求和自身的数学知识经验,灵活运用数学方法和工具,进行问的建模和求解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值