package com.hygenics.facialrec;
import ij3d.ImgLibVolume;
import imagetools.FileTypeException;
import imagetools.GetEdges;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
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;
/**
* Generates the points on someones face. Finds the most oval object by trying
* to fit an oval to someones face. At different angles until the Best Fitting
* Oval is Found. The proportion is based on the average width. Discontinuitues
* are dealt with by turning the oval into a minimum bounding oval.
*
* Cascades will need to be set. The default for them is the OpenCV_2_8\openc\source\dat\haarcascades folder
* Haar seems to perform better than lbp.
*
* This is the company's but is also open source. I'm not taking pennies on the dollar for edge-detection, splines,custom haar cascade generation; etc. when those are upper level concepts
* and capable of generating good products. This program uses OpenCV which is pre-trained and utilizes math that can be redone in just about any fashion in case
* I want to develop something on my own.
*
* @author aevans
*
*/
public class GetFacialFeatures{
private String mouthcascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_mcs_mouth.xml";
private String smilecascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_smile.xml";
private String nosecascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_mcs_nose.xml";
private String leftearcascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_mcs_leftear.xml";
private String rightearcascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_mcs_rightear.xml";
private String eyeglasscascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_eye_tree_eyeglasses.xml";
private String eyescascade="C:\\User/aevan/Document/OpenCV_2_8_/openc/source/dat/haarcascade/haarcascade_eye.xml";
private BufferedImage bi;
//this is by pixel
private int widthoffset=1;
private String temporaryfpath="C:\\Users\\aevans\\Pictures\\FaceImages\\testimage.jpg";
private ArrayList<ObjectRect> objects=new ArrayList<ObjectRect>();
private boolean mouth=false;
private boolean ears=false;
private boolean eyes=false;
private boolean nose=false;
private boolean glasses=false;
private boolean smile=false;
private boolean markoriginal=false;
private boolean addOtherFeatures=false;
public GetFacialFeatures() {
}
public boolean isMarkoriginal() {
return markoriginal;
}
public void setMarkoriginal(boolean markoriginal) {
this.markoriginal = markoriginal;
}
public boolean isSmile() {
return smile;
}
public void setSmile(boolean smile) {
this.smile = smile;
}
public boolean isMouth() {
return mouth;
}
public void setMouth(boolean mouth) {
this.mouth = mouth;
}
public boolean isEars() {
return ears;
}
public void setEars(boolean ears) {
this.ears = ears;
}
public boolean isEyes() {
return eyes;
}
public void setEyes(boolean eyes) {
this.eyes = eyes;
}
public boolean isNose() {
return nose;
}
public void setNose(boolean nose) {
this.nose = nose;
}
public boolean isGlasses() {
return glasses;
}
public void setGlasses(boolean glasses) {
this.glasses = glasses;
}
public boolean isAddOtherFeatures() {
return addOtherFeatures;
}
public void setAddOtherFeatures(boolean addOtherFeatures) {
this.addOtherFeatures = addOtherFeatures;
}
public int getWidthoffset() {
return widthoffset;
}
public void setWidthoffset(int widthoffset) {
this.widthoffset = widthoffset;
}
public String getMouthcascade() {
return mouthcascade;
}
public void setMouthcascade(String mouthcascade) {
this.mouthcascade = mouthcascade;
}
public String getSmilecascade() {
return smilecascade;
}
public void setSmilecascade(String smilecascade) {
this.smilecascade = smilecascade;
}
public String getNosecascade() {
return nosecascade;
}
public void setNosecascade(String nosecascade) {
this.nosecascade = nosecascade;
}
public String getLeftearcascade() {
return leftearcascade;
}
public void setLeftearcascade(String leftearcascade) {
this.leftearcascade = leftearcascade;
}
public String getRightearcascade() {
return rightearcascade;
}
public void setRightearcascade(String rightearcascade) {
this.rightearcascade = rightearcascade;
}
public String getEyeglasscascade() {
return eyeglasscascade;
}
public void setEyeglasscascade(String eyeglasscascade) {
this.eyeglasscascade = eyeglasscascade;
}
public String getEyescascade() {
return eyescascade;
}
public void setEyescascade(String eyescascade) {
this.eyescascade = eyescascade;
}
public BufferedImage getBi() {
return bi;
}
public void setBi(BufferedImage bi) {
this.bi = bi;
}
/**
* Finds features for mapping splines
*/
private void findFeatures()
{
//TODO get the eyes, eyeglasses, nose, mouth, and ears from the image and get them as a marked
//box, the points will be obtained in the form of a starting x,y and width and returned
//as an object
//cascade array
ArrayList<String> cascades=new ArrayList<String>();
if(mouth){
cascades.add(mouthcascade);
}
if(smile){
cascades.add(smilecascade);
}
if(nose){
cascades.add(nosecascade);
}
if(ears){
cascades.add(leftearcascade);
cascades.add(rightearcascade);
}
if(glasses){
cascades.add(eyeglasscascade);
}
if(eyes){
cascades.add(eyescascade);
}
//load library
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//save image if it has not been saved
try {
ImageIO.write(bi,".jpg", new File(temporaryfpath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//perform detection for each part of the cascade
for(String cascade : cascades)
{
if(cascade.toLowerCase().contains(".xml")==true)
{
CascadeClassifier faceDetector = new CascadeClassifier(cascade);
if( faceDetector.empty()==false)
{
//read image if cascade found
Mat image = Highgui.imread(temporaryfpath);
//face detect
if(image.empty()==false)
{
System.out.println("Finding Faces");
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);
System.out.println("Found "+faceDetections.toArray().length+" objects.");
//get each rectangle and set as an object with appropriate height, width, x, and y, positions
for(Rect rect : faceDetections.toArray())
{
//set the appropriate boolean
if(cascade.compareTo(leftearcascade)==0|cascade.compareTo(rightearcascade)==0)
{
//ears
ears=true;
}
else if(cascade.compareTo(mouthcascade)==0)
{
//mouth (not smile)
mouth=true;
}
else if(cascade.compareTo(smilecascade)==0){
//smile only
smile=true;
}
else if(cascade.compareTo(nosecascade)==0)
{
//nose
nose=true;
}
else if(cascade.compareTo(eyescascade)==0)
{
//eyes
eyes=true;
}
else if(cascade.compareTo(eyeglasscascade)==0)
{
//eyeglasses
glasses=true;
}
//create the appropriate found object
ObjectRect or=new ObjectRect();
or.setX(rect.x);
or.setY(rect.y);
or.setHeight(rect.height);
or.setWidth(rect.width);
//set the object in the array
objects.add(or);
if(markoriginal){
//TODO Mark a green rectange ON THE ORIGINAL IMAGE
//if a request is made to mark the original, mark the detected feature (this would be useful for testing)
//the color can be changed but bright green works well (opencv does something similar, its nice and ugly)
//mark the horizontal bars
for(int x=rect.x;x<(rect.x+rect.width);x++){
bi.setRGB(x, rect.y, new Color(0,255,0).getRGB());
bi.setRGB(x, (rect.y+rect.height), new Color(0,255,0).getRGB());
}
//mark the vertical bars
for(int y=rect.y; y<(rect.y+rect.height);y++){
bi.setRGB(rect.x, y, new Color(0,255,0).getRGB());
bi.setRGB((rect.x+rect.width), y, new Color(0,255,0).getRGB());
}
}
}
}
else{
try{
throw new NullPointerException("No Image Found");
}catch(NullPointerException e)
{
e.printStackTrace();
}
}
}
else
{
try{
throw new FileTypeException("Cascade Must be of TYpe XML");
}catch(FileTypeException e){
e.printStackTrace();
}
}
}
}
}
/**
* Find prominent features from an image which are usedin the formation of points
*/
private void findOtherFeatures(){
//TODO find large chunks of noise from the image
//use a laplace filter to grab drastic changes in the image (the map of noise points in denoise)
//find the noisy points
//find clusters of points that may represent prominent features
}
/**
* Get an edge detected image
*
* @return
*/
private BufferedImage getEdges(){
//TODO Get the Edge Detected Image
//get edges and add points to them
GetEdges edges=new GetEdges();
edges.setImage(bi);
//get cleaner and less edges
edges.edge_detect(false);
//get the image which is prepped for
return edges.getImage();
}
/**
* Run facial point generator
*/
public void run() {
//get the features
findFeatures();
if(addOtherFeatures){
//at this point, this is mainly for silhuoette detection since different poses will seriously effect the outcome
findOtherFeatures();
}
}
}