OpenCV training its own object detection classifier steps

Environment: Python 3.7   OpenCV3.4.3.18

Tools:

opencv_annotation.exe

opencv_createsamples.exe

opencv_traincascade.exe

Environment and tools download and installation

Terminal command of OpenCV Library under cmd
 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python==3.4.3.18
It includes the main modules of OpenCV and opencv contribution library
Tools can be downloaded from GitHub
https://github.com/opencv/opencv/releases?after=3.4.3

Install OpenCV in the following directory

1, Preparation stage

  File template

  positive_images to place positive sample images and negative_image places the negative sample image and xml as the trained classifier file

Sample collection

Positive sample: the sample corresponding to the category we want to correctly classify. For example, if we want to classify a picture to determine whether it belongs to pineapple, the picture of pineapple will be a positive sample during training.

Negative sample: either the sample corresponding to the classification we want, or the picture of pineapple

The more sample data, the better the detection effect, the more obvious the characteristics of positive samples, and the more complex the background of negative samples.

1. Go to www.kaggle.com to download the data set you want, or use scratch + selenium to crawl pictures in batches

2. Take pictures of the object you want to detect

2, Pretreatment

Image water injection processing: automatically rotate, translate and zoom the image to increase the number of samples

For example, by rotating

"path Is the picture path. After execution, 11 pictures rotated by 30 degrees will be generated in the same directory"
def spin(path):   
    retval=cv2.imread(path)
    he,we=retval.shape[:2]
    for x in range(1,12):
        M=cv2.getRotationMatrix2D(center=(we/2,he/2),angle=x*30,scale=1)
        M=cv2.warpAffine(retval,M,(we,he))
        new_path=path[:-3]+'-spin'+str(x)+'.jpg'
        #print(new_path)
        cv2.imwrite(new_path,M)

  Adjust brightness:

"path Is the picture path. After execution, five pictures with increasing brightness will be generated in the same directory"
def light(path):
    retval=cv2.imread(path)
    img_hsv = cv2.cvtColor(retval, cv2.COLOR_BGR2HSV)
    darker_hsv = img_hsv.copy()
    for y in range(1,6):
        darker_hsv[:, :, 2] = darker_hsv2[:, :, 2]+2*y
        darker_img = cv2.cvtColor(darker_hsv, cv2.COLOR_HSV2BGR)
        new_path=path[:-3]+'-light+'+str(x)+'ipg'
        cv2.imwrite(new_path, darker_img)

Unified image size processing (40 * 40):

Batch rename picture files in folders

import os
from PIL import Image


class BatchRename():
    def __init__(self):
        self.path = r'.\positive_images'
 
    def rename(self):
        filelist = os.listdir(self.path)
        total_num = len(filelist)
        i = 0
        for item in filelist:
            if item.endswith('.jpg'):
                src = os.path.join(os.path.abspath(self.path), item)
                print(src)
                dst = os.path.join(os.path.abspath(self.path), str(i) + '.jpg')
                try:
                    os.rename(src, dst)
                    print ('converting %s to %s ...' % (src, dst))
                    i = i + 1
                except :
                    continue
        print ('total %d to rename & converted %d jpgs' % (total_num, i))
 
if __name__ == '__main__':
    demo = BatchRename()
    demo.rename()
    pass

After execution  

Batch modify picture size

from PIL import Image
import os.path
import glob

def convertjpg(jpgfile,outdir,width=40,height=40):
    img=Image.open(jpgfile)
    try:
        new_img=img.resize((width,height),Image.BILINEAR)   
        new_img.save(os.path.join(outdir,os.path.basename(jpgfile)))
    except Exception as e:
        print(e)
for jpgfile in glob.glob(r".\positive_images\*.jpg"):
    #The modified pixels are stored in the images file
    convertjpg(jpgfile,r".\positive_images")

3, Generate sample description file

To generate a positive sample description file, you can use the annotation tool opencv_annotation.exe

opencv_ For the use of annotation.exe, enter opencv under cmd in the current directory_ Annotation.exe can see the instructions

  For example: opencv_annotation.exe  - a = generated pos.txt path  - i = positive sample folder path

 

Mark with the left mouse button and select the object to be recognized in a rectangular box  

  In English, 'c' is the confirmation box,'d 'deletes the selected box,' n 'is the next one,' esc 'is the stop.

If there is only one object in the picture, you can directly generate a description file (try to label it with opencv_annotation, the effect is better)

file_dir=os.getcwd()
print(file_dir)
file_dir=r'.\positive_images'
L=[]
i=0
with open(r".\pos.txt","w+") as f:
    for root, dirs, files in os.walk(file_dir):
        for file in files:  
            if os.path.splitext(file)[1] == '.jpg':
                L.append(os.path.join(root, file))
                f.write(L[i]+' 1'+' 0'+' 0'+' 40'+' 40'+'\n')
                i+=1

Generate pos.txt  

Generate negative sample description file (without annotation)

file_dir=r'.\negative_image'
L=[]
i=0
with open(r".\neg.txt","w+") as f:
    for root, dirs, files in os.walk(file_dir):  
        for file in files:  
            if os.path.splitext(file)[1] == '.jpg':  
                L.append(os.path.join(root, file))
                f.write(L[i]+'\n')
                i+=1
print("ok")

Generate neg.txt

4, Composite sample vec file

Here, you only need to synthesize the vec file of positive samples, but not negative samples. Opencv is used here_ createsamples.exe

opencv_ For the use of createsamples.exe, enter opencv under cmd in the current directory_ Createsamples.exe can see the instructions

  For example, opencv_createsamples.exe -vec pos.vec   - info pos.txt -num 50 -w 40 -h 40

-The vec parameter represents the storage location of the. vec file;

-info represents the location of the generated annotation;

-num number of positive samples generated

-w width of the window- h window height;

  After that, the pos.vec file is generated in the current directory

5, Training model

The training model uses opencv_traincascade.exe

opencv_ For the use of traincascade.exe, enter opencv under cmd in the current directory_ Traincascade.exe can see the instructions for use

  For example: opencv_traincascade.exe -data xml -vec pos.vec -bg neg.txt -numPos 10 -numNeg 2000 -numStages 15 -w 40 -h 40 -minHitRate 0.999 -maxFalseAlarmRate 0.5 -mode ALL

-data: specify the folder to save the training results;

-vec: specify positive sample set;

-bg: specify the description folder of negative samples;

-numPos: specify the number of positive samples participating in training at each level (less than the total number of positive samples);

-numNeg: specify the number of negative samples participating in training at each level (which can be greater than the total number of negative sample pictures);

-numStage: training level;

-w: Width of positive sample- h: The height of positive samples; (must be consistent with the - W and - H values used in opencv_createsample)

-minHitRate: the hit rate required for each level (generally 0.95-0.995);

-Maxfalse alarmrate: the maximum error detection rate allowed for each level;

-mode: used when Haar like feature is used. BASIC, CORE or ALL are optional; (ALL uses vertical and 45 degree rotation features.)

(this screenshot is the result of running opencv_traincascade.exe again after training the model)

  The trained classifier files are in the xml folder

6, Test model

import numpy as np
import cv2

#Load cascader
pineapple_cascade = cv2.CascadeClassifier(r'xml\cascade.xml')

#testing
def detect(image):
    #Convert image to grayscale image
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    #Call cascader
    pineapples = face_cascade.detectMultiScale(gray,
                                         scaleFactor=1.15,
                                         minNeighbors=5,
                                         minSize=(10, 10))
    print(pineapples)
    print("find{0}A pineapple!".format(len(pineapples)))
    #Draw the pineapple area
    for (x, y, w, h) in pineapples:
        cv2.circle(image, (int((x + x + w) / 2), int((y + y + h) / 2)),
                   int(w / 2), (0, 255, 0), 2)
    return image

retval=cv2.imread(r'test.jpg')
image=detect(retval)
cv2.imwrite('detect.jpg',image)

  After running, the detected image detect.jpg is generated (this is just a demonstration, there are few samples, and the effect is not very good)

 

  The above is just a simple training step display for reference and learning

 

Tags: Python OpenCV Object Detection machine vision

Posted on Thu, 07 Oct 2021 11:12:24 -0400 by Kingskin