#include <wx/wx.h>#include <wx/thread.h>#include <opencv2/video/tracking.hpp>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/objdetect/objdetect.hpp>using namespace std;using namespace cv;class App : public wxApp{ virtual bool OnInit();};IMPLEMENT_APP(App);class GUI : public wxFrame{public: GUI(); void OnPaint(wxPaintEvent &evt); void OnSize(wxSizeEvent &evt); void Notify(wxImage &image);private: wxBitmap m_bmp; DECLARE_EVENT_TABLE();};BEGIN_EVENT_TABLE(GUI, wxFrame) EVT_PAINT(GUI::OnPaint) EVT_SIZE(GUI::OnSize)END_EVENT_TABLE()class FTThread : public wxThread{public: FTThread(GUI *gui); virtual void * Entry();private: void ToGUI(wxImage &image); void Mat2wxImage(Mat &frame, wxImage &image); Mat convertType(const Mat& srcImg, int toType, double alpha, double beta); GUI *m_gui;};class FaceTracker{public: FaceTracker(); ~FaceTracker(){} bool Init(Mat &frame); void Track(Mat &frame);private: Mat m_hist; Rect m_facerect; CascadeClassifier m_cascade;};bool App::OnInit(){ wxInitAllImageHandlers(); GUI *gui = new GUI; gui->Show(true); SetTopWindow(gui); FTThread *thread = new FTThread(gui); if(wxTHREAD_NO_ERROR != thread->Create()) { wxLogError("Can't create the thread!"); return false; } if(wxTHREAD_NO_ERROR != thread->Run()) { wxLogError("Can't create the thread!"); return false; } return true;}GUI::GUI():wxFrame(NULL,-1,"FaceTracker",wxPoint(-1,-1),wxSize(800,600)){ wxImage img("sample.jpg"); img.Rescale(800,600); m_bmp = wxBitmap(img); SetBackgroundColour(*wxBLACK);}void GUI::Notify(wxImage &image){ m_bmp = wxBitmap(image.Scale(800,600)); Refresh(false);}void GUI::OnPaint(wxPaintEvent &evt){ wxPaintDC dc(this); dc.DrawBitmap(m_bmp,wxPoint(-1,-1));}void GUI::OnSize(wxSizeEvent &evt){ wxImage image = m_bmp.ConvertToImage(); wxSize size = evt.GetSize(); m_bmp = wxBitmap(image.Scale(size.GetWidth(),size.GetHeight())); Refresh(false);}FTThread::FTThread(GUI *gui):wxThread(){ m_gui = gui;}void *FTThread::Entry(){ unsigned char count=5; Mat frame; wxImage image; VideoCapture cap(0); if(!cap.isOpened()) return NULL; FaceTracker tracker; while(1) { cap>>frame; if(frame.empty()) continue; if(5 == count++) { if(!tracker.Init(frame)) { count = 5; continue; } else count = 0; } tracker.Track(frame); Mat2wxImage(frame,image); ToGUI(image); Sleep(100); } return NULL;}void FTThread::ToGUI(wxImage &image){ m_gui->Notify(image);}Mat FTThread::convertType(const Mat& srcImg, int toType, double alpha, double beta){ Mat dstImg; srcImg.convertTo(dstImg, toType, alpha, beta); return dstImg;}void FTThread::Mat2wxImage(Mat &frame, wxImage &image){ // data dimension int w = frame.cols, h = frame.rows; int size = w*h*3*sizeof(unsigned char);// allocate memory for internal wxImage dataunsigned char * wxData = (unsigned char*) malloc(size);// the matrix stores BGR image for conversionMat cvRGBImg = Mat(h, w, CV_8UC3, wxData); switch (frame.channels()) { case 1: // 1-channel case: expand and copy { // convert type if source is not an integer matrix if (frame.depth() != CV_8U) {cvtColor(convertType(frame, CV_8U, 255,0), cvRGBImg, CV_GRAY2RGB); } else { cvtColor(frame, cvRGBImg, CV_GRAY2RGB); } } break; case 3: // 3-channel case: swap R&B channels { int mapping[] = {0,2,1,1,2,0}; // CV(BGR) to WX(RGB) mixChannels(&frame, 1, &cvRGBImg, 1, mapping, 3); } break; default: { wxLogError(wxT("Cv2WxImage : input image (#channel=%d) should be either 1- or 3-channel"), frame.channels()); } } image.Destroy(); // free existing data if there's any image = wxImage(w, h, wxData);}FaceTracker::FaceTracker(){ String face_cascade_name = "haarcascade_frontalface_alt.xml"; if(!m_cascade.load(face_cascade_name)) { wxLogError("error load cascade file"); }}bool FaceTracker::Init(Mat &frame){ Mat frame_gray; vector<Rect> faces; int ch[] = {0,0}; int hsize = 16;float hranges[] = {0,180};const float *pRanges = hranges;Mat hsv,mask,hue; // Detect a facecvtColor(frame,frame_gray,CV_BGR2GRAY);equalizeHist(frame_gray, frame_gray);m_cascade.detectMultiScale(frame_gray,faces,1.1,2,0|CV_HAAR_SCALE_IMAGE,Size(30,30)); if(!faces.size()) return false;// 如果这次检测不到,那么尽可能用上一次的结果进行工作m_facerect = faces[0];cvtColor(frame,hsv,CV_BGR2HSV); // =>HSVinRange(hsv,Scalar(0,30,10),Scalar(180,256,256),mask); // =>MASKhue.create(hsv.size(),hsv.depth());mixChannels(&hsv,1,&hue,1,ch,1); // =>HMat roi(hue,m_facerect), maskroi(mask,m_facerect);calcHist(&roi,1,0,maskroi,m_hist,1,&hsize,&pRanges);normalize(m_hist,m_hist,0,255,CV_MINMAX);return true;}void FaceTracker::Track(Mat &frame){ static Mat hsv,hue,mask,backproj;static RotatedRect trackBox;static int ch[] = {0,0};static float HueRange[] = {0,180};static const float * pRanges = HueRange;cvtColor(frame,hsv,CV_BGR2HSV); // =>HSVinRange(hsv,Scalar(0,30,10),Scalar(180,256,256),mask); // =>MASKhue.create(hsv.size(),hsv.depth());mixChannels(&hsv,1,&hue,1,ch,1); // =>HcalcBackProject(&hue,1,0,m_hist,backproj,&pRanges);backproj &= mask;trackBox = CamShift(backproj,m_facerect, // 下面是给Meanshift的约束条件TermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,10,1 ));ellipse(frame,trackBox,Scalar(0,0,255),3,CV_AA);}