2016-06-20 7 views
14

今日、私はJavaとOpenCvで笑顔を検出するプロジェクトをテストします。認識の顔と口のプロジェクトにはhaarcascade_frontalface_altとhaarcascade_mcs_mouthを使用しましたが、私はなぜプロジェクトが口として鼻を検出するのか理解できません。 私は二つの方法があります:Javaとhaarascadeの顔と口の検出 - 鼻の口

private ArrayList<Mat> detectMouth(String filename) { 
    int i = 0; 
    ArrayList<Mat> mouths = new ArrayList<Mat>(); 
    // reading image in grayscale from the given path 
    image = Highgui.imread(filename, Highgui.CV_LOAD_IMAGE_GRAYSCALE); 
    MatOfRect faceDetections = new MatOfRect(); 
    // detecting face(s) on given image and saving them to MatofRect object 
    faceDetector.detectMultiScale(image, faceDetections); 
    System.out.println(String.format("Detected %s faces", faceDetections.toArray().length)); 
    MatOfRect mouthDetections = new MatOfRect(); 
    // detecting mouth(s) on given image and saving them to MatOfRect object 
    mouthDetector.detectMultiScale(image, mouthDetections); 
    System.out.println(String.format("Detected %s mouths", mouthDetections.toArray().length)); 
    for (Rect face : faceDetections.toArray()) { 
     Mat outFace = image.submat(face); 
     // saving cropped face to picture 
     Highgui.imwrite("face" + i + ".png", outFace); 
     for (Rect mouth : mouthDetections.toArray()) { 
      // trying to find right mouth 
      // if the mouth is in the lower 2/5 of the face 
      // and the lower edge of mouth is above of the face 
      // and the horizontal center of the mouth is the enter of the face 
      if (mouth.y > face.y + face.height * 3/5 && mouth.y + mouth.height < face.y + face.height 
        && Math.abs((mouth.x + mouth.width/2)) - (face.x + face.width/2) < face.width/10) { 
       Mat outMouth = image.submat(mouth); 
       // resizing mouth to the unified size of trainSize 
       Imgproc.resize(outMouth, outMouth, trainSize); 
       mouths.add(outMouth); 
       // saving mouth to picture 
       Highgui.imwrite("mouth" + i + ".png", outMouth); 
       i++; 
      } 
     } 
    } 
    return mouths; 
} 

と笑顔

private void detectSmile(ArrayList<Mat> mouths) { 
     trainSVM(); 
     CvSVMParams params = new CvSVMParams(); 
     // set linear kernel (no mapping, regression is done in the original feature space) 
     params.set_kernel_type(CvSVM.LINEAR); 
    // train SVM with images in trainingImages, labels in trainingLabels, given params with empty samples 
     clasificador = new CvSVM(trainingImages, trainingLabels, new Mat(), new Mat(), params); 
     // save generated SVM to file, so we can see what it generated 
     clasificador.save("svm.xml"); 
     // loading previously saved file 
     clasificador.load("svm.xml"); 
     // returnin, if there aren't any samples 
     if (mouths.isEmpty()) { 
      System.out.println("No mouth detected"); 
      return; 
     } 
     for (Mat mouth : mouths) { 
      Mat out = new Mat(); 
      // converting to 32 bit floating point in gray scale 
      mouth.convertTo(out, CvType.CV_32FC1); 
      if (clasificador.predict(out.reshape(1, 1)) == 1.0) { 
       System.out.println("Detected happy face"); 
      } else { 
       System.out.println("Detected not a happy face"); 
      } 
     } 
    } 

例検出:その絵については

enter image description here

が正しくこのmounthを検出:

enter image description here

が、他の画像に

enter image description here

鼻が enter image description here

を検出され、あなたの意見では問題は何ですか?

答えて

10

顔の割合(目から口への距離が長すぎるため、目の間の距離に比べて)の割合が非常に高いため、画像に間違いがあると考えられます。 haar検出器を用いた口と鼻の検出はそれほど安定ではないので、アルゴリズムは通常顔の幾何学モデルを使用して顔の特徴毎に特徴候補の最良の組み合わせを選択する。いくつかの実装では、口の候補が見つからなければ、目に基づいて口の位置を予測しようとすることさえできます。

Haar検出器は、この時点で機能検出のために最新かつ最もよく知られたものではありません。変形可能な部品モデルの実装を使用してみてください。これを試してください、彼らは効率的なC++の最適化された関数でmatlabのコードを持っています: https://www.ics.uci.edu/~xzhu/face/