手动制作Haar分类器 haar_xxxx.xml文件并测试

在人脸检测中,有时候会用到haar分类器,我们会使用opencv\sources\data\haarcascades下haarcascade_frontalface_alt.xml文件,但是系统提供xml文件场景有限,有时候我们需要自己定制。比如说,如果检测手掌,这个时候系统没有提供相关的xml,就需要自己制作。
以下为制作和测试流程:

1.下载负类图像样本并采集目标图片
采用爬虫的方式,这里采集Image Net上的图片作为负样本,代码如下:

def download_images():
    #Image Net 挖掘机类图片
    img_url = 'http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n03996416'
    # 创建图片保存目录
    if not os.path.exists('neg'):
        os.makedirs('neg')

    urls = urllib.request.urlopen(img_url).read().decode()

    img_index = 1
    url_list = urls.split('\n')
    for index, url in enumerate(url_list):
        try:
            print(url)
            urllib.request.urlretrieve(url, 'neg/' + str(img_index) + '.jpg')
            # 把图片转为灰度图片
            gray_img = cv2.imread('neg/' + str(img_index) + '.jpg', cv2.IMREAD_GRAYSCALE)
            # 更改图像大小
            image = cv2.resize(gray_img, (150, 150))
            # 保存图片
            cv2.imwrite('neg/' + str(img_index) + '.jpg', image)
            img_index += 1
        except Exception as e:
            print(e)
    # 去除重复的图片
    delete_dup_files()

执行完后,在neg目录中会生成 灰度图像如下,
手动制作Haar分类器 haar_xxxx.xml文件并测试_第1张图片
目标图像根据需求制定,如下hand.jpg:
手动制作Haar分类器 haar_xxxx.xml文件并测试_第2张图片

2.制作xml

def make_neg_txt_file():
    file_list = os.listdir('neg')
    for s_file in file_list:
        temp_list = s_file.split('_')
        if len(temp_list) > 1:
            new_filename = temp_list[1]
            os.rename('neg/' + s_file, 'neg/' + new_filename)

    with open('neg.txt', 'w') as f:
        for img in os.listdir('neg'):
            line = 'neg/' + img + '\n'
            f.write(line)

def make_xml_file():
    # 制作负样本TXT文件
    if not os.path.exists('neg.txt'):
        make_neg_txt_file()

    # 生成pos.txt 文件,其中hand.jpg为目标图像
    if not os.path.exists('pos.txt'):
        cmd_pos = 'opencv_createsamples -img hand.jpg -bg neg.txt -info pos.txt -maxxangle 0.5 -maxyangle 0.5'
        os.system(cmd_pos)

    # 生成向量文件 pos.vec
    if not os.path.exists('pos.vec'):
        cmd_vec = 'opencv_createsamples -info pos.txt -num 30 -w 20 -h 30 -vec pos.vec'
        os.system(cmd_vec)

    # 开始训练,生成xml文件
    if not os.path.exists('data'):
        os.system('mkdir data')

    # numPos一般是numNeg的1倍,一般比样本数小
    if not os.path.exists('data/cascade.xml'):
        print('=' * 30)
        cmd_train = 'opencv_traincascade -data data -vec pos.vec -bg neg.txt -numPos 30 -numNeg 15 -numStages 15 -w 20 -h 30'
        os.system(cmd_train)
        print('=' * 30)

执行完后在当前目录会生成如下:
neg.txt=>其中为负样本的路径
pos.txt=>其中为目标图像在负样本中的坐标
pos.vec=>pos.txt的向量格式

3.测试
测试代码如下:

# 测试 haar分类器
def test_haar_clasifier(cascade_file="data/cascade.xml"):
    mouse_haar = cv2.CascadeClassifier(cascade_file)
    cam = cv2.VideoCapture(0)

    while True:
        ret, img = cam.read()
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        mouse = mouse_haar.detectMultiScale(gray_img, 1.2, 3)  # 调整参数

        for mouse_x, mouse_y, mouse_w, mouse_h in mouse:
            cv2.rectangle(img, (mouse_x, mouse_y), (mouse_x + mouse_w, mouse_y + mouse_h), (0, 255, 0), 2)

        cv2.imshow('img', img)
        key = cv2.waitKey(30) & 0xff
        if key == 27:
            break

    cam.release()
    cv2.destroyAllWindows()

测试结果如下:
手动制作Haar分类器 haar_xxxx.xml文件并测试_第3张图片
手掌可以检测到,但是效果不好,可以通过增加负类样本改善效果。
完整代码下载

你可能感兴趣的:(14-python,xml,opencv,爬虫)