fanfuhan OpenCV 教學103 ~ opencv-103-HOG特徵描述子之使用描述子特徵生成樣本數據

fanfuhan OpenCV 教學103 ~ opencv-103-HOG特徵描述子之使用描述子特徵生成樣本數據

fanfuhan OpenCV 教學103 ~ opencv-103-HOG特徵描述子之使用描述子特徵生成樣本數據


資料來源: https://fanfuhan.github.io/

https://fanfuhan.github.io/2019/05/21/opencv-103/

GITHUB:https://github.com/jash-git/fanfuhan_ML_OpenCV


對於HOG特徵,我們可以通過預先訓練的特徵數據,進行多尺度的對象檢測,OpenCV中基於HOG的行人檢測是一個典型案例,同時我們還可以實現自定義對象的檢測,這種自定義對象檢測,可以分為兩個部分,第一部分:通過提取樣本的HOG描述子,生成樣本的特徵數據,第二部分通過SVM進行分類學習與訓練,保存為模型。這樣我們以後就可以通過模型來實現自定義對象檢測啦。今天我們分享第二部分,使用HOG描述子特徵數據生成數據集,進行SVM分類訓練,實現對象分類識別。


這裡我已一個很常見的應用,電錶檢測為例,這類問題早期主要通過特徵匹配實現,但是這個方法比較容易受到各種因素干擾,不是很好,通過提取HOG特徵、進行SVM特徵分類、然後開窗檢測,是一個很好的解決方法。


在OpenCV中訓練SVM模型,其數據格式常見的是“行模式”就是一行(多列向量)是一個樣本,對應一個整數標籤(label)。這裡採用默認的窗口大小為64×128 提取HOG特徵向量,得到的每個樣本的向量數目等於7x15x36=3780,有多少個樣本就有多少行, 對於的標籤是每一行對應自己的標籤,有多少個訓練樣本,標籤就有多少行!


C++

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace cv::ml;
using namespace std;

string positive_dir = "D:/images/train_data/elec_watch/positive/";
string negative_dir = "D:/images/train_data/elec_watch/negative/";
void get_hog_descripor(Mat &image, vector<float> &desc);
void generate_dataset(Mat &trainData, Mat &labels);

int main(int argc, char** argv) {
	Mat trainData = Mat::zeros(Size(3780, 26), CV_32FC1);
	Mat labels = Mat::zeros(Size(1, 26), CV_32SC1);
	generate_dataset(trainData, labels);
	waitKey(0);
	return 0;
}

void get_hog_descripor(Mat &image, vector<float> &desc) {
	HOGDescriptor hog;
	int h = image.rows;
	int w = image.cols;
	float rate = 64.0 / w;
	Mat img, gray;
	resize(image, img, Size(64, int(rate*h)));
	cvtColor(img, gray, COLOR_BGR2GRAY);
	Mat result = Mat::zeros(Size(64, 128), CV_8UC1);
	result = Scalar(127);
	Rect roi;
	roi.x = 0;
	roi.width = 64;
	roi.y = (128 - gray.rows) / 2;
	roi.height = gray.rows;
	gray.copyTo(result(roi));
	hog.compute(result, desc, Size(8, 8), Size(0, 0));
}

void generate_dataset(Mat &trainData, Mat &labels) {
	vector<string> images;
	glob(positive_dir, images);
	int pos_num = images.size();
	for (int i = 0; i < images.size(); i++) {
		Mat image = imread(images[i].c_str());
		vector<float> fv;
		imshow("image", image);
		waitKey(0);
		get_hog_descripor(image, fv);
		printf("image path : %s, feature data length: %d \n", images[i].c_str(), fv.size());
		for (int j = 0; j < fv.size(); j++) {
			trainData.at<float>(i, j) = fv[j];
		}
		labels.at<int>(i, 0) = 1;
	}

	images.clear();
	glob(negative_dir, images);
	for (int i = 0; i < images.size(); i++) {
		Mat image = imread(images[i].c_str());
		vector<float> fv;
		imshow("image", image);
		waitKey(0);
		get_hog_descripor(image, fv);
		printf("image path : %s, feature data length: %d \n", images[i].c_str(), fv.size());
		for (int j = 0; j < fv.size(); j++) {
			trainData.at<float>(i+pos_num, j) = fv[j];
		}
		labels.at<int>(i+ pos_num, 0) = -1;
	}
}


Python

"""
HOG特征描述子之使用描述子特征生成样本数据
"""

import cv2 as cv
import os
import numpy as np


def get_hog_descriptor(image):
    hog = cv.HOGDescriptor()
    h, w = image.shape[:2]
    # 预处理输入图像
    rate = 64 / w
    image = cv.resize(image, (64, np.int(rate * h)))
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    bg = np.zeros((128, 64), dtype=np.uint8)
    bg[:,:] = 127
    h, w = gray.shape
    dy = (128 - h) // 2
    bg[dy:h+dy,:] = gray
    cv.waitKey(0)
    # 64x128 = 3780
    fv = hog.compute(bg, winStride=(8, 8), padding=(0, 0))
    return fv


def generate_dataset(pdir, ndir):
    train_data = []
    labels = []
    for file_name in os.listdir(pdir):
        img_dir = os.path.join(pdir, file_name)
        img = cv.imread(img_dir)
        hog_desc = get_hog_descriptor(img)
        one_fv = np.zeros([len(hog_desc)], dtype=np.float32)
        for i in range(len(hog_desc)):
            one_fv[i] = hog_desc[i][0]
        train_data.append(one_fv)
        labels.append(1)

    for file_name in os.listdir(ndir):
        img_dir = os.path.join(ndir, file_name)
        img = cv.imread(img_dir)
        hog_desc = get_hog_descriptor(img)
        one_fv = np.zeros([len(hog_desc)], dtype=np.float32)
        for i in range(len(hog_desc)):
            one_fv[i] = hog_desc[i][0]
        train_data.append(one_fv)
        labels.append(-1)
    return np.array(train_data, dtype=np.float32), np.array(labels, dtype=np.int32)


if __name__ == '__main__':
    generate_dataset("images/elec_watch/positive/",
                     "images/elec_watch/negative/")
    cv.destroyAllWindows()

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *