I am trying to detect the mouth in an image with openCV, so I am using the following code:
#include "face_detection.h"
using namespace cv;
// Function detectAndDisplay
void detectAndDisplay(const std::string& file_name, cv::CascadeClassifier& face_cascade, cv::CascadeClassifier& mouth_cascade)
{
Mat frame = imread(file_name);
std::vector<Rect> faces;
Mat frame_gray;
Mat crop;
Mat res;
Mat gray;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
// Detect faces
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 3, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
for(unsigned int i=0;i<faces.size();i++)
{
rectangle(frame,faces[i],Scalar(255,0,0),1,8,0);
Mat face = frame(faces[i]);
cvtColor(face,face,CV_BGR2GRAY);
std::vector <Rect> mouthi;
mouth_cascade.detectMultiScale(face, mouthi);
for(unsigned int k=0;k<mouthi.size();k++)
{
Point pt1(mouthi[k].x+faces[i].x , mouthi[k].y+faces[i].y);
Point pt2(pt1.x+mouthi[k].width, pt1.y+mouthi[k].height);
rectangle(frame, pt1,pt2,Scalar(0,255,0),1,8,0);
}
}
imshow("Frame", frame);
waitKey(33);
}
The classifiers are haarcascade_frontalface_alt.xml and haarcascade_mcs_mouth.xml.
The face is detected correctly but the mouth is not: I also obtain the eyes and some other parts, like the forehead.
Is there a way to detect only the mouth?
I think I managed to solve the problem: focusing on the lower half of the face and increasing the scale factor did the trick and now I am able to detect the mouth with a good precision. Anyway this task seems much more complicated than face detection, even if I am using "simple" images, which means straight and full frontal.
Here are two examples: a success and a failure.
I was facing the same problem, so I focused only on the lower half of the face
and created an ROI from the detected face. It looks something like this:
Mat ROI=image(Rect(face.x,face.y+face.height*0.6,face.width,face.height*0.3));
Where face is the detected face from the image.
This created an ROI from the detected face for the lower half only. Else the mouth detector was detecting the eyes also as mouth.
Then use the MouthCascade.xml from this link: http://alereimondo.no-ip.org/OpenCV/34
which is far more efficient than the inbuilt OpenCV one.
Related
I'm using Haar-Cascade Classifier in order to detect faces.
I'm currently facing some problems with the following function:
void ImageManager::detectAndDisplay(Mat frame, CascadeClassifier face_cascade){
string window_name = "Capture - Face detection";
string filename;
std::vector<Rect> faces;
std::vector<Rect> eyes;
Mat frame_gray;
Mat crop;
Mat res;
Mat gray;
string text;
stringstream sstm;
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));
// Set Region of Interest
cv::Rect roi_b;
cv::Rect roi_c;
size_t ic = 0; // ic is index of current element
for (ic = 0; ic < faces.size(); ic++) // Iterate through all current elements (detected faces)
{
roi_c.x = faces[ic].x;
roi_c.y = faces[ic].y;
roi_c.width = (faces[ic].width);
roi_c.height = (faces[ic].height);
crop = frame_gray(roi_c);
faces_img.push_back(crop);
rectangle(frame, Point(roi_c.x, roi_c.y), Point(roi_c.x + roi_c.width, roi_c.y + roi_c.height), Scalar(0,0,255), 2);
}
imshow("test", frame);
waitKey(0);
cout << faces_img.size();
}
The frame is the photo I'm trying to scan.
The face_cascade is the classifier.
internally, the CascadeClassifier does several detections, and groups those.
minNeighbours (in the detectMultiScale call) is the amount of detections in about the same place nessecary to count as a valid detection, so increase that from your current 2 to maybe 5 or so, until you start to miss positives.
As an addition to berak's statement, it's not only about reducing/increasing of detectMultiScale parameters if you're not doing the stuff only on an image. You'll face performance problems that do not let the user use the application.
Performance issues are relying on miscalculations. And what calculation takes is just testing.
If you are not trying to have the best results under different light conditions(since this is visual-dependent information) you'll have to scale the input array before sending it as an argument to detectMultiScale function. Once detection's completed, rescale to the previous size(it may be done by changing the rectangle's size that's used as an argument for detectMultiScale).
I have written a C++ program using OpenCV that can detect and highlight the edges of any object from a live video. But now I don't know how to extract the four corners of the cube from the many edges that are being detected in the video. So I am looking for some help here.
Here is the link of the paper that I am using as a guide for my this project.
http://www.cs.ubc.ca/~andrejk/525project/525report.pdf
You can find the program code for this paper in the link below. It's written in Python. (I am using C++ and I don't know Python)
http://www.cs.ubc.ca/~andrejk/525project/cubefinder.py
According to the paper the next step would be, 'edge segmentation with adaptive threshold.'
Which I don't really understand. And also I don't know how to extract the corners of the cube then.
The short summary of the method that I have used is as following.
1. Input from webcam
2. Apply Laplacian filter
3. Apply Hough Line Transform.
I get the following result.
Code
using namespace std;
using namespace cv;
Mat laplacianFilter(Mat image)
{
Mat hImage;
GaussianBlur(image,hImage,Size(3,3),0,0,BORDER_DEFAULT);
cvtColor(hImage,hImage,CV_RGB2GRAY);
Laplacian(hImage,hImage,CV_16SC1,3,1,0,BORDER_DEFAULT);
convertScaleAbs(hImage,hImage,1,0);
return hImage;
}
Mat hghTransform(Mat image, Mat &image2)
{
Mat lImage;
Canny(image,image,50,200,3);
cvtColor(image,lImage,CV_GRAY2BGR);
vector<Vec4i> lines;
HoughLinesP(image, lines, 1, CV_PI/180, 50, 50, 10 );
for( size_t i = 0; i < lines.size(); i++ )
{
Vec4i l = lines[i];
line( image2, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,255,0), 3, CV_AA);
}
return lImage;
}
int main()
{
int c;
VideoCapture cap(0);
Mat image;
Mat image2;
namedWindow("hghtransform");
namedWindow("laplacianfilter");
namedWindow("cannyOutput");
while(1)
{
cap>>image;
cap>>image2;
//Output
imshow("laplacianfilter",laplacianFilter(image));
imshow("cannyOutput",hghTransform(laplacianFilter(image),image2));
imshow("hghtransform",image2);
c=waitKey(33);
if(c==27)
return 0;
}
return 0;
}
Adaptive threshold will give you a clear line of edges which enables you to get 9 squares of a rubik side properly.
You can see a decent comparison of global and adaptive threshold here:
here: https://sites.google.com/site/qingzongtseng/adaptivethreshold
original image:
global threshold:
adaptive threshold:
For the corner, I am not sure whether it's stated in the paper, but I would do something like:
==> finding area like 1, 2, 3, 4 for upper-left, upper-right, lower-left, and lower-right corner respectively
==> with a template matching algorithm.
hope it helps.
note: you might want to have a background with less noise there. =)
I am making an application in which i have to open the camera and track the motion from camera live video/stream. and then detect the number of faces in the current frame.
I have done the face detection part by using CIDetector but unable to do the Motion detection.
Can any one please guide me how to do it.
I have used the GPUImage but it does not support multiple face detection.
I have developed a similar app. I used OpenCV to do both motion detection and face detection. The process would involve converting your Pixel Buffer ref into an OpenCV Mat object, converting this to grayscale and performing absDiff() and threshold() functions to calculate the diff (motion) between two images.
You can then process the same frame again for faces. This maybe not as efficient as GPUImage which can now do motion detection as well using GPU acceleration.
int motionValue;
// Blur images to reduce noise and equalize
cv::Mat processedFrame = cv::Mat(originFrame.size(), CV_8UC1);
cv::blur(originFrame, processedFrame, cv::Size(2,2));
// Get absolute difference image
cv::Mat diffMat;
cv::absdiff(processedFrame, prevFrame, diffMat);
// Apply threshold to each channel and combine the results
cv::Mat treshMat;
cv::threshold(diffMat, treshMat, kCCAlgorithmMotionSensitivity, 255, CV_THRESH_TOZERO);
// Find all contours
std::vector<std::vector<cv::Point> > contours;
cv::findContours(treshMat, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Count all motion areas
std::vector<std::vector<cv::Point> > intruders;
for (int i = 0; i < contours.size(); i++) {
double area = cv::contourArea(contours[i]);
//NSLog(#"Area %d = %f",i, area);
if (area > kCCAlgorithmMotionMinAreaDetection){
intruders.push_back(contours[i]);
motionValue += area;
}
}
Ive been reading about feature detection and wanted to try harris corner detector. I realize that it is achieved by calling
void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType=BORDER_DEFAULT )
where the dst is an image of floats containing corner strengths at each pixel.
I wanted to see it work so I wanted to apply it to the following picture:
The result produced was this:
As you can tell the results are not good. It looks to me that it just picked up noise, the main corners were not even detected.
Here is the code I used to print corners on the image, I used threshold and set any arbitrary value for threshold.
int _tmain(int argc, _TCHAR* argv[])
{
Mat img, dst, threshed;
img = imread("c:\\laptop.jpg",0);
dst = Mat::zeros(img.size(), CV_32FC1);
cornerHarris(img, dst, 2, 3, 0.04, BORDER_DEFAULT);
threshold(dst, threshed, 0.00001, 255, THRESH_BINARY_INV);
namedWindow("meh", CV_WINDOW_AUTOSIZE);
imshow("meh", threshed);
//imwrite("harris.jpg", threshed);
waitKey(0);
return 0;
If I reduce threshold the result is white with just a few black dots (detections) Increasing threshold just produces a more noisy like image.
Am I missing something? How can I improve the quality of this function?
Thank you
You can try a goodFeaturesToTrack function. It is built on top of Harris corner detector but filters our the noise and returns only strong corners.
I wrote the code for hough transformation and it works well. Also I can crop the eye location of a face. Now I want to detect the iris of the crop image with applying the Hough transformation(cvHoughCircle). However when I try this procedure, the system is not able to find any circle on the image.
Maybe, the reason is, there are noises in the image but I don't think it's the reason.
So, how can I detect the iris? I have the code of binary thresholding maybe I can use it, but
I don't know how to do?
If anyone helps I really appreciate it. thx :)
You say that with binary thresold you get an iris that is pure white : that is not what you want to have. Use something like cvCanny in order to get only the edge of the iris.
Are you detecting the edges correctly?
Can you display the binary image and see the iris clearly?
circular hough transforms normally have a radius window (otherwise you are searching a 3d solution space) are you setting the window to a reasonable value?
void houghcircle()
{
//cvSmooth( graybin,graybin, CV_GAUSSIAN, 5,5 );
CvMemStorage* storage = cvCreateMemStorage(0);
// smooth it, otherwise a lot of false circles may be detected
CvSeq* circles = cvHoughCircles( edge, storage, CV_HOUGH_GRADIENT, 5, edge->height/4,1,1,2,50, 70 );
int i;
for( i = 0; i < circles->total; i++ )
{
float* p = (float*)cvGetSeqElem( circles, i);
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), 2, CV_RGB(0,255,0), -1, 2, 0 );
cvCircle( img, cvPoint(cvRound(p[0]),cvRound(p[1])), cvRound(p[2]), CV_RGB(255,0,0), 1, 2, 0 );
cvNamedWindow( "circles", 1 );
cvShowImage( "circles", img );
cvWaitKey();
}
}