Qt OpenCV 快速角点校测

#ifndef IMAGEPROC_H
#define IMAGEPROC_H
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <QImage>
#include <QThread>
#include <iostream>
#include "BadPointDetector.h"
#include <QPoint>
using namespace cv;
class ImageProc: public QObject
{
    Q_OBJECT

public:

    ImageProc();

    void readImg();

    void readImg(QString imgPath, QImage &desImg, QImage::Format format);

    QImage mat2qimage_ref(cv::Mat &m, QImage::Format format);

    QImage mat2qimage_cpy(cv::Mat &m, QImage::Format format);


signals:

   void sig_frameStream(QImage);
   void sig_keyPoints(std::vector<QPoint>);

public slots:
    void slot_openCamera();  // 打开本地摄像头 0

    void slot_closeCamera();

private:
    std::vector<cv::KeyPoint> m_keyPoints;
    cv::VideoCapture m_camera;
    BadPointDetector m_badPointDetector;
    bool m_videoState;

};

#endif // IMAGEPROC_H

#include "ImageProc.h"
#include "opencv2/imgproc.hpp"
#include <QDebug>

ImageProc::ImageProc()
{

}

void ImageProc::readImg()
{
    cv::Mat srcImage;
    srcImage = imread("D:\\code\\TestOpenCV\\iamge\\m2.jpeg", IMREAD_COLOR);
    if (srcImage.empty()) {
        return;
    }
    namedWindow("orginalimage", WINDOW_AUTOSIZE);
    imshow("orginal image", srcImage);

    // Shallow copy

    // Shallow copy
}

void ImageProc::readImg(QString imgPath, QImage &desImg, QImage::Format format)
{
    cv::Mat srcImage;
    srcImage = imread(imgPath.toStdString(), IMREAD_COLOR);
    desImg = mat2qimage_cpy(srcImage, format);
}

// 线程单独读取数据
void ImageProc::slot_openCamera()
{
    cv::VideoCapture m_camera(0);
    if (true == m_camera.isOpened()) {
        m_videoState = true;
        while (m_videoState) {
            cv::Mat frame;
            //qDebug() << "capture one frame." << "current thread id=" << QThread::currentThreadId();
            m_camera >> frame;

            // 检测角点坐标列表
            m_badPointDetector.getFastFeatureDetector(frame, 20, m_keyPoints);

            std::vector<QPoint> tmpPoints;
            foreach (cv::KeyPoint it, m_keyPoints) {
               tmpPoints.push_back(QPoint(it.pt.x, it.pt.y));
            }

            emit sig_keyPoints(tmpPoints);

            // 发送到界面
            emit sig_frameStream(mat2qimage_cpy(frame, QImage::Format_RGB888));
       }
    }
}

void ImageProc::slot_closeCamera()
{
    m_camera.release();
    m_videoState = false;


    qDebug() << "close camera";

    return;
}

QImage ImageProc::mat2qimage_ref(cv::Mat &m, QImage::Format format)
{
    return QImage(m.data, m.cols, m.rows, (int)m.step, format);
}

// Deep copy
QImage ImageProc::mat2qimage_cpy(cv::Mat &m, QImage::Format format)
{
    cv::cvtColor(m, m, COLOR_BGR2RGB);  // cv 默认图像格式 BGR,不然显示颜色顺序不对

    return QImage(m.data, m.cols, m.rows, (int)m.step, format).copy();
}



#ifndef BADPOINTDETECTOR_H
#define BADPOINTDETECTOR_H
#include <opencv2\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\features2d.hpp>
#include <string.h>
#include <QImage>
#include <QObject>
#include <iostream>
using namespace std;

class BadPointDetector: public QObject
{
    Q_OBJECT

public:
    BadPointDetector();

//    int getCornerPosList(cv::Mat&, cv::Point2d&);

    bool loadSrcImage(const string &name);

    bool loadSrcImage(const cv::Mat m);

    void setThreshold(double threshold, double high);  // 对外用户调参接口。控制角点检测准确性

    cv::Mat getDstImage();

    cv::Mat getDstImageByCanny(double low , double high);

    void getFastFeatureDetector(cv::Mat srcImg, int ketPoints, std::vector<cv::KeyPoint> &keypoints);

    std::vector<QPoint> getKeyPoints();     // 获取检测角点

signals:
    void sig_updateImg(QImage newFrame);    //更新界面窗口显示的图像需要的数据

private:
    cv::Mat m_srcImage;
    cv::Mat m_dstImage;
    double m_threshold;
};

#endif // BADPOINTDETECTOR_H

#include "BadPointDetector.h"
#include <QDebug>

BadPointDetector::BadPointDetector()
{
    cv::Mat image1= cv::imread("D:/code/TestOpenCV/images/myImage/color2.jpg", cv::IMREAD_GRAYSCALE);
   // cv::Mat image1= cv::imread("D:/code/TestOpenCV/images/images/church02.jpg", cv::IMREAD_GRAYSCALE);

    m_srcImage = image1;
   // cv::namedWindow("SRC_IMAGE");
   // cv::imshow("SRC_IMAGE", image1);
    QImage newImg(m_srcImage.cols, m_srcImage.rows, QImage::Format_Indexed8);
    emit sig_updateImg(newImg);

    cv::Mat cornerStrength;
    cv::cornerHarris(image1,
                     cornerStrength,
                     3,
                     3,
                     0.001);

    cv::Mat harrisCorners;  //角点强度图像
//    double threshold = 0.001;
    double threshold = 100;
    cv::threshold(cornerStrength,
                  harrisCorners,
                  threshold,
                  255,
                  cv::THRESH_BINARY_INV);

   // cv::namedWindow("harrisCorner");
    //cv::imshow("harrisCorner", cornerStrength);
}

//int BadPointDetector::getCornerPosList(cv::Mat &srcImg, cv::Point2d &posLits)
//{
//    if (!loadSrcImage(srcImg)) {

//        return -1;
//    }

//    getDstImage();

//    return 0;
//}

bool BadPointDetector::loadSrcImage(const string &name)
{
    m_srcImage = cv::imread((name), 0);

    if (!m_srcImage.data) {
        return false;
    }

    return true;
}

//bool BadPointDetector::loadSrcImage(const cv::Mat m)
//{
//    if (m.data == nullptr) {
//        return false;
//    }

//    m_srcImage = m;
//    return true;
//}

void BadPointDetector::setThreshold(double threshold , double high)
{
    qDebug() <<"srcImageSize=" <<*m_srcImage.size <<"threshold=" << threshold;
    if (!*m_srcImage.size || threshold==NULL) {
        return;
    }

    m_threshold = threshold;

    qDebug() << "threshold = "<< m_threshold;

    cv::Mat dstCVImg = getDstImageByCanny(threshold, high);
    QImage qimage(dstCVImg.cols, dstCVImg.rows, QImage::Format_Grayscale8);
    emit sig_updateImg(qimage);
}

cv::Mat BadPointDetector::getDstImage()
{
    cv::Mat cornerStrength;
    cv::cornerHarris(m_srcImage,        // 必须是单通道的图像
                     cornerStrength,
                     3,
                     3,
                     0.004);    //经验参数,取值范围 0.04 ~ 0.06

    cv::threshold(cornerStrength,
                  m_dstImage,
                  m_threshold,
                  255,
                  cv::THRESH_BINARY_INV);

    return m_dstImage;
}

cv::Mat BadPointDetector::getDstImageByCanny(double low , double high)
{
    cv::Canny(m_srcImage, // 灰度图像
     m_dstImage, // 输出轮廓
     low, // 低阈值
     high); // 高阈值

    return m_dstImage;
}

void BadPointDetector::getFastFeatureDetector(cv::Mat srcImg, int ketPoints, std::vector<cv::KeyPoint> &keypoints)
{
    m_srcImage = srcImg;
    // FAST 特征检测器,阈值为 40
    cv::Ptr<cv::FastFeatureDetector> ptrFAST = cv::FastFeatureDetector::create(ketPoints);
    // 检测关键点
    ptrFAST->detect(m_srcImage, keypoints);

    cv::drawKeypoints(m_srcImage, // 原始图像
                      keypoints, // 关键点的向量
                      m_srcImage, // 输出图像
                      cv::Scalar(255,255,255), // 关键点的颜色
                      cv::DrawMatchesFlags::DRAW_OVER_OUTIMG); // 画图标志
}


界面

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QTimer>
#include <QPainter>
#include "BadPointDetector.h"
#include "ImageProc.h"
#include "PointsForm.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void sig_openCamera();
    void sig_closeCamera();

private slots:
    void on_pushButtonOpen_clicked();

    void slot_showImg(QImage img);

    void slot_changeThreshold();

    void slot_showKeyPoint(std::vector<QPoint>);

    void on_pushButtonShowPoints_clicked();

private:
    Ui::MainWindow *ui;

    ImageProc *m_imgProc;
    QThread *m_videoReadThd;
    QTimer m;
    BadPointDetector m_badPointDetector;
    QPixmap m_labelPixMap;
    PointsForm m_pointsTable;
};
#endif // MAINWINDOW_H

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->pushButtonOpen->setText("open");
    m_videoReadThd = new QThread;
    m_imgProc = new ImageProc;
    m_imgProc->moveToThread(m_videoReadThd);
    m_videoReadThd->start();

    connect(this, &MainWindow::sig_openCamera, m_imgProc, &ImageProc::slot_openCamera);
    connect(this, &MainWindow::sig_closeCamera, m_imgProc, &ImageProc::slot_closeCamera);
    connect(m_imgProc, &ImageProc::sig_frameStream, this, &MainWindow::slot_showImg);
    connect(ui->lineEditThreshold, &QLineEdit::editingFinished, this, &MainWindow::slot_changeThreshold);
    connect(&m_badPointDetector, &BadPointDetector::sig_updateImg, this, &MainWindow::slot_showImg);
    connect(m_imgProc, &ImageProc::sig_keyPoints, this, &MainWindow::slot_showKeyPoint);
}

MainWindow::~MainWindow()
{
    delete ui;
    m_imgProc->deleteLater();
}

void MainWindow::on_pushButtonOpen_clicked()
{
    // 打开camnera 设备
   if (ui->pushButtonOpen->text() == "open") {
       ui->pushButtonOpen->setText("close");        // 必须使用信号启动
       emit sig_openCamera();
   }
   else if (ui->pushButtonOpen->text() == "close") {             // close camera
        ui->pushButtonOpen->setText("open");
//      m_imgProc->slot_closeCamera();
        emit sig_closeCamera();
   }
}

void MainWindow::slot_showImg(QImage img)
{
    m_labelPixMap.convertFromImage(img);
    ui->labelImg->setPixmap(m_labelPixMap);
}

void MainWindow::slot_changeThreshold()
{
    qDebug() << "change threshold.";
    double thresholdTmp = (ui->lineEditThreshold->text()).toDouble();
    m_badPointDetector.setThreshold(thresholdTmp, ui->lineEditThresholdHigh->text().toDouble());
}

void MainWindow::slot_showKeyPoint(std::vector<QPoint> points)
{
    //在 table 展示坐标
    QAction act;
    act.data() = 0;

    m_pointsTable.addAction(&act);
}


void MainWindow::on_pushButtonShowPoints_clicked()
{
    m_pointsTable.show();
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值