Combate tradicional de detección de objetivos: HOG+SVM

Combate tradicional de detección de objetivos: HOG+SVM

1. Introducción

1.1 Tradición y profundidad

Antes de la aparición del aprendizaje profundo, los métodos tradicionales de detección de objetivos se dividían aproximadamente en tres partes: selección de región (ventana deslizante), extracción de características (SIFT, HOG, etc.) y **clasificadores (SVM, Adaboost, etc.)** Los principales problemas son dos aspectos: por un lado, la estrategia de selección de la ventana deslizante no está dirigida, la complejidad del tiempo es alta y la ventana es redundante, por otro lado, la solidez de las funciones diseñadas a mano es deficiente. Desde el surgimiento del aprendizaje profundo, la detección de objetivos ha hecho un gran avance. Las dos direcciones más notables son:

  • Región Los algoritmos de detección de objetivos de aprendizaje profundo basados ​​en propuestas representados por RCNN (RCNN, SPP-NET, Fast-RCNN, Faster-RCNN, etc.), son de dos etapas, necesitan usar el método heurístico (búsqueda selectiva) o CNN primero. red (RPN) genera una propuesta de región y luego realiza la clasificación y la regresión en la propuesta de región.
  • El algoritmo de detección de objetivos de aprendizaje profundo basado en regresión (YOLO, SSD, etc.) representado por YOLO solo utiliza una red CNN para predecir directamente la categoría y la posición de diferentes objetivos.

1.2 ¿Qué es la detección tradicional de objetos?

En primer lugar, comprendamos qué es la detección de objetivos. En pocas palabras, es encontrar e identificar el objetivo existente en la imagen. Encontramos esto fácil para nosotros los humanos, pero ¿cómo lo hace para una computadora?

  • El método tradicional de detección de objetivos se divide en tres partes: selección de área → extracción de características → clasificador,
    es decir, primero seleccione algunas áreas candidatas en una imagen dada, luego extraiga características de estas áreas y finalmente use el clasificador entrenado para la clasificación. A continuación presentamos estas tres etapas respectivamente.
  1. Selección de área: Este paso es para ubicar la ubicación del objetivo. Dado que el objetivo puede aparecer en cualquier parte de la imagen, y el tamaño y la relación de aspecto del objetivo también son inciertos, la estrategia de la ventana deslizante se usa inicialmente para recorrer toda la imagen y es necesario establecer diferentes escalas y relaciones de aspecto. Aunque esta estrategia exhaustiva incluye todas las posiciones posibles del objetivo, sus desventajas también son obvias: la complejidad del tiempo es demasiado alta y se generan demasiadas ventanas redundantes, lo que también afecta seriamente la velocidad y el rendimiento de la posterior extracción y clasificación de características. (De hecho, debido al problema de la complejidad del tiempo, la relación de aspecto de la ventana deslizante generalmente es fija y se establece en unos pocos, por lo que para la detección de objetivos de múltiples categorías con una gran relación de aspecto flotante, incluso el recorrido de la ventana deslizante no puede obtener un buen resultado.Zona).

  2. Extracción de características: no es tan fácil diseñar una característica robusta debido a la diversidad de la forma del objetivo, la diversidad de cambios de iluminación y la diversidad del fondo. Sin embargo, la calidad de las características extraídas afecta directamente la precisión de la clasificación. (Las funciones comúnmente utilizadas en esta etapa son SIFT, HOG, etc.)

  3. Clasificador: principalmente SVM, Adaboost, etc.

1.3 Métodos de detección de objetivos tradicionales insuficientes

En resumen, hay dos problemas principales en la detección de objetivos tradicional:

  • La estrategia de selección de región basada en la ventana deslizante no está dirigida, la complejidad del tiempo es alta y la ventana es redundante;
  • Las características artesanales no son muy resistentes a los cambios de diversidad.

2. Conocimientos previos

  1. Una breve introducción a las funciones de visión artificial: HOG, SIFT, SURF, ORB, LBP, HAAR
  2. skimage.feature–corner_harris、hog、local_binary_pattern说明
  3. SVM se entiende bien, es un clasificador

3. Marco del proyecto

**Este artículo es principalmente para el proyecto de detección de objetivos de grietas. ** También se puede extender a la detección de otros objetos. ! ! !

3.1 Estructura de archivos

1

  • data representa la carpeta de datos, hay img (la imagen original tiene muestras positivas (con grietas) y muestras negativas (sin grietas)), característica (después de extraer características de la imagen original, obtenga características de muestra positivas y características de muestra negativas), modelo (guardar clasificador entrenado), resultado (resultado previsto) y test_img (imagen utilizada en la predicción).
  • El resto de los archivos py se describen en detalle a continuación.

3.2 Breve introducción del método

321

322
323

4. Función de utilidad (utils.py)

from skimage.feature import hog, local_binary_pattern

# settings for LBP
radius = 3
n_points = 8 * radius

# settings for HOG
ppc = (32, 32)
cpb = (3, 3)


def get_hog_feature(img):
    return hog(img, orientations=9, pixels_per_cell=ppc, cells_per_block=cpb, block_norm='L1', transform_sqrt=False, feature_vector=True)

def get_lbp_feature(img):
    return local_binary_pattern(img, n_points, radius)


def sliding_window(image, window_size, step_size):
    for row in range(0, image.shape[0], step_size[0]):
        for col in range(0, image.shape[1], step_size[1]):
            yield (row, col, image[row:row + window_size[0], col:col + window_size[1]])


def overlapping_area(detection_1, detection_2, show = False):
    '''
    计算两个检测区域覆盖大小,detection:(x, y, pred_prob, width, height, area)
    '''
    # Calculate the x-y co-ordinates of the
    # rectangles
    # detection_1的 top left 和 bottom right
    x1_tl = detection_1[0]
    y1_tl = detection_1[1]
    x1_br = detection_1[0] + detection_1[3]
    y1_br = detection_1[1] + detection_1[4]

    # detection_2的 top left 和 bottom right
    x2_tl = detection_2[0]
    y2_tl = detection_2[1]
    x2_br = detection_2[0] + detection_2[3]
    y2_br = detection_2[1] + detection_2[4]

    # 计算重叠区域
    x_overlap = max(0, min(x1_br, x2_br) - max(x1_tl, x2_tl))
    y_overlap = max(0, min(y1_br, y2_br) - max(y1_tl, y2_tl))
    overlap_area = x_overlap * y_overlap
    area_1 = detection_1[3] * detection_1[4]
    area_2 = detection_2[3] * detection_2[4]

    # 1. 重叠比例计算1
    # total_area = area_1 + area_2 - overlap_area
    # return overlap_area / float(total_area)

    # 2.重叠比例计算2
    area = area_1
    if area_1 < area_2: 
        area = area_2
    return float(overlap_area / area)


def nms(detections, threshold=0.5):
    '''
    抑制策略:
    1. 最大的置信值先行
    2. 最大的面积先行
    非极大值抑制减少重叠区域, detection:(x, y, pred_prob, width, height)
    '''
    if len(detections) == 0:
        return []
    # Sort the detections based on confidence score
    # 根据预测值大小排序预测结果
    detections = sorted(detections, key=lambda detections: detections[2], reverse=True)
    # print((detections[0][5], detections[-1][5]))
    # Unique detections will be appended to this list
    # 非极大值抑制后的检测区域
    new_detections=[]
    # Append the first detection
    # 默认第一个区域置信度最高是正确检测区域
    new_detections.append(detections[0])
    # Remove the detection from the original list
    # 去除以检测为正确的区域
    del detections[0]
    # For each detection, calculate the overlapping area
    # and if area of overlap is less than the threshold set
    # for the detections in `new_detections`, append the
    # detection to `new_detections`.
    # In either case, remove the detection from `detections` list.
    print(len(detections))

    for index, detection in enumerate(detections):
        if len(new_detections) >= 20:
            break
        overlapping_small = True
        # 重叠区域过大,则删除该区域,同时结束检测,过小则继续检测
        for new_detection in new_detections:
            if overlapping_area(detection, new_detection) > threshold:
                overlapping_small = False
                break
        # 整个循环中重叠区域都小那么增加
        if overlapping_small:
            new_detections.append(detection)
    return new_detections

5. Extracción de funciones (extract_feature.py)

import numpy as np
import joblib
import os
import glob
from utils import *
import cv2

# setting for img_resize
window_size = (256, 256)

train_dataset_path = os.path.expanduser('./data/img')
feat_path = './data/feature'
feat_pos_path = os.path.join(feat_path, 'pos')
feat_neg_path = os.path.join(feat_path, 'neg')

train_dataset_pos_lists = glob.glob(os.path.join(train_dataset_path, 'pos/*.jpg'))
train_dataset_neg_lists = glob.glob(os.path.join(train_dataset_path, 'neg/*.jpg'))

# 正样本特征存储
for pos_path in train_dataset_pos_lists:
    pos_im = cv2.imread(pos_path, cv2.IMREAD_GRAYSCALE)
    pos_im = cv2.resize(pos_im, window_size)
    pos_lbp = get_hog_feature(pos_im)
    pos_lbp = pos_lbp.reshape(-1)
    feat_pos_name = os.path.splitext(os.path.basename(pos_path))[0] + '.feat'
    joblib.dump(pos_lbp, os.path.join(feat_pos_path, feat_pos_name))

# 负样本特征存储
for neg_path in train_dataset_neg_lists:
    neg_im = cv2.imread(neg_path, cv2.IMREAD_GRAYSCALE)
    neg_im = cv2.resize(neg_im, window_size)
    neg_lbp = get_hog_feature(neg_im)
    neg_lbp = neg_lbp.reshape(-1)
    feat_neg_name = os.path.splitext(os.path.basename(neg_path))[0] + '.feat'
    joblib.dump(neg_lbp, os.path.join(feat_neg_path, feat_neg_name))

6. Entrena al clasificador (train.py)

from sklearn.svm import LinearSVC, SVC
import numpy as np
import joblib
import os
import glob

feat_path = './data/feature'
feat_pos_path = os.path.join(feat_path, 'pos')
feat_neg_path = os.path.join(feat_path, 'neg')
train_feat_pos_lists = glob.glob(os.path.join(feat_pos_path, '*.feat'))
train_feat_neg_lists = glob.glob(os.path.join(feat_neg_path, '*.feat'))
X = []
y = []

# 加载正例样本
for feat_pos in train_feat_pos_lists:
    feat_pos_data = joblib.load(feat_pos)
    X.append(feat_pos_data)
    y.append(1)
#     print('feat_pos_data.shape:', feat_pos_data.shape)

# 加载负例样本
for feat_neg in train_feat_neg_lists:
    feat_neg_data = joblib.load(feat_neg)
    X.append(feat_neg_data)
    y.append(0)
#     print('feat_neg_data.shape:', feat_neg_data.shape)

clf = LinearSVC(dual = False)
# clf = SVC()
clf.fit(X, y)
clf.score(X, y)

model_path = './data/model'
joblib.dump(clf, os.path.join(model_path, 'svm.model'))
print(len(X),X[0].shape)

7. Prueba (prueba.py)

import numpy as np
import joblib
import os
import glob
from skimage.transform import pyramid_gaussian
import cv2
from utils import *

window_size = (256, 256)

step_size = (128, 128)

img_name = '2.jpg'
test_image = cv2.imread("./data/test_img/" + img_name, cv2.IMREAD_GRAYSCALE)

model_path = './data/model'
clf = joblib.load(os.path.join(model_path, 'svm.model'))

scale = 0
detections = []
downscale = 1.25

for test_image_pyramid in pyramid_gaussian(test_image, downscale=downscale):
    if test_image_pyramid.shape[0] < window_size[0] or test_image_pyramid.shape[1] < window_size[1]:
        break
    for (row, col, sliding_image) in sliding_window(test_image_pyramid, window_size, step_size):
        if sliding_image.shape != window_size:
            continue
        sliding_image_lbp = get_hog_feature(sliding_image)
        sliding_image_lbp = sliding_image_lbp.reshape(1, -1)
        pred = clf.predict(sliding_image_lbp)
        if pred==1:
            pred_prob = clf.decision_function(sliding_image_lbp)
            (window_height, window_width) = window_size
            real_height = int(window_height*downscale**scale)
            real_width = int(window_width*downscale**scale)
            detections.append((int(col*downscale**scale), int(row*downscale**scale), pred_prob, real_width, real_height, real_height*real_width))
    scale+=1

test_image1 = cv2.imread("./data/test/" + img_name, 1)
test_image_detect = test_image1.copy()
for detection in detections:
    col = detection[0]
    row = detection[1]
    width = detection[3]
    height = detection[4]
    cv2.rectangle(test_image_detect, pt1=(col, row), pt2=(col+width, row+height), color=(255, 0, 0), thickness=4)

print('before NMS')
cv2.imwrite("./data/result/_"+ img_name, test_image_detect)

threshold = 0.2
detections_nms = nms(detections, threshold)

test_image_detect = test_image1.copy()
for detection in detections_nms:
    col = detection[0]
    row = detection[1]
    width = detection[3]
    height = detection[4]
    cv2.rectangle(test_image_detect, pt1=(col, row), pt2=(col+width, row+height), color=(0, 255, 0), thickness=4)

print('after NMS')
cv2.imwrite("./data/result/"+ img_name, test_image_detect)

8. Minería de muestra difícil (neg_mining.py)

Dado que hay una gran desviación en los resultados predichos, el entrenamiento no está en su lugar. En este momento, aquellas muestras con predicciones incorrectas necesitan ser entrenadas nuevamente.

from sklearn.svm import LinearSVC, SVC
import matplotlib.pyplot as plt
import numpy as np
from scipy import misc
import joblib
import os
import glob
from skimage.feature import hog
feat_path = './data/feature'
feat_pos_path = os.path.join(feat_path, 'pos')
feat_neg_path = os.path.join(feat_path, 'neg')
train_feat_pos_lists = glob.glob(os.path.join(feat_pos_path, '*.feat'))
train_feat_neg_lists = glob.glob(os.path.join(feat_neg_path, '*.feat'))

model_path = './data/model'
clf = joblib.load(os.path.join(model_path, 'svm.model'))

# 128
for i in range(0, 5):
    x = []
    y = []
    cnt = 0
    for feat_neg in train_feat_neg_lists:
        feat_neg_data = joblib.load(feat_neg)
        feat_neg_data1 = feat_neg_data.reshape(1, -1)
        pred = clf.predict(feat_neg_data1)
        if pred == 1:
            cnt += 1
            x.append(feat_neg_data)
            y.append(0)
    cnt1 = 0
    for feat_pos in train_feat_pos_lists:
        feat_pos_data = joblib.load(feat_pos)
        feat_pos_data1 = feat_pos_data.reshape(1, -1)
        pred = clf.predict(feat_pos_data1)
        if pred == 0:
            cnt1 += 1
            x.append(feat_pos_data)
            y.append(1)
    clf.fit(x, y)
    print(cnt, cnt1)

# model_path = './data/model'
# joblib.dump(clf, os.path.join(model_path, 'svm.model'))

9. Resumen

A través de dicho marco de código de detección de objetivos, no se pueden obtener malos resultados. ¡Por favor, señale cualquier error!

Supongo que te gusta

Origin blog.csdn.net/qq_51392112/article/details/128974801
Recomendado
Clasificación