Detecting a face and saving the detected face in OpenCV - c

I am trying to detect the face in the image and trying to save the detected face as an image in OpenCV.
Having some problems in the detectfaces function below.
#include "stdafx.h"
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detectFaces( IplImage *img );
int _tmain(int argc, _TCHAR* argv[])
{
//CvCapture *capture;
IplImage *img;//*out;
int key = 0;
char *filename = "C:/OpenCV2.1/data/haarcascades/haarcascade_frontalface_alt.xml";
cascade = ( CvHaarClassifierCascade* )cvLoad( filename, 0, 0, 0 );
storage = cvCreateMemStorage( 0 );
img = cvLoadImage("Yurico.png");
assert( cascade && storage && img );
cvNamedWindow( "video:", 1 );
//cvNamedWindow( "video1:", 1 );
//out = detectFaces( img );
detectFaces( img );
cvWaitKey( 0 );
//cvShowImage( "video", out );
cvDestroyWindow( "video:" );
//cvDestroyWindow( "video1:" );
cvReleaseImage( &img );
cvReleaseHaarClassifierCascade( &cascade );
cvReleaseMemStorage( &storage );
return 0;
}
void detectFaces( IplImage *img )
{
int i;
CvRect *r;
CvSeq *faces = cvHaarDetectObjects(
img,
cascade,
storage,
1.1,
3,
0 /*CV_HAAR_DO_CANNY_PRUNNING*/,
cvSize( 40, 40) );
for( i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ ) {
CvRect *r = ( CvRect* )cvGetSeqElem( faces, i );
cvRectangle( img,
cvPoint( r->x, r->y ),
cvPoint( r->x + r->width, r->y + r->height ),
CV_RGB( 255, 0, 0 ), 1, 8, 0 );
}
//cvShowImage( "video:", img );
cvSetImageROI(img, CvRect *r);
IplImage *img2 = cvCreateImage(cvGetSize(img),
img->depth,
img->nChannels);
cvSaveImage("Lakshmen.jpg",img2);
}
Have a error saying this :
Error 1 error C2664: 'cvSetImageROI' : cannot convert parameter 2 from 'CvRect *' to 'CvRect' c:\users\hp\documents\visual studio 2010\projects\facedetect\facedetect\facedetect.cpp 67 1 facedetect
Want to save the region of interest into another image. Any corrections or improvements do tell me..

you need to pass a CvRect and not a CvRect*, so you do not need the pointer (*) before r.
and since it is already a cvRect you should just write:
cvSetImageROI(img, &r);

cvSetImageROI() takes a cvRect as the 2nd argument, and it uses it as input parameter to clip the image to that area.
In other words, you need to create a cvRect with valid info. You can do it before calling the function, or inline:
cvSetImageROI(img_corr, cvRect(x_pos, y_pos, width, height));
I also noticed that in your code, you create CvRect* r; on at least 3 diferent locations inside the same function. Bad practice! Tip: create variables in your code at the moment you are going to use them, not before that.

Just replace the CvRect *r as r=(CvRect*)cvGetSeqElem( faces,i) and after the for-loop write the two lines
cvSetImageROI(img, cvRect(r->x,r->y,r->width,r->height));
cvSaveImage("C1.jpg",img);

Related

How to load multiple images as command line arguments to sprintf() and cvLoadImage() in OpenCV...?

This is the code i have., which will detect the faces in the image and draws rectangle around the face.
CvHaarClassifierCascade *cascade;
CvMemStorage *storage;
void detectFaces (IplImage *newframe);
int key;
int iImg;
int Num_Images=20;
int main( int argc, char** argv )
{
string filename = M:/Trend/FaceDetection/MyCascadeFolder/haarcascade_frontalface_alt2.xml";
storage = cvCreateMemStorage(0) ;
cascade = ( CvHaarClassifierCascade* )cvLoad( filename.c_str());
**//to load a single image**
**IplImage* inImage = cvLoadImage("M:/Trend/FaceDetection775/MyImages/face1.jpg",1);**
//IplImage* inImage = cvLoadImage(argv[1],1); >> It also works fine through command line
detectFaces( inImage );
cvShowImage("FaceDetection2",inImage);
cvSaveImage("M:/FaceDetection/MyImages/OpImages/faces.jpg",inImage);
cvReleaseImage( &inImage);
// **to load no. of images or a complete folder**
char buf[20];
for(iImg=0; iImg<=Num_Images; iImg++)
{
**sprintf(buf, "M:/FaceDetection/ImagesFolder/P%04d.jpg", iImg);**
*// sprintf(buf, argv[2], iImg); // I Tried with this., but its not working*
printf("\n");
inImage = cvLoadImage(buf, CV_LOAD_IMAGE_UNCHANGED);
printf("Input Image = P%04d.jpg\n", iImg);
detectFaces( inImage );
cvShowImage("FaceDetection",inImage);
cvReleaseImage( &inImage );
key= cvWaitKey(0);
if ( key == 'q' || key == 'Q' )
return(0);
}
cvReleaseHaarClassifierCascade( &cascade );
cvReleaseMemStorage( &storage );
return 0;
}
**// the actual detectfaces() function goes like this**
void detectFaces( IplImage *newframe)
{
CvSeq *faces = cvHaarDetectObjects( newframe, cascade, storage, 1.15, 5, 0, cvSize( 30, 30 ) );
for( int i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ )
{
CvRect *r = ( CvRect *)cvGetSeqElem( faces, i );
cvRectangle(newframe,cvPoint( r->x, r->y ),cvPoint( r->x + r->width, r->y + r->height ),CV_RGB( 0, 255, 0 ), 2, 8, 0 );
}
}
Here., sprintf() method is taking multiple images statically (within the program itself). But I want to pass those multiple images as a single folder through command line argument.
I try to use cvLoadImage() function, but it also takes only one image as input instead of a folder.
Also I am not able to count the number of rectangles it draws for every single face in the image., how can I do that also...?
Please help me in this regards.
I am working on face detection project "www.MahdiRezaei.com" for my academics., and I am using visual studio-2010 with C, C++ and OpenCV.
Thankz in advance.
You can change the following code to use it with arguments.
#include<Windows.h>
#include<iostream>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
int main()
{
WIN32_FIND_DATA data;
HANDLE h = FindFirstFile(L"c:\\Images\\*.*", &data); // first file is the current directory
FindNextFile(h, &data); //second file is the parent directory
vector<Mat> Images;
if (h != INVALID_HANDLE_VALUE)
{
while (FindNextFile(h, &data))
{
string filename = data.cFileName;
sprintf(filename, "%s%s","C:\\Images\\", filename.c_str());
Images.push_back(imread(filename, 1));
delete[] nPtr;
}
}
else
cout << "Error: No such folder." << endl;
FindClose(h);
return 0;
}

Error with working cvConvexityDefect

I am right now working with OpenCV and Image processing. and Current topic that i am going through is, Convexity Defect. Following code that is simple program that can illustrates convexity defect, but i am getting error the error which is shown after the code. So please help me
Code :-
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
int g_thresh = 128;
int main(int argc, char **argv)
{
CvMemStorage *hull = cvCreateMemStorage(0);
CvMemStorage *mem = NULL;
CvMemStorage *defe_mem = cvCreateMemStorage(0);
mem = cvCreateMemStorage(0);
CvSeq *contours = NULL;
CvSeq *poly;
CvSeq *convex;
CvSeq *i;
CvSeq *defect;
IplImage *img = cvLoadImage(argv[1], CV_LOAD_IMAGE_COLOR);
IplImage *gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvCvtColor(img, gray, CV_RGB2GRAY);
cvShowImage("Source", img);
cvWaitKey(0);
cvShowImage("DEstination", gray);
cvWaitKey(0);
cvThreshold(gray, gray, g_thresh, 255, CV_THRESH_OTSU);
cvShowImage("BinaryImage", gray);
cvWaitKey(0);
int a = cvFindContours(gray, mem, &contours, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
cvDrawContours(gray, contours, cvScalarAll(255), cvScalarAll(255), 1, 1, 8, cvPoint(0, 0));
cvShowImage("Output",gray);
cvWaitKey(0);
convex = cvConvexHull2(contours, hull, CV_CLOCKWISE, 1);
cvDrawContours(gray, convex, cvScalarAll(255), cvScalarAll(255), 1, 1, 8, cvPoint(0, 0));
cvShowImage("Convex_Hull", gray);
cvWaitKey(0);
//Program Completely Works till here, every thing massed up after this line..
defect = cvConvexityDefects(contours, convex, defe_mem);
for( i = contours; i != 0; i = i->h_next){
cvDrawContours(gray, defect, cvScalarAll(255), cvScalarAll(255), 1, 1, 8, cvPoint(0, 0));
}
//fprintf(stderr, "Convexity Defect::%d\n", cvCheckContourConvexity(contours));
cvShowImage("Convexity", gray );
cvWaitKey(0);
}
Error :-
OpenCV Error: Unsupported format or combination of formats (Convex hull must represented as a sequence of indices or sequence of pointers) in cvConvexityDefects, file /home/akshit/OpenCV/OpenCV-2.4.3/modules/imgproc/src/convhull.cpp, line 544
terminate called after throwing an instance of 'cv::Exception'
what(): /home/akshit/OpenCV/OpenCV-2.4.3/modules/imgproc/src/convhull.cpp:544: error: (-210) Convex hull must represented as a sequence of indices or sequence of pointers in function cvConvexityDefects
Convex hull is found out properly with output, but convexity defect is not found out properly
Any Suggestion?
I think this code snippet should help:
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <time.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
String window_name = "Hand_HSV";
Mat frame,copyFrame;
// Detect Skin from YCrCb
Mat DetectYCrCb(Mat img,Scalar min, Scalar max)
{
Mat skin;
cvtColor(img, skin, cv::COLOR_RGB2YCrCb);
inRange(skin, min, max, skin);
Mat rect_12 = getStructuringElement(cv::MORPH_RECT, Size(12,12) , Point(6,6));
erode(skin, skin, rect_12,Point(),1);
Mat rect_6 = getStructuringElement(cv::MORPH_RECT, Size(6,6) , Point(3,3));
dilate(skin,skin,rect_6,Point(),2);
return skin;
}
void DetectContour(Mat img)
{
Mat drawing = Mat::zeros( img.size(), CV_8UC3 );
vector<vector<Point> > contours;
vector<vector<Point> > bigContours;
vector<Vec4i> hierarchy;
findContours(img,contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE, Point());
if(contours.size()>0)
{
vector<vector<int> >hull( contours.size() );
vector<vector<Vec4i>> convDef(contours.size() );
vector<vector<Point>> hull_points(contours.size());
vector<vector<Point>> defect_points(contours.size());
for( int i = 0; i < contours.size(); i++ )
{
if(contourArea(contours[i])>5000)
{
convexHull( contours[i], hull[i], false );
convexityDefects( contours[i],hull[i], convDef[i]);
// start_index, end_index, farthest_pt_index, fixpt_depth
for(int k=0;k<hull[i].size();k++)
{
int ind=hull[i][k];
hull_points[i].push_back(contours[i][ind]);
}
for(int k=0;k<convDef[i].size();k++)
{
if(convDef[i][k][3]>20*256)
{
int ind_0=convDef[i][k][0];
int ind_1=convDef[i][k][1];
int ind_2=convDef[i][k][2];
defect_points[i].push_back(contours[i][ind_2]);
cv::circle(drawing,contours[i][ind_0],5,Scalar(0,255,0),-1);
cv::circle(drawing,contours[i][ind_1],5,Scalar(0,255,0),-1);
cv::circle(drawing,contours[i][ind_2],5,Scalar(0,0,255),-1);
cv::line(drawing,contours[i][ind_2],contours[i][ind_0],Scalar(0,0,255),1);
cv::line(drawing,contours[i][ind_2],contours[i][ind_1],Scalar(0,0,255),1);
}
}
drawContours( drawing, contours, i, Scalar(0,255,0), 1, 8, vector<Vec4i>(), 0, Point() );
drawContours( drawing, hull_points, i, Scalar(255,0,0), 1, 8, vector<Vec4i>(), 0, Point() );
}
}
}
namedWindow( "Hull demo",cv::WINDOW_AUTOSIZE );
imshow( "Hull demo", drawing );
}
int main( int argc, char** argv )
{
VideoCapture capture(0);
//VideoCapture capture("Video_Hand.MPG");
namedWindow( window_name, cv::WINDOW_AUTOSIZE );
if (capture.isOpened()){
while(true)
{
//capture.read(frame);
//flip(frame,frame,1);
capture >> frame;
imshow( window_name, frame);
Mat skinYCrCb = DetectYCrCb(frame,Scalar(0, 100, 80), Scalar(255, 185, 135));
imshow("Result",skinYCrCb);
DetectContour(skinYCrCb);
int c = waitKey(10);
if( (char)c == 27 )
{
break;
}
}
}
return 0;
}

OpenCV: Error in cvHoughCircles usage

I am using cvHoughCircles to find the two white ovals in the following image:
I first used thresholding for locating the white regions and then used Hough Transforms. But the output is not coming correct as shown below:
I am not able to understand what is happening? Why it is detecting 3 circles and why only one is being detected correctly? Any suggestions?
Below is my code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include "opencv/cv.h"
#include "opencv/highgui.h"
#include<conio.h>
#include<malloc.h>
using namespace cv;
using namespace std;
int main( ) {
IplImage* image = cvLoadImage(
"testing.bmp",
CV_LOAD_IMAGE_GRAYSCALE
);
IplImage* src = cvLoadImage("testing.bmp");
CvMemStorage* storage = cvCreateMemStorage(0);
cvThreshold( src, src, 200, 255, CV_THRESH_BINARY );
CvSeq* results = cvHoughCircles(
image,
storage,
CV_HOUGH_GRADIENT,
3,
image->width/10
);
for( int i = 0; i < results->total; i++ )
{
float* p = (float*) cvGetSeqElem( results, i );
CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
cvCircle(
src,
pt,
cvRound( p[2] ),
CV_RGB(0xff,0,0)
);
}
cvNamedWindow( "HoughCircles", 1 );
cvShowImage( "HoughCircles", src);
cvWaitKey(0);
}
Edit:
Since I am not get satisfactory results with Hough Transform, I am willing to go for some other way. I can assume that each white blob in the figure is of equal size (size is known)and also the distance between the blob is known. Is there a non-trivial way I can find a vertical line (a tangent) touching the left side of left white blob? Once I know this tangent, I get an idea of the boundary location, then I will draw a circle at x=(this location + radius(which is known)), y= this location. Can I find such x and y coordinates using some non-trivial ways?
Solved, by changing as per below:
cvThreshold(image, image, 220, 255, CV_THRESH_BINARY );
cvCanny(image, image, 255, 255, 3);
cvNamedWindow( "edge", 1 );
cvShowImage( "edge", image);
cvWaitKey(0);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* results = cvHoughCircles(
image,
storage,
CV_HOUGH_GRADIENT,
4,
image->width/4, 100,100,0,50);
Here is the output:
It's all about the parameters:
IplImage* src = cvLoadImage(argv[1]);
if (!src)
{
cout << "Failed: unable to load image " << argv[1] << endl;
return -1;
}
//IplImage* image = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
IplImage* image = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
cvCvtColor(src, image, CV_RGB2GRAY);
cvThreshold(image, image, 220, 255, CV_THRESH_BINARY );
// cvNamedWindow( "thres", 1 );
// cvShowImage( "thres", image);
// cvWaitKey(0);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* results = cvHoughCircles(
image,
storage,
CV_HOUGH_GRADIENT,
4,
image->width/3);
std::cout << "> " << results->total << std::endl;
for( int i = 0; i < results->total; i++ )
{
float* p = (float*) cvGetSeqElem( results, i );
CvPoint pt = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
cvCircle(src,
pt,
cvRound( p[2] ),
CV_RGB(0xff,0,0));
}
cvNamedWindow( "HoughCircles", 1 );
cvShowImage( "HoughCircles", src);
cvWaitKey(0);
If you've done a little bit more experimentation you would have eventually found out that with different parameters you get different results:
You should use edge detected image as input, not the thresholded.
Secondly, Hough circles will not work for elipses, unless they are very close to circles. I recommend reading about Generalized Hough Transform and implementing it for ellipses.

Error with OpenCV

I'm trying to run simple code with installed OpenCV library
And have an error: The application was unable to start correctly (0xc0150002).
visual studio 2010
OpenCV 2.1.0
I've searched everywhere but cant find how to solve this problem...
This is my code. What can I do?
#include "stdafx.h"
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#ifdef _EiC
#define WIN32
#endif
static CvMemStorage* storage_face = 0; //Memory Storage to Sore faces
static CvHaarClassifierCascade* cascade_face = 0;
void detect_and_draw( IplImage* image );
//Haar cascade - if your openc CV is installed at location C:/OpenCV2.0/
const char* cascade_name_face ="C:/OpenCV2.0/data/haarcascades/haarcascade_frontalface_alt.xml";
/////////////////////////////////////////////////////////////////////////////////
int main()
{
IplImage *image =0;
image = cvLoadImage("picci.jpg",1);
if(!image)
{
printf("Error loading image\n");
return -1;
}
cascade_face = (CvHaarClassifierCascade*)cvLoad( cascade_name_face, 0, 0, 0 );
if( !cascade_face )
{
printf("ERROR: Could not load classifier of face cascade\n" );
return -1;
}
storage_face = cvCreateMemStorage(0);
cvNamedWindow( "result", 1 );
// Call function to detect and Draw rectagle around face
detect_and_draw( image);
// Wait for key event.
cvWaitKey(0);
// release resourses
cvReleaseImage( &image );
cvReleaseHaarClassifierCascade(&cascade_face );
cvReleaseMemStorage( &storage_face);
cvDestroyWindow("result");
return 0;
}
//////////////////////////// Function To detect face //////////////////////////
void detect_and_draw( IplImage* img )
{
double scale = 2;
// create a gray image for the input image
IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
// Scale down the ie. make it small. This will increase the detection speed
IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),cvRound (img->height/scale)),8, 1 );
int i;
cvCvtColor( img, gray, CV_BGR2GRAY );
cvResize( gray, small_img, CV_INTER_LINEAR );
// Equalise contrast by eqalizing histogram of image
cvEqualizeHist( small_img, small_img );
cvClearMemStorage( storage_face);
if( cascade_face )
{
// Detect object defined in Haar cascade. IN our case it is face
CvSeq* faces = cvHaarDetectObjects( small_img, cascade_face, storage_face,
1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30, 30) );
// Draw a rectagle around all detected face
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect r = *(CvRect*)cvGetSeqElem( faces, i );
cvRectangle( img, cvPoint(r.x*scale,r.y*scale),cvPoint((r.x+r.width)*scale,(r.y+r.height)*scale),CV_RGB(255,0,0),3,8,0 );
}
}
cvShowImage( "result", img );
cvReleaseImage( &gray );
cvReleaseImage( &small_img );
}
Two potential problems:
Your app cannot find the OpenCV DLLs, you might need to copy the OpenCV DLLs into your respective bin/release or bin/debug dir.
Or the OpenCV binaries were built with a different version of CRT than what you have installed on your system. Did you build OpenCV binaries on your system? That could help.

Need help in opencv sequences !

I'm using opencv sequences to store points resulted from cvhoughline2.
I create the sequence and make some operations on it, but when I run the program it breaks in the line cvseqremove(seq,index) and gives me the exception:
exception at memory location
When I put the cursor on the seq in cvseqremove(seq,index), it writes to me: h_prev=0*000000000000000.
I wrote that code, i'll appreciate any help
void APPROXIMATE_LINES(IplImage* image,unsigned int xsize,unsigned int ysize,double width)
{
unsigned int i;
IplImage* color_dst = cvCreateImage(cvGetSize(image), 8,3);
IplImage* dst = cvCreateImage(cvGetSize(image), 8,1);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* Filtered_Lines=0;
boolean isbreak;
double distance=4.0;
CvPoint Mid_Point;
CvPoint First_Mid_Point;
CvSeq* lines = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),storage);
cvCanny(image,dst,180,250,3);
cvCvtColor(dst,color_dst,CV_GRAY2BGR);
lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC, 4, CV_PI/165, 95, 93, 75);
while (lines->total>1)
{
CvPoint* First_Line = (CvPoint*)cvGetSeqElem(lines,0);
First_Mid_Point=mid(First_Line[0],First_Line[1]);
isbreak=FALSE;
for( i =1; i < lines->total; i++ )
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines,i);
Mid_Point=mid(line[0],line[1]);
if(dist(First_Mid_Point.x,First_Mid_Point.y,Mid_Point.x,Mid_Point.y)<distance)
{
cvSeqRemove(lines,i);
isbreak=TRUE;
break;
}
} /*End_for*/
if(!isbreak)
{
cvSeqPushFront(Filtered_Lines,First_Line); // <--- breaks here
cvSeqRemove(lines,0);
}
} /*End_while*/
for(i=0;i<Filterd_Lines;i++)
{
CvPoint* Filtered = (CvPoint*)cvGetSeqElem(Filterd_Lines,i);
cvLine(color_dst, Filtered[0], Filtered[1], cvScalar(0,0,255,0),1,8,0);
}
cvNamedWindow( "Example1", CV_WINDOW_AUTOSIZE );
cvShowImage( "Example1",color_dst);
cvWaitKey(0);
cvReleaseImage( &color_dst);
cvDestroyWindow( "Example1" );
}
The function signature is:
void cvSeqRemove(CvSeq* seq, int index)
But on one part of the code you are doing:
cvSeqRemove(lines,&i);
Which means you are passing the memory address of the variable i instead of it's value, and this is not what you want to do.
There might be other bugs.

Resources