图像识别(12)——LED灯光点捕获+基于QT平台绘制轨迹(2)

博主QQ:1356438802

QQ群:473383394——UVC&OpenCV473383394


平台:Win7 64bits + Qt 5.3.0 MinGW 32bit + OpenCV 2.4.10



1. 虽然在Windows64系统上运行,图像分析的帧率可以达到25FPM,但是如果做平均值滤波,手写笔运动速度较快时,首先会导致时间延迟, 滞后现象,另外滤波后导致采样点数量减少,最终绘制的轨迹不圆滑,呈线段型。


2. 鉴于人类视觉延迟要求大概就是25FPM,而且25FPM可能就是该摄像头的输出帧率,所以在捕捉到LED灯光点坐标后,进行滤波消除抖动的做法,并不可行!暂时思考后的解决办法是:


a. 改进硬件。当前实验使用是手机的闪光灯,有散光和手机外壳反射光的干扰,排除这些干扰,让LED灯的捕捉检测更加准确。另外还要求红外LED灯的各个方向一致性,因为在手写笔书写过程中,LED灯可能是倾斜的,对于图像识别会有影响,可以包裹漫反射材料解决。


b. 软件算法进行类滤波处理。使用OpenCV中的图像模糊算法,对光点坐标集进行平滑处理,再给QT绘制!
但是这样的处理会导致整个绘制过程相比于手写笔的操作,整体滞后很多,估计印象的投影仪效果就是这样导致的。


下面是增加了平均值滤波的代码

mainwindow.cpp

#include 
#include 
#include 

#include "cfg.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    mIsFirstPoint = true;
    mCenterPoint = mPrevCenterPoint = QPointF(0.0, 0.0);
    mPointsBuffer.clear();
    mLines.clear();

    //把LED灯追踪放入一个子线程里面运行
    mTracker = new Track();
    mTrackThread = new QThread(this);
    mTracker->moveToThread(mTrackThread);

    connect(this, SIGNAL(startTrack()), mTracker, SLOT(startTrack()));
    connect(mTracker, SIGNAL(TrackPoint(QPointF)), this, SLOT(setPoints(QPointF)));
    connect(mTracker, SIGNAL(errnum(int)), this, SLOT(errProc(int)));

    mTrackThread->start();

}

MainWindow::~MainWindow()
{
    //停止图像识别
    mTracker->StopTrack();

    //结束线程
    mTrackThread->quit();
    mTrackThread->wait();

    delete mTrackThread;
    delete mTracker;

    mPointsBuffer.empty();
    mLines.empty();

    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);

    // 反走样 反锯齿
    painter.setRenderHint(QPainter::Antialiasing, true);

    QPen pen(QColor(0, 160, 230));
    pen.setWidth(4);

    // 设置画笔
    painter.setPen(pen);


    // 绘制所有直线
    foreach (QLineF line, mLines)
    {
        painter.drawLine(line);
    }


}



void MainWindow::setPoints(QPointF Point)
{

    // 先将捕捉到的点坐标,存入缓冲区,待处理
    mPointsBuffer.append(Point);

    // ##滤波后轨迹不平滑
    // 在缓冲区中进行--平均值滤波
    // 滤波区间宽度取决于帧率(Windows64上帧率大概为25)。
    const int WIDE = 2;
    if(mPointsBuffer.size() >= WIDE)
    {
        qreal xpos = 0.0, ypos = 0.0;
        foreach (QPointF point, mPointsBuffer)
        {
            xpos += point.x();
            ypos += point.y();
        }

        qDebug() <<"mPointsBuffer.size() = " << mPointsBuffer.size();
        qDebug() <<"xpos = " << xpos << " ypos = " << ypos;

        // 求x/y的平均值
        mCenterPoint = QPointF(xpos / mPointsBuffer.size(), ypos / mPointsBuffer.size());


        qDebug() << "===========mCenterPoint: x = " << mCenterPoint.x() << " y = " << mCenterPoint.y();

        if(true == mIsFirstPoint)
        {
            mPrevCenterPoint = mCenterPoint;
            mIsFirstPoint = false;
        }

        // 将线段(两点构成一条线段)压入队列,待绘制
        mLines.append(QLineF(mPrevCenterPoint, mCenterPoint));

        // 保存当前点坐标,待下次使用
        mPrevCenterPoint = mCenterPoint;

        mPointsBuffer.clear();      //清空缓冲区

        // 开始重绘
        update();
    }


}

void MainWindow::errProc(int err)
{
    if(CFG::CAMERA_OPEN_FAILED == err)
    {
        QMessageBox::warning(this, "警告", "摄像头打开失败");
    }
}

void MainWindow::on_btnStartTrack_clicked()
{
    emit startTrack();
}

void MainWindow::on_btnClear_clicked()
{
    mLines.clear();
    mIsFirstPoint = true;

    update();
}


完整源码打包下载:

LED_track-20170210.rar



特别补充:

==========20170217==========
1. 实验用的Camera参数:FPS=30; width=640; height=480;
2. 按照[20170210]2.b想法,对捕捉到的LED灯光点坐标,进行OpenCV中的图像平滑算法blur。经过实验,平滑区间设置为16或者8,对于正常的书写速度都不合适,会导致轨迹绘制呈现一阵一阵的阶段性绘制;设置为4,勉强接受;设置为1,也差不多!
3. 总结来说:由于摄像头帧率和图像处理速度的限制,每秒只有25个采样点坐标,这时再进行滤波平滑处理,就会导致轨迹绘制滞后。相比绘制轨迹不平滑有毛刺来说,轨迹绘制滞后的用户体验更差!
4. 所以唯一的办法就是改进硬件,提高LED灯光点的识别准确率!







你可能感兴趣的:(openCV,图像识别)