how is PCA implemented on a camera captured image? - c++

I have successfully implemented face detection part in my Face Recognition project.Now i have a rectangular region of face in an image.Now i have to implement PCA on this detected rectangular region to extract important features.I have used examples of implementing PCA on face databases.I want to know how we can pass our detected face to function implementing PCA?Is it that we pass the rectangle frame?
This is the code for my face detection.
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
// Create a string that contains the exact cascade name
const char* cascade_name =
"haarcascade_frontalface_alt.xml";
/* "haarcascade_profileface.xml";*/
// Function prototype for detecting and drawing an object from an image
void detect_and_draw( IplImage* image );
// Main function, defines the entry point for the program.
int main( int argc, char** argv )
{
// Create a sample image
IplImage *img = cvLoadImage("Image018.jpg");
if(!img)
{
printf("could not load image");
return -1;
}
// Call the function to detect and draw the face positions
detect_and_draw(img);
// Wait for user input before quitting the program
cvWaitKey();
// Release the image
cvReleaseImage(&img);
// Destroy the window previously created with filename: "result"
cvDestroyWindow("result");
// return 0 to indicate successfull execution of the program
return 0;
}
// Function to detect and draw any faces that is present in an image
void detect_and_draw( IplImage* img )
{
// Create memory for calculations
static CvMemStorage* storage = 0;
// Create a new Haar classifier
static CvHaarClassifierCascade* cascade = 0;
int scale = 1;
// Create a new image based on the input image
IplImage* temp = cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 );
// Create two points to represent the face locations
CvPoint pt1, pt2;
int i;
// Load the HaarClassifierCascade
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
// Check whether the cascade has loaded successfully. Else report and error and quit
if( !cascade )
{
fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
return;
}
// Allocate the memory storage
storage = cvCreateMemStorage(0);
// Create a new named window with title: result
cvNamedWindow( "result", 1 );
// Clear the memory storage which was used before
cvClearMemStorage( storage );
// Find whether the cascade is loaded, to find the faces. If yes, then:
if( cascade )
{
// There can be more than one face in an image. So create a growable sequence of faces.
// Detect the objects and store them in the sequence
CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,
1.1, 2, CV_HAAR_DO_CANNY_PRUNING,
cvSize(40, 40) );
// Loop the number of faces found.
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
// Create a new rectangle for drawing the face
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
// Find the dimensions of the face,and scale it if necessary
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
// Draw the rectangle in the input image
cvRectangle( img, pt1, pt2, CV_RGB(255,0,0), 3, 8, 0 );
}
}
// Show the image in the window named "result"
cvShowImage( "result", img );
// Release the temp image created.
cvReleaseImage( &temp );
}

Edit:
Just to notify anyone visiting this site. I have written some sample code to perform face recognition in videos using my libfacerec library:
https://github.com/bytefish/libfacerec/blob/master/samples/facerec_video.cpp
Original post:
I assume your problem is the following. You've used the Cascade Classifier cv::CascadeClassifier coming with OpenCV to detect and extract faces from images. Now you want to perform a face recognition on the images.
You want to use the Eigenfaces for face recognition. So the first thing you have to do is to learn the Eigenfaces from the images you've gathered. I rewrote the Eigenfaces class for you to make it simpler. To learn the eigenfaces simply pass a vector with your face images and the corresponding labels (the subject) either to Eigenfaces::Eigenfaces or Eigenfaces::compute. Make sure all your images have the same size, you can use cv::resize to ensure this.
Once you have computed the Eigenfaces, you can get predictions from your model. Simply call Eigenfaces::predict on a computed model. The main.cpp shows you how to use the class and its methods (for prediction, projection, reconstruction of images), here's how to get a prediction for an image.
Now I see where your problem is. You are using the old OpenCV C API. That makes it's hard to interface with the new OpenCV2 C++ API my code is written in. Not to be offending, but if you want to interface with my code you better use the OpenCV2 C++ API. I can't give a guide on learning C++ and the OpenCV2 API here, there's a lot of documentation coming with OpenCV. A good start is the OpenCV C++ Cheat Sheet (also available at http://opencv.willowgarage.com/) or the OpenCV Reference Manual.
For recognizing images from the Cascade Detector, I repeat: First learn the Eigenfaces model with the persons you want to recognize, it's shown in the example coming with my code. Then you need to get the Region Of Interest (ROI), that's the face, the Rectangle the Cascade Detector outputs. Finally you can get a prediction for the ROI from the Eigenfaces model (you have computed it above), it's shown in the example coming with my code. You probably have to convert your image to grayscale, but that's all. That's how it's done.

Related

Detecting all note head wether it is a whole note or half note

I need to detect all whole and half note from the given image and print the all detected note into a new image. But it seems that the code does not detect the half note it only detects the whole note.
This is the source code I have
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// Read image
Mat im = imread("beethoven_ode_to_joy.jpg", IMREAD_GRAYSCALE);
// Setup SimpleBlobDetector parameters.
SimpleBlobDetector::Params params;
// Change thresholds
params.minThreshold = 10;
params.maxThreshold = 200;
// Filter by Area.
params.filterByArea = true;
params.minArea = 25;
// Filter by Circularity
params.filterByCircularity = true;
params.minCircularity = 0.1;
// Filter by Convexity
params.filterByConvexity = true;
params.minConvexity = 0.87;
// Filter by Inertia
params.filterByInertia = true;
params.minInertiaRatio = 0.01;
// Storage for blobs
vector<KeyPoint> keypoints;
#if CV_MAJOR_VERSION < 3 // If you are using OpenCV 2
// Set up detector with params
SimpleBlobDetector detector(params);
// Detect blobs
detector.detect(im, keypoints);
#else
// Set up detector with params
Ptr<SimpleBlobDetector> detector = SimpleBlobDetector::create(params);
// Detect blobs
detector->detect(im, keypoints);
#endif
// Draw detected blobs as red circles.
// DrawMatchesFlags::DRAW_RICH_KEYPOINTS flag ensures
// the size of the circle corresponds to the size of blob
Mat im_with_keypoints;
drawKeypoints(im, keypoints, im_with_keypoints, Scalar(0, 0, 255), DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// Show blobs
imshow("keypoints", im_with_keypoints);
waitKey(0);
}
Actually, I don't have openCV now.But I try something to solve this in matlab in short time.Firstly,in this image you will realize that head of the notes are darker than staves.When we get more inside it we see that centers of the notes have 0 value in this image . I suggest you that you can convert yor RGB image to grayscale image, after that can apply thresholding.If the values of pixels is equal to 0 they're ok you should get them but if not you don't get them.Its result is here in this image .Then, I think you can apply some morphologic operations like dilation. Because detected head of notes will be a little bit smaller than original.If you want to eliminate the up side of notes(I mean stick part of notes) you can detect this part with hough line transformation, opencv has functions for this operation (HoughLines or houghLinesP).After detection you can delete this part or if you don't want, you can pass this step.After all, you can find circular objects on the image with hough transform.HoughCircles functions perform this task in opencv.In Matlab it is a little bit easier with findcircles function.Finally, you can draw founded circles with circle function in opencv or viscircles function in matlab.Result is here
Notice that I didn't apply morphologic operations to improve size of heads of notes.Also, I didn't apply houghline transformation to detect and erase stick parts.If you can apply them ,I think you will get better result.
This algorithm is only a suggestion,you can find better algorithm by trying some other operations.

opencv - shrink objects to pixels

I am processing such an image as shown in Fig.1, which is composed of an array of points and required to convert to Fig. 2.
Fig.1 original image
Fig.2 wanted image
In order to finish the conversion, firstly I detect the edge of every point and then operate dilation. The result is satisfactory after choosing the proper parameters, seen in Fig. 3.
Fig.3 image after dilation
I processed the same image before in MATLAB. When it comes to shrink objects (in Fig.3) to pixels, function bwmorph(Img,'shrink',Inf) works and the result is exactly where Fig. 2 comes from. So how to get the same wanted image in opencv? It seems that there is no similar shrink function.
Here is my code of finding edge and dilation operation:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
using namespace cv;
// Global variables
Mat src, dilation_dst;
int dilation_size = 2;
int main(int argc, char *argv[])
{
IplImage* img = cvLoadImage("c:\\001a.bmp", 0); // 001a.bmp is Fig.1
// Perform canny edge detection
cvCanny(img, img, 33, 100, 3);
// IplImage to Mat
Mat imgMat(img);
src = img;
// Create windows
namedWindow("Dilation Demo", CV_WINDOW_AUTOSIZE);
Mat element = getStructuringElement(2, // dilation_type = MORPH_ELLIPSE
Size(2*dilation_size + 1, 2*dilation_size + 1),
Point(dilation_size, dilation_size));
// Apply the dilation operation
dilate(src, dilation_dst, element);
imwrite("c:\\001a_dilate.bmp", dilation_dst);
imshow("Dilation Demo", dilation_dst);
waitKey(0);
return 0;
}
1- Find all the contours in your image.
2- Using moments find their center of masses. Example:
/// Get moments
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mu[i] = moments( contours[i], false ); }
/// Get the mass centers:
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); }
3- Create zero(black) image and write all the center points on it.
4- Note that you will have extra one or two points coming from border contours. Maybe you can apply some pre-filtering according to the contour areas, since the border is a big connected contour having large area.
It's not very fast, but I implemented the morphological filtering algorithm from Digital Image Processing, 4th Edition by William K. Pratt. This should be exactly what you're looking for.
The code is MIT licensed and available on GitHub at cgmb/shrink.
Specifically, I've defined cv::Mat cgmb::shrink_max(cv::Mat in) to shrink a given cv::Mat of CV_8UC1 type until no further shrinking can be done.
So, if we compile Shrink.cxx with your program and change your code like so:
#include "Shrink.h" // add this line
...
dilate(src, dilation_dst, element);
dilation_dst = cgmb::shrink_max(dilation_dst); // and this line
imwrite("c:\\001a_dilate.bmp", dilation_dst);
We get this:
By the way, your image revealed a bug in Octave Image's implementation of bwmorph shrink. Figure 2 should not be the result of a shrink operation on Figure 3, as the ring shouldn't be broken by a shrink operation. If that ring disappeared in MATLAB, it presumably also suffers from some sort of similar bug.
At present, Octave and I have slightly different results from MATLAB, but they're pretty close.

dataset for emotion detection

I am working on a code using opencv library which is tracking the user's face and the features on the face. I have managed to do live detection of face and the features like eyes, lips from the webcam. I would like to now extract the emotion from the detected features. I would like to know is there any available dataset which I can use to compare the emotion and how it can be done.
here is the code for face detection
CvRect detectFaceInImage(const IplImage *inputImg, const CvHaarClassifierCascade* cascade )
{
const CvSize minFeatureSize = cvSize(20, 20);
const int flags = CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH; // Only search for 1 face.
const float search_scale_factor = 1.1f;
IplImage *detectImg;
IplImage *greyImg = 0;
CvMemStorage* storage;
CvRect rc;
double t;
CvSeq* rects;
int i;
storage = cvCreateMemStorage(0);
cvClearMemStorage( storage );
// If the image is color, use a greyscale copy of the image.
detectImg = (IplImage*)inputImg; // Assume the input image is to be used.
if (inputImg->nChannels > 1)
{
greyImg = cvCreateImage(cvSize(inputImg->width, inputImg->height), IPL_DEPTH_8U, 1 );
cvCvtColor( inputImg, greyImg, CV_BGR2GRAY );
detectImg = greyImg; // Use the greyscale version as the input.
}
// Detect all the faces.
t = (double)cvGetTickCount();
rects = cvHaarDetectObjects( detectImg, (CvHaarClassifierCascade*)cascade, storage,
search_scale_factor, 3, flags, minFeatureSize );
t = (double)cvGetTickCount() - t;
printf("[Face Detection took %d ms and found %d objects]\n", cvRound( t/((double)cvGetTickFrequency()*1000.0) ), rects->total );
// Get the first detected face (the biggest).
if (rects->total > 0) {
rc = *(CvRect*)cvGetSeqElem( rects, 0 );
}
else
rc = cvRect(-1,-1,-1,-1); // Couldn't find the face.
//cvReleaseHaarClassifierCascade( &cascade );
//cvReleaseImage( &detectImg );
if (greyImg)
cvReleaseImage( &greyImg );
cvReleaseMemStorage( &storage );
return rc; // Return the biggest face found, or (-1,-1,-1,-1).
}
I am using the Karolinska Directed Emotional Faces (KDEF) photographs for an educational research project. Information regarding the data set is available at http://www.emotionlab.se/resources/kdef.
Note that you will probably need to crop, resize, center, straighten, and normalize the images to use them with OpenCV. Once properly prepared, the images work quite well with all the OpenCV2 FaceRecognizer class functions.
As to how facial expression recognition can be done: no standard approach exists. Start by reading the FaceRecognizer documentation and working through the tutorials. For what it's worth: I have found that using Local Binary Pattern Histograms produces the most accurate results.

OpenCV - HoughCircles causing program to crash

I want to detect circles in an image using OpenCV and C++. I COULD do that by referring to the official documentation and adjusting the parameters of the piece of code written by the OpenCV Team.
So, the code I'm working with is as follows: (parameters already adjusted)
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
int main(int, char** argv)
{
Mat src, src_gray;
/// Read the image
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// Convert it to gray
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 6.0, 5, 110, 70, 3, 20 );
/// Draw the circles detected
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][2]));
int radius = cvRound(circles[i][3]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
/// Show your results
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
imshow( "Hough Circle Transform Demo", src );
waitKey(0);
src.release();
src_gray.release();
return 0;
}
And the image whose circles I want to detect is the following: Test image
These are actually the contour of two blobs that I obtained using cvBlobsLib and redrew as a new image.
That algorithm is able to identify the centers of each circle, but, when I hit any key to close the program, it crashes... :( And I have to forcefully close it.
I need to adapt that algorithm to run in a camera, so I cannot proceed with the implementation while it crashes like that.
So, does anyone know what could be causing this problem?
I'm doing the development on Visual Studio 2012 and OpenCV version 2.4.2.
If someone could give me a suggestion of what it could be or maybe try running the algorithm, I would be very grateful!
I have four advices for you.
First: To see whether a Mat is empty or not, you use
if( src.empty() ) // instead of !src.data.
The chances are src.data has random (stale) value for an empty Mat.
Second: correct the indices like this:
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
(actually you don't need cvRound, but whatever).
Third: It is worth to check whether imread understood that you want to load the image in color mode, by checking its number of channels:
src.channels()==3
//or
src.type()==CV_8UC3; // that is what you are counting for, really.
Otherwise a line like CV_BGR2GRAY on a gray image could cause weird behaviour.
Fourth: you don't need to release Mat's. That's the reason they created Mat class in the first place, so that they automatically take care of releasing.
I don't see anything obvious except that you are overrunning the Vec3f bounds:
Point center(cvRound(circles[i][0]), cvRound(circles[i][2]));
int radius = cvRound(circles[i][3]);
Instead of index 2 and 3, I think you meant 1 and 2.
That wouldn't necessarily be causing the crash (by corrupting the stack or heap), but then again it is undefined behaviour...
The other thing I suggest is removing the two lines that follow the waitKey call:
src.release();
src_gray.release();
These are handled automatically by the destructor in the object, so I don't see why you need to do it manually. That might not change a thing, of course.
From there, if you are still getting crashes you should start omitting sections of your code until you can isolate the one that crashes it.
I started feeling suspicious about the environment, so I got a friend who had OpenCV all set up to try out my code and he could run it with no problem...
So I reinstalled everything, but this time I chose Microsoft Visual Studio 2010 SP1 and OpenCV 2.4.3, and it worked correctly.
If someone is having the same problem, I recommend downgrading to VS2010. Also, this video installation guide was really helpful when I was setting the environment!
Thank you :)
I was having the same problem. Please ensure that while running your application in release mode, you are using opencv release dll's. Doing this solved my problem.
Reference:
https://code.ros.org/trac/opencv/ticket/953

Adjusting the threshold in Canny edge algorithm

I wanted to try my hand at text recognition, so i've used opencv to trace out the edges and c++ to find slopes, curves etc, the edge algorithm works well on big and uncluttered sets of characters but when it comes against small printed text or text with a lot of background noise like embedded in captcha it struggles and looks incomplete, my guess was i hadn't set the threshold values correctly and tried different values with no success.
Here is my code :
#include "cv.h"
#include "highgui.h"
using namespace cv;
const int low_threshold = 50;
const int high_threshold = 150;
int main()
{
IplImage* newImg;
IplImage* grayImg;
IplImage* cannyImg;
newImg = cvLoadImage("ocv.bmp",1);
grayImg = cvCreateImage( cvSize(newImg->width, newImg->height), IPL_DEPTH_8U, 1 );
cvCvtColor( newImg, grayImg, CV_BGR2GRAY );
cannyImg = cvCreateImage(cvGetSize(newImg), IPL_DEPTH_8U, 1);
cvCanny(grayImg, cannyImg, low_threshold, high_threshold, 3);
cvNamedWindow ("Source", 1);
cvNamedWindow ("Destination",1);
cvShowImage ("Source", newImg );
cvShowImage ("Destination", cannyImg );
cvWaitKey(0);
cvDestroyWindow ("Source" );
cvDestroyWindow ("Destination" );
cvReleaseImage (&newImg );
cvReleaseImage (&grayImg );
cvReleaseImage (&cannyImg );
return 0;
}
I've looked across the net and have seen some complicated thresholding conditions like in this code from this site :
% Set direction to either 0, 45, -45 or 90 depending on angle.
[x,y]=size(f1);
for i=1:x-1,
for j=1:y-1,
if ((gradAngle(i,j)>67.5 && gradAngle(i,j)<=90) || (gradAngle(i,j)>=-90 && gradAngle(i,j)<=-67.5))
gradDirection(i,j)=0;
elseif ((gradAngle(i,j)>22.5 && gradAngle(i,j)<=67.5))
gradDirection(i,j)=45;
elseif ((gradAngle(i,j)>-22.5 && gradAngle(i,j)<=22.5))
gradDirection(i,j)=90;
elseif ((gradAngle(i,j)>-67.5 && gradAngle(i,j)<=-22.5))
gradDirection(i,j)=-45;
end
end
end
If this is the solution can somebody provide me the c++ equivalent of this algorithm, if it's not what else can i do ?
Canny edge detector is a multi-step detector using hysteresis thresholding (it uses two threshold instead of one), and edge tracking (your last snippet is the part of this step). I suggest reading the wikipedia entry first. One possible solution could be to choose the high threshold, so e.g. 70% of the image pixels would be classified as edge (initially - you could do this quickly using histograms), than choose the low threshold as e.g. 40% of the high threshold. It might be a good idea to try to perform edge detection on image block rather than the whole image, so your algorithm could calculate different thresholds for different areas.
Note that CAPTCHA-s are designed to be hard to segment, and adding noise that broke edge detection is one technique to achive this (you might need to smooth the image first).