OpenCV Java Smile Detection - java

I've tried to create a smile detector with source code that I've found on the Internet. It detects face and works pretty well. It uses Haar classifiers, I've found the Haar classifiers for smile recognition and tried it, however it doesn't work. I've tried to use it in the same way that was used to recognize face. Tried the same with eye classifier - and it worked. All classifiers I've found in opencv/data folder, could somebody give me a tip, what could I do more with given code?
import java.io.File;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.objdetect.CascadeClassifier;
public class SmileDetector {
public void detectSmile(String filename) {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
System.out.println("\nRunning SmileDetector");
CascadeClassifier faceDetector = new CascadeClassifier(new File(
"src/main/resources/haarcascade_frontalface_alt.xml").getAbsolutePath());
CascadeClassifier smileDetector = new CascadeClassifier(
new File("src/main/resources/haarcascade_smile.xml").getAbsolutePath());
Mat image = Highgui.imread(filename);
MatOfRect faceDetections = new MatOfRect();
MatOfRect smileDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));
for (Rect rect : faceDetections.toArray()) {
Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
Mat face = image.submat(faceDetections.toArray()[0]);
smileDetector.detectMultiScale(face, smileDetections);
for (Rect rect : smileDetections.toArray()) {
Core.rectangle(face, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0));
}
String outputFilename = "ouput.png";
System.out.println(String.format("Writing %s", outputFilename));
Highgui.imwrite(outputFilename, image);
Highgui.imwrite("ee.png", face);
}
}

To answer Vi Matviichuk comment:
Yes I was partially able to fix the problem. I've used mouth classifier instead of smile, the name of mouth classifier from opencv samples is haarcascade_mcs_mouth.xml ; then you look for faces, crop them and look for mouths on faces. However it will give you a lot of mouths, so you have to filter them by:
/**
* Detects face(s) and then for each detects and crops mouth
*
* #param filename path to file on which smile(s) will be detected
* #return List of Mat objects with cropped mouth pictures.
*/
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;
}
Then you have to find a smile, I tried to do this with SVM training machine, but I hadn't got enough samples so it wasn't perfect. However, whole code I got can be found here: https://bitbucket.org/cybuch/smile-detector/src/ac8a309454c3467ffd8bc1c34ad95879cb059328/src/main/java/org/cybuch/smiledetector/SmileDetector.java?at=master

Related

Exception in thread "main" java.lang.UnsatisfiedLinkError: org.opencv.imgcodecs.Imgcodecs.imread_0(Ljava/lang/String;I)J

I have started working on the opencv libary and in this code I want impelement face detection but its throwing the complie time error I also check native libary path and also checked in the wheather the given file is exist or not but at the time imread() function getting error
Thanks in advance
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat mat = Mat.eye(3, 3, CvType.CV_8UC1);
System.out.println("mat = " + mat.dump());
CascadeClassifier faceDetector = new CascadeClassifier();
faceDetector.load("C:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml");
// Input image
File file = new File("C:\\Users\\bill.jpg");
if (file.exists()) {
System.out.println("file found at " + file.getAbsolutePath());
// This is true
Mat image = Imgcodecs.imread(file.getAbsolutePath(), Imgcodecs.CV_LOAD_IMAGE_COLOR); // file.getPath() also
// same
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
for (Rect rect : faceDetections.toArray()) {
Imgproc.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
}
}
String filename = "Ouput.jpg";
// Imgcodecs.imwrite("D:\\"+filename, image);

Want to store detected cropped images in a file

I have successfully detected human faces using haarcascade in opencv. I have run a loop in which it will crop only the detected portion of the image and store into the system. But it crops only one detected face and rest of the faces doesn't get cropped and save into the system. I am attaching my code. please help to to solve my issue. Eg. if image contains 4 people then haarcascade detect 4 faces but the loop only crops one detected image and rest 3 images does not get cropped..!
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
public class FaceDetection
{
public static void main(String[] args)
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
CascadeClassifier faceDetector = new CascadeClassifier();
faceDetector.load("G:\\haarcascade_frontalface_alt.xml");
//System.out.println ( "Working" );
// Input image
Mat image = Imgcodecs.imread("G:\\sample.jpg");
// Detecting faces
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
System.out.println(String.format("Detected %s faces",
faceDetections.toArray().length));
// Creating a rectangular box showing faces detected
Rect rectCrop=null;
for (Rect rect : faceDetections.toArray())
{
Imgproc.rectangle(image, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(0, 255, 0),2);
rectCrop = new Rect(rect.x, rect.y, rect.width, rect.height);
}
Rect[] count = faceDetections.toArray();
System.out.println(""+count.length);
// Saving the output image
String filename = "Ouput.jpg";
Imgcodecs.imwrite("G:\\"+filename, image);
Mat markedImage = new Mat(image,rectCrop);
Imgcodecs.imwrite("G:\\crop1.jpg",markedImage );
}
}
Your code is looping over all of them and choosing the last face and then saving that face. You need it to either a) crop them separately and add meta that tags them together, or b)crop them all together.
For option a, inside your loop, you need to save each file separately. Simply move you saving file code into your loop and adjust it so that it works.
For option b, you might need some additional software to crop all of the faces together. This could be done a number of ways. You could concatenate all of the a)pixle arrays, or b)individual bytes. Then when you need to find connections between people you simply have to run the face recognition software on the files again.

Java and haarcascade face and mouth detection - mouth as the nose

Today I begin to test the project which detects a smile in Java and OpenCv. To recognition face and mouth project used haarcascade_frontalface_alt and haarcascade_mcs_mouth But i don't understand why in some reasons project detect nose as a mouth.
I have two methods:
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;
}
and detect smile
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");
}
}
}
Examples:
For that picture
correctly detects this mounth:
but in other picture
nose is detected
What's the problem in your opinion ?
Most likely it detects it wrong on your picture, because of proportion of face (too long distance from eyes to mouth compared to distance between eyes). Detection of mouth and nose using haar detector isn't very stable, so algorithms usually use geometry model of face, to choose best combination of feature candidates for each facial feature. Some implementations can even try to predict mouth position based on eyes, if no mouth candidates was found.
Haar detector isn't the newest and best known at this time for feature detection. Try to use deformable parts model implementations. Try this, they have matlab code with efficient c++ optimized functions:
https://www.ics.uci.edu/~xzhu/face/

OpenCV Object Detection and Splitting, clustering?

I'm currently working on an application that will split a scanned image (that contains multiple receipts) into individual receipt images.
Below is the sample image:
sample image
I was able to detect the edges of each receipts in the scanned image using canny function of OpenCV.
Below is the sample image with detected edges:
sample image with detected edges
... and the sample code is
Mat src = Highgui.imread(filename);
Mat gray = new Mat();
int threshold = 12;
Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
Imgproc.blur(gray, gray, new Size(3, 3));
Imgproc.Canny(gray, gray, threshold, threshold * 3, 3, true);
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(gray, contours, hierarchy,
Imgproc.RETR_CCOMP,
Imgproc.CHAIN_APPROX_SIMPLE);
if (hierarchy.size().height > 0 && hierarchy.size().width > 0) {
for (int idx = 0; idx >= 0; idx = (int) hierarchy.get(0, idx)[0]) {
Rect rect = Imgproc.boundingRect(contours.get(idx));
Core.rectangle(src, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height),
new Scalar(255, 0, 0));
}
}
Now my problem is, I don't know how am I going to identify the 3rd receipt since unlike with the first 2 it is not enclosed in one rectangular shape which I will use as the basis for splitting the image.
I've heard that for me to extract the 3rd image, I must use a clustering algorithm like DBSCAN, unfortunately I can't find one.
Anyone knows how am I going to identify the 3rd image?
Thank you in advance!

Drawing the shape of the detected object?

I successfully detected the upperbody of the person in a picture. But all I can do now is draw a rectangle around the upperbody. How can I trace the upperbody?, i.e. draw a line (that looks like the upperbody) around the detected upperbody. I'm working with OpenCV.
Here's some code from the detection system.
if(new File("E:\\OpenCV\\opencv\\data\\haarcascades\\haarcascade_mcs_upperbody.xml\\").isFile())
{ System.out.println("file there"); }
cascadeClassifier = new CascadeClassifier("E:\\OpenCV\\opencv\\data\\haarcascades\\haarcascade_mcs_upperbody.xml");
inputPic = Highgui.imread(picSrcDir + picName);
MatOfInt intw = new MatOfInt(1);
MatOfDouble dble = new MatOfDouble(1.05);
rect = new MatOfRect();
cascadeClassifier.detectMultiScale(inputPic, rect, intw, dble);
Scalar color = new Scalar(0, 0, 255);
System.out.println("Number Of Hits: " + rect.toArray().length);
Rect[] rectArr = rect.toArray();
System.out.println(rectArr.length);
int i=0;
for(Rect recta : rectArr){
System.out.println(rectArr[i]); i++;
Core.rectangle(inputPic, new Point(recta.x, recta.y), new Point(recta.x+recta.width, recta.y+recta.height), color);
}
Highgui.imwrite(picName, inputPic);
After detecting the people upperbody rect:
Remove the rect background, keeping just the person upperbody.
Binarize the image.
Apply morphological boundary algorithm to trace the upperbody.
Example:
OpenCV provides these algorithms. However, the example above was developed using Marvin. The source code is presented below:
public class TraceShape {
public TraceShape(){
// Load Plug-in
MarvinImagePlugin boundary = MarvinPluginLoader.loadImagePlugin("org.marvinproject.image.morphological.boundary");
// Load image
MarvinImage image = MarvinImageIO.loadImage("./res/person.jpg");
// Binarize
MarvinImage binImage = MarvinColorModelConverter.rgbToBinary(image, 245);
MarvinImageIO.saveImage(binImage, "./res/person_bin.png");
// Boundary
boundary.process(binImage.clone(), binImage);
MarvinImageIO.saveImage(binImage, "./res/person_boundary.png");
}
public static void main(String[] args) {
new TraceShape();
}
}

Categories

Resources