Eye detection in Oscar selfie - c++

I have to perform eye detection on each of the faces in the famous Oscar selfie image.I tried using Haar Casacades on the faces since most of them are near-frontal, but the eye detection is totally random and no eyes are being recognized at all.
I have have tried the same haar cascade xml file for eye detection on images with single faces and it worked fine.
What steps could I take to correctly detect the eyes?
The image I used for eye detection can be downloaded from here:
https://drive.google.com/file/d/0B3jt6sHgpxO-d1plUjg5eU5udW8/view?usp=sharing
Below is the code I have written for face and eye detection. Basic idea is I first detect the face using viola jones algorithm and within each face, I try to detect the eyes.
#include <opencv2/highgui/highgui.hpp>
#include <cv.h>
#include <opencv2/objdetect/objdetect.hpp>
#include <vector>
using namespace cv;
using namespace std;
int x,y,w,h;
int main(int argc, const char** argv)
{
Mat image = imread("oscarSelfie.jpg",CV_LOAD_IMAGE_UNCHANGED);
Mat gray_img;
cvtColor(image, gray_img, CV_BGR2GRAY);
string faceCascade_file = "haarcascade_frontalface_alt2.xml";
string eyeCascade_file = "haarcascade_eye.xml";
CascadeClassifier faceCascade;
CascadeClassifier eyeCascade;
//Cascade classifier is a class which has a method to load the classifier from file
if( !faceCascade.load( faceCascade_file ) )
{ cout<<"--(!)Error loading\n"; return -1; };
//If it returns zero, it means an error has occured in loading the classifier
if( !eyeCascade.load( eyeCascade_file ) )
{ cout<<"--(!)Error loading\n"; return -1; };
equalizeHist(gray_img, gray_img);
//Increases contrast and make image more distingushable
/***** Detecting Faces in Image *******/
vector<Rect> faces;
vector<Rect> eyes;
//Rect is a class handling the rectangle datatypes
faceCascade.detectMultiScale(gray_img, faces, 1.1, 1, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
//faces.size()-it will return number of faces detected
for( int i = 0; i < faces.size(); i++ )
{
x = faces[i].x;
y = faces[i].y;
w = faces[i].width;
h = faces[i].height;
//Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
//ellipse( image, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
rectangle(image, cvPoint(x,y), cvPoint(x+w,y+h), CV_RGB(0,255,0), 2, 8 );
/******** Detecting eyes ***********/
eyeCascade.detectMultiScale(gray_img, eyes, 1.1, 50, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
for(int j=0; j < eyes.size(); j++)
{
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( image, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
namedWindow("oscarSelfie :)", CV_WINDOW_AUTOSIZE);
imshow("oscarSelfie :)", image);
waitKey(0);
destroyWindow("pic");
return 0;
}
`

i get the following result with facedetect.cpp (uses haarcascade_eye_tree_eyeglasses.xml)
don't expect to find all faces and eyes
i also tried dlib's face_landmark_detection_ex.cpp to compare results
dlib has an extra feature that gives you aligned faces like seen below

You may want to use CLM-framework for face landmark detection. As far as I have experience CLM-framework performance satisfactory.
Some examples of the system in action: http://youtu.be/V7rV0uy7heQ

Related

Counting coins using OpenCV

I have been trying to develop a program - written with C++ and using OpenCV -which counts the overall value of coins shown in some image.
I should note that I am new to the opencv platform.
In order to achieve this goal, as far as I understand - there has to be a use of the Hough transform to detect the ratio of the coins. I found this code example on the OpenCV site, but I can't put a value for the coins.
Here is what I have done so far.
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
namespace
{
const std::string windowName = "Coins detection";
const std::string cannyThresholdTrackbarName = "Canny threshold";
const std::string accumulatorThresholdTrackbarName = "Accumulator Threshold";
const int cannyThresholdInitialValue = 41;
const int accumulatorThresholdInitialValue = 87;
const int maxAccumulatorThreshold = 200;
const int maxCannyThreshold = 255;
void HoughDetection(const Mat& src_gray, const Mat& src_display, int cannyThreshold, int accumulatorThreshold)
{
std::vector<Vec3f> circles;
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, cannyThreshold, accumulatorThreshold, 0, 0 );
Mat display = src_display.clone();
for( size_t i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );
circle( display, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
imshow( windowName, display);
}
}
int main(int argc, char** argv)
{
Mat src, src_gray;
String imageName("c:\\moedas.jpg");
if (argc > 1)
{
imageName = argv[1];
}
src = imread( imageName, IMREAD_COLOR );
if( src.empty() )
{
std::cerr<<"Invalid input image\n";
return -1;
}
cvtColor( src, src_gray, COLOR_BGR2GRAY );
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
int cannyThreshold = cannyThresholdInitialValue;
int accumulatorThreshold = accumulatorThresholdInitialValue;
namedWindow( windowName, WINDOW_AUTOSIZE );
createTrackbar(cannyThresholdTrackbarName, windowName, &cannyThreshold,maxCannyThreshold);
createTrackbar(accumulatorThresholdTrackbarName, windowName, &accumulatorThreshold, maxAccumulatorThreshold);
char key = 0;
while(key != 'q' && key != 'Q')
{
cannyThreshold = std::max(cannyThreshold, 1);
accumulatorThreshold = std::max(accumulatorThreshold, 1);
HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);
key = (char)waitKey(10);
}
return 0;
}
The code you have so far only segments circle shapes in an input image. This is just the first step to count the coins. There are many ways to perform that task, ranging from simple contour counting techniques to complicated deep learning, and the explanation of such techniques is too broad and large in scope to put efficiently and concisely in an SO answer. However, here are some coin detectors/counter implementations/tutorials that you can check:
Implementation 1 in Python. This is the best of the list, although the code file is larger than yours, not too hard to port to C++. It has the best detection/counting performance but deals with Neural Networks, specifically, a Multilayer Perceptron.
Implementation 2 in Python. This is a very small code file, nearly as large as yours and has no idiomatic Python code, porting it to C++ is a no brainer, you should start here. This implementation uses mere contour counting with the aid of the Canny edge detector.
Tutorial 1 in C++. A simple tutorial in C++, but only serves introductory purposes, the implementations listed above are the real thing.

opencv detects multiple small circles, but not larger one

I am very new to OpenCV and I am trying to detect just the penny image, but I am getting a bunch of smaller circles. Can someone tell me what Im doing wrong?
Code from here: https://github.com/opencv/opencv/blob/master/samples/cpp/houghcircles.cpp
Only things I changed were to make min circle radius 400, and max of circle 0. Because I know the image will be 600x480 so the penny circle must be at least 400.
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
cout << "\nThis program demonstrates circle finding with the Hough transform.\n"
"Usage:\n"
"./houghcircles <image_name>, Default is ../data/board.jpg\n" << endl;
}
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv,
"{help h ||}{#image|../data/board.jpg|}"
);
if (parser.has("help"))
{
help();
return 0;
}
//![load]
string filename = parser.get<string>("#image");
Mat img = imread(filename, IMREAD_COLOR);
if(img.empty())
{
help();
cout << "can not open " << filename << endl;
return -1;
}
//![load]
//![convert_to_gray]
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
//![convert_to_gray]
//![reduce_noise]
medianBlur(gray, gray, 5);
//![reduce_noise]
//![houghcircles]
vector<Vec3f> circles;
HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
gray.rows/16, // change this value to detect circles with different distances to each other
100, 30, 400,0 // change the last two parameters
// (min_radius & max_radius) to detect larger circles
);
//![houghcircles]
//![draw]
for( size_t i = 0; i < circles.size(); i++ )
{
Vec3i c = circles[i];
circle( img, Point(c[0], c[1]), c[2], Scalar(0,0,255), 3, LINE_AA);
circle( img, Point(c[0], c[1]), 2, Scalar(0,255,0), 3, LINE_AA);
}
//![draw]
//![display]
imshow("detected circles", img);
waitKey();
//![display]
return 0;
}
You've got radius and diameter mixed up. Your minimum radius cannot be 400 if your image is only 600x480. Set your min_radius to 200.
HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
max(gray.cols,gray.rows), // to find only the biggest perfect circle
100, 100, 0,0 // leave other params as default
);

C++ OpenCV Reading HaarCascades Slowing Down Computer

I'm writing a program using C++ and OpenCV. It's actually my first so what I'm asking is probably something very basic I've overlooked. Much of it is copied - not copy+pasted mind you, but copied by hand, going line by line, understanding what each line was doing as I wrote it - from some of OpenCV's tutorials. I'll paste the code below.
The problem I'm encountering is that as soon as the webcam starts trying to implement facial recognition, everything just SLOWS. DOWN. As I understand it, its because the .exe is trying to read from two MASSIVE .xml files every frame update, but I don't have any idea how to fix it. It was worse before I constrained the height, width, and framerate of the video.
If anyone has any ideas at this point, I'd love to hear them. I'm very new to software programming - until now I've mostly done web development, so I'm not used to worrying about system memory and other factors.
Thanks in advance!
EDIT: Here are my system specs: Mac, OSX 10.9.4, 2.5 GHz Intel Core i5, 4 GB 1600 MHz DDR3 RAM.
#include "opencv2/objdetect.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame );
/** Global variables */
String face_cascade_name = "haarcascade_frontalface_alt.xml";
String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
String window_name = "Capture - Face detection";
/** #function main */
int main( void )
{
cv::VideoCapture capture;
Mat frame;
//-- 1. Load the cascades
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading face cascade\n"); return -1; };
if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading eyes cascade\n"); return -1; };
//-- 2. Read the video stream
capture.open( -1 );
if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; }
capture.set(CV_CAP_PROP_FRAME_WIDTH,640);
capture.set(CV_CAP_PROP_FRAME_HEIGHT,480);
capture.set(CV_CAP_PROP_FPS, 15);
while ( capture.read(frame) )
{
if( frame.empty() )
{
printf(" --(!) No captured frame -- Break!");
break;
}
//-- 3. Apply the classifier to the frame
detectAndDisplay( frame );
int c = waitKey(10);
if( (char)c == 27 ) { break; } // escape
}
return 0;
}
/** #function detectAndDisplay */
void detectAndDisplay( Mat frame )
{
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
for ( size_t i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes;
//-- In each face, detect eyes
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CASCADE_SCALE_IMAGE, Size(30, 30) );
for ( size_t j = 0; j < eyes.size(); j++ )
{
Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
//-- Show what you got
imshow( window_name, frame );
}
A quick solution would be to replace:
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CASCADE_SCALE_IMAGE, Size(30, 30) );
by
eyes_cascade.detectMultiScale( faceROI, eyes, 1.3, 2, 0 |CASCADE_SCALE_IMAGE, Size(60, 60), Size(350, 350) );
1.3 is the scale factor, Size(60, 60) the min windows size and Size(350, 350) the max one. It means basically that it will start to search for 60*60 faces then increase size by oldWindowSize*1.3 until it reach 350*350. It is assumed there that your faces are min 60*60 and max 350 * 350.
You can tune it even more depending what you want. The minSize will have a the most impact on performance as well as scale (but 1.3 is already high). The maxSize will have less impact.
After this update, your prog should be twice faster or decrease CPU usage by half. However, I am still surprise that with your current tunings and you computer you have performances problems...
Give us a feedback if it works.

Detecting Circle Using Hough Transform

I'm trying to detect circles with using hough transform.
With my current code I can detect the one below
But I want to find black hole inside the circle I've detected.
however changing parameters of houghcircle method is not helped me. Actually it found circles that are not exist.
Also I've tried crop the circle I've found and do another hough transform on this new part it also didn't help me.
here is my code
#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/opencv.hpp" // needs imgproc, imgcodecs & highgui
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat src, circleroi;
/// Read the image
src = imread( "/Users/Rodrane/Documents/XCODE/test/mkedenemeleri/alev/delikli/gainfull.jpg", 2 );
/// Convert it to gray
// cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src, src, Size(3, 3), 2, 2 );
// adaptiveThreshold(src,src,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,9,14);
vector<Vec3f> circles,circlessmall;
// Canny( src, src, 50 , 70, 3 );
/// Apply the Hough Transform to find the circles
HoughCircles( src, circles, CV_HOUGH_GRADIENT, 1, src.rows/8, 200, 100, 0, 0 );
/// Draw the circles detected
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][4]));
int radius = cvRound(circles[i][5]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,255,0), 3, 8, 0 );
circleroi = src(Rect(center.x - radius, // ROI x-offset, left coordinate
center.y - radius, // ROI y-offset, top coordinate
2*radius, // ROI width
2*radius));
// imshow( "Hough Circle Transform Demo", circleroi );
}
resize(src, src, Size(src.cols/2, src.rows/2));
// threshold( circleroi, circleroi, 50, 255,CV_THRESH_BINARY );
// cout<<circleroi<<endl;
imshow("asd",src);
// imwrite("/Users/Rodrane/Documents/XCODE/test/mkedenemeleri/alev/cikti/deliksiz.jpg",circleroi);
waitKey(0);
return 0;
}
Update: since hough uses canny inside I'm manually used canny to see wether it finds the circle or not.
here canny results with
Canny(src,src, 100, 200,3);
thank you
You're setting one of the HoughCircles parameters minDist = src.rows/8, which is fairly large. The docs explain:
minDist – Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
The method can't return both the circle that it does find and the circle that you want, since they have nearly the same center (to within src.rows/8), just different sizes. If you set maxRadius to a value around 30 in order to exclude the larger circle, do you get the desired smaller circle?

How to detect the Sun from the space sky in OpenCv?

I need to detect the Sun from the space sky.
These are examples of the input images:
I've got such results after Morphologic filtering ( open operation for twice )
Here's the algorithm code of this processing:
// Color to Gray
cvCvtColor(image, gray, CV_RGB2GRAY);
// color threshold
cvThreshold(gray,gray,150,255,CV_THRESH_BINARY);
// Morphologic open for 2 times
cvMorphologyEx( gray, dst, NULL, CV_SHAPE_RECT, CV_MOP_OPEN, 2);
Isn't it too heavy processing for such a simple task? And how to find the center of the Sun? If I find white points, than I'll find white points of big Earth ( left top corner on first example image )
Please advise me please my further action to detect the Sun.
UPDATE 1:
Trying algorithm of getting centroid by formula : {x,y} = {M10/M00, M01/M00}
CvMoments moments;
cvMoments(dst, &moments, 1);
double m00, m10, m01;
m00 = cvGetSpatialMoment(&moments, 0,0);
m10 = cvGetSpatialMoment(&moments, 1,0);
m01 = cvGetSpatialMoment(&moments, 0,1);
// calculating centroid
float centroid_x = m10/m00;
float centroid_y = m01/m00;
cvCircle( image,
cvPoint(cvRound(centroid_x), cvRound(centroid_y)),
50, CV_RGB(125,125,0), 4, 8,0);
And where Earth is in the photo, I got such a result:
So, centroid is on the Earth. :(
UPDATE 2:
Trying cvHoughCircles:
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* circles = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 12,
dst->width/2, 255, 100, 0, 35);
if ( circles->total > 0 ) {
// getting first found circle
float* circle = (float*)cvGetSeqElem( circles, 0 );
// Drawing:
// green center dot
cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])),
3, CV_RGB(0,255,0), -1, 8, 0 );
// wrapping red circle
cvCircle( image, cvPoint(cvRound(circle[0]),cvRound(circle[1])),
cvRound(circle[2]), CV_RGB(255,0,0), 3, 8, 0 );
}
First example: bingo, but the second - no ;(
I've tried different configuration of cvHoughCircles() - couldn't find configuration to fit every my example photo.
UPDATE3:
matchTemplate approach worked for me ( response of mevatron ). It worked with big number of tests.
How about trying a simple matchTemplate approach. I used this template image:
And, it detected the 3 out of 3 of the sun images I tried:
This should work due to the fact that circles (in your case the sun) are rotationally invariant, and since you are so far away from the sun it should be roughly scale invariant as well. So, template matching will work quite nicely here.
Finally, here is the code that I used to do this:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
/// Load image and template
string inputName = "sun2.png";
string outputName = "sun2_detect.png";
Mat img = imread( inputName, 1 );
Mat templ = imread( "sun_templ.png", 1 );
/// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
Mat result( result_cols, result_rows, CV_32FC1 );
/// Do the Matching and Normalize
matchTemplate(img, templ, result, CV_TM_CCOEFF);
normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat());
Point maxLoc;
minMaxLoc(result, NULL, NULL, NULL, &maxLoc);
rectangle(img, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);
rectangle(result, maxLoc, Point( maxLoc.x + templ.cols , maxLoc.y + templ.rows ), Scalar(0, 255, 0), 2);
imshow("img", img);
imshow("result", result);
imwrite(outputName, img);
waitKey(0);
return 0;
}
Hope you find that helpful!
Color Segmentation Approach
Do a color segmentation on the images to identify objects on the black background. You may identify the sun according to its area (given this uniquely identifies it, resp. don't varies largely accross images).
A more sophisticated approach could compute image moments, e.g. hu moments of the objects. See this page for these features.
Use a classification algorithm of your choice to do the actual classification of the objects found. The most simple approach is to manually specify thresholds, resp. value ranges that turn out to work for all(most) of your object/image combinations.
You may compute the actual position from the raw moments, as for the circular sun the position is equal to the center of mass
Centroid: {x, y } = { M10/M00, M01/M00 }
Edge Map Approach
Another option would be a circle hough transformation of the edge map, this will hopefully return some candidate circles (by position and radius). You may select the sun-circle according to the radius you expect (if you are lucky there is at most one).
A simple addition to your code is to filter out objects based on their size. If you always expect the earth to be much bigger than the sun, or the sun to have almost the same area in each picture, you can filter it by area.
Try Blob detector for this task.
And note that it may be good to apply a morphological opening/closing instead of simple erode or dilate, so your sun will have almost the same area before and after processing.