在ubuntu环境下进行Opencv分类器的训练

开发语言:python
开发环境:windows,ubuntu
图像数据库:ImageNet

实验目的:图像识别,识别手表

文章结构:

  • OpenCV4Python环境配置
  • 数据准备
  • 训练过程
  • 使用生成的xml文件进行识别

OpenCV4Python环境配置

windows:
下载安装Anaconda3,然后下载文件

opencv_python-3.2.0-cp36-cp36m-win_amd64.whl

并放到目录

C:\Anaconda3\Lib\site-packages

下,执行pip install opencv_python-3.2.0-cp36-cp36m-win_amd64.whl
打开cmd,输入python后,输入

import cv2

若不报错,则环境配置成功。
ubuntu:
在root用户下:
sudo apt install libopencv-dev python-opencv

sudo apt install build-essential

sudo apt install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
创建一个文件夹:
mkdir opencv_workspace
然后clone opencv源码到当前目录:
git clone https://github.com/Itseez/opencv.git
至此环境配置完成。

数据准备

需要的图像数据分为正样本和负样本,正样本只有一副手表的图片(正样本的数量看情况而定,对于复杂的图像比如人脸,正样本的数量需要很多才行,而对于简单的样本识别,正样本需要一张就够了)
正样本:
图像尺寸为50*50
处理图像尺寸的python代码:

import cv2
import numpy as np

img = cv2.imread('watch.jpg',cv2.IMREAD_GRAYSCALE)
img5050 = cv2.resize(img,(50,50))
cv2.imwrite('watch5050.jpg',img5050)

负样本:
负样本越多越好,我从ImgNet获取负样本数据,获取图像的URL集合的地址(随意,只要不是手表就行)

http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n02992529

然后访问该地址会返回一堆图片的链接集合:
像这样:

http://www.newsmobile.it/n/xeniumx530_11.jpg
http://farm4.static.flickr.com/3176/2825095151_f114959525.jpg
http://farm2.static.flickr.com/1135/921900930_54f4036d52.jpg
http://www.telefonino.net/news/images/13388_04.jpg
http://farm1.static.flickr.com/90/218188661_35ab70df72.jpg
http://passionemobile.files.wordpress.com/2008/09/passionemobileworld116.jpg
http://farm1.static.flickr.com/24/123429226_53b56824bb.jpg
http://farm4.static.flickr.com/3007/2654921621_9414540318.jpg
http://www.agenciainfomania.com/images/user/Image/NotaRoja/06Robo%20celular_1.jpg
http://farm4.static.flickr.com/3283/2496609968_2a993b0458.jpg
http://farm3.static.flickr.com/2084/1547357191_c80e5b36b7.jpg
http://www.giordanoshop.com/images/fotoinserzioni/3315/telefonino-g3315-5.jpg
http://files.splinder.com/683fe5ed949a1b1b1fbfb8a47d5e875b.jpg
http://farm3.static.flickr.com/2092/2264605380_a43ebdd11e.jpg
http://s3.amazonaws.com/rede_prod/assets/0046/9805/2340078090_7808eacc4e_m_thumb.jpg
http://farm1.static.flickr.com/231/446448280_54f7fd97d6.jpg
http://farm1.static.flickr.com/133/363412760_cee4855645.jpg
http://farm2.static.flickr.com/1423/856683107_b64988031e.jpg
http://farm4.static.flickr.com/3082/2595357619_7674575e62.jpg
……

将这些链接对应的图片下载到本地,存储到文件夹neg中,当前文件夹目录结构:

/
neg/
watch5050.jpg
img_handle.py

获取图像到本地的python代码:

def store_raw_images():
    neg_images_link = 'http://www.image-net.org/api/text/imagenet.synset.geturls?wnid=n02992529'
    neg_images_urls = urllib.request.urlopen(neg_images_link).read().decode()

    if not os.path.exists('neg'):
        os.makedirs('neg')

    pic_num = 1
    for i in neg_images_urls.split('\n'):
        try:
            print(i)
            urllib.request.urlretrieve(i,"neg/"+str(pic_num)+'.jpg')
            img = cv2.imread("neg/"+str(pic_num)+'.jpg',cv2.IMREAD_GRAYSCALE)
            resized_image = cv2.resize(img,(100,100))
            cv2.imwrite("neg/"+str(pic_num)+'.jpg',resized_image)
            pic_num += 1
        except Exception as e:
            print(str(e))

图片下载后会发现,会有一些无效的图片,新建一个文件夹uglies,随便选一张五项的图片(因为这些图片都是一样的)放入到该文件夹中:

/
neg/
uglies/
watch5050.jpg
img_handle.py
删除无效图片的python代码:

#删除损坏的数据文件
def find_uglies():
    for file_type in ['neg']:
        for img in os.listdir(file_type):
            for ugly in os.listdir('uglies'):
                try:
                    current_image_path = str(file_type)+'/'+str(img)
                    ugly = cv2.imread('uglies/'+str(ugly))
                    question = cv2.imread(current_image_path)

                    if ugly.shape == question.shape and not(np.bitwise_xor(ugly,question).any()):
                        print('Useless image')
                        print(current_image_path)
                        os.remove(current_image_path)

                except Exception as e:
                    print(str(e))

创建对于负样本的描述文件bg.txt,代码如下:

#创建描述文件(包含一些图像的路径及文件名信息)
def create_pos_n_neg():
    for file_type in ['neg']:
        for img in os.listdir(file_type):
            if(file_type=='neg'):
                line = file_type+'/'+img+'\n'
                with open('bg.txt','a') as f:
                    f.write(line)
            elif (file_type == 'pos'):
                line = file_type + '/' + img + ' 1 0 0 50 50\n'
                with open('info.txt', 'a') as f:
                    f.write(line)

至此,windows本地的工作告一段落。

训练过程

训练过程在我的一台linux服务器上进行,将刚才生成的文件夹neg,文件bg.txtwatch5050.jpg上传到目录opencv_workspace下,并在当前目录下创建文件夹:

mkdir data #用于存储Cascade分类器数据
mkdir info #用于存放正样本图像数据

接下来,生成正样本数据:

opencv_createsamples -img watch5050.jpg -bg bg.txt -info info/info.lst -pngoutput info -maxxangle -0.5 -maxyangle 0.5 -maxzangle 0.5 -num 1100

参数介绍如下:

-img 正样本图像,你也可以替换成你自己的图像,用于识别其他物体,而不只限于是手表
-bg 用于传入负样本描述信息文件的名称
-info 用于生成正样本的信息,类似于bg.txt,包括图片路径,图片中对象的个数以及这些对象的位置
-pngoutput 图像的输出路径,生成的正样本图像都保存到这个目录下
-num 生成的正样本的数量

接下来生产成vector文件:

opencv_createsamples -info info/info.lst -num 1100 -w 20 -h 20 -vec positives.vec

Note:
-w,-h选择为20的原因是节约训练时间(越大越耗时)

最后,训练分类器文件:

opencv_traincascade -data data -vec positives.vec -bg bg.txt -numPos 500 -numNeg 250 -numStages 16 -w 20 -h 20

参数:

-data 用于指定输出文件所在的位置
-numPos 每级分类器训练时所用到的正样本数目,应小于vec文件中正样本的数目,具体数目限制条件为:numPos+(numStages-1)numPos(1-minHitRate)<=vec文件中正样本的数目
-numNeg 每级分类器训练时所用到的负样本数目,可以大于-bg指定的图片数目(和上面一样,具体大小要根据主机内存的大小而定,内存不足设置过大会导致训练过程被KILLED)
-numStages 训练分类器的级数,强分类器的个数

注意,若训练时间比较长,而你又想在关闭putty等终端的情况下让训练继续进行,需要在上述的代码前加一条指令nohup,这样进程会被放入到后台继续运行。可通过命令‘htop’命令查看系统中各个进程运行情况。

至此,训练结束,查看data文件夹,会发现分类器文件已经生成。
通过改变

opencv_traincascade -data data -vec positives.vec -bg bg.txt -numPos 500 -numNeg 250  -numStages 16 -w 20 -h 20

-numStages选项,可以改变加载的分类器的不同的stage

使用生成的xml文件进行识别

源代码:

import cv2

watch_cascade = cv2.CascadeClassifier('watch-cascade-12stages.xml')

img = cv2.imread('test.jpg')

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

watches = watch_cascade.detectMultiScale(gray)

for (x,y,w,h) in watches:
    cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

    roi_gray = gray[y:y+h,x:x+w]
    roi_color = img[y:y+h,x:x+w]

cv2.imshow('img',img)
k = cv2.waitKey(0)

结果如图:
识别的结果

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值