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()