i'm trying to do a C++ program for fingertip recognition using kinect with the libraries OpenNi and OpenCV 2.4.
Here i list my main function (I intentionally avoided to write down here other function/classes that probably are not cause of the error):
// xml to initialize OpenNI
#define SAMPLE_XML_PATH "/home/jacopo/workspace/opencv_fingertip_detector/Sample-Tracking.xml"
int main(int argc, char ** argv)
{
XnStatus rc = XN_STATUS_OK;
xn::EnumerationErrors errors;
// Initialize OpenNI
rc = g_Context.InitFromXmlFile(SAMPLE_XML_PATH, g_ScriptNode, &errors);
CHECK_ERRORS(rc, errors, "InitFromXmlFile");
CHECK_RC(rc, "InitFromXmlFile");
rc = g_Context.FindExistingNode(XN_NODE_TYPE_DEPTH, g_DepthGenerator);
CHECK_RC(rc, "Find depth generator");
rc = g_Context.FindExistingNode(XN_NODE_TYPE_HANDS, g_HandsGenerator);
CHECK_RC(rc, "Find hands generator");
rc = g_Context.FindExistingNode(XN_NODE_TYPE_GESTURE, g_GestureGenerator);
CHECK_RC(rc, "Find gesture generator");
XnCallbackHandle h;
if (g_HandsGenerator.IsCapabilitySupported(XN_CAPABILITY_HAND_TOUCHING_FOV_EDGE))
{
g_HandsGenerator.GetHandTouchingFOVEdgeCap().RegisterToHandTouchingFOVEdge(TouchingCallback, NULL, h);
}
XnCallbackHandle hGestureIntermediateStageCompleted, hGestureProgress, hGestureReadyForNextIntermediateStage;
g_GestureGenerator.RegisterToGestureIntermediateStageCompleted(GestureIntermediateStageCompletedHandler, NULL, hGestureIntermediateStageCompleted);
g_GestureGenerator.RegisterToGestureReadyForNextIntermediateStage(GestureReadyForNextIntermediateStageHandler, NULL, hGestureReadyForNextIntermediateStage);
g_GestureGenerator.RegisterGestureCallbacks(NULL, GestureProgressHandler, NULL, hGestureProgress);
// Create NITE objects
g_pSessionManager = new XnVSessionManager;
rc = g_pSessionManager->Initialize(&g_Context, "Click,Wave", "RaiseHand");
CHECK_RC(rc, "SessionManager::Initialize");
g_pSessionManager->RegisterSession(NULL, SessionStarting, SessionEnding, FocusProgress);
g_pDrawer = new XnVPointDrawer(20, g_DepthGenerator);
g_pFlowRouter = new XnVFlowRouter;
g_pFlowRouter->SetActive(g_pDrawer);
g_pSessionManager->AddListener(g_pFlowRouter);
g_pDrawer->RegisterNoPoints(NULL, NoHands);
g_pDrawer->SetDepthMap(g_bDrawDepthMap);
// Initialization done. Start generating
rc = g_Context.StartGeneratingAll();
CHECK_RC(rc, "StartGenerating");
cv::Mat depthshow;
int key_pre = 0 ;
for( ; ; )
{
if (key_pre == 27)
break ;
XnMapOutputMode mode;
g_DepthGenerator.GetMapOutputMode(mode);
g_Context.WaitOneUpdateAll(g_DepthGenerator);
//TEST
g_DepthGenerator.GetMetaData(depthMD);
XnDepthPixel* pDepth = depthMD.WritableData();
// Update NITE tree
g_pSessionManager->Update(&g_Context);
if(g_pDrawer->handFound)
{
for (XnUInt y = 0; y < depthMD.YRes(); ++y)
{
for (XnUInt x = 0; x < depthMD.XRes(); ++x, ++pDepth)
{
if (*pDepth>g_pDrawer->pt3D.Z+50 || *pDepth<g_pDrawer->pt3D.Z-50)
{
*pDepth=0;
}
}
}
}
//for opencv Mat
cv::Mat depth16(480,640,CV_16SC1,(unsigned short*)depthMD.WritableData());
//convert depth 11 bit image 2 8 bit image
//depth16.convertTo(depthshow,CV_8U,-255/4096.0,255);
depth16.convertTo(depthshow, CV_8UC1, 0.025);
if(g_pDrawer->handFound)
{
cv::Point handPos(g_pDrawer->ptProjective.X, g_pDrawer->ptProjective.Y);
cv::circle(depthshow, handPos, 5, cv::Scalar(0xffff), 10, 8, 0);
Mat src_gray;
int thresh = 10;
RNG rng(12345);
blur( depthshow, src_gray, Size(3,3) );
Mat threshold_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
/// Find contours
findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Find the convex hull object for each contour
vector<vector<int> > hullsI (contours.size());
vector<vector<Point> > hullsP (contours.size() );
vector<vector<Vec4i> > defects (contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
convexHull(contours[i], hullsI[i], false, false);
convexHull(contours[i], hullsP[i], false, true);
if (contours[i].size() >3 )
{
convexityDefects(contours[i], hullsI[i], defects[i]);
}
}
/// Draw contours + hull results
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i < defects.size(); i++)
{
Vec4i defect(defects[i][0]);
Point start = contours[i][defect[0]];
Point end = contours[i][defect[1]];
Point far = contours[i][defect[2]];
std::cout << "Roba mia: "<< start << "\t" << end << "\t" << far << std::endl;
line(drawing, start, end, Scalar( 255, 0, 0 ), 1);
circle(drawing, far, 5, Scalar( 255, 0, 0 ), 1);
}
for( int i = 0; i < contours.size(); i++ )
{
Scalar color = Scalar( 255, 0, 0 );
drawContours( drawing, contours, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
drawContours( drawing, hullsP, i, color, 1, 8, vector<Vec4i>(), 0, Point() );
}
/// Show in a window
namedWindow( "Hull demo", CV_WINDOW_AUTOSIZE );
imshow( "Hull demo", drawing );
}
cv::imshow("PrimeSense Nite Point Viewer", depthshow);
key_pre = cv::waitKey(33);
}
cv::destroyWindow("PrimeSense Nite Point Viewer");
CleanupExit();
return 0;
}
The segmentation fault happen when i try to use one of the variable start, end or far, indeed if I comment the three lines (std::cout, line and circle) right after I assign the three variables the code run normally without problems.
Does someone of you have an idea on how to solve this issue?
Thanks for reading
J.
Related
I have an input image:
I use few functions to find contours in this image:
cv::Mat srcImg = cv::imread("input.png");
cv::Mat grayImg{};
cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
cv::Mat threshImg;
cv::adaptiveThreshold(grayImg, threshImg, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2);
My picture after thresholding is as below:
Now I want to find contours:
std::vector<std::vector<cv::Point>> ptContours{};
cv::findContours(threshImg, ptContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
And here is my question: how can I use drawContours() to fill the inner area of the character A?
I want to achieve something like this:
If you get the binary image via Otsu Thresholding, you get a nice binary blob without any "filling problems":
// Read the input image:
std::string imageName = "D://opencvImages//UZUd5.png";
cv::Mat testImage = cv::imread( imageName );
// Convert BGR to Gray:
cv::Mat grayImage;
cv::cvtColor( testImage, grayImage, cv::COLOR_RGB2GRAY );
// Get Binary via Otsu:
cv::Mat binaryImage;
cv::threshold( grayImage, binaryImage, 0, 255, cv::THRESH_OTSU );
This is the result:
If you don't want to use Otsu, and instead use your current approach, this is a possible way of filling the blob. It basically filters every contour by area and hierarchy. I look for the outmost and inmost contours, and perform some flood-fills accordingly - outside of the outer contour, to fill the canvas and inside the inner contour to fill the hole:
// Get Binary via Adaptive Thresh:
cv::Mat binaryImage;
cv::adaptiveThreshold( grayImage, binaryImage, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 11, 2 );
// Containers:
std::vector< std::vector<cv::Point> > contours;
std::vector< cv::Vec4i > hierarchy;
// Create a new matrix where things will be drawn:
cv::Mat filledBlob = cv::Mat::ones( binaryImage.size(), CV_8UC3 );
// Find contours:
cv::findContours(binaryImage, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
// Filling colors:
cv::Scalar fillColor = cv::Scalar( 0,0,0 );
cv::Scalar canvasColor = cv::Scalar( 255,255,255 );
for( int i = 0; i < (int)contours.size(); i++ ){
// Get Blob area:
float blobArea = cv::contourArea( contours[i] );
// Filter smaller blobs:
int minArea = 3000;
if ( blobArea > minArea) {
// Get contour heirarchy:
int contourHierarchy = hierarchy[i][3];
// Process the child contour:
if ( contourHierarchy != -1 ){
// Draw "hole":
cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
// Get bounding rectangle:
cv::Rect bBox = cv::boundingRect(contours[i]);
// Compute centroid:
cv::Point centroid;
centroid.x = bBox.x + 0.5*bBox.width;
centroid.y = bBox.y + 0.5*bBox.height;
// Flood-fill at centroid with canvas color:
cv::floodFill( filledBlob, centroid, canvasColor, (cv::Rect*)0, cv::Scalar(), 0);
}else{
// Process the parent contour:
if ( contourHierarchy == -1 ){
// Draw outline:
cv::drawContours( filledBlob, contours, (int)i, fillColor, 1, cv::LINE_8, hierarchy, 0 );
// Flood-fill at canvas (outside of contour):
cv::floodFill( filledBlob, cv::Point( 1, 1 ), canvasColor, (cv::Rect*)0, cv::Scalar(), 0);
}
}
// Show image
cv::imshow( "Filled Blob", filledBlob );
cv::waitKey(0);
}
}
Which yields this image:
If you want an inverted image, just subtract 255 - filledBlob:
cv::subtract( 255, filledBlob, filledBlob );
My difficulty in implementing optical flow method to track vehicles with input from the haar cascade.
So far I can only implement Optical flow but input not from Haar Cascade.
can you help me .. ??
this is my code
using namespace cv;
using namespace std;
int main()
{
int count= 0; double areax, areay, KoorX, KoorY;
Mat prev_frame, gray, temp, prev_img;
Mat frameROI, imgROI, frameLKP;
Mat ROI, prevROI, ROIOF;
//Parameter OFLKP
int win_size = 24;
int maxCorners =24;
int maxlevel =8;
TermCriteria termcrit(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS,20,0.01);
vector<uchar>found;
vector<float>error;
//Parameter Shi-Tomasi
vector<Point2f> prevcorners, corners;
double qualityLevel = 0.05; //0.4
double minDistance = 1; //2
int blockSize = 3;
bool useHarrisDetector = false;
double k = 0.04;
vector<Point2f> frame_corners; // CvPoint array of features
frame_corners.reserve(maxCorners);
vector<Point2f> prevframe_corners;
prevframe_corners.reserve(maxCorners);
//=======> Manggil dan buka video
VideoCapture video("Uji1.avi");
//=======> Manggil .xml
CascadeClassifier Casmobil;
String Casmobil_file = "car2500.xml";
Casmobil.load(Casmobil_file);
namedWindow("Video", 1);
namedWindow("Tracking OF", 1);
namedWindow("Deteksi Haar", 1);
video >> prev_frame;
Rect roi = Rect(50, 180, 540, 240);
prevROI=prev_frame(roi);
cvtColor(prevROI, gray, CV_BGR2GRAY);
gray.convertTo(prev_img, CV_8UC1);
while(true)
{
//=====> baca frame dr video
video >> frameROI;
//=====> ROI
Rect roi = Rect(50, 180, 540, 240);
Mat ROI=frameROI(roi);
cvtColor(ROI, gray, CV_BGR2GRAY); //=====> RGB to Grayscale
gray.convertTo(imgROI, CV_8UC1);
Mat ROIOF = frameROI(roi);
//======> Deteksi
vector<Rect> mobil;
Casmobil.detectMultiScale(gray, mobil, 1.1, 3,
CV_HAAR_DO_CANNY_PRUNING|CV_HAAR_SCALE_IMAGE,
Size(0,0));
//======> Gambar kotak
for (size_t i = 0; i < mobil.size(); i++)
{
Rect kotak = mobil[i];
areax = (mobil[i].x + mobil[i].width*0.5);
areay = (mobil[i].y + mobil[i].height*0.5);
Point center = Point(areax ,areay);
rectangle(ROI, kotak,CV_RGB(0,255,0),2,8,0);
circle(ROI, center, 3,CV_RGB(255, 0, 0),-2);
}
//prev_frame
goodFeaturesToTrack(imgROI, frame_corners,maxCorners,
qualityLevel,minDistance,Mat(),
blockSize,useHarrisDetector,k);
cornerSubPix(imgROI, frame_corners, Size(win_size, win_size),
Size( -1, -1 ),termcrit);
calcOpticalFlowPyrLK(imgROI, prev_img, frame_corners,
prevframe_corners, found, error,
Size(win_size, win_size), maxlevel,termcrit);
for( int j = 0; j < frame_corners.size(); j++ )
{
circle(ROIOF, frame_corners[j], 2, CV_RGB(255, 0, 0), -1);
circle(ROIOF, prevframe_corners[j], 2, CV_RGB(0, 0, 255), -1);
//circle(copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255)), -1, 8, 0 );
line(ROIOF, prevframe_corners[j], frame_corners[j], CV_RGB(0, 255, 0),2, 8, 0);
}
prev_img = imgROI.clone();
imshow("Video ", frameROI);
imshow("Deteksi Haar", ROI);
imshow("Tracking OF", ROIOF);
if(waitKey(400) >= 0) break;
}
return 0;
}
Thanks,,
do I need to replace the input image from goodfeaturesToTrack by croping images from Haar Results ??
like :
Mat Crop = imgROI(mobil[i]);
goodFeaturesToTrack(Crop,frame_corners,maxCorners,qualityLevel,minDistance,Mat(),blockSize,useHarrisDetector,k);
so I am working on an assignment in which I have to classify road signs based on input images. So naturally I used the canny function, and findContours, followed by approxPolyPD in order to get the corners of the image that I will be transforming.
However for some reason, I keep getting an error when I attempt to use getPerspectiveTransform for the next step. Please help.
Error:
OpenCV Error: Assertion failed (0 <= i && i < (int)vv.size()) in getMat_, file /home/path_to_opencv/opencv/modules/core/src/matrix.cpp, line 1192
terminate called after throwing an instance of 'cv::Exception'
what(): /home/path_to_opencv/opencv/modules/core/src/matrix.cpp:1192: error: (-215) 0 <= i && i < (int)vv.size() in function getMat_
Aborted (core dumped)
Code used:
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define WARPED_XSIZE 200
#define WARPED_YSIZE 300
using namespace cv;
using namespace std;
Mat src; Mat src_gray, warped_result; Mat dst;
Mat speed_80, speed_40;
int canny_thresh = 154;
#define VERY_LARGE_VALUE 100000
#define NO_MATCH 0
#define STOP_SIGN 1
#define SPEED_LIMIT_40_SIGN 2
#define SPEED_LIMIT_80_SIGN 3
RNG rng(12345);
/** #function main */
int main(int argc, char** argv)
{
int sign_recog_result = NO_MATCH;
speed_40 = imread("speed_40.bmp", 0);
speed_80 = imread("speed_80.bmp", 0);
// you run your program on these three examples (uncomment the two lines below)
//string sign_name = "stop4";
string sign_name = "speedsign12";
//string sign_name = "speedsign3";
//string sign_name = "speedsign4";
string final_sign_input_name = sign_name + ".jpg";
string final_sign_output_name = sign_name + "_result" + ".jpg";
/// Load source image and convert it to gray
src = imread(final_sign_input_name, 1);
/// Convert image to gray and blur it
cvtColor(src, src_gray, COLOR_BGR2GRAY);
blur(src_gray, src_gray, Size(3, 3));
warped_result = Mat(Size(WARPED_XSIZE, WARPED_YSIZE), src_gray.type());
// here you add the code to do the recognition, and set the variable
// sign_recog_result to one of STOP_SIGN, SPEED_LIMIT_40_SIGN, SPEED_LIMIT_80_SIGN, or NO_MATCH
// PART 1 of Assignment 2
Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny(src_gray, canny_output, canny_thresh, canny_thresh*2, 3);
findContours(canny_output, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));
vector<vector<Point> > contours_poly(contours.size());
for (unsigned int i = 0; i < contours.size(); ++i) {
approxPolyDP(Mat(contours[i]), contours_poly[i], contours_poly[i].size()*.02, true);
}
// Part 2 of Assignment 2
vector<vector<Point> > transform_result(contours_poly.size());
warped_result = getPerspectiveTransform(contours_poly, transform_result);
warpPerspective(src, dst, warped_result, dst.size());
//imshow("input", src);
//imshow("output", dst);
/*
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for(unsigned int i = 0; i< contours_poly.size(); i++ ) {
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
drawContours( drawing, contours_poly, i, color, 2, 8, hierarchy, 0, Point() );
}
// Show in a window
namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );
//*/
// Returning to the predetermined code.
string text;
if (sign_recog_result == SPEED_LIMIT_40_SIGN) text = "Speed 40";
else if (sign_recog_result == SPEED_LIMIT_80_SIGN) text = "Speed 80";
else if (sign_recog_result == STOP_SIGN) text = "Stop";
else if (sign_recog_result == NO_MATCH) text = "Fail";
int fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
double fontScale = 2;
int thickness = 3;
cv::Point textOrg(10, 130);
cv::putText(src, text, textOrg, fontFace, fontScale, Scalar::all(255), thickness, 8);
/// Create Window
char* source_window = "Result";
namedWindow(source_window, WINDOW_AUTOSIZE);
imshow(source_window, src);
imwrite(final_sign_output_name, src);
waitKey(0);
return(0);
}
Some warnings appear in terminal during running:
OpenCV Error: Assertion failed(s>=0) in setSize, file /home/me/opencv2.4/modules/core/src/matrix.cpp, line 116
The program compiled without error and executes, the problem is the eye ROI size changes when user moves closer/farther away from webcam, due to the changing of size, the warning appears. I managed to solve these warnings by setting the eye ROI size equal to my eye template size. However, it ends up the program fails to classify user's eyes open/close because the minVal obtained is 0. The method used is OpenCV Template Matching. Alternatively, I fix my distance from webcam and fix the eye template size could avoid the warning. Every time warning appears, the program fails to classify open/close eyes. The program doesn't work effectively because sometimes it mistakenly classifies the open eyes as closed and vice versa.
Questions:
Is there any alternative to identify open and close eyes other than template matching?
Any ideas how to improve the program in classification of blinking?
Any working example that you know in opencv C/C++ API can classify open and close eyes and count accurately the blinking times?
static CvMemStorage* storage = 0;
// Create a new Haar classifier
static CvHaarClassifierCascade* cascade = 0;
// Function prototype for detecting and drawing an object from an image
bool detect_and_draw( IplImage* image ,CvHaarClassifierCascade* cascade);
const char *cascade_name[1]={"eyes.xml"};
cv::Mat roiImg;
int threshold_value = 200;
int threshold_type = 3;;
int const max_value = 255;
int const max_type = 4;
int const max_BINARY_value = 255;
int hough_thr = 35;
cv::Mat src_gray, dst;
using namespace cv;
Mat img1; Mat img2; Mat templ; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";
int match_method=0;
int max_Trackbar = 5;
int eye_open=0;
int eye_close=0;
//Matching with 2 images ,eye closed or open
void MatchingMethod(cv::Mat templ,int id )
{
/// Source image to display
cv::Mat img_display;
roiImg.copyTo( img_display );
/// Create the result matrix
int result_cols = roiImg.cols - templ.cols + 1;
int result_rows = roiImg.rows - templ.rows + 1;
result.create( result_cols, result_rows, CV_32FC1 );
/// Do the Matching and Normalize
cv::matchTemplate( roiImg, templ, result, match_method );
cv::normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
/// Localizing the best match with minMaxLoc
double minVal; double maxVal; Point minLoc; Point maxLoc;
cv::Point matchLoc;
cv::minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
///Justing checkin the match template value reaching the threashold
if(id == 0 && (minVal < 0))
{
eye_open=eye_open+1;
if(eye_open == 1)
{
std::cout<<"Eye Open"<<std::endl;
eye_open=0;
eye_close=0;
}
}
else if(id == 1 && (minVal < 0))
eye_close=eye_close+1;
if(eye_close == 1)
{
std::cout<<"Eye Closed"<<std::endl;
eye_close=0;
system("python send_arduino.py");
}
/// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if( match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
/// Show me what you got
cv::rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
cv::rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
cv::imshow( image_window, img_display );
cv::imshow( result_window, result );
return;
}
void detect_blink(cv::Mat roi)
{
try
{
MatchingMethod(img1,0);
MatchingMethod(img2,1);
}
catch( cv::Exception& e )
{
std::cout<<"An exception occued"<<std::endl;
}
}
// Main function, defines the entry point for the program.
int main( int argc, char** argv )
{
if(argc <= 1)
{
std::cout<<"\n Help "<<std::endl;
std::cout<<"\n ------------------------------------\n"<<std::endl;
std::cout<<"./blink_detect open_eye.jpg close_eye.jpg\n"<<std::endl;
std::cout<<"Eg :: ./blink_detect 2.jpg 3.jpg\n"<<std::endl;
std::cout<<"\n ------------------------------------\n"<<std::endl;
exit(0);
}
// Structure for getting video from camera or avi
CvCapture* capture = 0;
// Images to capture the frame from video or camera or from file
IplImage *frame, *frame_copy = 0;
// Used for calculations
int optlen = strlen("--cascade=");
// Input file name for avi or image file.
const char* input_name;
img1 = imread( argv[1], 1 );
img2 = imread( argv[2], 1 );
// Load the HaarClassifierCascade
/// Create windows
cv::namedWindow( image_window, CV_WINDOW_AUTOSIZE );
cv::namedWindow( result_window, CV_WINDOW_AUTOSIZE );
// Allocate the memory storage
storage = cvCreateMemStorage(0);
capture = cvCaptureFromCAM( 0);
// Create a new named window with title: result
cvNamedWindow( "original_frame", 1 );
// If loaded succesfully, then:
if( capture )
{
// Capture from the camera.
for(;;)
{
// Capture the frame and load it in IplImage
if( !cvGrabFrame( capture ))
break;
frame = cvRetrieveFrame( capture );
// If the frame does not exist, quit the loop
if( !frame )
break;
// Allocate framecopy as the same size of the frame
if( !frame_copy )
frame_copy = cvCreateImage( cvSize(frame->width,frame->height),
IPL_DEPTH_8U, frame->nChannels );
// Check the origin of image. If top left, copy the image frame to frame_copy.
if( frame->origin == IPL_ORIGIN_TL )
cvCopy( frame, frame_copy, 0 );
// Else flip and copy the image
for(int i=0;i<1;i++)
{
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name[i], 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 -1;
}
// Call the function to detect and draw the face
if(detect_and_draw(frame_copy,cascade))
{
std::cout<<"Detected"<<std::endl;
}
}
// Wait for a while before proceeding to the next frame
if( cvWaitKey( 1 ) >= 0 )
break;
}
// Release the images, and capture memory
cvReleaseHaarClassifierCascade(&cascade);
cvReleaseImage( &frame_copy );
cvReleaseCapture( &capture );
cvReleaseMemStorage(&storage);
}
return 0;
}
// Function to detect and draw any faces that is present in an image
bool detect_and_draw( IplImage* img,CvHaarClassifierCascade* cascade )
{
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;
// 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, 8, 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 );
cv::Mat image(img);
cv::Rect rect;
rect = cv::Rect(pt1.x,pt1.y,(pt2.x-pt1.x),(pt2.y-pt1.y));
roiImg = image(rect);
cv::imshow("roi",roiImg);
///Send to arduino
detect_blink(roiImg);
}
}
cvShowImage( "original_frame", img );
if(i > 0)
return 1;
else
return 0;
cvReleaseImage( &temp );
}
Reference:
Website referred
I have worked with kmeans and would like to use adaptive methods.
Do you know any library or a way to do that in OpenCV?
You might want to try the function k-nearest neighbor in OpenCV. Here is an example of how to use it:
#include "ml.h"
#include "highgui.h"
int main( int argc, char** argv )
{
const int K = 10;
int i, j, k, accuracy;
float response;
int train_sample_count = 100;
CvRNG rng_state = cvRNG(-1);
CvMat* trainData = cvCreateMat( train_sample_count, 2, CV_32FC1 );
CvMat* trainClasses = cvCreateMat( train_sample_count, 1, CV_32FC1 );
IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
float _sample[2];
CvMat sample = cvMat( 1, 2, CV_32FC1, _sample );
cvZero( img );
CvMat trainData1, trainData2, trainClasses1, trainClasses2;
// form the training samples
cvGetRows( trainData, &trainData1, 0, train_sample_count/2 );
cvRandArr( &rng_state, &trainData1, CV_RAND_NORMAL, cvScalar(200,200), cvScalar(50,50) );
cvGetRows( trainData, &trainData2, train_sample_count/2, train_sample_count );
cvRandArr( &rng_state, &trainData2, CV_RAND_NORMAL, cvScalar(300,300), cvScalar(50,50) );
cvGetRows( trainClasses, &trainClasses1, 0, train_sample_count/2 );
cvSet( &trainClasses1, cvScalar(1) );
cvGetRows( trainClasses, &trainClasses2, train_sample_count/2, train_sample_count );
cvSet( &trainClasses2, cvScalar(2) );
// learn classifier
CvKNearest knn( trainData, trainClasses, 0, false, K );
CvMat* nearests = cvCreateMat( 1, K, CV_32FC1);
for( i = 0; i < img->height; i++ )
{
for( j = 0; j < img->width; j++ )
{
sample.data.fl[0] = (float)j;
sample.data.fl[1] = (float)i;
// estimates the response and get the neighbors' labels
response = knn.find_nearest(&sample,K,0,0,nearests,0);
// compute the number of neighbors representing the majority
for( k = 0, accuracy = 0; k < K; k++ )
{
if( nearests->data.fl[k] == response)
accuracy++;
}
// highlight the pixel depending on the accuracy (or confidence)
cvSet2D( img, i, j, response == 1 ?
(accuracy > 5 ? CV_RGB(180,0,0) : CV_RGB(180,120,0)) :
(accuracy > 5 ? CV_RGB(0,180,0) : CV_RGB(120,120,0)) );
}
}
// display the original training samples
for( i = 0; i < train_sample_count/2; i++ )
{
CvPoint pt;
pt.x = cvRound(trainData1.data.fl[i*2]);
pt.y = cvRound(trainData1.data.fl[i*2+1]);
cvCircle( img, pt, 2, CV_RGB(255,0,0), CV_FILLED );
pt.x = cvRound(trainData2.data.fl[i*2]);
pt.y = cvRound(trainData2.data.fl[i*2+1]);
cvCircle( img, pt, 2, CV_RGB(0,255,0), CV_FILLED );
}
cvNamedWindow( "classifier result", 1 );
cvShowImage( "classifier result", img );
cvWaitKey(0);
cvReleaseMat( &trainClasses );
cvReleaseMat( &trainData );
return 0;
}
http://opencv.willowgarage.com/documentation/cpp/k_nearest_neighbors.html
If you want to use this in c++ there is a great tutorial on this website:
http://aishack.in/tutorials/knearest-neighbors-in-opencv/