基于QT和opencv的瞳孔定位及跟踪程序

本篇博客是基于上一篇博客《基于opencv和QT的瞳孔精确检测程序》的进一步开发和完善,实现了瞳孔坐标和位置的输出功能,本文将给出完整的瞳孔定位及跟踪程序,本文是作者的独立开发成果,转载请注明出处http://blog.csdn.net/zyx1990412/article/details/51254127

实现原理:通过上一篇博客的介绍,我们可以实现对每一帧图像进行瞳孔检测,并得到瞳孔的精确坐标,即实现了瞳孔定位的功能。为了实现瞳孔跟踪的功能,我们可以通过手动按钮记录下瞳孔当前帧的坐标,作为跟踪的参考标准,然后将参考坐标与后续定位的坐标作比较,得到后续帧的相对坐标。本文的瞳孔跟踪功能是简单地计算当前帧相对于参考帧的相对位置,以确定瞳孔的当前相对位置。其原理图可以用图一表示。


图一

2.首先利用QT搭建一个界面,如图二。

图二

2.实现摄像头视频的读取和显示功能,详细的方法在《基于QT和opencv的摄像头(本地图片)读取并输出程序》这篇博客中有介绍。

3.建立一个图像处理类,对每一帧图像进行处理。主要功能是检测瞳孔中心,显示瞳孔中心定位结果图,并将瞳孔中心的绝对坐标保存在 Lcircles Rcircles中,方便外部函数读取。这个类的实现在后文给出。

class ImgProcess
{
    private:
        Mat inimg;//输入图像
        Mat outimg;//输出结果
        Mat Leye;
        Mat Reye;
        Mat Leye_G;
        Mat Reye_G;
        CvRect drawing_box;
    public:
        vector<Vec3f> Lcircles;
        vector<Vec3f> Rcircles;
        ImgProcess(Mat image):inimg(image),drawing_box(cvRect(0, 0, 50, 20)){}
        void EyeDetect();//人眼检测
        Mat Outputimg();//输出结果
        void DivideEye();//分左右眼
        Mat OutLeye();//输出结果
        Mat OutReye();
        Mat EdgeDetect(Mat &edgeimg);//边缘检测
        void EyeEdge();//分别检测左右眼
        vector<Vec3f> Hough(Mat &midImage);//hough变换
        void FindCenter();//定位中心
        Mat PlotC(vector<Vec3f> circles,Mat &midImage);//画HOUGH变换的检测结果
};

4.在mainwindow中编写槽函数,触发定位和跟踪事件。

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();//打开摄像头,进行瞳孔精确检测及定位
    void on_pushButton_2_clicked();//打开本地图片
    void on_pushButton_3_clicked();//瞳孔定位,建立标准坐标
    void on_pushButton_4_clicked();//是够启动瞳孔跟踪
    void on_pushButton_5_clicked();//关闭摄像头

private:
    Ui::MainWindow *ui;
    CvRect lpc_box=cvRect( 0,0,0,0);//保存当前帧的瞳孔坐标
    CvRect rpc_box=cvRect( 0,0,0,0);
    CvRect lp_bz=cvRect( 0,0,0,0);//保存标准瞳孔坐标
    CvRect rp_bz=cvRect( 0,0,0,0);
    Mat pic1;//坐标图
    Mat pic2;
    bool Lstop=false;
    bool Tack=false;
    void eyeTack();//瞳孔跟踪函数
    //cv::Mat image;
};

(1)打开摄像头后,图像处理类对每一帧图像进行处理,并将图像处理类得到的瞳孔绝对坐标保存到lpc_box和rpc_box中,详细介绍参考《基于opencv和QT的瞳孔精确检测程序》。

(2)触发瞳孔定位函数后,将图像处理类中得到的瞳孔绝对坐标保存到参考坐标lp_bz和rp_bz中。并将结果在lcdNumber上输出

(3)触发瞳孔跟踪函数后,通过当前帧绝对坐标和参考坐标的计算,得到相对坐标。并将结果在lcdNumber上输出。

(4)关闭摄像头,循环终止。


图三

最终的效果如图三,由于参数的设置和函数的精确等问题,其定位的效果还不能达到最佳效果。佩戴眼镜时的检测效果不好。图中的坐标图是直接读取已经画好的坐标图,如图四,图中的蓝点是根据相对坐标在坐标图上用opencv的画圆函数画出的。


图四

PS:本文所编写的瞳孔跟踪函数实际上核心是瞳孔的实时检测和定位,并没有用到传统意义上的目标跟踪函数。作者在毕业设计中的研究重点是基于MeanShift算法的目标跟踪算法,针对瞳孔跟踪,进行了加入帧差法和LBP的改进,作者将在以后的博客中进行详细介绍,并利用vs2013+opencv进行编程验证。

源代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "ui_mainwindow.h"
#include "detectanddisplay.h"
#include "imgprocess.h"
#include <QLabel>
#include"Mat2QImage.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();//打开摄像头,进行瞳孔精确检测及定位
    void on_pushButton_2_clicked();//打开本地图片
    void on_pushButton_3_clicked();//瞳孔定位,建立标准坐标
    void on_pushButton_4_clicked();//是够启动瞳孔跟踪
    void on_pushButton_5_clicked();//关闭摄像头

private:
    Ui::MainWindow *ui;
    CvRect lpc_box=cvRect( 0,0,0,0);//保存当前帧的瞳孔坐标
    CvRect rpc_box=cvRect( 0,0,0,0);
    CvRect lp_bz=cvRect( 0,0,0,0);//保存标准瞳孔坐标
    CvRect rp_bz=cvRect( 0,0,0,0);
    Mat pic1;//坐标图
    Mat pic2;
    bool Lstop=false;
    bool Tack=false;
    void eyeTack();//瞳孔跟踪函数
    //cv::Mat image;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()//打开摄像头,进行瞳孔精确检测及定位
{
    VideoCapture cap(0);    //打开默认摄像头
    if(!cap.isOpened())
    {
       cout<<"no cap"<<endl;
    }
    Mat frame; //保存当前帧的图像
    Lstop=false;//控制是否循环检测


    while(!Lstop)
    {
        cap>>frame;//将摄像头的当前帧输出到frame

        ImgProcess pro(frame);//建立视频处理类
        pro.EyeDetect();//人眼检测
        Mat image=pro.Outputimg();//输出检测图像
        imshow( "camera", image );
        QImage img=Mat2QImage(image);//将mat格式转换为Qimage格式
        ui->label->setPixmap(QPixmap::fromImage(img));//将结果在label上显示
        //ui->label->setScaledContents(true);//使图像尺寸与label大小匹配
        pro.DivideEye();//分成左右眼
        pro.EyeEdge();//瞳孔边缘检测
        pro.FindCenter();//hough变换求圆心
        Mat mleye=pro.OutLeye();//输出瞳孔定位结果
        QImage qleye=Mat2QImage(mleye);
        ui->label_2->setPixmap(QPixmap::fromImage(qleye));
        //ui->label_2->setScaledContents(true);
        Mat mreye=pro.OutReye();
        QImage qreye=Mat2QImage(mreye);
        ui->label_3->setPixmap(QPixmap::fromImage(qreye));
        //ui->label_3->setScaledContents(true);
        if (pro.Lcircles.size()>0)//将检测结果输出
         {

            lpc_box.x=pro.Lcircles[0][0];
            lpc_box.y=pro.Lcircles[0][1];
            lpc_box.height=pro.Lcircles[0][2];
            lpc_box.width=pro.Lcircles[0][2];
        }
        ui->lcdNumber_6->display(lpc_box.x);//显示坐标
        ui->lcdNumber_5->display(lpc_box.y);
        ui->lcdNumber_9->display(lpc_box.height);

        if (pro.Rcircles.size()>0)
         {

            rpc_box.x=pro.Rcircles[0][0];
            rpc_box.y=pro.Rcircles[0][1];
            rpc_box.height=pro.Rcircles[0][2];
            rpc_box.width=pro.Rcircles[0][2];
        }
        ui->lcdNumber_8->display(rpc_box.x);
        ui->lcdNumber_7->display(rpc_box.y);
        ui->lcdNumber_10->display(rpc_box.height);

        if( Tack==true)//是够启动跟踪功能
        {
            eyeTack();
        }

        int c = waitKey(30);//每一帧间隔30ms
        if (c >= 0)//任意键暂停
        {
            waitKey(0);
        }

    }
     cvDestroyWindow("camera");
}

void MainWindow::on_pushButton_2_clicked()//打开本地图片
{
    Mat image0;
    image0=cv::imread("IF.jpg");//图片的路径
    ImgProcess pro(image0);
    pro.EyeDetect();
    Mat image=pro.Outputimg();
    QImage img=Mat2QImage(image);
    ui->label->setPixmap(QPixmap::fromImage(img));
   // ui->label->setScaledContents(true);

    pro.DivideEye();
    pro.EyeEdge();
    pro.FindCenter();
    Mat mleye=pro.OutLeye();
    QImage qleye=Mat2QImage(mleye);
    ui->label_2->setPixmap(QPixmap::fromImage(qleye));
    //ui->label_2->setScaledContents(true);
    Mat mreye=pro.OutReye();
    QImage qreye=Mat2QImage(mreye);
    ui->label_3->setPixmap(QPixmap::fromImage(qreye));
    //ui->label_3->setScaledContents(true);
     waitKey(1000);

}

void MainWindow::on_pushButton_3_clicked()//瞳孔定位,建立标准坐标
{
    lp_bz=lpc_box;
    rp_bz=rpc_box;
    ui->lcdNumber->display(lpc_box.x);
    ui->lcdNumber_2->display(lpc_box.y);
    ui->lcdNumber_4->display(rpc_box.x);
    ui->lcdNumber_3->display(rpc_box.y);
    pic1=cv::imread("zb.jpg");//读坐标图
    cv::resize(pic1,pic1,Size(100,100));
    QImage zbimg1=Mat2QImage(pic1);
    ui->label_4->setPixmap(QPixmap::fromImage(zbimg1));
    ui->label_4->setScaledContents(true);
    pic2=cv::imread("zb1.jpg");
    cv::resize(pic2,pic2,cvSize(100,100));
    QImage zbimg2=Mat2QImage(pic2);
    ui->label_5->setPixmap(QPixmap::fromImage(zbimg2));
    ui->label_5->setScaledContents(true);
}

void MainWindow::on_pushButton_4_clicked()//是够启动瞳孔跟踪
{
    Tack=true;
}


void MainWindow::eyeTack()//瞳孔跟踪函数
{
    float ldx,ldy,rdx,rdy,plx,ply,prx,pry;//左右眼瞳孔坐标,d相对坐标差
    ldx=(lpc_box.x-lp_bz.x)/lp_bz.width;
    ldy=(lpc_box.y-lp_bz.y)/lp_bz.width;
    rdx=(rpc_box.x-rp_bz.x)/rp_bz.width;
    rdy=(rpc_box.y-rp_bz.y)/rp_bz.width;

    plx=ldx*10+50;
    ply=ldy*10+50;
    Point Lcenter(plx, ply);//瞳孔中心在坐标图中的位置
    pic1=cv::imread("zb.jpg");
    cv::resize(pic1,pic1,Size(100,100));
    circle( pic1, Lcenter, 3, Scalar(255,0,0), -1,8);//画瞳孔中心
    QImage zbimg1=Mat2QImage(pic1);
    ui->label_4->setPixmap(QPixmap::fromImage(zbimg1));
    ui->label_4->setScaledContents(true);

    prx=rdx*10+50;//右眼
    pry=rdy*10+50;
    Point Rcenter(prx, pry);
    pic2=cv::imread("zb1.jpg");
    cv::resize(pic2,pic2,Size(100,100));
    circle( pic2, Rcenter, 3, Scalar(255,0,0), -1,8);
    QImage zbimg2=Mat2QImage(pic2);
    ui->label_5->setPixmap(QPixmap::fromImage(zbimg2));
    ui->label_5->setScaledContents(true);

    ui->lcdNumber->display(ldx);
    ui->lcdNumber_2->display(ldy);
    ui->lcdNumber_4->display(rdx);
    ui->lcdNumber_3->display(rdy);
}


void MainWindow::on_pushButton_5_clicked()//关闭摄像头
{
    Lstop=true;
}

imgprocess.h

#ifndef IMGPROCESS_H
#define IMGPROCESS_H
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include "detectanddisplay.h"


//视频处理类
class ImgProcess
{
    private:
        Mat inimg;//输入图像
        Mat outimg;//输出结果
        Mat Leye;
        Mat Reye;
        Mat Leye_G;
        Mat Reye_G;
        CvRect drawing_box;


    public:
        vector<Vec3f> Lcircles;
        vector<Vec3f> Rcircles;
        ImgProcess(Mat image):inimg(image),drawing_box(cvRect(0, 0, 50, 20)){}
        void EyeDetect();//人眼检测
        Mat Outputimg();//输出结果
        void DivideEye();//分左右眼
        Mat OutLeye();//输出结果
        Mat OutReye();
        Mat EdgeDetect(Mat &edgeimg);//边缘检测
        void EyeEdge();//分别检测左右眼
        vector<Vec3f> Hough(Mat &midImage);//hough变换
        void FindCenter();//定位中心
        Mat PlotC(vector<Vec3f> circles,Mat &midImage);//画HOUGH变换的检测结果
};

#endif // IMGPROCESS_H



imgprocess.cpp
#include "imgprocess.h"

void ImgProcess::EyeDetect()
{
    detectAndDisplay( inimg,drawing_box );
    outimg=inimg;
}

Mat ImgProcess::Outputimg()
{
    return outimg;
}

void ImgProcess::DivideEye()
{
    if (drawing_box.width>0)
    {
        CvRect leye_box;
        leye_box.x=drawing_box.x+1;
        leye_box.y=drawing_box.y+1;
        leye_box.height=drawing_box.height-1;
        leye_box.width=floor(drawing_box.width/2)-1;
        CvRect reye_box;
        reye_box.x=leye_box.x+leye_box.width;
        reye_box.y=drawing_box.y+1;
        reye_box.height=drawing_box.height-1;
        reye_box.width=leye_box.width-1;
        Leye=inimg(leye_box);
        Reye=inimg(reye_box);
//    imshow("L",Leye);
//    imshow("R",Reye);
    }
}

Mat ImgProcess::OutLeye()
{
    return Leye;
}

Mat ImgProcess::OutReye()
{
    return Reye;
}

Mat ImgProcess::EdgeDetect(Mat &edgeimg)
{
    Mat edgeout;
    cvtColor(edgeimg,edgeimg,CV_BGR2GRAY);
    GaussianBlur( edgeimg,edgeimg, Size(9, 9), 2, 2 );
    equalizeHist( edgeimg, edgeimg );
    Canny(edgeimg,edgeout,100,200,3);//输入图像,输出图像,低阈值,高阈值,opencv建议是低阈值的3倍,内部sobel滤波器大小
    return edgeout;
}

void ImgProcess::EyeEdge()
{
    Leye_G=EdgeDetect(Leye);   
    Reye_G=EdgeDetect(Reye);
  //imshow("L",Leye_G);
  //imshow("R",Reye_G);
}

 vector<Vec3f> ImgProcess::Hough(Mat &midImage)
{
    vector<Vec3f> circles;


    HoughCircles( midImage, circles, CV_HOUGH_GRADIENT,1.5, 5, 100, 20, drawing_box.height/4, drawing_box.height/3 );
    return circles;
}

 Mat ImgProcess::PlotC(vector<Vec3f> circles,Mat &midImage)
 {
     for( size_t i = 0; i < circles.size(); i++ )
       {
         Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
         int radius = cvRound(circles[i][2]);
         //cout<<i<<":"<<circles[i][0]<<","<<circles[i][1]<<","<<circles[i][2]<<endl;
         //绘制圆心cvRound进行四舍五入
         circle( midImage, center, 1, Scalar(255,0,0), -1,8);
         //绘制圆轮廓
         circle( midImage, center, radius, Scalar(255,0,0), 1,8 );
       }
     return midImage;
 }
void ImgProcess::FindCenter()
{
    Lcircles=Hough(Leye_G);
    Rcircles=Hough(Reye_G);
    Leye=PlotC(Lcircles,Leye);
    Reye=PlotC(Rcircles,Reye);
}


detectanddisplay.h

#ifndef DETECTANDDISPLAY_H
#define DETECTANDDISPLAY_H
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;

//检测人眼区域
void  detectAndDisplay( Mat &frame,CvRect &box );

#endif // DETECTANDDISPLAY_H


detectanddisplay.cpp
#include "detectanddisplay.h"

void  detectAndDisplay( Mat &frame,CvRect &box )
{
    string face_cascade_name = "haarcascade_mcs_eyepair_big.xml";//导入已经训练完成的样本
    CascadeClassifier face_cascade;//建立分类器
    string window_name = "camera";
    if( !face_cascade.load( face_cascade_name ) ){
        printf("[error] no cascade\n");
    }

    std::vector<Rect> faces;//用于保存检测结果的向量
    Mat frame_gray;

    cvtColor( frame, frame_gray, CV_BGR2GRAY );//转换成灰度图
    equalizeHist( frame_gray, frame_gray );//直方图均值化

    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );//用于检测人眼的函数
    //画方框
    for( int i = 0; i < faces.size(); i++ ){
        Point centera( faces[i].x, faces[i].y);
        Point centerb( faces[i].x + faces[i].width, faces[i].y + faces[i].height );
        rectangle(frame,centera,centerb,Scalar(255,0,0));
        box=faces[0];
    }

    //imshow( window_name, frame );
}


Mat2QImage.h
#ifndef MAT2QIMAGE_H
#define MAT2QIMAGE_H

#include <QtGui>
#include <QDebug>
#include <iostream>
#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace cv;
using namespace std;

QImage Mat2QImage(const Mat&);//mat格式转换为Qimage格式

#endif
Mat2QImage.cpp
#include "Mat2QImage.h"

QImage Mat2QImage(const Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS=1
    if(mat.type()==CV_8UC1)
    {
       // cout<<"1"<<endl;
        // Set the color table (used to translate colour indexes to qRgb values)
        QVector<QRgb> colorTable;
        for (int i=0; i<256; i++)
            colorTable.push_back(qRgb(i,i,i));
        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8);
        img.setColorTable(colorTable);
        return img;
    }
    // 8-bits unsigned, NO. OF CHANNELS=3
    if(mat.type()==CV_8UC3)
    {
       // cout<<"3"<<endl;
        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return img.rgbSwapped();

    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}
main.cpp
#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
test0.pro

#-------------------------------------------------
#
# Project created by QtCreator 2016-03-16T10:24:54
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = test0
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp \
    imgprocess.cpp \
    detectanddisplay.cpp \
    others.cpp \
    Mat2QImage.cpp

HEADERS  += mainwindow.h \
    detectanddisplay.h \
    imgprocess.h \
    others.h \
    Mat2QImage.h

FORMS    += mainwindow.ui
INCLUDEPATH += d:\opencv\build\include\
INCLUDEPATH += d:\opencv\build\include\opencv\
INCLUDEPATH += d:\opencv\build\include\opencv2\

CONFIG(debug,debug|release) {
LIBS += -Ld:\opencv\build\x64\vc12\lib \
    -lopencv_core2410d \
    -lopencv_highgui2410d \
    -lopencv_imgproc2410d \
    -lopencv_features2d2410d \
    -lopencv_calib3d2410d \
    -lopencv_video2410d \
    -lopencv_objdetect2410d
} else {
LIBS += -Ld:\opencv\build\x64\vc12\lib \
    -lopencv_core2410 \
    -lopencv_highgui2410 \
    -lopencv_imgproc2410 \
    -lopencv_features2d2410 \
    -lopencv_calib3d2410 \
    -lopencv_video2410 \
    -lopencv_objdetect2410
}





  • 8
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
随着城市化的快速发展,停车位的紧张程度越来越大。因此,开发一款基于QtOpenCV的停车场管理系统非常有必要。该系统将利用Qt作为用户界面,OpenCV作为图像处理的基础,实现停车场内车辆的自动检测、计数、记录、管理等一系列功能。 首先,车辆检测是基于OpenCV的目标检测技术实现的,可以进行车牌号的读取和车辆的类型分辨。当有车辆进入停车场时,系统会自动识别车辆的证件类型、车辆品牌和车牌号码,并生成车辆进入记录。当车辆离开停车场时,系统会自动识别车辆,同时查询车辆停放的时间和费用,生成相应的账单。 其次,该系统可以根据停车位的可用情况和停车区域的拥挤程度,为车主提供一系列方便易用的功能。车主可以通过智能手机或者电脑网页来实时地查看停车位的占用比例以及停车场的拥挤程度,以便选择更合适的停车位。同时,停车场管理员可以通过电脑来管理和查看停车位的使用情况,以便进行进一步的优化和调整。 最后,该系统具有良好的安全性和可靠性,利用的是先进的图像处理技术和车辆识别技术,可以保证车辆进出停车场的准确性、安全性和便捷性。该系统还支持多种语言和多种格式,可以满足不同国家和地区的需求。 总之,基于QtOpenCV的停车场管理系统是一款高效、智能、安全和可靠的系统,它可以为车主和停车场管理员提供便捷的服务,同时可以缓解城市停车位紧张的问题,解决城市交通拥堵的难题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值