public class Svm_train {
/**
* SVM训练
*/
public void svm_train(){
Integer ITERATION_NUM = 3000;
String traintxt = "E:\\biyesheji\\image\\traindata.txt";//行人
//String traintxt = "E:\\biyesheji\\image\\traindata2.txt";//人脸
ArrayList<String> img_path = new ArrayList<String>();
ArrayList<Float> img_label = new ArrayList<Float>();
//System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.load("E:\\biyesheji\\opencv\\build\\java\\x64\\opencv_java330.dll");
System.out.println("类库加载成功·");
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(traintxt)),
"UTF-8"));
//System.out.println("读取文件");
String linetxt = null;
Integer nline = 0;
while((linetxt = br.readLine()) !=null){
nline++;
String []path_label = linetxt.split("\t");
//System.out.println(path_label[0] + ' ' + path_label[1]);
img_path.add(path_label[0]);
img_label.add(Float.valueOf(path_label[1]).floatValue());
}
br.close();
//一个block内有4个cell,每个cell含9维特征向量,故每个block就由4x9=36维特征向量来表征
//128x64(高128,宽64),即有(128÷8)x(64÷8)=16x8个cell,也即有15x7个block
//在提取每个窗口的HOG特征,则可得到105x36=3780维HOG特征向量
Integer SAMPLE_COUNT = nline; //样本数
Integer PICTURE_FEATURE_DIM = 3780;//图片特征维数,64*64(1764),64*128(3780),128*128(8100)
//Integer PICTURE_FEATURE_DIM = 1764;//人脸
Mat data_mat = new Mat(SAMPLE_COUNT, PICTURE_FEATURE_DIM, CvType.CV_32FC1);//行,列,类型
Mat res_mat = new Mat(SAMPLE_COUNT, 1, CvType.CV_32SC1);
//svm descriptors
ArrayList<float[]> descriptors = new ArrayList<float[]>();
for (Integer i=0;i<img_path.size();i++){
System.out.println("GetHog:"+img_path.get(i));
Mat src = Imgcodecs.imread(img_path.get(i));
if(src.empty()){
System.out.println(img_path.get(i));
throw new Exception("no such picture");
}
if(img_label.get(i)==1)
{
if(src.cols()>64 || src.rows()>128)//行人128
{
//去掉上下左右16个像素
Rect Roi=new Rect(new Point(16,16),new Size(64,128));//行人128
Mat image= src.submat(Roi);//子图
HOGDescriptor hog = new HOGDescriptor(new Size(64, 128), new Size(16, 16), new Size(8, 8), new Size(8, 8), 9);//行人128
MatOfFloat descriptorsOfMat = new MatOfFloat();
hog.compute(image, descriptorsOfMat);//调用计算函数
float[] descriptor = descriptorsOfMat.toArray();//一列
descriptors.add(descriptor);
}else{
HOGDescriptor hog = new HOGDescriptor(new Size(64, 128), new Size(16, 16), new Size(8, 8), new Size(8, 8), 9);//行人
//HOGDescriptor hog = new HOGDescriptor(new Size(64, 64), new Size(16, 16), new Size(8, 8), new Size(8, 8), 9);//人脸
MatOfFloat descriptorsOfMat = new MatOfFloat();
hog.compute(src, descriptorsOfMat);//调用计算函数
float[] descriptor = descriptorsOfMat.toArray();//一列
descriptors.add(descriptor);
}
}else if(img_label.get(i)==0){
//Hog特征,窗口大小(宽,高),块大小,块滑动增量,胞元大小,梯度方向数
HOGDescriptor hog = new HOGDescriptor(new Size(64, 128), new Size(16, 16), new Size(8, 8), new Size(8, 8), 9);//行人128
MatOfFloat descriptorsOfMat = new MatOfFloat();
hog.compute(src, descriptorsOfMat);//调用计算函数
float[] descriptor = descriptorsOfMat.toArray();//一列
descriptors.add(descriptor);
}
}
for (Integer m = 0; m < descriptors.size(); m++) {
for (int n = 0; n < descriptors.get(m).length; n++) {
data_mat.put(m, n, descriptors.get(m)[n]);//按行存储
}
res_mat.put(m, 0, img_label.get(m));//一列向量
}
System.out.println("开始训练。。。。。");
SVM svm = SVM.create();
svm.setType(SVM.C_SVC);
svm.setKernel(SVM.LINEAR);//线性,HogDescriptor检测函数只支持线性检测
svm.setC(0.01);
svm.setGamma(0.5);
svm.setTermCriteria(new TermCriteria(TermCriteria.MAX_ITER, ITERATION_NUM, 1e-6));
svm.train(data_mat, Ml.ROW_SAMPLE, res_mat);
svm.save("E:\\biyesheji\\image\\svm_java");//行人
//svm.save("E:\\biyesheji\\image\\svm_java2");//人脸
System.out.println("保存模型。。");
}catch (Exception e){
System.err.println("read err:" + e);
}
}
//自定义检测器
public Mat myDetector()
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//SVM svm = SVM.load("E:\\biyesheji\\image\\svm_java2");//人脸
SVM svm = SVM.load("E:\\biyesheji\\image\\svm_java");//行人
//获取支持向量
Mat svecsmat = svm.getSupportVectors();
int numofsv = svecsmat.rows();//支持向量个数
System.out.println("支持向量个数:"+numofsv);
int svdim = svm.getVarCount();//特征向量维数,即HOG描述子的维数
System.out.println("特征向量维数:"+svdim);
//初始化alphamat和svindex
Mat alphaMat = Mat.zeros(1, numofsv, CvType.CV_32F);
Mat supportVectorMat = Mat.zeros(numofsv, svdim, CvType.CV_32FC1);
Mat resultMat = Mat.zeros(1, svdim, CvType.CV_32FC1);
Mat svidx = Mat.zeros(1, numofsv, CvType.CV_32F);
//获得模型中的rho
double rho = svm.getDecisionFunction(0, alphaMat, svidx);
System.out.println("rho:"+rho);
alphaMat.convertTo(alphaMat, CvType.CV_32F);
//System.out.println(alphaMat.rows()+","+alphaMat.cols());
//将支持向量和alpha复制到对应Mat中
supportVectorMat = svecsmat;
//alpha*src1*src2 + beta*src3,-1 * alphamat * supportVectorMat,点乘
Core.gemm(alphaMat, supportVectorMat, -1, new Mat(), 0, resultMat);
//定义一个大一维的向量,便于后面添加rho
Mat myDetector = new Mat(1, svdim+1, CvType.CV_32FC1);
for(int j=0;j<svdim;j++)
{
double[] value2 = resultMat.get(0, j);
myDetector.put(0, j, value2[0]);
}
//添加rho
myDetector.put(0, svdim, rho);
System.out.println("rho:"+myDetector.get(0, svdim)[0]);
return myDetector;
//开始检测
}
}
|